TensorFlow.js działa w przeglądarce i Node.js, a na obu platformach dostępnych jest wiele różnych konfiguracji. Każda platforma ma unikalny zestaw zagadnień, 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 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 jednego globalnego backendu oraz zestawu flag, które kontrolują szczegółowe funkcje TensorFlow.js.
Zaplecze
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 dla Ciebie najlepszy backend w aktualnym środowisku. Czasami jednak ważne jest, aby wiedzieć, który backend jest używany i jak go zmienić.
Aby dowiedzieć się, którego 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ż backend waniliowego procesora. Tensory są przechowywane jako tekstury WebGL, a operacje matematyczne są implementowane w shaderach WebGL. Oto kilka przydatnych rzeczy, o których należy wiedzieć podczas korzystania z tego backendu: \
Unikaj blokowania wątku interfejsu użytkownika
Gdy wywoływana jest operacja, taka jak tf.matMul(a, b), wynikowy tf.Tensor jest zwracany synchronicznie, jednak obliczenie mnożenia macierzy może nie być jeszcze gotowe. Oznacza to, że zwrócony tf.Tensor jest tylko uchwytem do obliczeń. Gdy wywołasz x.data()
lub x.array()
, wartości zostaną rozwiązane po faktycznym zakończeniu obliczeń. Dlatego ważne jest, aby używać asynchronicznych x.data()
i x.array()
ich synchronicznych odpowiedników x.dataSync()
i x.arraySync()
, aby uniknąć blokowania wątku interfejsu użytkownika podczas wykonywania obliczeń.
Zarządzanie pamięcią
Jedynym zastrzeżeniem przy korzystaniu z backendu WebGL jest potrzeba jawnego zarządzania pamięcią. WebGLTextures, w którym ostatecznie przechowywane są dane Tensora, nie są automatycznie zbierane 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 łączy się wiele operacji w jednej aplikacji. Posiadanie odwołania do wszystkich zmiennych pośrednich w celu ich usunięcia może zmniejszyć czytelność kodu. Aby rozwiązać ten problem, TensorFlow.js udostępnia tf.tidy()
, która czyści wszystkie tf.Tensor
, które nie są zwracane przez funkcję po jej wykonaniu, podobnie jak czyszczone są zmienne lokalne 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 trenowana z 32-bitowymi wagami zmiennoprzecinkowymi i aktywacjami. 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 ciężary 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 jest to fałsz, 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 32-bitowych tekstur.
Kompilacja shaderów i przesyłanie tekstur
TensorFlow.js wykonuje operacje na GPU, uruchamiając programy do cieniowania WebGL. Te shadery 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 będzie 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. Gdy tf.Tensor
jest tworzony, nie przesyłamy danych od razu do GPU, ale przechowujemy dane na procesorze do momentu tf.Tensor
w operacji. Jeśli tf.Tensor
zostanie użyty po raz drugi, dane znajdują się już na GPU, więc nie ma kosztów przesyłania. W typowym modelu uczenia maszynowego oznacza to, że wagi są przesyłane podczas pierwszej prognozy przez model, a drugie przejście przez model będzie znacznie szybsze.
Jeśli zależy Ci na wydajności pierwszej prognozy za pośrednictwem Twojego modelu lub kodu TensorFlow.js, zalecamy rozgrzanie modelu przez przekazanie wejściowego Tensora 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 backendzie TensorFlow Node.js, 'node', TensorFlow C API służy do przyspieszania operacji. Spowoduje to użycie dostępnej akceleracji sprzętowej maszyny, takiej jak CUDA, jeśli jest dostępna.
W tym zapleczu, podobnie jak zapleczu WebGL, operacje zwracają tf.Tensor
s synchronicznie. Jednak w przeciwieństwie do backendu WebGL, operacja jest zakończona przed odzyskaniem tensora. Oznacza to, że wywołanie tf.matMul(a, b)
zablokuje wątek interfejsu użytkownika.
Z tego powodu, jeśli zamierzasz użyć tego w aplikacji produkcyjnej, powinieneś uruchomić TensorFlow.js w wątkach roboczych, aby nie blokować głównego wątku.
Więcej informacji o Node.js znajdziesz w tym przewodniku.
Zaplecze WASM
TensorFlow.js zapewnia backend WebAssembly ( wasm
), który oferuje akcelerację procesora i może być używany jako alternatywa dla backendów vanilla JavaScript CPU ( cpu
) i 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 serwer obsługuje plik .wasm
w innej ścieżce lub pod inną nazwą, użyj setWasmPath
przed zainicjowaniem backendu. Więcej informacji znajdziesz w sekcji „Korzystanie z pakietów” 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 uruchamiania w sieci. WASM jest obsługiwany przez 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 JavaScript : pliki binarne WASM są zazwyczaj znacznie szybsze niż pakiety JavaScript, aby przeglądarki ładowały, analizowały i wykonywały. JavaScript jest wpisywany dynamicznie i zbierane są śmieci, które mogą powodować spowolnienia w czasie wykonywania.
W porównaniu z 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 modułów cieniujących WebGL. Poniższa sekcja „Kiedy powinienem użyć WASM” omawia heurystykę przy podejmowaniu tej decyzji.
Przenośność i stabilność
WASM ma przenośną 32-bitową arytmetykę zmiennoprzecinkową, oferując precyzyjną parzystość na wszystkich urządzeniach. Z drugiej strony, WebGL jest specyficzny dla sprzętu, a różne urządzenia mogą mieć różną precyzję (np. powrót do 16-bitowych pływaków 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 używać WASM?
Rozmiar modelu i zapotrzebowanie obliczeniowe
Ogólnie rzecz biorąc, WASM jest dobrym wyborem, gdy modele są mniejsze lub zależy Ci na niższych urządzeniach, które nie obsługują WebGL (rozszerzenie OES_texture_float
) lub mają słabsze GPU. Poniższy wykres pokazuje czasy wnioskowania (od TensorFlow.js 1.5.2) w Chrome na MacBooku Pro 2018 dla 5 naszych oficjalnie obsługiwanych modeli w backendach WebGL, WASM i CPU:
Mniejsze modele
Model | WebGL | BYŁ M | procesor | Pamięć |
---|---|---|---|---|
BlazeTwarz | 22,5 ms | 15,6 ms | 315,2 ms | .4 MB |
FaceMesh | 19,3 ms | 19,2 ms | 335 ms | 2,8 MB |
Większe modele
Model | WebGL | BYŁ M | procesor | Pamięć |
---|---|---|---|---|
PoseNet | 42,5 ms | 173,9 ms | 1514,7 ms | 4,5 MB |
BodyPix | 77 ms | 188,4 ms | 2683 ms | 4,6 MB |
MobileNet 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 JS CPU we wszystkich modelach i konkurencyjny z WebGL dla 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 na wykonanie operacji, wyjaśnia to, dlaczego modele takie jak BlazeFace są szybsze w WASM.
Te wyniki będą się różnić w zależności od urządzenia. Najlepszym sposobem określenia, czy WASM jest odpowiedni dla Twojej aplikacji, jest przetestowanie jej na różnych backendach.
Wnioskowanie a szkolenie
Aby zająć się podstawowym przypadkiem użycia dla wdrożenia wstępnie wytrenowanych modeli, programowanie zaplecza WASM nada priorytet wnioskowaniu przed obsługą szkolenia . 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 węzła (TensorFlow C++) lub zaplecza WebGL.
Zaplecze procesora
Backend procesora, 'cpu', jest najmniej wydajnym backendem, jednak jest najprostszy. Wszystkie operacje są zaimplementowane w waniliowym JavaScript, co czyni je mniej równoległymi. Blokują również 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 zawiera zestaw flag środowiska, które są automatycznie oceniane i określają najlepszą konfigurację na bieżącej platformie. Te flagi są w większości wewnętrzne, ale kilka flag globalnych można kontrolować za pomocą publicznego API.
-
tf.enableProdMode():
włącza tryb produkcyjny, który usuwa walidację modelu, kontrole NaN i inne kontrole poprawności na rzecz wydajności. -
tf.enableDebugMode()
: włącza tryb debugowania, który rejestruje w konsoli każdą wykonaną operację, a także informacje o wydajności środowiska wykonawczego, takie jak zużycie pamięci i całkowity czas wykonania jądra. Zauważ, że znacznie spowolni to twoją aplikację, nie używaj tego w środowisku produkcyjnym.