Учебные модели

В этом руководстве предполагается, что вы уже прочитали руководство по моделям и слоям .

В TensorFlow.js есть два способа обучения модели машинного обучения:

  1. используя Layers API с LayersModel.fit() или LayersModel.fitDataset() .
  2. используя Core API с Optimizer.minimize() .

Во-первых, мы рассмотрим API слоев, который представляет собой API более высокого уровня для построения и обучения моделей. Затем мы покажем, как обучить ту же модель с помощью Core API.

Введение

Модель машинного обучения — это функция с изучаемыми параметрами, которая сопоставляет входные данные с желаемыми выходными данными. Оптимальные параметры получаются путем обучения модели на данных.

Обучение включает в себя несколько этапов:

  • Получение пакета данных для модели.
  • Попросите модель сделать прогноз.
  • Сравнение этого прогноза с «истинным» значением.
  • Решить, насколько изменить каждый параметр, чтобы модель могла сделать лучший прогноз в будущем для этой партии.

Хорошо обученная модель обеспечит точное сопоставление входных данных с желаемыми выходными данными.

Параметры модели

Давайте определим простую двухуровневую модель, используя Layers API:

const model = tf.sequential({
 layers: [
   tf.layers.dense({inputShape: [784], units: 32, activation: 'relu'}),
   tf.layers.dense({units: 10, activation: 'softmax'}),
 ]
});

Под капотом у моделей есть параметры (часто называемые весами ), которые можно изучить путем обучения на данных. Выведем имена весов, связанных с этой моделью, и их формы:

model.weights.forEach(w => {
 console.log(w.name, w.shape);
});

Мы получаем следующий вывод:

> dense_Dense1/kernel [784, 32]
> dense_Dense1/bias [32]
> dense_Dense2/kernel [32, 10]
> dense_Dense2/bias [10]

Всего утяжелителей 4, по 2 на плотный слой. Это ожидается, поскольку плотные слои представляют собой функцию, которая отображает входной тензор x в выходной тензор y с помощью уравнения y = Ax + b , где A (ядро) и b (смещение) являются параметрами плотного слоя.

ПРИМЕЧАНИЕ. По умолчанию плотные слои включают смещение, но вы можете исключить его, указав {useBias: false} в параметрах при создании плотного слоя.

model.summary() — полезный метод, если вы хотите получить обзор вашей модели и увидеть общее количество параметров:

Слой (тип) Выходная форма Параметр #
плотности_Dense1 (Плотные) [ноль, 32] 25120
плотности_Dense2 (Плотные) [ноль, 10] 330
Всего параметров: 25450
Обучаемые параметры: 25450
Необучаемые параметры: 0

Каждый вес в модели поддерживается объектом Variable . В TensorFlow.js Variable представляет собой Tensor с плавающей запятой с одним дополнительным методом assign() , используемым для обновления его значений. Layers API автоматически инициализирует веса в соответствии с рекомендациями. Ради демонстрации мы могли бы перезаписать веса, вызвав assign() для базовых переменных:

model.weights.forEach(w => {
  const newVals = tf.randomNormal(w.shape);
  // w.val is an instance of tf.Variable
  w.val.assign(newVals);
});

Оптимизатор, потеря и метрика

Прежде чем приступить к какой-либо тренировке, вам необходимо решить три вещи:

  1. Оптимизатор . Задача оптимизатора состоит в том, чтобы решить, насколько изменить каждый параметр в модели с учетом текущего прогноза модели. При использовании Layers API вы можете указать либо строковый идентификатор существующего оптимизатора (например, 'sgd' или 'adam' ), либо экземпляр класса Optimizer .
  2. Функция потерь . Цель, которую модель попытается минимизировать. Его цель - дать одно число для того, «насколько ошибочным» было предсказание модели. Потери вычисляются для каждого пакета данных, чтобы модель могла обновлять свои веса. При использовании Layers API вы можете предоставить либо строковый идентификатор существующей функции потерь (например, 'categoricalCrossentropy' ), либо любую функцию, которая принимает предсказанное и истинное значение и возвращает потерю. См. список доступных потерь в нашей документации по API.
  3. Список показателей. Подобно потерям, метрики вычисляют одно число, суммируя, насколько хорошо работает наша модель. Метрики обычно вычисляются по всем данным в конце каждой эпохи. По крайней мере, мы хотим следить за тем, чтобы наши потери со временем уменьшались. Однако нам часто нужна более удобная для человека метрика, такая как точность. При использовании Layers API вы можете указать либо строковый идентификатор существующей метрики (например, 'accuracy' ), либо любую функцию, которая принимает прогнозируемое и истинное значение и возвращает оценку. См. список доступных метрик в нашей документации по API.

Когда вы решили, скомпилируйте LayersModel , вызвав model.compile() с предоставленными параметрами:

model.compile({
  optimizer: 'sgd',
  loss: 'categoricalCrossentropy',
  metrics: ['accuracy']
});

Во время компиляции модель выполнит некоторую проверку, чтобы убедиться, что выбранные вами параметры совместимы друг с другом.

Подготовка

Существует два способа обучения LayersModel :

  • Использование model.fit() и предоставление данных в виде одного большого тензора.
  • Использование model.fitDataset() и предоставление данных через объект Dataset .

модель.fit()

Если ваш набор данных помещается в основную память и доступен как один тензор, вы можете обучить модель, вызвав метод fit() :

// Generate dummy data.
const data = tf.randomNormal([100, 784]);
const labels = tf.randomUniform([100, 10]);

function onBatchEnd(batch, logs) {
  console.log('Accuracy', logs.acc);
}

// Train for 5 epochs with batch size of 32.
model.fit(data, labels, {
   epochs: 5,
   batchSize: 32,
   callbacks: {onBatchEnd}
 }).then(info => {
   console.log('Final accuracy', info.history.acc);
 });

Под капотом model.fit() может многое сделать для нас:

  • Разделяет данные на обучающий и проверочный наборы и использует проверочный набор для измерения прогресса во время обучения.
  • Перемешивает данные, но только после разделения. Чтобы быть в безопасности, вы должны предварительно перемешать данные перед передачей их в fit() .
  • Разбивает большой тензор данных на меньшие тензоры размера batchSize.
  • Вызывает optimizer.minimize() при вычислении потери модели по отношению к пакету данных.
  • Он может уведомлять вас о начале и конце каждой эпохи или партии. В нашем случае мы получаем уведомление в конце каждого пакета, используя опцию callbacks.onBatchEnd . Другие параметры включают: onTrainBegin , onTrainEnd , onEpochBegin , onEpochEnd и onBatchBegin .
  • Он уступает основному потоку, чтобы гарантировать, что задачи, поставленные в очередь в цикле событий JS, могут быть обработаны своевременно.

Для получения дополнительной информации см. документацию по fit() . Обратите внимание: если вы решите использовать Core API, вам придется реализовать эту логику самостоятельно.

модель.fitDataset()

Если ваши данные не помещаются полностью в память или передаются в потоковом режиме, вы можете обучить модель, вызвав fitDataset() , который принимает объект Dataset . Вот тот же обучающий код, но с набором данных, в который встроена функция-генератор:

function* data() {
 for (let i = 0; i < 100; i++) {
   // Generate one sample at a time.
   yield tf.randomNormal([784]);
 }
}

function* labels() {
 for (let i = 0; i < 100; i++) {
   // Generate one sample at a time.
   yield tf.randomUniform([10]);
 }
}

const xs = tf.data.generator(data);
const ys = tf.data.generator(labels);
// We zip the data and labels together, shuffle and batch 32 samples at a time.
const ds = tf.data.zip({xs, ys}).shuffle(100 /* bufferSize */).batch(32);

// Train the model for 5 epochs.
model.fitDataset(ds, {epochs: 5}).then(info => {
 console.log('Accuracy', info.history.acc);
});

Для получения дополнительной информации о наборах данных см. документацию model.fitDataset() .

Прогнозирование новых данных

Как только модель будет обучена, вы можете вызвать model.predict() , чтобы делать прогнозы по невидимым данным:

// Predict 3 random samples.
const prediction = model.predict(tf.randomNormal([3, 784]));
prediction.print();

Основной API

Ранее мы упоминали, что существует два способа обучения модели машинного обучения в TensorFlow.js.

Общее эмпирическое правило заключается в том, чтобы сначала попытаться использовать API-интерфейс Layers, так как он смоделирован после хорошо принятого API-интерфейса Keras. Layers API также предлагает различные готовые решения, такие как инициализация веса, сериализация модели, обучение мониторингу, переносимость и проверка безопасности.

Вы можете использовать Core API всякий раз, когда:

  • Вам нужна максимальная гибкость или контроль.
  • И вам не нужна сериализация или вы можете реализовать свою собственную логику сериализации.

Дополнительные сведения об этом API см. в разделе «Основной API» руководства « Модели и слои ».

Та же модель, что и выше, написанная с использованием Core API, выглядит так:

// The weights and biases for the two dense layers.
const w1 = tf.variable(tf.randomNormal([784, 32]));
const b1 = tf.variable(tf.randomNormal([32]));
const w2 = tf.variable(tf.randomNormal([32, 10]));
const b2 = tf.variable(tf.randomNormal([10]));

function model(x) {
  return x.matMul(w1).add(b1).relu().matMul(w2).add(b2);
}

В дополнение к Layers API, Data API также без проблем работает с Core API. Давайте повторно используем набор данных, который мы определили ранее в разделе model.fitDataset() , который выполняет для нас перетасовку и пакетную обработку:

const xs = tf.data.generator(data);
const ys = tf.data.generator(labels);
// Zip the data and labels together, shuffle and batch 32 samples at a time.
const ds = tf.data.zip({xs, ys}).shuffle(100 /* bufferSize */).batch(32);

Давайте обучим модель:

const optimizer = tf.train.sgd(0.1 /* learningRate */);
// Train for 5 epochs.
for (let epoch = 0; epoch < 5; epoch++) {
  await ds.forEachAsync(({xs, ys}) => {
    optimizer.minimize(() => {
      const predYs = model(xs);
      const loss = tf.losses.softmaxCrossEntropy(ys, predYs);
      loss.data().then(l => console.log('Loss', l));
      return loss;
    });
  });
  console.log('Epoch', epoch);
}

Приведенный выше код является стандартным рецептом при обучении модели с помощью Core API:

  • Цикл по количеству эпох.
  • Внутри каждой эпохи перебирайте свои пакеты данных. При использовании Dataset dataset.forEachAsync() — это удобный способ перебора пакетов.
  • Для каждого пакета вызовите optimizer.minimize(f) , который выполняет f и минимизирует его вывод, вычисляя градиенты по отношению к четырем переменным, которые мы определили ранее.
  • f вычисляет потери. Он вызывает одну из предопределенных функций потерь, используя прогноз модели и истинное значение.