Interfejs API warstw w TensorFlow.js jest wzorowany na Keras i staramy się, aby interfejs API warstw był jak najbardziej podobny do Keras i był rozsądny, biorąc pod uwagę różnice między JavaScriptem i Pythonem. Ułatwia to użytkownikom z doświadczeniem w tworzeniu modeli Keras w języku Python migrację do warstw TensorFlow.js w JavaScript. Na przykład następujący kod Keras tłumaczy się na JavaScript:
# Python:
import keras
import numpy as np
# Build and compile model.
model = keras.Sequential()
model.add(keras.layers.Dense(units=1, input_shape=[1]))
model.compile(optimizer='sgd', loss='mean_squared_error')
# Generate some synthetic data for training.
xs = np.array([[1], [2], [3], [4]])
ys = np.array([[1], [3], [5], [7]])
# Train model with fit().
model.fit(xs, ys, epochs=1000)
# Run inference with predict().
print(model.predict(np.array([[5]])))
// JavaScript:
import * as tf from '@tensorflow/tfjs';
// Build and compile model.
const model = tf.sequential();
model.add(tf.layers.dense({units: 1, inputShape: [1]}));
model.compile({optimizer: 'sgd', loss: 'meanSquaredError'});
// Generate some synthetic data for training.
const xs = tf.tensor2d([[1], [2], [3], [4]], [4, 1]);
const ys = tf.tensor2d([[1], [3], [5], [7]], [4, 1]);
// Train model with fit().
await model.fit(xs, ys, {epochs: 1000});
// Run inference with predict().
model.predict(tf.tensor2d([[5]], [1, 1])).print();
Istnieją jednak pewne różnice, które chcielibyśmy wskazać i wyjaśnić w tym dokumencie. Gdy zrozumiesz te różnice i ich uzasadnienie, migracja z Pythona do JavaScript (lub migracja w odwrotnym kierunku) powinna przebiegać stosunkowo gładko.
Konstruktory przyjmują obiekty JavaScript jako konfiguracje
Porównaj następujące linie Pythona i JavaScript z powyższego przykładu: oba tworzą warstwę Dense .
# Python:
keras.layers.Dense(units=1, inputShape=[1])
// JavaScript:
tf.layers.dense({units: 1, inputShape: [1]});
Funkcje JavaScript nie mają odpowiednika argumentów słów kluczowych w funkcjach Pythona. Chcemy uniknąć implementowania opcji konstruktorów jako argumentów pozycyjnych w JavaScript, co byłoby szczególnie kłopotliwe do zapamiętania i użycia w przypadku konstruktorów z dużą liczbą argumentów słów kluczowych (np. LSTM ). Dlatego używamy obiektów konfiguracyjnych JavaScript. Takie obiekty zapewniają ten sam poziom niezmienności pozycyjnej i elastyczności, co argumenty słów kluczowych w języku Python.
Niektóre metody klasy Model, np. Model.compile()
, również pobierają jako dane wejściowe obiekt konfiguracyjny JavaScript. Należy jednak pamiętać, że Model.fit()
, Model.evaluate()
i Model.predict()
są nieco inne. Ponieważ te metody przyjmują obowiązkowe dane x
(cechy) i y
(etykiety lub cele) jako dane wejściowe; x
i y
są argumentami pozycyjnymi oddzielnymi od wynikającego z nich obiektu konfiguracyjnego, który pełni rolę argumentów słów kluczowych. Na przykład:
// JavaScript:
await model.fit(xs, ys, {epochs: 1000});
Model.fit() jest asynchroniczny
Model.fit()
to podstawowa metoda, za pomocą której użytkownicy przeprowadzają szkolenie modeli w TensorFlow.js. Ta metoda może często być długotrwała, trwać sekundy lub minuty. Dlatego wykorzystujemy funkcję async
języka JavaScript, aby można było z niej korzystać w sposób nieblokujący głównego wątku interfejsu użytkownika podczas działania w przeglądarce. Jest to podobne do innych potencjalnie długotrwałych funkcji JavaScript, takich jak async
pobieranie . Zauważ, że async
to konstrukcja, która nie istnieje w Pythonie. Podczas gdy metoda fit()
w Keras zwraca obiekt History, odpowiednik metody fit()
w JavaScript zwraca Obietnicę Historii, na którą można poczekać (jak w powyższym przykładzie) lub użyć z metodą then().
Brak NumPy dla TensorFlow.js
Użytkownicy Pythona Keras często używają NumPy do wykonywania podstawowych operacji numerycznych i tablicowych, takich jak generowanie tensorów 2D w powyższym przykładzie.
# Python:
xs = np.array([[1], [2], [3], [4]])
W TensorFlow.js tego rodzaju podstawowe operacje numeryczne są wykonywane na samym pakiecie. Na przykład:
// JavaScript:
const xs = tf.tensor2d([[1], [2], [3], [4]], [4, 1]);
Przestrzeń nazw tf.*
udostępnia także wiele innych funkcji dla operacji na tablicach i algebrze liniowej, takich jak mnożenie macierzy. Aby uzyskać więcej informacji, zobacz dokumentację TensorFlow.js Core .
Używaj metod fabrycznych, a nie konstruktorów
Ta linia w Pythonie (z powyższego przykładu) jest wywołaniem konstruktora:
# Python:
model = keras.Sequential()
Jeśli zostanie przetłumaczone wyłącznie na JavaScript, równoważne wywołanie konstruktora będzie wyglądać następująco:
// JavaScript:
const model = new tf.Sequential(); // !!! DON'T DO THIS !!!
Zdecydowaliśmy się jednak nie używać „nowych” konstruktorów, ponieważ 1) słowo kluczowe „new” spowodowałoby, że kod byłby bardziej rozdęty oraz 2) „nowy” konstruktor jest uważany za „złą część” JavaScript: potencjalną pułapkę, ponieważ argumentuje się w JavaScript: dobre części . Aby utworzyć modele i warstwy w TensorFlow.js, wywołujesz metody fabryczne, które mają nazwy lessCamelCase, na przykład:
// JavaScript:
const model = tf.sequential();
const layer = tf.layers.batchNormalization({axis: 1});
Wartości ciągu opcji to LowerCamelCase, a nie Snake_case
W JavaScript częściej używa się wielkości wielbłąda do nazw symboli (np. zobacz Przewodnik po stylu JavaScript Google ) w porównaniu z Pythonem, gdzie wielkość liter typu „węże” jest powszechna (np. w Keras). W związku z tym zdecydowaliśmy się użyć lessCamelCase dla wartości łańcuchowych dla opcji, w tym:
- DataFormat,
channelsFirst
channels_first
- Inicjator, np.
glorotNormal
zamiastglorot_normal
- Strata i metryki, np.
meanSquaredError
zamiastmean_squared_error
,categoricalCrossentropy
zamiastcategorical_crossentropy
.
Na przykład, jak w powyższym przykładzie:
// JavaScript:
model.compile({optimizer: 'sgd', loss: 'meanSquaredError'});
Jeśli chodzi o serializację i deserializację modelu, możesz być spokojny. Wewnętrzny mechanizm TensorFlow.js zapewnia prawidłową obsługę przypadków węży w obiektach JSON, np. podczas ładowania wstępnie wytrenowanych modeli z Pythona Keras.
Uruchamiaj obiekty warstw za pomocą Apply(), a nie wywołując je jako funkcje
W Keras obiekt Layer ma zdefiniowaną metodę __call__
. Dlatego użytkownik może wywołać logikę warstwy wywołując obiekt jako funkcję, np.
# Python:
my_input = keras.Input(shape=[2, 4])
flatten = keras.layers.Flatten()
print(flatten(my_input).shape)
Ta składnia Pythona jest zaimplementowana jako metoda Apply() w TensorFlow.js:
// JavaScript:
const myInput = tf.input({shape: [2, 4]});
const flatten = tf.layers.flatten();
console.log(flatten.apply(myInput).shape);
Layer.apply() obsługuje imperatywną (chętną) ocenę konkretnych tensorów
Obecnie w Keras metoda wywołania może działać tylko na obiektach tf.Tensor
(Python) TensorFlow (przy założeniu zaplecza TensorFlow), które są symboliczne i nie przechowują rzeczywistych wartości liczbowych. To właśnie pokazano na przykładzie z poprzedniej sekcji. Jednak w TensorFlow.js metoda Apply() warstw może działać zarówno w trybie symbolicznym, jak i imperatywnym. Jeśli apply()
zostanie wywołana z SymbolicTensorem (bliska analogia tf.Tensor), zwracaną wartością będzie SymbolicTensor. Dzieje się tak zazwyczaj podczas budowania modelu. Ale jeśli apply()
zostanie wywołana z rzeczywistą konkretną wartością Tensora, zwróci konkretny Tensor. Na przykład:
// JavaScript:
const flatten = tf.layers.flatten();
flatten.apply(tf.ones([2, 3, 4])).print();
Ta funkcja przypomina Eager Execution (Python) TensorFlow. Zapewnia większą interaktywność i możliwość debugowania podczas opracowywania modelu, a także otwiera drzwi do tworzenia dynamicznych sieci neuronowych.
Optymalizatory są w trakcie opracowywania. , a nie optymalizatory.
W Keras konstruktory obiektów Optimizer znajdują się w przestrzeni nazw keras.optimizers.*
. W warstwach TensorFlow.js metody fabryczne optymalizatorów znajdują się w przestrzeni nazw tf.train.*
. Na przykład:
# Python:
my_sgd = keras.optimizers.sgd(lr=0.2)
// JavaScript:
const mySGD = tf.train.sgd({lr: 0.2});
LoadLayersModel() ładuje z adresu URL, a nie z pliku HDF5
W Keras modele zapisywane są zazwyczaj w postaci pliku HDF5 (.h5), który można później wczytać metodą keras.models.load_model()
. Metoda pobiera ścieżkę do pliku .h5. Odpowiednikiem funkcji load_model()
w TensorFlow.js jest tf.loadLayersModel()
. Ponieważ HDF5 nie jest formatem pliku przyjaznym dla przeglądarki, tf.loadLayersModel()
przyjmuje format specyficzny dla TensorFlow.js. tf.loadLayersModel()
przyjmuje plik model.json jako argument wejściowy. Plik model.json można przekonwertować z pliku Keras HDF5 przy użyciu pakietu pip tensorflowjs.
// JavaScript:
const model = await tf.loadLayersModel('https://foo.bar/model.json');
Należy również pamiętać, że tf.loadLayersModel()
zwraca Promise
tf.Model
.
Ogólnie rzecz biorąc, zapisywanie i ładowanie tf.Model
s w TensorFlow.js odbywa się odpowiednio przy użyciu metod tf.Model.save
i tf.loadLayersModel
. Zaprojektowaliśmy te interfejsy API tak, aby były podobne do API zapisu i ładowania modelu Keras. Jednak środowisko przeglądarki różni się znacznie od środowiska zaplecza, na którym działają podstawowe platformy głębokiego uczenia się, takie jak Keras, szczególnie pod względem szeregu tras utrwalania i przesyłania danych. Dlatego istnieją pewne interesujące różnice między interfejsami API zapisywania/ładowania w TensorFlow.js i Keras. Więcej szczegółów znajdziesz w naszym samouczku na temat zapisywania i ładowania tf.Model .
Użyj fitDataset()
do uczenia modeli przy użyciu obiektów tf.data.Dataset
W pliku tf.keras Pythona TensorFlow model można trenować przy użyciu obiektu Dataset . Metoda fit()
modelu akceptuje taki obiekt bezpośrednio. Model TensorFlow.js można również trenować za pomocą odpowiednika JavaScript obiektów Dataset (zobacz dokumentację interfejsu API tf.data w TensorFlow.js ). Jednak w przeciwieństwie do Pythona, szkolenie oparte na Dataset odbywa się za pomocą dedykowanej metody, a mianowicie fitDataset . Metoda fit() przeznaczona jest wyłącznie do uczenia modeli opartych na tensorach.
Zarządzanie pamięcią obiektów warstw i modeli
TensorFlow.js działa w przeglądarce WebGL, gdzie wagi obiektów Layer i Model są wspierane przez tekstury WebGL. Jednak WebGL nie ma wbudowanej obsługi usuwania śmieci. Obiekty warstwy i modelu wewnętrznie zarządzają pamięcią tensora użytkownika podczas wywołań wnioskowania i uczenia. Ale pozwalają także użytkownikowi na ich pozbycie się w celu zwolnienia zajmowanej przez nich pamięci WebGL. Jest to przydatne w przypadkach, gdy wiele instancji modelu jest tworzonych i udostępnianych w ramach jednej strony. Aby pozbyć się obiektu warstwy lub modelu, użyj metody dispose()
.