API di livelli TensorFlow.js per utenti Keras

Mantieni tutto organizzato con le raccolte Salva e classifica i contenuti in base alle tue preferenze.

L'API Layers di TensorFlow.js è modellata su Keras e ci sforziamo di rendere l' API Layers tanto simile a Keras quanto ragionevole date le differenze tra JavaScript e Python. Ciò semplifica la migrazione a TensorFlow.js Layers in JavaScript per gli utenti con esperienza nello sviluppo di modelli Keras in Python. Ad esempio, il seguente codice Keras si traduce in 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();

Tuttavia, ci sono alcune differenze che vorremmo evidenziare e spiegare in questo documento. Una volta comprese queste differenze e la logica alla base di esse, la migrazione da Python a JavaScript (o la migrazione nella direzione inversa) dovrebbe essere un'esperienza relativamente fluida.

I costruttori prendono gli oggetti JavaScript come configurazioni

Confronta le seguenti righe Python e JavaScript dell'esempio sopra: entrambe creano un livello Dense .

# Python:
keras.layers.Dense(units=1, inputShape=[1])
// JavaScript:
tf.layers.dense({units: 1, inputShape: [1]});

Le funzioni JavaScript non hanno un equivalente degli argomenti delle parole chiave nelle funzioni Python. Vogliamo evitare di implementare le opzioni del costruttore come argomenti posizionali in JavaScript, che sarebbe particolarmente ingombrante da ricordare e utilizzare per i costruttori con un gran numero di argomenti di parole chiave (ad esempio, LSTM ). Questo è il motivo per cui utilizziamo gli oggetti di configurazione JavaScript. Tali oggetti forniscono lo stesso livello di invarianza posizionale e flessibilità degli argomenti delle parole chiave Python.

Alcuni metodi della classe Model, ad esempio Model.compile() , accettano anche un oggetto di configurazione JavaScript come input. Tuttavia, tieni presente che Model.fit() , Model.evaluate() e Model.predict() sono leggermente diversi. Poiché questi metodi prendono i dati obbligatori x (caratteristiche) e y (etichette o target) come input; x sono y posizionali separati dall'oggetto di configurazione risultante che svolge il ruolo degli argomenti della parola chiave. Per esempio:

// JavaScript:
await model.fit(xs, ys, {epochs: 1000});

Model.fit() è asincrono

Model.fit() è il metodo principale con cui gli utenti eseguono l'addestramento del modello in TensorFlow.js. Questo metodo può spesso essere di lunga durata, della durata di secondi o minuti. Pertanto, utilizziamo la funzione async del linguaggio JavaScript, in modo che questa funzione possa essere utilizzata in un modo che non blocchi il thread dell'interfaccia utente principale durante l'esecuzione nel browser. Questo è simile ad altre funzioni potenzialmente di lunga durata in JavaScript, come async fetch . Nota che async è un costrutto che non esiste in Python. Mentre il metodo fit() in Keras restituisce un oggetto History, la controparte del metodo fit() in JavaScript restituisce una Promise of History, che può essere attesa (come nell'esempio sopra) o usata con il metodo then().

Nessun NumPy per TensorFlow.js

Gli utenti di Python Keras usano spesso NumPy per eseguire operazioni numeriche e di matrice di base, come la generazione di tensori 2D nell'esempio sopra.

# Python:
xs = np.array([[1], [2], [3], [4]])

In TensorFlow.js, questo tipo di operazioni numeriche di base vengono eseguite con il pacchetto stesso. Per esempio:

// JavaScript:
const xs = tf.tensor2d([[1], [2], [3], [4]], [4, 1]);

Lo spazio dei nomi tf.* fornisce anche una serie di altre funzioni per operazioni di array e algebra lineare come la moltiplicazione di matrici. Per ulteriori informazioni, vedere la documentazione di TensorFlow.js Core .

Usa metodi di fabbrica, non costruttori

Questa riga in Python (dall'esempio sopra) è una chiamata del costruttore:

# Python:
model = keras.Sequential()

Se tradotta rigorosamente in JavaScript, la chiamata del costruttore equivalente sarebbe simile alla seguente:

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

Tuttavia, abbiamo deciso di non utilizzare i "nuovi" costruttori perché 1) la parola chiave "nuovo" renderebbe il codice più gonfio e 2) il "nuovo" costruttore è considerato una "parte negativa" di JavaScript: una potenziale trappola, poiché è argomentato in JavaScript: the Good Parts . Per creare modelli e livelli in TensorFlow.js, chiami i metodi factory, che hanno nomi CamelCase inferiori, ad esempio:

// JavaScript:
const model = tf.sequential();

const layer = tf.layers.batchNormalization({axis: 1});

I valori della stringa di opzione sono lowerCamelCase, non snake_case

In JavaScript, è più comune usare il caso del cammello per i nomi dei simboli (ad esempio, consulta la Guida allo stile di JavaScript di Google ), rispetto a Python, dove il caso del serpente è comune (ad esempio, in Keras). Pertanto, abbiamo deciso di utilizzare lowerCamelCase per i valori di stringa per le opzioni tra cui le seguenti:

  • DataFormat, ad esempio, channelsFirst invece di channels_first
  • Inizializzatore, ad esempio glorotNormal invece di glorot_normal
  • Perdita e metriche, ad esempio meanSquaredError invece di mean_squared_error , categoricalCrossentropy invece di categorical_crossentropy .

Ad esempio, come nell'esempio sopra:

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

Per quanto riguarda la serializzazione e la deserializzazione del modello, state tranquilli. Il meccanismo interno di TensorFlow.js garantisce che i casi di serpente negli oggetti JSON vengano gestiti correttamente, ad esempio durante il caricamento di modelli pre-addestrati da Python Keras.

Esegui oggetti Layer con apply(), non chiamandoli come funzioni

In Keras, un oggetto Layer ha il metodo __call__ definito. Pertanto l'utente può invocare la logica del livello chiamando l'oggetto come una funzione, ad es.

# Python:
my_input = keras.Input(shape=[2, 4])
flatten = keras.layers.Flatten()

print(flatten(my_input).shape)

Questo zucchero della sintassi Python è implementato come metodo apply() in TensorFlow.js:

// JavaScript:
const myInput = tf.input({shape: [2, 4]});
const flatten = tf.layers.flatten();

console.log(flatten.apply(myInput).shape);

Layer.apply() supporta la valutazione imperativa (desiderosa) sui tensori concreti

Attualmente, in Keras, il metodo call può operare solo su (Python) oggetti tf.Tensor di TensorFlow (supponendo il back-end TensorFlow), che sono simbolici e non contengono valori numerici effettivi. Questo è ciò che viene mostrato nell'esempio nella sezione precedente. Tuttavia, in TensorFlow.js, il metodo apply() dei livelli può operare sia in modalità simbolica che imperativa. Se apply() viene invocato con un SymbolicTensor (una stretta analogia di tf.Tensor), il valore restituito sarà un SymbolicTensor. Questo accade in genere durante la costruzione del modello. Ma se apply() viene invocato con un valore Tensor concreto effettivo, restituirà un Tensor concreto. Per esempio:

// JavaScript:
const flatten = tf.layers.flatten();

flatten.apply(tf.ones([2, 3, 4])).print();

Questa funzione ricorda (Python) Eager Execution di TensorFlow. Offre una maggiore interattività e possibilità di debug durante lo sviluppo del modello, oltre ad aprire le porte alla composizione di reti neurali dinamiche.

Gli ottimizzatori sono in corso. , non ottimizzatori.

In Keras, i costruttori per gli oggetti Optimizer si trovano nello spazio dei nomi keras.optimizers.* . In TensorFlow.js Layers, i metodi factory per gli ottimizzatori si trovano nello spazio dei nomi tf.train.* . Per esempio:

# Python:
my_sgd = keras.optimizers.sgd(lr=0.2)
// JavaScript:
const mySGD = tf.train.sgd({lr: 0.2});

loadLayersModel() viene caricato da un URL, non da un file HDF5

In Keras, i modelli vengono generalmente salvati come file HDF5 (.h5), che può essere successivamente caricato utilizzando il metodo keras.models.load_model() . Il metodo prende un percorso per il file .h5. La controparte di load_model() in TensorFlow.js è tf.loadLayersModel() . Poiché HDF5 non è un formato di file compatibile con i browser, tf.loadLayersModel() accetta un formato specifico di TensorFlow.js. tf.loadLayersModel() accetta un file model.json come argomento di input. Il model.json può essere convertito da un file Keras HDF5 utilizzando il pacchetto tensorflowjs pip.

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

Si noti inoltre che tf.loadLayersModel() restituisce una Promise di tf.Model .

In generale, il salvataggio e il caricamento di tf.Model s in TensorFlow.js vengono eseguiti utilizzando rispettivamente i metodi tf.Model.save e tf.loadLayersModel . Abbiamo progettato queste API per essere simili all'API save e load_model di Keras. Ma l'ambiente del browser è abbastanza diverso dall'ambiente back-end su cui vengono eseguiti i framework di deep learning di base come Keras, in particolare nella serie di percorsi per la persistenza e la trasmissione dei dati. Quindi ci sono alcune differenze interessanti tra le API di salvataggio/caricamento in TensorFlow.js e in Keras. Consulta il nostro tutorial su Salvataggio e caricamento di tf.Model per maggiori dettagli.

Usa fitDataset() per addestrare modelli usando oggetti tf.data.Dataset

In tf.keras di Python TensorFlow, un modello può essere addestrato utilizzando un oggetto Dataset . Il metodo fit() del modello accetta direttamente tale oggetto. Un modello TensorFlow.js può essere addestrato anche con l'equivalente JavaScript degli oggetti Dataset (consultare la documentazione dell'API tf.data in TensorFlow.js ). Tuttavia, a differenza di Python, l'addestramento basato su Dataset viene eseguito tramite un metodo dedicato, ovvero fitDataset . Il metodo fit() è solo per l'addestramento del modello basato sul tensore.

Gestione della memoria degli oggetti Layer e Model

TensorFlow.js viene eseguito su WebGL nel browser, dove i pesi degli oggetti Layer e Model sono supportati dalle trame WebGL. Tuttavia, WebGL non ha un supporto integrato per la raccolta dei rifiuti. Gli oggetti Layer e Model gestiscono internamente la memoria del tensore per l'utente durante le chiamate di inferenza e di addestramento. Ma consentono anche all'utente di smaltirli per liberare la memoria WebGL che occupano. Ciò è utile nei casi in cui molte istanze del modello vengono create e rilasciate all'interno di un singolo caricamento di pagina. Per eliminare un oggetto Layer o Model, utilizzare il metodo dispose() .