Assistez au symposium Women in ML le 7 décembre Inscrivez-vous maintenant

API de couches TensorFlow.js pour les utilisateurs de Keras

Restez organisé à l'aide des collections Enregistrez et classez les contenus selon vos préférences.

L'API Layers de TensorFlow.js est calquée sur Keras et nous nous efforçons de rendre l' API Layers aussi similaire à Keras que raisonnable compte tenu des différences entre JavaScript et Python. Cela permet aux utilisateurs expérimentés dans le développement de modèles Keras en Python de migrer plus facilement vers TensorFlow.js Layers en JavaScript. Par exemple, le code Keras suivant se traduit en 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();

Cependant, il existe certaines différences que nous aimerions signaler et expliquer dans ce document. Une fois que vous avez compris ces différences et leur justification, votre migration Python vers JavaScript (ou migration dans le sens inverse) devrait être une expérience relativement fluide.

Les constructeurs prennent les objets JavaScript comme configurations

Comparez les lignes Python et JavaScript suivantes de l'exemple ci-dessus : elles créent toutes deux une couche Dense .

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

Les fonctions JavaScript n'ont pas d'équivalent des arguments de mots-clés dans les fonctions Python. Nous voulons éviter d'implémenter des options de constructeur en tant qu'arguments positionnels dans JavaScript, ce qui serait particulièrement fastidieux à mémoriser et à utiliser pour les constructeurs avec un grand nombre d'arguments de mots clés (par exemple, LSTM ). C'est pourquoi nous utilisons des objets de configuration JavaScript. De tels objets offrent le même niveau d'invariance de position et de flexibilité que les arguments de mot-clé Python.

Certaines méthodes de la classe Model, par exemple, Model.compile() , prennent également un objet de configuration JavaScript comme entrée. Cependant, gardez à l'esprit que Model.fit() , Model.evaluate() et Model.predict() sont légèrement différents. Étant donné que ces méthodes prennent en entrée les données obligatoires x (caractéristiques) et y (étiquettes ou cibles); x et y sont des arguments de position distincts de l'objet de configuration suivant qui joue le rôle des arguments de mot-clé. Par exemple:

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

Model.fit() est asynchrone

Model.fit() est la méthode principale avec laquelle les utilisateurs effectuent l'entraînement du modèle dans TensorFlow.js. Cette méthode peut souvent être longue et durer quelques secondes ou minutes. Par conséquent, nous utilisons la fonctionnalité async du langage JavaScript, afin que cette fonction puisse être utilisée d'une manière qui ne bloque pas le thread principal de l'interface utilisateur lors de l'exécution dans le navigateur. Ceci est similaire à d'autres fonctions potentiellement longues en JavaScript, telles que async fetch . Notez que async est une construction qui n'existe pas en Python. Alors que la méthode fit() de Keras renvoie un objet History, la contrepartie de la méthode fit() de JavaScript renvoie une promesse d'historique, qui peut être wait ed (comme dans l'exemple ci-dessus) ou utilisée avec la méthode then() .

Pas de NumPy pour TensorFlow.js

Les utilisateurs de Python Keras utilisent souvent NumPy pour effectuer des opérations numériques et de tableau de base, telles que la génération de tenseurs 2D dans l'exemple ci-dessus.

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

Dans TensorFlow.js, ce type d'opérations numériques de base est effectué avec le package lui-même. Par exemple:

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

L'espace de noms tf.* fournit également un certain nombre d'autres fonctions pour les opérations de tableau et d'algèbre linéaire telles que la multiplication matricielle. Consultez la documentation TensorFlow.js Core pour plus d'informations.

Utiliser des méthodes d'usine, pas des constructeurs

Cette ligne en Python (de l'exemple ci-dessus) est un appel de constructeur :

# Python:
model = keras.Sequential()

S'il était traduit strictement en JavaScript, l'appel de constructeur équivalent ressemblerait à ceci :

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

Cependant, nous avons décidé de ne pas utiliser les "nouveaux" constructeurs car 1) le mot-clé "nouveau" rendrait le code plus gonflé et 2) le constructeur "nouveau" est considéré comme une "mauvaise partie" de JavaScript : un piège potentiel, comme est argumenté en JavaScript : the Good Parts . Pour créer des modèles et des calques dans TensorFlow.js, vous appelez des méthodes de fabrique, qui ont des noms en minusculesCamelCase, par exemple :

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

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

Les valeurs de chaîne d'option sont lowerCamelCase, pas snake_case

En JavaScript, il est plus courant d'utiliser la casse camel pour les noms de symboles (par exemple, voir Google JavaScript Style Guide ), par rapport à Python, où la casse serpent est courante (par exemple, dans Keras). En tant que tel, nous avons décidé d'utiliser lowerCamelCase pour les valeurs de chaîne pour les options suivantes :

  • DataFormat, par exemple, channelsFirst au lieu de channels_first
  • Initialiseur, par exemple, glorotNormal au lieu de glorot_normal
  • Perte et métriques, par exemple, meanSquaredError au lieu de mean_squared_error , categoricalCrossentropy au lieu de categorical_crossentropy .

Par exemple, comme dans l'exemple ci-dessus :

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

En ce qui concerne la sérialisation et la désérialisation des modèles, rassurez-vous. Le mécanisme interne de TensorFlow.js garantit que les cas de serpent dans les objets JSON sont gérés correctement, par exemple lors du chargement de modèles pré-entraînés à partir de Python Keras.

Exécutez les objets Layer avec apply(), et non en les appelant en tant que fonctions

Dans Keras, un objet Layer a la méthode __call__ définie. Par conséquent, l'utilisateur peut invoquer la logique de la couche en appelant l'objet en tant que fonction, par exemple,

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

print(flatten(my_input).shape)

Ce sucre de syntaxe Python est implémenté en tant que méthode apply() dans TensorFlow.js :

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

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

Layer.apply() prend en charge l'évaluation impérative (empressée) sur les tenseurs concrets

Actuellement, dans Keras, la méthode d'appel ne peut fonctionner que sur les objets tf.Tensor de (Python) TensorFlow (en supposant que le backend TensorFlow), qui sont symboliques et ne contiennent pas de valeurs numériques réelles. C'est ce qui est montré dans l'exemple de la section précédente. Cependant, dans TensorFlow.js, la méthode apply() des calques peut fonctionner à la fois en mode symbolique et en mode impératif. Si apply() est invoqué avec un SymbolicTensor (une analogie proche de tf.Tensor), la valeur de retour sera un SymbolicTensor. Cela se produit généralement lors de la construction du modèle. Mais si apply() est invoqué avec une valeur Tensor concrète réelle, il renverra un Tensor concret. Par exemple:

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

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

Cette fonctionnalité rappelle Eager Execution de (Python) TensorFlow. Il offre une plus grande interactivité et débogabilité lors du développement du modèle, en plus d'ouvrir les portes à la composition de réseaux de neurones dynamiques.

Les optimiseurs sont en cours de formation. , pas les optimiseurs.

Dans Keras, les constructeurs des objets Optimizer se trouvent sous l'espace de noms keras.optimizers.* . Dans TensorFlow.js Layers, les méthodes d'usine pour les optimiseurs se trouvent sous l'espace de noms tf.train.* . Par exemple:

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

loadLayersModel() se charge à partir d'une URL, pas d'un fichier HDF5

Dans Keras, les modèles sont généralement enregistrés sous forme de fichier HDF5 (.h5), qui peut être chargé ultérieurement à l'aide de la méthode keras.models.load_model() . La méthode prend un chemin vers le fichier .h5. L'équivalent de load_model() dans TensorFlow.js est tf.loadLayersModel() . Étant donné que HDF5 n'est pas un format de fichier convivial pour les navigateurs, tf.loadLayersModel() prend un format spécifique à TensorFlow.js. tf.loadLayersModel() prend un fichier model.json comme argument d'entrée. Le model.json peut être converti à partir d'un fichier Keras HDF5 à l'aide du package pip tensorflowjs.

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

Notez également que tf.loadLayersModel() renvoie une Promise de tf.Model .

En général, l'enregistrement et le chargement de tf.Model s dans TensorFlow.js sont effectués à l'aide des méthodes tf.Model.save et tf.loadLayersModel , respectivement. Nous avons conçu ces API pour qu'elles soient similaires à l'API save et load_model de Keras. Mais l'environnement du navigateur est assez différent de l'environnement backend sur lequel s'exécutent les frameworks d'apprentissage en profondeur de base comme Keras, en particulier dans la gamme de routes pour la persistance et la transmission des données. Il existe donc des différences intéressantes entre les API de sauvegarde/chargement dans TensorFlow.js et dans Keras. Voir notre tutoriel sur l' enregistrement et le chargement de tf.Model pour plus de détails.

Utilisez fitDataset() pour former des modèles à l'aide d'objets tf.data.Dataset

Dans tf.keras de Python TensorFlow, un modèle peut être formé à l'aide d'un objet Dataset . La méthode fit() du modèle accepte directement un tel objet. Un modèle TensorFlow.js peut également être entraîné avec l'équivalent JavaScript des objets Dataset (voir la documentation de l'API tf.data dans TensorFlow.js ). Cependant, contrairement à Python, la formation basée sur Dataset se fait via une méthode dédiée, à savoir fitDataset . La méthode fit () est uniquement destinée à l'entraînement de modèle basé sur le tenseur.

Gestion de la mémoire des objets Layer et Model

TensorFlow.js s'exécute sur WebGL dans le navigateur, où les poids des objets Layer et Model sont soutenus par des textures WebGL. Cependant, WebGL n'a pas de prise en charge intégrée de la récupération de place. Les objets Layer et Model gèrent en interne la mémoire du tenseur pour l'utilisateur lors de leurs appels d'inférence et d'apprentissage. Mais ils permettent aussi à l'utilisateur de les disposer afin de libérer la mémoire WebGL qu'ils occupent. Ceci est utile dans les cas où de nombreuses instances de modèle sont créées et publiées dans un seul chargement de page. Pour supprimer un objet Layer ou Model, utilisez la méthode dispose() .