API de capas TensorFlow.js para usuarios de Keras

La API de capas de TensorFlow.js está modelada a partir de Keras y nos esforzamos por hacer que la API de capas sea lo más similar a Keras posible dadas las diferencias entre JavaScript y Python. Esto facilita que los usuarios con experiencia en el desarrollo de modelos Keras en Python migren a TensorFlow.js Layers en JavaScript. Por ejemplo, el siguiente código Keras se traduce a 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();

Sin embargo, existen algunas diferencias que nos gustaría señalar y explicar en este documento. Una vez que comprenda estas diferencias y la lógica detrás de ellas, su migración de Python a JavaScript (o migración en la dirección inversa) debería ser una experiencia relativamente fluida.

Los constructores toman objetos JavaScript como configuraciones.

Compare las siguientes líneas de Python y JavaScript del ejemplo anterior: ambas crean una capa densa .

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

Las funciones de JavaScript no tienen un equivalente de los argumentos de palabras clave en las funciones de Python. Queremos evitar implementar opciones de constructor como argumentos posicionales en JavaScript, lo que sería especialmente engorroso de recordar y usar para constructores con una gran cantidad de argumentos de palabras clave (por ejemplo, LSTM ). Es por eso que utilizamos objetos de configuración de JavaScript. Estos objetos proporcionan el mismo nivel de invariancia posicional y flexibilidad que los argumentos de palabras clave de Python.

Algunos métodos de la clase Model, por ejemplo, Model.compile() , también toman un objeto de configuración de JavaScript como entrada. Sin embargo, tenga en cuenta que Model.fit() , Model.evaluate() y Model.predict() son ligeramente diferentes. Dado que estos métodos toman datos obligatorios x (características) e y (etiquetas u objetivos) como entradas; x son argumentos posicionales separados del objeto de configuración resultante que desempeña el papel de los argumentos y palabras clave. Por ejemplo:

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

Model.fit() es asíncrono

Model.fit() es el método principal con el que los usuarios realizan el entrenamiento de modelos en TensorFlow.js. Este método a menudo puede ser de larga duración, durando segundos o minutos. Por lo tanto, utilizamos la función async del lenguaje JavaScript, para que esta función se pueda usar de una manera que no bloquee el hilo principal de la interfaz de usuario cuando se ejecuta en el navegador. Esto es similar a otras funciones potencialmente de larga duración en JavaScript, como async fetch . Tenga en cuenta que async es una construcción que no existe en Python. Mientras que el método fit() en Keras devuelve un objeto Historial, la contraparte del método fit() en JavaScript devuelve una Promesa de Historia, que puede esperarse (como en el ejemplo anterior) o usarse con el método then().

Sin NumPy para TensorFlow.js

Los usuarios de Python Keras suelen utilizar NumPy para realizar operaciones numéricas y de matrices básicas, como generar tensores 2D en el ejemplo anterior.

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

En TensorFlow.js, este tipo de operaciones numéricas básicas se realizan con el propio paquete. Por ejemplo:

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

El espacio de nombres tf.* también proporciona otras funciones para operaciones de álgebra lineal y de matrices, como la multiplicación de matrices. Consulte la documentación de TensorFlow.js Core para obtener más información.

Utilice métodos de fábrica, no constructores.

Esta línea en Python (del ejemplo anterior) es una llamada al constructor:

# Python:
model = keras.Sequential()

Si se traduce estrictamente a JavaScript, la llamada al constructor equivalente tendría el siguiente aspecto:

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

Sin embargo, decidimos no utilizar los constructores "nuevos" porque 1) la palabra clave "nuevo" haría que el código fuera más inflado y 2) el constructor "nuevo" se considera una "parte mala" de JavaScript: un peligro potencial, como se argumenta en JavaScript: las partes buenas . Para crear modelos y capas en TensorFlow.js, llama a métodos de fábrica, que tienen nombres de CamelCase inferiores, por ejemplo:

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

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

Los valores de la cadena de opción son lowerCamelCase, no Snake_case

En JavaScript, es más común usar mayúsculas y minúsculas para nombres de símbolos (por ejemplo, consulte la Guía de estilo de JavaScript de Google ), en comparación con Python, donde las mayúsculas y minúsculas son comunes (por ejemplo, en Keras). Como tal, decidimos usar lowerCamelCase para valores de cadena para opciones que incluyen las siguientes:

  • DataFormat, por ejemplo, channelsFirst en lugar de channels_first
  • Inicializador, por ejemplo, glorotNormal en lugar de glorot_normal
  • Pérdida y métricas, por ejemplo, meanSquaredError en lugar de mean_squared_error , categoricalCrossentropy en lugar de categorical_crossentropy .

Por ejemplo, como en el ejemplo anterior:

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

Con respecto a la serialización y deserialización del modelo, tenga la seguridad. El mecanismo interno de TensorFlow.js garantiza que los casos de serpientes en objetos JSON se manejen correctamente, por ejemplo, al cargar modelos previamente entrenados desde Python Keras.

Ejecute objetos de capa con apply(), no llamándolos como funciones

En Keras, un objeto Layer tiene definido el método __call__ . Por lo tanto, el usuario puede invocar la lógica de la capa llamando al objeto como una función, por ejemplo,

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

print(flatten(my_input).shape)

Este azúcar de sintaxis de Python se implementa como el método apply() en TensorFlow.js:

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

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

Layer.apply() admite la evaluación imperativa (ansiosa) de tensores concretos

Actualmente, en Keras, el método de llamada solo puede operar en los objetos tf.Tensor de TensorFlow (Python) (suponiendo el backend de TensorFlow), que son simbólicos y no contienen valores numéricos reales. Esto es lo que se muestra en el ejemplo de la sección anterior. Sin embargo, en TensorFlow.js, el método de capas apply() puede operar tanto en modo simbólico como imperativo. Si se invoca apply() con un SymbolicTensor (una analogía cercana de tf.Tensor), el valor de retorno será un SymbolicTensor. Esto suele ocurrir durante la construcción del modelo. Pero si se invoca apply() con un valor de Tensor concreto real, devolverá un Tensor concreto. Por ejemplo:

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

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

Esta característica recuerda a Eager Execution de (Python) TensorFlow. Proporciona una mayor interactividad y depuración durante el desarrollo del modelo, además de abrir puertas a la composición de redes neuronales dinámicas.

Los optimizadores están en marcha. , no optimizadores.

En Keras, los constructores de los objetos Optimizer se encuentran en el espacio de nombres keras.optimizers.* . En las capas de TensorFlow.js, los métodos de fábrica para los optimizadores se encuentran en el espacio de nombres tf.train.* . Por ejemplo:

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

loadLayersModel() se carga desde una URL, no desde un archivo HDF5

En Keras, los modelos generalmente se guardan como un archivo HDF5 (.h5), que luego se puede cargar usando el método keras.models.load_model() . El método toma una ruta al archivo .h5. La contraparte de load_model() en TensorFlow.js es tf.loadLayersModel() . Dado que HDF5 no es un formato de archivo compatible con el navegador, tf.loadLayersModel() toma un formato específico de TensorFlow.js. tf.loadLayersModel() toma un archivo model.json como argumento de entrada. El model.json se puede convertir desde un archivo Keras HDF5 utilizando el paquete pip tensorflowjs.

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

También tenga en cuenta que tf.loadLayersModel() devuelve una Promise de tf.Model .

En general, guardar y cargar tf.Model s en TensorFlow.js se realiza utilizando los métodos tf.Model.save y tf.loadLayersModel , respectivamente. Diseñamos estas API para que sean similares a la API save y load_model de Keras. Pero el entorno del navegador es bastante diferente del entorno backend en el que se ejecutan los marcos básicos de aprendizaje profundo como Keras, particularmente en la variedad de rutas para persistir y transmitir datos. Por lo tanto, existen algunas diferencias interesantes entre las API de guardar/cargar en TensorFlow.js y Keras. Consulte nuestro tutorial sobre Guardar y cargar tf.Model para obtener más detalles.

Utilice fitDataset() para entrenar modelos utilizando objetos tf.data.Dataset

En tf.keras de Python TensorFlow, se puede entrenar un modelo utilizando un objeto Dataset . El método fit() del modelo acepta dicho objeto directamente. También se puede entrenar un modelo de TensorFlow.js con el equivalente de JavaScript de los objetos del conjunto de datos (consulte la documentación de la API tf.data en TensorFlow.js ). Sin embargo, a diferencia de Python, el entrenamiento basado en conjuntos de datos se realiza mediante un método dedicado, llamado fitDataset . El método fit() es solo para el entrenamiento de modelos basados ​​en tensores.

Gestión de memoria de objetos de capa y modelo.

TensorFlow.js se ejecuta en WebGL en el navegador, donde los pesos de los objetos Capa y Modelo están respaldados por texturas WebGL. Sin embargo, WebGL no tiene soporte integrado para la recolección de basura. Los objetos de capa y modelo administran internamente la memoria tensorial para el usuario durante sus llamadas de inferencia y entrenamiento. Pero también permiten al usuario disponer de ellos para liberar la memoria WebGL que ocupan. Esto es útil en los casos en los que se crean y publican muchas instancias de modelo dentro de una sola carga de página. Para eliminar un objeto Capa o Modelo, utilice el método dispose() .