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

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 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'});

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() .