TensorFlow.js działa w przeglądarce oraz w Node.js, a na obu platformach dostępnych jest wiele różnych konfiguracji. Każda platforma ma unikalny zestaw czynników, które będą miały wpływ na sposób tworzenia aplikacji.
W przeglądarce TensorFlow.js obsługuje urządzenia mobilne, a także urządzenia stacjonarne. Każde urządzenie ma określony zestaw ograniczeń, takich jak dostępne interfejsy API WebGL, które są automatycznie określane i konfigurowane.
W Node.js TensorFlow.js obsługuje wiązanie bezpośrednio z interfejsem API TensorFlow lub działanie z wolniejszymi implementacjami procesora waniliowego.
Środowiska
Kiedy wykonywany jest program TensorFlow.js, konkretna konfiguracja nazywana jest środowiskiem. Środowisko składa się z pojedynczego globalnego backendu oraz zestawu flag kontrolujących szczegółowe funkcje TensorFlow.js.
Backendy
TensorFlow.js obsługuje wiele różnych backendów, które implementują przechowywanie tensorów i operacje matematyczne. W danym momencie aktywny jest tylko jeden backend. W większości przypadków TensorFlow.js automatycznie wybierze najlepszy dla Ciebie backend, biorąc pod uwagę bieżące środowisko. Czasami jednak ważne jest, aby wiedzieć, który backend jest używany i jak go przełączyć.
Aby dowiedzieć się, jakiego backendu używasz:
console.log(tf.getBackend());
Jeśli chcesz ręcznie zmienić backend:
tf.setBackend('cpu');
console.log(tf.getBackend());
Zaplecze WebGL
Backend WebGL, „webgl”, jest obecnie najpotężniejszym backendem dla przeglądarki. Ten backend jest do 100 razy szybszy niż podstawowy backend procesora. Tensory są przechowywane jako tekstury WebGL, a operacje matematyczne są implementowane w shaderach WebGL. Oto kilka przydatnych rzeczy, które warto wiedzieć podczas korzystania z tego backendu: \
Unikaj blokowania wątku interfejsu użytkownika
Po wywołaniu operacji, takiej jak tf.matMul(a, b), wynikowy tf.Tensor jest zwracany synchronicznie, jednak obliczenia mnożenia macierzy mogą jeszcze nie być gotowe. Oznacza to, że zwrócony tf.Tensor jest jedynie uchwytem obliczenia. Kiedy wywołasz x.data()
lub x.array()
, wartości zostaną rozpoznane po faktycznym zakończeniu obliczeń. Dlatego ważne jest, aby używać asynchronicznych x.data()
i x.array()
zamiast ich synchronicznych odpowiedników x.dataSync()
i x.arraySync()
aby uniknąć blokowania wątku interfejsu użytkownika po zakończeniu obliczeń.
Zarządzanie pamięcią
Jedynym zastrzeżeniem podczas korzystania z zaplecza WebGL jest potrzeba jawnego zarządzania pamięcią. Tekstury WebGL, w których ostatecznie przechowywane są dane Tensora, nie są automatycznie usuwane przez przeglądarkę.
Aby zniszczyć pamięć tf.Tensor
, możesz użyć metody dispose()
:
const a = tf.tensor([[1, 2], [3, 4]]);
a.dispose();
Bardzo często zdarza się, że w aplikacji łączy się wiele operacji. Trzymanie odniesienia do wszystkich zmiennych pośrednich w celu ich usunięcia może zmniejszyć czytelność kodu. Aby rozwiązać ten problem, TensorFlow.js udostępnia metodę tf.tidy()
, która czyści wszystkie tf.Tensor
, które nie są zwracane przez funkcję po jej wykonaniu, podobnie jak zmienne lokalne są czyszczone podczas wykonywania funkcji:
const a = tf.tensor([[1, 2], [3, 4]]);
const y = tf.tidy(() => {
const result = a.square().log().neg();
return result;
});
Precyzja
Na urządzeniach mobilnych WebGL może obsługiwać tylko 16-bitowe tekstury zmiennoprzecinkowe. Jednak większość modeli uczenia maszynowego jest szkolona przy użyciu 32-bitowych wag zmiennoprzecinkowych i aktywacji. Może to powodować problemy z precyzją podczas przenoszenia modelu na urządzenie mobilne, ponieważ 16-bitowe liczby zmiennoprzecinkowe mogą reprezentować tylko liczby z zakresu [0.000000059605, 65504]
. Oznacza to, że należy uważać, aby wagi i aktywacje w Twoim modelu nie przekraczały tego zakresu. Aby sprawdzić, czy urządzenie obsługuje tekstury 32-bitowe, sprawdź wartość tf.ENV.getBool('WEBGL_RENDER_FLOAT32_CAPABLE')
. Jeśli ma wartość false, urządzenie obsługuje tylko 16-bitowe tekstury zmiennoprzecinkowe. Możesz użyć tf.ENV.getBool('WEBGL_RENDER_FLOAT32_ENABLED')
aby sprawdzić, czy TensorFlow.js używa obecnie tekstur 32-bitowych.
Kompilacja shaderów i przesyłanie tekstur
TensorFlow.js wykonuje operacje na GPU, uruchamiając programy cieniujące WebGL. Te moduły cieniujące są składane i kompilowane leniwie, gdy użytkownik prosi o wykonanie operacji. Kompilacja modułu cieniującego odbywa się na procesorze w głównym wątku i może być powolna. TensorFlow.js automatycznie buforuje skompilowane shadery, dzięki czemu drugie wywołanie tej samej operacji z tensorami wejściowymi i wyjściowymi o tym samym kształcie jest znacznie szybsze. Zazwyczaj aplikacje TensorFlow.js będą używać tych samych operacji wiele razy w okresie istnienia aplikacji, więc drugie przejście przez model uczenia maszynowego jest znacznie szybsze.
TensorFlow.js przechowuje również dane tf.Tensor jako WebGLTextures. Kiedy tf.Tensor
jest tworzony, nie przesyłamy od razu danych do GPU, raczej przechowujemy dane w procesorze do czasu użycia tf.Tensor
w operacji. Jeśli tf.Tensor
zostanie użyty po raz drugi, dane znajdują się już na GPU, więc nie ma żadnych kosztów przesyłania. W typowym modelu uczenia maszynowego oznacza to, że wagi są przesyłane podczas pierwszego przewidywania przez model, a drugie przejście przez model będzie znacznie szybsze.
Jeśli zależy Ci na wydajności pierwszej predykcji za pomocą modelu lub kodu TensorFlow.js, zalecamy rozgrzanie modelu poprzez przekazanie Tensora wejściowego o tym samym kształcie przed użyciem rzeczywistych danych.
Na przykład:
const model = await tf.loadLayersModel(modelUrl);
// Warmup the model before using real data.
const warmupResult = model.predict(tf.zeros(inputShape));
warmupResult.dataSync();
warmupResult.dispose();
// The second predict() will be much faster
const result = model.predict(userData);
Backend Node.js TensorFlow
W backendie TensorFlow Node.js, „węźle”, interfejs API TensorFlow C służy do przyspieszania operacji. Spowoduje to wykorzystanie dostępnej akceleracji sprzętowej komputera, takiej jak CUDA, jeśli jest dostępna.
W tym backendie, podobnie jak w WebGL, operacje zwracają synchronicznie tf.Tensor
s. Jednakże, w przeciwieństwie do backendu WebGL, operacja jest zakończona zanim odzyskasz tensor. Oznacza to, że wywołanie tf.matMul(a, b)
zablokuje wątek interfejsu użytkownika.
Z tego powodu, jeśli zamierzasz używać tego w aplikacji produkcyjnej, powinieneś uruchomić TensorFlow.js w wątkach roboczych, aby nie blokować głównego wątku.
Więcej informacji na temat Node.js znajdziesz w tym przewodniku.
Zaplecze WASM
TensorFlow.js zapewnia backend WebAssembly ( wasm
), który oferuje przyspieszenie procesora i może być używany jako alternatywa dla standardowych backendów JavaScript CPU ( cpu
) i akcelerowanych przez WebGL ( webgl
). Aby z niego skorzystać:
// Set the backend to WASM and wait for the module to be ready.
tf.setBackend('wasm');
tf.ready().then(() => {...});
Jeśli Twój serwer udostępnia plik .wasm
w innej ścieżce lub pod inną nazwą, użyj setWasmPath
przed zainicjowaniem backendu. Więcej informacji znajdziesz w sekcji „Korzystanie z programów pakujących” w pliku README:
import {setWasmPath} from '@tensorflow/tfjs-backend-wasm';
setWasmPath(yourCustomPath);
tf.setBackend('wasm');
tf.ready().then(() => {...});
Dlaczego WASM?
WASM został wprowadzony w 2015 roku jako nowy internetowy format binarny, zapewniający programy napisane w JavaScript, C, C++ itp. jako cel kompilacji do działania w Internecie. WASM jest obsługiwany przez przeglądarki Chrome, Safari, Firefox i Edge od 2017 roku i jest obsługiwany przez 90% urządzeń na całym świecie.
Wydajność
Backend WASM wykorzystuje bibliotekę XNNPACK do zoptymalizowanej implementacji operatorów sieci neuronowych.
W porównaniu z JavaScriptem : pliki binarne WASM są na ogół znacznie szybsze niż pakiety JavaScript, jeśli chodzi o ładowanie, analizowanie i wykonywanie przez przeglądarki. JavaScript jest wpisywany dynamicznie i zbierane są śmieci, co może powodować spowolnienie w czasie wykonywania.
Kontra WebGL : WebGL jest szybszy niż WASM w przypadku większości modeli, ale w przypadku małych modeli WASM może przewyższać WebGL ze względu na stałe koszty ogólne wykonywania shaderów WebGL. W poniższej sekcji „Kiedy powinienem używać WASM” omówiono heurystyki potrzebne do podejmowania tej decyzji.
Przenośność i stabilność
WASM posiada przenośną 32-bitową arytmetykę zmiennoprzecinkową, oferującą precyzyjną parzystość na wszystkich urządzeniach. Z drugiej strony WebGL jest specyficzne dla sprzętu i różne urządzenia mogą mieć różną precyzję (np. powrót do 16-bitowych wersji zmiennoprzecinkowych na urządzeniach z systemem iOS).
Podobnie jak WebGL, WASM jest oficjalnie obsługiwany przez wszystkie główne przeglądarki. W przeciwieństwie do WebGL, WASM może działać w Node.js i być używany po stronie serwera bez konieczności kompilowania bibliotek natywnych.
Kiedy powinienem stosować WASM?
Rozmiar modelu i wymagania obliczeniowe
Ogólnie WASM jest dobrym wyborem, gdy modele są mniejsze lub zależy Ci na urządzeniach z niższej półki, które nie obsługują WebGL (rozszerzenie OES_texture_float
) lub mają słabsze procesory graficzne. Poniższy wykres przedstawia czasy wnioskowania (od wersji TensorFlow.js 1.5.2) w przeglądarce Chrome na MacBooku Pro 2018 dla 5 naszych oficjalnie obsługiwanych modeli z backendami WebGL, WASM i CPU:
Mniejsze modele
Model | WebGL | WASM | Procesor | Pamięć |
---|---|---|---|---|
BlazeFace | 22,5 ms | 15,6 ms | 315,2 ms | 0,4 MB |
FaceMesh | 19,3 ms | 19,2 ms | 335 ms | 2,8MB |
Większe modele
Model | WebGL | WASM | Procesor | Pamięć |
---|---|---|---|---|
PoseNet | 42,5 ms | 173,9 ms | 1514,7 ms | 4,5MB |
BodyPix | 77 ms | 188,4 ms | 2683 ms | 4,6MB |
Sieć komórkowa v2 | 37 ms | 94 ms | 923,6 ms | 13 MB |
Powyższa tabela pokazuje, że WASM jest 10-30 razy szybszy niż zwykły backend procesora JS w różnych modelach i konkurencyjny z WebGL w przypadku mniejszych modeli, takich jak BlazeFace , który jest lekki (400 KB), ale ma przyzwoitą liczbę operacji (~140). Biorąc pod uwagę, że programy WebGL mają stały koszt wykonania operacji, wyjaśnia to, dlaczego modele takie jak BlazeFace są szybsze w WASM.
Wyniki te będą się różnić w zależności od urządzenia. Najlepszym sposobem ustalenia, czy WASM jest odpowiedni dla Twojej aplikacji, jest przetestowanie go na naszych różnych backendach.
Wnioskowanie a szkolenie
Aby uwzględnić główny przypadek użycia dotyczący wdrażania wstępnie wyszkolonych modeli, rozwój zaplecza WASM będzie priorytetem dla wnioskowania przed wsparciem szkoleniowym . Zobacz aktualną listę obsługiwanych operacji w WASM i daj nam znać, jeśli Twój model ma nieobsługiwaną operację. W przypadku modeli szkoleniowych zalecamy użycie zaplecza Node (TensorFlow C++) lub zaplecza WebGL.
Zaplecze procesora
Backend procesora, „cpu”, jest najmniej wydajnym, aczkolwiek najprostszym backendem. Wszystkie operacje są zaimplementowane w waniliowym JavaScript, co sprawia, że są mniej równoległe. Blokują także wątek interfejsu użytkownika.
Ten backend może być bardzo przydatny do testowania lub na urządzeniach, na których WebGL jest niedostępny.
Flagi
TensorFlow.js posiada zestaw flag środowiskowych, które są automatycznie oceniane i określają najlepszą konfigurację na bieżącej platformie. Flagi te są przeważnie wewnętrzne, ale kilkoma flagami globalnymi można sterować za pomocą publicznego interfejsu API.
-
tf.enableProdMode():
włącza tryb produkcyjny, który usuwa walidację modelu, kontrole NaN i inne kontrole poprawności na korzyść wydajności. -
tf.enableDebugMode()
: włącza tryb debugowania, który rejestruje w konsoli każdą wykonaną operację, a także informacje o wydajności w czasie wykonywania, takie jak zużycie pamięci i całkowity czas wykonania jądra. Pamiętaj, że spowoduje to znaczne spowolnienie aplikacji. Nie używaj tego w środowisku produkcyjnym.