API слоев TensorFlow.js для пользователей Keras

API слоев TensorFlow.js создан по образцу Keras, и мы стремимся сделать API слоев максимально похожим на Keras, насколько это разумно, учитывая различия между JavaScript и Python. Это упрощает переход на слои TensorFlow.js в JavaScript для пользователей, имеющих опыт разработки моделей Keras на Python. Например, следующий код Keras преобразуется в 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();

Однако есть некоторые различия, которые мы хотели бы отметить и объяснить в этом документе. Как только вы поймете эти различия и их обоснование, ваша миграция с Python на JavaScript (или миграция в обратном направлении) должна пройти относительно гладко.

Конструкторы принимают объекты JavaScript в качестве конфигураций.

Сравните следующие строки Python и JavaScript из приведенного выше примера: они обе создают плотный слой.

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

Функции JavaScript не имеют эквивалента аргументов ключевого слова в функциях Python. Мы хотим избежать реализации опций конструктора в качестве позиционных аргументов в JavaScript, что было бы особенно сложно запомнить и использовать для конструкторов с большим количеством аргументов ключевых слов (например, LSTM ). Вот почему мы используем объекты конфигурации JavaScript. Такие объекты обеспечивают тот же уровень позиционной инвариантности и гибкости, что и аргументы ключевых слов Python.

Некоторые методы класса Model, например Model.compile() , также принимают на вход объект конфигурации JavaScript. Однако имейте в виду, что Model.fit() , Model.evaluate() и Model.predict() немного отличаются. Поскольку эти методы принимают обязательные данные x (функции) и y (метки или цели) в качестве входных данных; x и y — это позиционные аргументы, отдельные от последующего объекта конфигурации, который играет роль аргументов ключевого слова. Например:

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

Model.fit() является асинхронным

Model.fit() — это основной метод, с помощью которого пользователи выполняют обучение модели в TensorFlow.js. Этот метод часто может работать долго, в течение нескольких секунд или минут. Поэтому мы используем async функцию языка JavaScript, чтобы эту функцию можно было использовать таким образом, чтобы не блокировать основной поток пользовательского интерфейса при запуске в браузере. Это похоже на другие потенциально долго выполняемые функции в JavaScript, такие как async fetch . Обратите внимание, что async — это конструкция, которой нет в Python. В то время как метод fit() в Keras возвращает объект History, аналог метода fit() в JavaScript возвращает Promise of History, который можно ожидать (как в примере выше) или использовать с методом then().

Нет NumPy для TensorFlow.js

Пользователи Python Keras часто используют NumPy для выполнения основных числовых операций и операций с массивами, таких как создание 2D-тензоров в приведенном выше примере.

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

В TensorFlow.js такого рода базовые числовые операции выполняются с помощью самого пакета. Например:

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

Пространство имен tf.* также предоставляет ряд других функций для операций с массивами и линейной алгебры, таких как умножение матриц. Дополнительную информацию см. в документации TensorFlow.js Core .

Используйте фабричные методы, а не конструкторы

Эта строка в Python (из примера выше) представляет собой вызов конструктора:

# Python:
model = keras.Sequential()

Если строго перевести на JavaScript, эквивалентный вызов конструктора будет выглядеть следующим образом:

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

Однако мы решили не использовать «новые» конструкторы, потому что 1) ключевое слово «new» сделает код более раздутым и 2) «новый» конструктор считается «плохой частью» JavaScript: потенциальной ловушкой, поскольку обсуждается в JavaScript: Good Parts . Чтобы создавать модели и слои в TensorFlow.js, вы вызываете фабричные методы, имена которых имеют нижнее значение CamelCase, например:

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

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

Значения строки параметра — LowerCamelCase, а не Snake_case.

В JavaScript для имен символов чаще используется верблюжий регистр (например, см. Руководство по стилю Google JavaScript ), по сравнению с Python, где распространен змеиный регистр (например, в Keras). Поэтому мы решили использовать lowCamelCase для строковых значений опций, включая следующие:

  • Формат данных, например, channelsFirst вместо channels_first
  • Инициализатор, например, glorotNormal вместо glorot_normal
  • Потери и метрики, например, meanSquaredError вместо mean_squared_error , categoricalCrossentropy вместо categorical_crossentropy .

Например, как в примере выше:

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

Что касается сериализации и десериализации модели, будьте уверены. Внутренний механизм TensorFlow.js гарантирует правильную обработку случаев змей в объектах JSON, например, при загрузке предварительно обученных моделей из Python Keras.

Запускайте объекты Layer с помощью apply(), а не вызывая их как функции.

В Keras для объекта Layer определен метод __call__ . Поэтому пользователь может вызвать логику уровня, вызвав объект как функцию, например:

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

print(flatten(my_input).shape)

Этот синтаксический сахар Python реализован как метод apply() в TensorFlow.js:

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

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

Layer.apply() поддерживает императивную (нетерпеливую) оценку конкретных тензоров.

В настоящее время в Keras метод вызова может работать только с объектами tf.Tensor (Python) TensorFlow (при условии, что используется бэкэнд TensorFlow), которые являются символическими и не содержат фактических числовых значений. Это то, что показано в примере в предыдущем разделе. Однако в TensorFlow.js метод слоев apply() может работать как в символическом, так и в императивном режимах. Если apply() вызывается с символическим тензором (близкая аналогия tf.Tensor), возвращаемым значением будет символический тензор. Обычно это происходит во время построения модели. Но если apply() вызывается с фактическим конкретным значением Тензора, он вернет конкретный Тензор. Например:

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

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

Эта функция напоминает Eager Execution (Python) TensorFlow. Это обеспечивает большую интерактивность и возможность отладки во время разработки модели, а также открывает возможности для создания динамических нейронных сетей.

Оптимизаторы находятся в стадии обучения. , а не оптимизаторы.

В Keras конструкторы объектов Optimizer находятся в пространстве имен keras.optimizers.* . В слоях TensorFlow.js фабричные методы для оптимизаторов находятся в пространстве имен tf.train.* . Например:

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

loadLayersModel() загружается из URL-адреса, а не из файла HDF5.

В Keras модели обычно сохраняются в виде файла HDF5 (.h5), который позже можно загрузить с помощью метода keras.models.load_model() . Метод принимает путь к файлу .h5. Аналогом load_model() в TensorFlow.js является tf.loadLayersModel() . Поскольку HDF5 не является форматом файлов, удобным для браузера, tf.loadLayersModel() принимает формат, специфичный для TensorFlow.js. tf.loadLayersModel() принимает файл model.json в качестве входного аргумента. Model.json можно преобразовать из файла Keras HDF5 с помощью пакета pip tensorflowjs.

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

Также обратите внимание, что tf.loadLayersModel() возвращает Promise tf.Model .

Как правило, сохранение и загрузка tf.Model в TensorFlow.js выполняется с использованием методов tf.Model.save и tf.loadLayersModel соответственно. Мы разработали эти API так, чтобы они были похожи на API сохранения и загрузки_модели Keras. Но среда браузера сильно отличается от серверной среды, в которой работают основные платформы глубокого обучения, такие как Keras, особенно в массиве маршрутов для сохранения и передачи данных. Следовательно, между API сохранения/загрузки в TensorFlow.js и Keras есть некоторые интересные различия. Дополнительную информацию см. в нашем руководстве по сохранению и загрузке tf.Model .

Используйте fitDataset() для обучения моделей с использованием объектов tf.data.Dataset .

В tf.keras Python TensorFlow модель можно обучить с помощью объекта Dataset . Метод модели fit() принимает такой объект напрямую. Модель TensorFlow.js также можно обучать с помощью JavaScript-эквивалента объектов Dataset (см. документацию API tf.data в TensorFlow.js ). Однако, в отличие от Python, обучение на основе набора данных осуществляется с помощью специального метода, а именно fitDataset . Метод fit() предназначен только для обучения модели на основе тензоров.

Управление памятью объектов слоев и моделей

TensorFlow.js работает на WebGL в браузере, где веса объектов Layer и Model поддерживаются текстурами WebGL. Однако в WebGL нет встроенной поддержки сборки мусора. Объекты Layer и Model внутренне управляют тензорной памятью пользователя во время его логических выводов и вызовов обучения. Но они также позволяют пользователю избавиться от них, чтобы освободить занимаемую ими память WebGL. Это полезно в тех случаях, когда за одну загрузку страницы создается и выпускается множество экземпляров модели. Чтобы удалить объект Layer или Model, используйте метод dispose() .