API de capas de TensorFlow.js para usuarios de Keras

Las capas API de TensorFlow.js es el modelo de Keras y nos esforzamos para que la API de capas como similar a Keras como razonable teniendo en cuenta las diferencias entre JavaScript y Python. Esto facilita que los usuarios con experiencia en el desarrollo de modelos de Keras en Python migren a las capas de TensorFlow.js en JavaScript. Por ejemplo, el siguiente código de 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 '@tensorlowjs/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 razón fundamental 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

Comparación de las siguientes líneas de Python y JavaScript en el ejemplo anterior: ambos crean una densa capa.

# 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 la aplicación de las posibles constructor como argumentos posicionales en JavaScript, que serían especialmente engorroso para recordar y uso de constructores con un gran número de argumentos de palabra clave (por ejemplo, LSTM ). Es por eso que usamos objetos de configuración de JavaScript. Dichos objetos proporcionan el mismo nivel de invariancia posicional y flexibilidad que los argumentos de palabras clave de Python.

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

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

Model.fit () es asincrónico

Model.fit() es el principal método con el que los usuarios realizan en el entrenamiento del modelo TensorFlow.js. Este método a menudo puede ser de larga duración, de segundos o minutos. Por lo tanto, utilizamos la async función del lenguaje JavaScript, por lo que esta función se puede utilizar de una manera que no bloquee el hilo principal interfaz de usuario cuando se ejecuta en el navegador. Esto es similar a otras funciones potencialmente-ejecutan largo en JavaScript, como el async ha podido recuperar . Tenga en cuenta que async es una construcción que no existe en Python. Mientras que el fit() método en el Keras devuelve un objeto de la historia, la contrapartida de la fit() método en el JavaScript devuelve una promesa de Historia, que puede ser await ed (como en el ejemplo anterior) o se utiliza con el método a continuación, ().

Sin NumPy para TensorFlow.js

Usuarios Python Keras menudo utilizan NumPy para realizar operaciones numéricas y de matriz básicas, tales como la generación de 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 paquete en sí. Por ejemplo:

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

La tf.* Espacio de nombres también proporciona un número de otras funciones para operaciones de matriz y de álgebra lineal, tales como la multiplicación de matrices. Consulte la documentación de TensorFlow.js Core para 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 se vería así:

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

Sin embargo, decidimos no usar los "nuevos" constructores porque 1) la palabra clave "nuevo" haría que el código fuera más hinchado y 2) el "nuevo" constructor se considera una "parte mala" de JavaScript: un error potencial, ya que 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 opciones son lowerCamelCase, no snake_case

En JavaScript, es más común en caso de uso de camello para nombres de símbolos (por ejemplo, véase la Guía de JavaScript de Google Estilo ), en comparación con Python, en caso serpiente es común (por ejemplo, en Keras). Como tal, decidimos usar lowerCamelCase para valores de cadena para opciones que incluyen lo siguiente:

  • 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 de modelos, 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 Layer con apply (), no llamándolos como funciones

En Keras, un objeto de capa tiene la __call__ método definido. 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 una evaluación imperativa (ansiosa) de tensores de hormigón

Actualmente, en Keras, el método de llamada sólo puede operar sobre (Python) de TensorFlow tf.Tensor objetos (suponiendo TensorFlow back-end), que son simbólicas y no estén en posesión de 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 apply () de capas puede operar tanto en modo simbólico como imperativo. Si apply() se invoca con un SymbolicTensor (una estrecha analogía de tf.Tensor), el valor de retorno será un SymbolicTensor. Esto ocurre normalmente durante la construcción del modelo. Pero si apply() se invoca con un valor real Tensor concreto, devolverá un concreto tensor. Por ejemplo:

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

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

Esta característica es una reminiscencia de (Python) de TensorFlow Ejecución Eager . Ofrece una mayor interactividad y depuración durante el desarrollo del modelo, además de abrir puertas para componer redes neuronales dinámicas.

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

En Keras, los constructores de objetos Optimizer están bajo el keras.optimizers.* Espacio de nombres. En TensorFlow.js capas, los métodos de fábrica para optimizadores están bajo el tf.train.* Espacio de nombres. 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 se suele guardarse como un archivo HDF5 (.h5), que puede ser posteriormente cargado usando el keras.models.load_model() método. El método toma una ruta al archivo .h5. La contrapartida de load_model() en TensorFlow.js es tf.loadLayersModel() . Desde HDF5 no es un formato de archivo compatible con explorador, tf.loadLayersModel() toma un formato TensorFlow.js específica. tf.loadLayersModel() toma un archivo model.json como argumento de entrada. El model.json se puede convertir desde un archivo Keras HDF5 usando 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, el ahorro y la carga tf.Model s en TensorFlow.js se realiza utilizando los tf.Model.save y tf.loadLayersModel métodos, respectivamente. Hemos diseñado estas API para ser similar a la operación de guardar y load_model API 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 datos persistentes y transimitadores. Por lo tanto, existen algunas diferencias interesantes entre las API de guardar / cargar en TensorFlow.js y en Keras. Vea nuestro tutorial sobre Almacenamiento y carga de tf.Model para más detalles.

Uso fitDataset() para modelos de trenes que utilizan tf.data.Dataset objetos

En tf.keras de Python TensorFlow, un modelo puede ser entrenado utilizando un conjunto de datos de objetos. El modelo de fit() método acepta un objeto tal directamente. Un modelo TensorFlow.js puede ser entrenado con el equivalente JavaScript del conjunto de datos de objetos también (véase la documentación de la API tf.data en TensorFlow.js ). Sin embargo, a diferencia de la formación en Python, conjunto de datos basados en se realiza a través de un método específico, a saber fitDataset . El ajuste () método es sólo para la formación modelo basado en el tensor.

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 Layer y Model están respaldados por texturas WebGL. Sin embargo, WebGL no tiene soporte integrado para la recolección de basura. Los objetos Layer y Model administran internamente la memoria tensorial para el usuario durante sus llamadas de inferencia y entrenamiento. Pero también permiten al usuario deshacerse 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 en una sola carga de página. Para disponer una capa o el objeto del modelo, utilice el dispose() método.