Interfejs API warstw TensorFlow.js dla użytkowników Keras

Interfejs Layers API w TensorFlow.js jest wzorowany na Kerasie i staramy się, aby interfejs Layers API był jak najbardziej podobny do Keras, biorąc pod uwagę różnice między JavaScript i Python. Ułatwia to użytkownikom z doświadczeniem w tworzeniu modeli Keras w Pythonie migrację do warstw TensorFlow.js w JavaScript. Na przykład poniższy kod Keras jest tłumaczony 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();

Jednak istnieją pewne różnice, które chcielibyśmy podkreślić i wyjaśnić w tym dokumencie. Gdy zrozumiesz te różnice i ich uzasadnienie, Twoja migracja z Pythona do JavaScript (lub migracja w odwrotnym kierunku) powinna być stosunkowo płynna.

Konstruktory przyjmują obiekty JavaScript jako konfiguracje

Porównaj następujące wiersze Pythona i JavaScriptu z powyższego przykładu: oba tworzą warstwę gęstą .

# 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ąć implementacji opcji konstruktorów jako argumentów pozycyjnych w JavaScript, co byłoby szczególnie kłopotliwe do zapamiętania i używania 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ść, co argumenty słów kluczowych Pythona.

Niektóre metody klasy Model, np. Model.compile() , również przyjmują jako dane wejściowe obiekt konfiguracyjny JavaScript. Należy jednak pamiętać, że Model.fit() , Model.evaluate() i Model.predict() są nieco inne. Ponieważ metody te przyjmują obowiązkowe dane x (cechy) i y (etykiety lub cele) jako dane wejściowe; x i y są argumentami pozycyjnymi niezależnymi od wynikającego z tego 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 modelu w TensorFlow.js. Ta metoda często może być długotrwała, trwać sekundy lub minuty. Dlatego korzystamy z funkcji async języka JavaScript, dzięki czemu funkcja ta może być używana w sposób, który nie blokuje głównego wątku interfejsu użytkownika podczas uruchamiania w przeglądarce. Jest to podobne do innych potencjalnie długotrwałych funkcji w JavaScript, takich jak pobieranie async . 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 również szereg innych funkcji do operacji na tablicach i algebry liniowej, takich jak mnożenie macierzy. Więcej informacji można znaleźć w dokumentacji TensorFlow.js Core .

Używaj metod fabrycznych, a nie konstruktorów

Ta linia w Pythonie (z powyższego przykładu) to wywołanie konstruktora:

# Python:
model = keras.Sequential()

Po przetłumaczeniu wyłącznie na JavaScript, równoważne wywołanie konstruktora wyglądałoby tak:

// JavaScript:
const model = new tf.Sequential();  // !!! DON'T DO THIS !!!

Zdecydowaliśmy się jednak nie używać konstruktorów „new”, ponieważ 1) słowo kluczowe „new” sprawiłoby, że kod byłby bardziej rozdęty, a 2) konstruktor „new” jest uważany za „złą część” JavaScriptu: potencjalna pułapka, ponieważ jest argumentowany w JavaScript: the Good Parts . Aby tworzyć modele i warstwy w TensorFlow.js, wywołujesz metody fabryczne, które mają nazwy LowerCamelCase, 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 liter wielbłąda dla nazw symboli (np. zobacz Przewodnik po stylu Google JavaScript ), w porównaniu z Pythonem, gdzie wielkość liter węży jest powszechna (np. w Keras). W związku z tym zdecydowaliśmy się użyć lowerCamelCase dla wartości łańcuchowych dla opcji, w tym:

  • DataFormat, np. channelsFirst zamiast channels_first
  • Inicjator, np. glorotNormal zamiast glorot_normal
  • Strata i metryki, np. meanSquaredError zamiast mean_squared_error , categoricalCrossentropy zamiast categorical_crossentropy .

Na przykład, jak w powyższym przykładzie:

// JavaScript:
model.compile({optimizer: 'sgd', loss: 'meanSquaredError'});

Zapewniamy, że w odniesieniu do serializacji i deserializacji modelu. Wewnętrzny mechanizm TensorFlow.js zapewnia, że ​​przypadki węży w obiektach JSON są obsługiwane poprawnie, np. podczas ładowania wstępnie wytrenowanych modeli z Python Keras.

Uruchamiaj obiekty Layer za pomocą apply(), a nie przez wywoływanie ich jako funkcji

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)

Ten cukier składni Pythona jest zaimplementowany 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ę na konkretnych tensorach

Obecnie w Keras metoda wywołania może działać tylko na obiektach tf.Tensor (zakładając zaplecze TensorFlow) TensorFlow (Python), które są symboliczne i nie przechowują rzeczywistych wartości liczbowych. Jest to pokazane w przykładzie w poprzedniej sekcji. Jednak w TensorFlow.js metoda apply() warstw może działać zarówno w trybie symbolicznym, jak i imperatywnym. Jeśli metoda apply() jest wywoływana z SymbolicTensor (bliska analogia tf.Tensor), wartością zwracaną będzie SymbolicTensor. Dzieje się tak zwykle podczas budowania modelu. Ale jeśli apply() zostanie wywołana z rzeczywistą konkretną wartością Tensor, 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 treningu. , a nie optymalizatory.

W Keras konstruktory obiektów Optimizer znajdują się w przestrzeni nazw keras.optimizers.* . W warstwach TensorFlow.js metody fabryczne dla 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 się z adresu URL, a nie z pliku HDF5

W Keras modele są zwykle zapisywane jako plik HDF5 (.h5), który można później wczytać za pomocą metody keras.models.load_model() . Metoda pobiera ścieżkę do pliku .h5. Odpowiednikiem load_model() w TensorFlow.js jest tf.loadLayersModel() . Ponieważ HDF5 nie jest formatem przyjaznym dla przeglądarek, tf.loadLayersModel() przyjmuje format specyficzny dla TensorFlow.js. tf.loadLayersModel() przyjmuje plik model.json jako argument wejściowy. Model.json można przekonwertować z pliku Keras HDF5 przy użyciu pakietu tensorflowjs pip.

// JavaScript:
const model = await tf.loadLayersModel('https://foo.bar/model.json');

Należy również zauważyć, że tf.loadLayersModel() zwraca Promise tf.Model .

Ogólnie rzecz biorąc, zapisywanie i ładowanie tf.Model s w TensorFlow.js odbywa się za pomocą odpowiednio metod tf.Model.save i tf.loadLayersModel . Zaprojektowaliśmy te interfejsy API, aby były podobne do API save i load_model Keras. Jednak środowisko przeglądarki różni się znacznie od środowiska zaplecza, na którym działają podstawowe platformy uczenia głębokiego, takie jak Keras, szczególnie w zakresie szeregu tras do utrwalania i przesyłania danych. W związku z tym istnieje kilka interesujących różnic między API do zapisywania/ładowania w TensorFlow.js i Keras. Zobacz nasz samouczek dotyczący zapisywania i ładowania tf.Model , aby uzyskać więcej informacji.

Użyj fitDataset() do trenowania modeli przy użyciu obiektów tf.data.Dataset

W tf.keras TensorFlow w Pythonie model można trenować przy użyciu obiektu Dataset . Metoda fit() modelu bezpośrednio akceptuje taki obiekt. Model TensorFlow.js można również wytrenować za pomocą odpowiednika JavaScript obiektów Dataset (zobacz dokumentację tf.data API w TensorFlow.js ). Jednak w przeciwieństwie do Pythona, szkolenie oparte na Dataset odbywa się za pomocą dedykowanej metody, a mianowicie fitDataset . Metoda fit() jest przeznaczona tylko do uczenia modelu opartego na tensorze.

Zarządzanie pamięcią obiektów warstw i modeli

TensorFlow.js działa na WebGL w przeglądarce, gdzie wagi obiektów Layer i Model są wspierane przez tekstury WebGL. Jednak WebGL nie ma wbudowanej obsługi wyrzucania śmieci. Obiekty Layer i Model wewnętrznie zarządzają pamięcią tensorową użytkownika podczas wnioskowania i wywołań uczących. Ale pozwalają również użytkownikowi na ich utylizację w celu zwolnienia zajmowanej przez nie pamięci WebGL. Jest to przydatne w przypadkach, gdy wiele instancji modelu jest tworzonych i zwalnianych w ramach pojedynczego ładowania strony. Aby usunąć obiekt Layer lub Model, użyj metody dispose() .