TensorFlow 2.0 RC is available Learn more

Keras

Читай на TensorFlow.org Запусти в Google Colab Изучай код на GitHub

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

  • Простота в использовании
    Keras имеет простой интерфейс, оптимизированный для большинства распространенных задач глубокого обучения. Также он дает конкретные подсказки как быстро исправить возможные ошибки
  • Модульность
    Модели Keras строятся при помощи объединения нескольких простых модулей, каждый из которых может быть настроен независимо, и не накладывает каких либо значительных ограничений
  • Легко расширить модель
    Ты можешь создавать свои собственные модули, чтобы свободно выражать свои идеи для исследования. Создавай новые слои, функции потерь и разрабатывай современные модели глубокого обучения

Импортируем tf.keras

tf.keras - это реализация спецификации Keras API в TensorFlow. Это высокоуровневый API для построения моделей глубокого обучения с первоклассной поддержкой функционала TensorFlow, например eager execution, конвееры tf.data и алгоритмы оценки Estimators. tf.keras делает TensorFlow простым в использовании, не теряя в гибкости и производительности.

Чтобы начать, просто импортируй tf.keras после TensorFlow в начале кода:

# Используй pyyaml если будешь сохранять в формате YAML
!pip install -q pyyaml
from __future__ import absolute_import, division, print_function, unicode_literals, unicode_literals

import tensorflow as tf
from tensorflow.keras import layers

print(tf.VERSION)
print(tf.keras.__version__)
1.12.0
2.1.6-tf

tf.keras может запускать любой совместимый с Keras код, но тем не менее помни:

  • Версия tf.keras в последнем релизе TensorFlow может быть не самой последнией версией keras, доступной в PyPI. Всегда проверяй версию при помощи tf.keras.__version__
  • Когда ты сохраняешь только веса модели, tf.keras по умолчанию сохраняет их в формате контрольной точки. Используй save_format='h5' чтобы сохранять как HDF5

Построим простую модель

Последовательная модель

В Keras мы используем слои для построения моделей. Обычно модель - это граф, состоящий из нескольких слоев. Самый распространенный тип модели это стэк идущих друг за другом слоев - последовательная модель tf.keras.Sequential.

Для начала давай построим простую полносвязную сеть (или многослойный перцептрон):

model = tf.keras.Sequential()
# Добавим в нашу модель слой Dense из 64 блоков:
model.add(layers.Dense(64, activation='relu'))
# И еще один:
model.add(layers.Dense(64, activation='relu'))
# Также добавим слой softmax с 10 выводящими блоками:
model.add(layers.Dense(10, activation='softmax'))

Конфигурация слоев

Существует много разных слоев tf.keras.layers с общими параметрами конфигурации:

  • activation: Устанавливает функцию активации для данного слоя. Этот параметр должен указываться в имени встроенной функции или использоваться как вызываемый объект. По умолчанию активация не используется
  • kernel_initializer и bias_initializer: Инициализация, которая создает веса данного слоя (ядро kernel и смещение bias). Этот параметр используется как имя или вызываемый объект. По умолчанию используется инициализатор "Glorot uniform"
  • kernel_regularizer и bias_regularizer: Регуляризация, которая применяется к весам слоя (ядро kernel и смещение bias), например L1 или L2. По умолчанию не используется

Следующий код используется для построения tf.keras.layers.Dense с настройкой конфигурации каждого слоя:

# Создаем сигмоидный слой:
layers.Dense(64, activation='sigmoid')
# Или:
layers.Dense(64, activation=tf.sigmoid)

# Линейный слой с регуляризацией L1 с коэффицентом 0.01 примененная к ядру матрицы:
layers.Dense(64, kernel_regularizer=tf.keras.regularizers.l1(0.01))

# Линейный слой с регуляризацией L2 с коэффицентом 0.01 примененная к вектору смещения (bias):
layers.Dense(64, bias_regularizer=tf.keras.regularizers.l2(0.01))

# Линейный слой с ядром, инициализированным в случайной прямоугольный матрице:
layers.Dense(64, kernel_initializer='orthogonal')

# Линейный слой с вектором смещения, инициализированным с коэффицентом 2:
layers.Dense(64, bias_initializer=tf.keras.initializers.constant(2.0))
<tensorflow.python.keras.layers.core.Dense at 0x7f3fa8e0f400>

Обучение и оценка

Настроим конфигурацию обучения

После того как модель построена давай обозначим процесс обучения с помощью метода compile:

model = tf.keras.Sequential([
# Добавим в нашу модель слой `Dense` из 64 блоков:
layers.Dense(64, activation='relu', input_shape=(32,)),
# И еще один:
layers.Dense(64, activation='relu'),
# Также добавим слой softmax с 10 выводящими блоками:
layers.Dense(10, activation='softmax')])

model.compile(optimizer=tf.train.AdamOptimizer(0.001),
              loss='categorical_crossentropy',
              metrics=['accuracy'])

У tf.keras.Model.compile есть три важных аргумента:

  • optimizer: Этот объект определяет процедуру обучения. Мы будем использовать оптимизаторы из модуля tf.train, например такие как tf.train.AdamOptimizer, tf.train.RMSPropOptimizer и tf.train.GradientDescentOptimizer
  • loss: Эта функция минимизации для решения задач оптимизации. Самыми распространенными выборами этого аргумента являются среднеквадратическое отклонение (mse), categorical_crossentropy, и binary_crossentropy. Функции потерь обозначены по имени или используются как вызываемые объекты из модуля tf.keras.losses
  • metrics: Используются для наблюдения за процессом обучения. Используются как строки или вызываемые объекты модуля tf.keras.metrics

Ниже пример конфигурации модели для обучения:

# Настраиваем регрессию модели, используем среднеквадратическое отклонение
model.compile(optimizer=tf.train.AdamOptimizer(0.01),
              loss='mse',       # среднеквадратическое отклонение
              metrics=['mae'])  # средняя абсолютная ошибка

# Настраиваем модель для классификации по категориям
model.compile(optimizer=tf.train.RMSPropOptimizer(0.01),
              loss=tf.keras.losses.categorical_crossentropy,
              metrics=[tf.keras.metrics.categorical_accuracy])

Используем данные NumPy

При работе с небольшими датасетами мы будем использовать загружаемые в память массивы данных NumPy для обучения и оценки моделей. Модель будет "подстраиваться" под тренировочные данные при помощи метода fit:

import numpy as np

data = np.random.random((1000, 32))
labels = np.random.random((1000, 10))

model.fit(data, labels, epochs=10, batch_size=32)
Epoch 1/10
1000/1000 [==============================] - 0s 254us/step - loss: 11.6090 - categorical_accuracy: 0.0920
Epoch 2/10
1000/1000 [==============================] - 0s 62us/step - loss: 11.5505 - categorical_accuracy: 0.0940
Epoch 3/10
1000/1000 [==============================] - 0s 63us/step - loss: 11.5391 - categorical_accuracy: 0.1010
Epoch 4/10
1000/1000 [==============================] - 0s 69us/step - loss: 11.5340 - categorical_accuracy: 0.1080
Epoch 5/10
1000/1000 [==============================] - 0s 70us/step - loss: 11.5302 - categorical_accuracy: 0.1140
Epoch 6/10
1000/1000 [==============================] - 0s 69us/step - loss: 11.5306 - categorical_accuracy: 0.0980
Epoch 7/10
1000/1000 [==============================] - 0s 67us/step - loss: 11.5294 - categorical_accuracy: 0.0920
Epoch 8/10
1000/1000 [==============================] - 0s 69us/step - loss: 11.5258 - categorical_accuracy: 0.1030
Epoch 9/10
1000/1000 [==============================] - 0s 69us/step - loss: 11.5235 - categorical_accuracy: 0.1160
Epoch 10/10
1000/1000 [==============================] - 0s 67us/step - loss: 11.5212 - categorical_accuracy: 0.1120

<tensorflow.python.keras.callbacks.History at 0x7f3fa967de48>

У tf.keras.Model.fit есть три важных аргумента:

  • epochs: Процесс обучения структурирован по эпохам. Эпоха означает один проход по всему набору входных данных, который происходит небольшими порциями в батчах
  • batch_size: Когда мы используем массивы NumPy модель делит данные на небольшие батчи и затем выполняет указанное количество проходов. Это число определяет размер батча. Помни, что последний батч может быть меньше если общее количество образцов данных не делится на размер батча
  • validation_data: Когда мы строим прототип модели, мы хотим легко наблюдать за ее точностью на проверочных данных. При помощи данного аргумента - обычно кортеж или метка - модель будет отображать потери и статистику в режиме выводов inference для прошедших через модель данных в конце каждой эпохи

Вот пример использования validation_data:

import numpy as np

data = np.random.random((1000, 32))
labels = np.random.random((1000, 10))

val_data = np.random.random((100, 32))
val_labels = np.random.random((100, 10))

model.fit(data, labels, epochs=10, batch_size=32,
          validation_data=(val_data, val_labels))
Train on 1000 samples, validate on 100 samples
Epoch 1/10
1000/1000 [==============================] - 0s 125us/step - loss: 11.6005 - categorical_accuracy: 0.0970 - val_loss: 11.7116 - val_categorical_accuracy: 0.1100
Epoch 2/10
1000/1000 [==============================] - 0s 68us/step - loss: 11.5961 - categorical_accuracy: 0.1080 - val_loss: 11.7018 - val_categorical_accuracy: 0.1000
Epoch 3/10
1000/1000 [==============================] - 0s 74us/step - loss: 11.5976 - categorical_accuracy: 0.1000 - val_loss: 11.7006 - val_categorical_accuracy: 0.0600
Epoch 4/10
1000/1000 [==============================] - 0s 76us/step - loss: 11.5963 - categorical_accuracy: 0.1080 - val_loss: 11.7117 - val_categorical_accuracy: 0.1300
Epoch 5/10
1000/1000 [==============================] - 0s 75us/step - loss: 11.5964 - categorical_accuracy: 0.1000 - val_loss: 11.7028 - val_categorical_accuracy: 0.0800
Epoch 6/10
1000/1000 [==============================] - 0s 75us/step - loss: 11.5953 - categorical_accuracy: 0.1150 - val_loss: 11.6966 - val_categorical_accuracy: 0.1000
Epoch 7/10
1000/1000 [==============================] - 0s 75us/step - loss: 11.5929 - categorical_accuracy: 0.1130 - val_loss: 11.6987 - val_categorical_accuracy: 0.1200
Epoch 8/10
1000/1000 [==============================] - 0s 75us/step - loss: 11.5933 - categorical_accuracy: 0.1190 - val_loss: 11.7032 - val_categorical_accuracy: 0.1300
Epoch 9/10
1000/1000 [==============================] - 0s 71us/step - loss: 11.5911 - categorical_accuracy: 0.1150 - val_loss: 11.7148 - val_categorical_accuracy: 0.0800
Epoch 10/10
1000/1000 [==============================] - 0s 72us/step - loss: 11.5886 - categorical_accuracy: 0.1230 - val_loss: 11.7216 - val_categorical_accuracy: 0.0400

<tensorflow.python.keras.callbacks.History at 0x7f3fa88c9240>

Используем датасеты tf.data

Чтобы обучать модель на больших датасетах или на нескольких устройствах мы можем воспользоваться Datasets API. Просто добавь tf.data.Dataset к методу fit:

# Инициализируем пробную инстанцию датасета:
dataset = tf.data.Dataset.from_tensor_slices((data, labels))
dataset = dataset.batch(32)
dataset = dataset.repeat()

# Не забудь указать количество шагов в каждой эпохе `steps_per_epoch` при использовании метода `fit`
model.fit(dataset, epochs=10, steps_per_epoch=30)
Epoch 1/10
30/30 [==============================] - 0s 6ms/step - loss: 11.5964 - categorical_accuracy: 0.1260
Epoch 2/10
30/30 [==============================] - 0s 2ms/step - loss: 11.5624 - categorical_accuracy: 0.1427
Epoch 3/10
30/30 [==============================] - 0s 2ms/step - loss: 11.5471 - categorical_accuracy: 0.1302
Epoch 4/10
30/30 [==============================] - 0s 2ms/step - loss: 11.5732 - categorical_accuracy: 0.1260
Epoch 5/10
30/30 [==============================] - 0s 2ms/step - loss: 11.5641 - categorical_accuracy: 0.1312
Epoch 6/10
30/30 [==============================] - 0s 2ms/step - loss: 11.5257 - categorical_accuracy: 0.1396
Epoch 7/10
30/30 [==============================] - 0s 2ms/step - loss: 11.5518 - categorical_accuracy: 0.1385
Epoch 8/10
30/30 [==============================] - 0s 2ms/step - loss: 11.5083 - categorical_accuracy: 0.1260
Epoch 9/10
30/30 [==============================] - 0s 2ms/step - loss: 11.5550 - categorical_accuracy: 0.1510
Epoch 10/10
30/30 [==============================] - 0s 2ms/step - loss: 11.5435 - categorical_accuracy: 0.1573

<tensorflow.python.keras.callbacks.History at 0x7f3fa88c9278>

Таким образом, метод fit использует аргумент steps_per_epoch - это количество шагов обучения, которые модель должна сделать прежде, чем перейти на следующую эпоху. Поскольку Dataset принимает батчи данных, то в этом примере кода нам не требуется указывать размер батча в batch_size.

Также dataset можно использовать для проверки точности модели:

dataset = tf.data.Dataset.from_tensor_slices((data, labels))
dataset = dataset.batch(32).repeat()

val_dataset = tf.data.Dataset.from_tensor_slices((val_data, val_labels))
val_dataset = val_dataset.batch(32).repeat()

model.fit(dataset, epochs=10, steps_per_epoch=30,
          validation_data=val_dataset,
          validation_steps=3)
Epoch 1/10
30/30 [==============================] - 0s 8ms/step - loss: 11.5609 - categorical_accuracy: 0.1521 - val_loss: 11.7549 - val_categorical_accuracy: 0.0833
Epoch 2/10
30/30 [==============================] - 0s 2ms/step - loss: 11.5177 - categorical_accuracy: 0.1646 - val_loss: 11.4992 - val_categorical_accuracy: 0.0521
Epoch 3/10
30/30 [==============================] - 0s 3ms/step - loss: 11.5087 - categorical_accuracy: 0.1677 - val_loss: 11.6696 - val_categorical_accuracy: 0.0625
Epoch 4/10
30/30 [==============================] - 0s 2ms/step - loss: 11.5312 - categorical_accuracy: 0.1562 - val_loss: 11.6022 - val_categorical_accuracy: 0.1250
Epoch 5/10
30/30 [==============================] - 0s 2ms/step - loss: 11.5260 - categorical_accuracy: 0.1635 - val_loss: 11.7886 - val_categorical_accuracy: 0.0729
Epoch 6/10
30/30 [==============================] - 0s 2ms/step - loss: 11.4881 - categorical_accuracy: 0.1844 - val_loss: 11.5321 - val_categorical_accuracy: 0.1458
Epoch 7/10
30/30 [==============================] - 0s 2ms/step - loss: 11.5113 - categorical_accuracy: 0.1990 - val_loss: 11.7011 - val_categorical_accuracy: 0.1146
Epoch 8/10
30/30 [==============================] - 0s 2ms/step - loss: 11.4692 - categorical_accuracy: 0.1833 - val_loss: 11.6737 - val_categorical_accuracy: 0.1146
Epoch 9/10
30/30 [==============================] - 0s 2ms/step - loss: 11.5151 - categorical_accuracy: 0.1885 - val_loss: 11.8630 - val_categorical_accuracy: 0.0938
Epoch 10/10
30/30 [==============================] - 0s 2ms/step - loss: 11.5101 - categorical_accuracy: 0.1771 - val_loss: 11.5909 - val_categorical_accuracy: 0.0312

<tensorflow.python.keras.callbacks.History at 0x7f3fa807a080>

Оценка и предсказание

Методы tf.keras.Model.evaluate и tf.keras.Model.predict могут использовать данные NumPy и tf.data.Dataset.

Используй следующий пример кода для оценки потерь и других показателей предсказаний на использованных данных:

data = np.random.random((1000, 32))
labels = np.random.random((1000, 10))

model.evaluate(data, labels, batch_size=32)

model.evaluate(dataset, steps=30)
1000/1000 [==============================] - 0s 78us/step
30/30 [==============================] - 0s 3ms/step

[11.568973731994628, 0.15625]

Для предсказания вывода последнего слоя как массив NumPy, используй следующий код:

result = model.predict(data, batch_size=32)
print(result.shape)
(1000, 10)

Построение сложных моделей

Функциональный API

Последовательная модель tf.keras.Sequential представляет из себя обычное наложение или стек слоев, которые не могут представлять произвольные модели. Используй функциональный API Keras для построения комплексных топологий моделей, например таких как:

  • Модели с множественными входами данных
  • Модели с множественными выводами данных
  • Модели с общими слоями, где один и тот же слой вызывается несколько раз
  • Модели с непоследовательным потоком данных, например где есть остаточные связи

Построение модели при помощи функционального API выглядит следующим образом:

  1. Слой вызывается и возвращает тензор
  2. Для определения tf.keras.Model используем входные и выводящие тензоры
  3. Модель обучается точно так же, как и Sequential

Следующий пример показывает как использовать функциональный API для построения простой полносвязной сети:

# Возвращает тензор-"заполнитель", который мы используем в качестве примера
inputs = tf.keras.Input(shape=(32,))

# Вызываемый на тензор слой, возвращает тензор
x = layers.Dense(64, activation='relu')(inputs)
x = layers.Dense(64, activation='relu')(x)
predictions = layers.Dense(10, activation='softmax')(x)

Обозначим вход и вывод данных нашей модели:

model = tf.keras.Model(inputs=inputs, outputs=predictions)

# При помощи метода `compile` настраиваем конфигурацию обучения
model.compile(optimizer=tf.train.RMSPropOptimizer(0.001),
              loss='categorical_crossentropy',
              metrics=['accuracy'])

# Тренируем модель в течение 5 эпох
model.fit(data, labels, batch_size=32, epochs=5)
Epoch 1/5
1000/1000 [==============================] - 0s 222us/step - loss: 11.7461 - acc: 0.0970
Epoch 2/5
1000/1000 [==============================] - 0s 66us/step - loss: 11.6676 - acc: 0.0940
Epoch 3/5
1000/1000 [==============================] - 0s 69us/step - loss: 11.6474 - acc: 0.1220
Epoch 4/5
1000/1000 [==============================] - 0s 77us/step - loss: 11.6381 - acc: 0.1090
Epoch 5/5
1000/1000 [==============================] - 0s 69us/step - loss: 11.6322 - acc: 0.0950

<tensorflow.python.keras.callbacks.History at 0x7f3fa8044ef0>

Создание подклассов моделей

Также ты можешь создать модель с нуля при помощи подклассов в tf.keras.Model и определения собственных прямых проходов. Создавай слои в методе __init__ и установи их как атрибуты класса. Прямой проход должен быть указан в методе call.

Создание подклассов моделей особенно полезно, когда активирован eager execution, так как прямой проход в этом случае всегда будет записан.

Ключевой момент: всегда используй правильный API для решения конкретной задачи. Поскольку создание подклассов модели предполагает определенную гибкость, эта гибкость осложняет определение структуры и может повлечь больше ошибок у пользователя. Если возможно, то всегда старайся использовать функциональный API.

Смотри следующий пример кода, в котором мы будем использовать подклассы tf.keras.Model и собственный прямой проход:

class MyModel(tf.keras.Model):

  def __init__(self, num_classes=10):
    super(MyModel, self).__init__(name='my_model')
    self.num_classes = num_classes
    # Здесь определим слои
    self.dense_1 = layers.Dense(32, activation='relu')
    self.dense_2 = layers.Dense(num_classes, activation='sigmoid')

  def call(self, inputs):
    # А здесь укажем прямой проход,
    # используя указанные выше слои (в `__init__`).
    x = self.dense_1(inputs)
    return self.dense_2(x)

  def compute_output_shape(self, input_shape):
    # Если ты хочешь использовать подклассы модели
    # в функциональном стиле, тогда эта функция будет переписана
    # во время запуска кода. В остальных случаях этот метод необязателен.
    shape = tf.TensorShape(input_shape).as_list()
    shape[-1] = self.num_classes
    return tf.TensorShape(shape)

Укажем класс новой модели:

model = MyModel(num_classes=10)

# При помощи метода `compile` настраиваем конфигурацию обучения
model.compile(optimizer=tf.train.RMSPropOptimizer(0.001),
              loss='categorical_crossentropy',
              metrics=['accuracy'])

# Обучаем в течение 5 эпох
model.fit(data, labels, batch_size=32, epochs=5)
Epoch 1/5
1000/1000 [==============================] - 0s 216us/step - loss: 11.7314 - acc: 0.1090
Epoch 2/5
1000/1000 [==============================] - 0s 63us/step - loss: 11.6940 - acc: 0.1080
Epoch 3/5
1000/1000 [==============================] - 0s 67us/step - loss: 11.6578 - acc: 0.0980
Epoch 4/5
1000/1000 [==============================] - 0s 69us/step - loss: 11.6441 - acc: 0.1040
Epoch 5/5
1000/1000 [==============================] - 0s 68us/step - loss: 11.6391 - acc: 0.1200

<tensorflow.python.keras.callbacks.History at 0x7f40cc6261d0>

Создание собственных слоев

Чтобы создать свой собственный слой при помощи подклассов tf.keras.layers.Layer нам потребуются следующие методы:

  • build: Создает веса слоя. Чтобы добавить веса в модель используй метод add_weight
  • call: Определяет прямой проход
  • compute_output_shape: Определяет как вычислить выводящую форму слоя для данной входной формы
  • Также слой можно сериализировать при помощи метода get_config и метода класса from_config

Вот пример использования нового слоя, в котором мы использовали matmul входа с матрицей ядра kernel:

class MyLayer(layers.Layer):

  def __init__(self, output_dim, **kwargs):
    self.output_dim = output_dim
    super(MyLayer, self).__init__(**kwargs)

  def build(self, input_shape):
    shape = tf.TensorShape((input_shape[1], self.output_dim))
    # Создаем обучаемую переменную весов для этого слоя
    self.kernel = self.add_weight(name='kernel',
                                  shape=shape,
                                  initializer='uniform',
                                  trainable=True)
    # Обязательно вызови метод `build` в конце
    super(MyLayer, self).build(input_shape)

  def call(self, inputs):
    return tf.matmul(inputs, self.kernel)

  def compute_output_shape(self, input_shape):
    shape = tf.TensorShape(input_shape).as_list()
    shape[-1] = self.output_dim
    return tf.TensorShape(shape)

  def get_config(self):
    base_config = super(MyLayer, self).get_config()
    base_config['output_dim'] = self.output_dim
    return base_config

  @classmethod
  def from_config(cls, config):
    return cls(**config)

Теперь создадим модель, используя наш новый слой:

model = tf.keras.Sequential([
    MyLayer(10),
    layers.Activation('softmax')])

# При помощи метода `compile` настраиваем конфигурацию обучения
model.compile(optimizer=tf.train.RMSPropOptimizer(0.001),
              loss='categorical_crossentropy',
              metrics=['accuracy'])

# Обучаем в течение 5 эпох
model.fit(data, labels, batch_size=32, epochs=5)
Epoch 1/5
1000/1000 [==============================] - 0s 250us/step - loss: 11.6439 - acc: 0.1090
Epoch 2/5
1000/1000 [==============================] - 0s 62us/step - loss: 11.6345 - acc: 0.1050
Epoch 3/5
1000/1000 [==============================] - 0s 64us/step - loss: 11.6320 - acc: 0.0940
Epoch 4/5
1000/1000 [==============================] - 0s 65us/step - loss: 11.6307 - acc: 0.0970
Epoch 5/5
1000/1000 [==============================] - 0s 64us/step - loss: 11.6286 - acc: 0.1050

<tensorflow.python.keras.callbacks.History at 0x7f3fa0132278>

Функции обратного вызова

Функция обратного вызова callback - это объект, который передается модели для обработки и расширения ее поведения во время обучения. Ты можешь написать свою собственную функцию callback, или использовать готовые tf.keras.callbacks в которые входят:

  • tf.keras.callbacks.ModelCheckpoint: Сохраняет контрольные точки твоей модели через заданный интервал
  • tf.keras.callbacks.LearningRateScheduler: Замедляет темп обучения learning rate для получения лучших результатов точности
  • tf.keras.callbacks.EarlyStopping: Останавливает обучение как только точность перестает увеличиваться
  • tf.keras.callbacks.TensorBoard: Следит за поведением модели при помощи TensorBoard

Чтобы использовать tf.keras.callbacks.Callback просто передай его в метод fit своей модели:

callbacks = [
  # Прерывает обучение если потери при проверке `val_loss` перестают
  # уменьшаться после 2 эпох
  tf.keras.callbacks.EarlyStopping(patience=2, monitor='val_loss'),
  # Записываем логи TensorBoard в папку `./logs`
  tf.keras.callbacks.TensorBoard(log_dir='./logs')
]
model.fit(data, labels, batch_size=32, epochs=5, callbacks=callbacks,
          validation_data=(val_data, val_labels))
Train on 1000 samples, validate on 100 samples
Epoch 1/5
1000/1000 [==============================] - 0s 175us/step - loss: 11.6273 - acc: 0.0950 - val_loss: 11.6923 - val_acc: 0.1300
Epoch 2/5
1000/1000 [==============================] - 0s 81us/step - loss: 11.6253 - acc: 0.0990 - val_loss: 11.6973 - val_acc: 0.0900
Epoch 3/5
1000/1000 [==============================] - 0s 87us/step - loss: 11.6245 - acc: 0.1090 - val_loss: 11.6960 - val_acc: 0.1100

<tensorflow.python.keras.callbacks.History at 0x7f3f98663c18>

Сохранение и загрузка

Сохраняем веса

Ты можешь сохранять и загружать веса модели при помощи tf.keras.Model.save_weights:

model = tf.keras.Sequential([
layers.Dense(64, activation='relu'),
layers.Dense(10, activation='softmax')])

model.compile(optimizer=tf.train.AdamOptimizer(0.001),
              loss='categorical_crossentropy',
              metrics=['accuracy'])
# Сохраняем веса в контрольную точку формата TensorFlow
model.save_weights('./weights/my_model')

# Восстанавливаем состояние модели,
# требуется использование модели с точно такой же архитектурой
model.load_weights('./weights/my_model')
<tensorflow.python.training.checkpointable.util.CheckpointLoadStatus at 0x7f3f9863e748>

По умолчанию, веса модели сохраняются в формате контрольой точки TensorFlow. Веса также могут быть сохранены в формате Keras HDF5, который является стандартным в бэкенд структуре Keras:

# Сохраняем веса в файл HDF5
model.save_weights('my_model.h5', save_format='h5')

# Загружаем текущее состояние модели
model.load_weights('my_model.h5')

Сохраняем конфигурацию

Конфигурация модели также может быть сохранена: такой метод сериализирует архитектуру модели без сохранения весов.

Сохраненная конфигурация можеть быть загружена и инициализирована как оригинальная модель, даже без кода изначальной модели.

Keras поддерживает форматы сериализации данных JSON и YAML:

# Сериализация модели в формат JSON
json_string = model.to_json()
json_string
'{"backend": "tensorflow", "class_name": "Sequential", "config": {"name": "sequential_3", "layers": [{"class_name": "Dense", "config": {"units": 64, "activity_regularizer": null, "trainable": true, "activation": "relu", "bias_constraint": null, "name": "dense_17", "kernel_regularizer": null, "kernel_constraint": null, "bias_initializer": {"class_name": "Zeros", "config": {"dtype": "float32"}}, "dtype": null, "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null, "dtype": "float32"}}, "bias_regularizer": null}}, {"class_name": "Dense", "config": {"units": 10, "activity_regularizer": null, "trainable": true, "activation": "softmax", "bias_constraint": null, "name": "dense_18", "kernel_regularizer": null, "kernel_constraint": null, "bias_initializer": {"class_name": "Zeros", "config": {"dtype": "float32"}}, "dtype": null, "use_bias": true, "kernel_initializer": {"class_name": "GlorotUniform", "config": {"seed": null, "dtype": "float32"}}, "bias_regularizer": null}}]}, "keras_version": "2.1.6-tf"}'
import json
import pprint
pprint.pprint(json.loads(json_string))
{'backend': 'tensorflow',
 'class_name': 'Sequential',
 'config': {'layers': [{'class_name': 'Dense',
                        'config': {'activation': 'relu',
                                   'activity_regularizer': None,
                                   'bias_constraint': None,
                                   'bias_initializer': {'class_name': 'Zeros',
                                                        'config': {'dtype': 'float32'}},
                                   'bias_regularizer': None,
                                   'dtype': None,
                                   'kernel_constraint': None,
                                   'kernel_initializer': {'class_name': 'GlorotUniform',
                                                          'config': {'dtype': 'float32',
                                                                     'seed': None}},
                                   'kernel_regularizer': None,
                                   'name': 'dense_17',
                                   'trainable': True,
                                   'units': 64,
                                   'use_bias': True}},
                       {'class_name': 'Dense',
                        'config': {'activation': 'softmax',
                                   'activity_regularizer': None,
                                   'bias_constraint': None,
                                   'bias_initializer': {'class_name': 'Zeros',
                                                        'config': {'dtype': 'float32'}},
                                   'bias_regularizer': None,
                                   'dtype': None,
                                   'kernel_constraint': None,
                                   'kernel_initializer': {'class_name': 'GlorotUniform',
                                                          'config': {'dtype': 'float32',
                                                                     'seed': None}},
                                   'kernel_regularizer': None,
                                   'name': 'dense_18',
                                   'trainable': True,
                                   'units': 10,
                                   'use_bias': True}}],
            'name': 'sequential_3'},
 'keras_version': '2.1.6-tf'}

Давай воссоздадим только что инициализированную модель из JSON:

fresh_model = tf.keras.models.model_from_json(json_string)

Сериализация модели в формат YAML требуется установки pyyaml до импорта TensorFlow:

yaml_string = model.to_yaml()
print(yaml_string)
backend: tensorflow
class_name: Sequential
config:
  layers:
  - class_name: Dense
    config:
      activation: relu
      activity_regularizer: null
      bias_constraint: null
      bias_initializer:
        class_name: Zeros
        config:
          dtype: float32
      bias_regularizer: null
      dtype: null
      kernel_constraint: null
      kernel_initializer:
        class_name: GlorotUniform
        config:
          dtype: float32
          seed: null
      kernel_regularizer: null
      name: dense_17
      trainable: true
      units: 64
      use_bias: true
  - class_name: Dense
    config:
      activation: softmax
      activity_regularizer: null
      bias_constraint: null
      bias_initializer:
        class_name: Zeros
        config:
          dtype: float32
      bias_regularizer: null
      dtype: null
      kernel_constraint: null
      kernel_initializer:
        class_name: GlorotUniform
        config:
          dtype: float32
          seed: null
      kernel_regularizer: null
      name: dense_18
      trainable: true
      units: 10
      use_bias: true
  name: sequential_3
keras_version: 2.1.6-tf

Восстановим модель из формата YAML:

fresh_model = tf.keras.models.model_from_yaml(yaml_string)
/usr/local/lib/python3.5/dist-packages/tensorflow/python/keras/engine/saving.py:331: YAMLLoadWarning: calling yaml.load() without Loader=... is deprecated, as the default Loader is unsafe. Please read https://msg.pyyaml.org/load for full details.
  config = yaml.load(yaml_string)

Важно: модели с подклассами не могут быть сериализированы, потому что их архитектура определяется кодом Python в методе call.

Сохраняем модель полностью

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

# Создаем простую модель
model = tf.keras.Sequential([
  layers.Dense(10, activation='softmax', input_shape=(32,)),
  layers.Dense(10, activation='softmax')
])
model.compile(optimizer='rmsprop',
              loss='categorical_crossentropy',
              metrics=['accuracy'])
model.fit(data, labels, batch_size=32, epochs=5)

# Сохраняем модель целиком в один файл формата HDF5
model.save('my_model.h5')

# Восстаналиваем ту же самую модель, включая веса и оптимизатор
model = tf.keras.models.load_model('my_model.h5')
Epoch 1/5
1000/1000 [==============================] - 0s 316us/step - loss: 11.6413 - acc: 0.1100
Epoch 2/5
1000/1000 [==============================] - 0s 79us/step - loss: 11.6314 - acc: 0.0890
Epoch 3/5
1000/1000 [==============================] - 0s 82us/step - loss: 11.6285 - acc: 0.0980
Epoch 4/5
1000/1000 [==============================] - 0s 84us/step - loss: 11.6274 - acc: 0.1000
Epoch 5/5
1000/1000 [==============================] - 0s 83us/step - loss: 11.6268 - acc: 0.0900

Eager execution

Eager execution - это окружение императивного программирования, в котором все операции вычисляются мгновенно. В нем не требуется Keras, однако tf.keras поддерживается и оказывается весьма полезен для проверки программы и отладки кода.

Все API tf.keras для построения моделей совместимы с eager execution. В то время как функциональный API и Sequential могут быть использованы и здесь, наибольшее преимущество получат модели с подклассами и модели с собственными слоями - это именно те API, в которых тебе необходимо указать прямой проход в виде кода (вместо тех API, которые создают модели посредством сборки существующих слоев).

Смотри Руководство по eager execution для ознакомления с примерами использования моделей Keras с уникальными циклами обучения tf.GradientTape.

Распределенное обучение

Алгоритмы оценки Estimators

API Estimators используется для обучения моделей в распределенном окружении. Он необходим для решения задач распределенного обучения на больших датасетах например для экспорта модели в продакшен.

tf.keras.Model может обучаться с API tf.estimator посредством конвертации модели в объект tf.estimator.Estimator при помощи tf.keras.estimator.model_to_estimator. Читай больше в статье Создание Estimators из моделей Keras.

model = tf.keras.Sequential([layers.Dense(10,activation='softmax'),
                          layers.Dense(10,activation='softmax')])

model.compile(optimizer=tf.train.RMSPropOptimizer(0.001),
              loss='categorical_crossentropy',
              metrics=['accuracy'])

estimator = tf.keras.estimator.model_to_estimator(model)
INFO:tensorflow:Using default config.
WARNING:tensorflow:Using temporary folder as model directory: /tmp/tmp2_m890rz
INFO:tensorflow:Using the Keras model provided.
INFO:tensorflow:Using config: {'_keep_checkpoint_max': 5, '_eval_distribute': None, '_session_config': allow_soft_placement: true
graph_options {
  rewrite_options {
    meta_optimizer_iterations: ONE
  }
}
, '_save_checkpoints_secs': 600, '_service': None, '_task_id': 0, '_num_worker_replicas': 1, '_model_dir': '/tmp/tmp2_m890rz', '_master': '', '_save_checkpoints_steps': None, '_cluster_spec': <tensorflow.python.training.server_lib.ClusterSpec object at 0x7f3f98199748>, '_experimental_distribute': None, '_task_type': 'worker', '_is_chief': True, '_device_fn': None, '_evaluation_master': '', '_num_ps_replicas': 0, '_tf_random_seed': None, '_save_summary_steps': 100, '_keep_checkpoint_every_n_hours': 10000, '_log_step_count_steps': 100, '_protocol': None, '_train_distribute': None, '_global_id_in_cluster': 0}

Совет: используй eager execution для отладки функций входа Estimator и проверки данных.

Обучение на нескольких GPU

Модели tf.keras могут обучаться на нескольких GPU при помощи tf.contrib.distribute.DistributionStrategy. Этот API обеспечивает распределенное обучение на нескольких GPU почти без изменений основного кода модели.

В настоящее время tf.contrib.distribute.MirroredStrategy является единственной поддерживаемой стратегией распределенного обучения. MirroredStrategy выполняет внутриграфную репликацию с синхронным обучением, используя функцию all-reduce на одном устройстве. Чтобы использовать DistributionStrategy вместе с Keras, конвертируй модель tf.keras.Model в tf.estimator.Estimator при помощи tf.keras.estimator.model_to_estimator, а затем обучи получившийся estimator.

В следующем примере мы посмотрим как распределить tf.keras.Model на нескольких GPU на одном устройстве.

Для начала определим простую модель:

model = tf.keras.Sequential()
model.add(layers.Dense(16, activation='relu', input_shape=(10,)))
model.add(layers.Dense(1, activation='sigmoid'))

optimizer = tf.train.GradientDescentOptimizer(0.2)

model.compile(loss='binary_crossentropy', optimizer=optimizer)
model.summary()
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense_23 (Dense)             (None, 16)                176       
_________________________________________________________________
dense_24 (Dense)             (None, 1)                 17        
=================================================================
Total params: 193
Trainable params: 193
Non-trainable params: 0
_________________________________________________________________

Затем определим функцию загрузки и обработки данных. Функция Input_fn возвращает объект tf.data.Dataset, который используется для распределения данных на нескольких устройствах, где каждый GPU обрабатывает свой входящий батч.

def input_fn():
  x = np.random.random((1024, 10))
  y = np.random.randint(2, size=(1024, 1))
  x = tf.cast(x, tf.float32)
  dataset = tf.data.Dataset.from_tensor_slices((x, y))
  dataset = dataset.repeat(10)
  dataset = dataset.batch(32)
  return dataset

Далее, создадим tf.estimator.RunConfig и передадим аргумент train_distribute к tf.contrib.distribute.MirroredStrategy. При создании MirroredStrategy ты можешь определить список устройств или передать аргумент num_gpus с заданным количеством GPU для обучения. По умолчанию используются все доступные GPU как в следующем примере:

strategy = tf.contrib.distribute.MirroredStrategy()
config = tf.estimator.RunConfig(train_distribute=strategy)
INFO:tensorflow:Initializing RunConfig with distribution strategies.
INFO:tensorflow:Not using Distribute Coordinator.

Конвертируем модель Keras в tf.estimator.Estimator:

keras_estimator = tf.keras.estimator.model_to_estimator(
  keras_model=model,
  config=config,
  model_dir='/tmp/model_dir')
INFO:tensorflow:Using the Keras model provided.
INFO:tensorflow:Using config: {'_keep_checkpoint_max': 5, '_eval_distribute': None, '_session_config': allow_soft_placement: true
graph_options {
  rewrite_options {
    meta_optimizer_iterations: ONE
  }
}
, '_save_checkpoints_secs': 600, '_distribute_coordinator_mode': None, '_service': None, '_task_id': 0, '_num_worker_replicas': 1, '_model_dir': '/tmp/model_dir', '_master': '', '_save_checkpoints_steps': None, '_cluster_spec': <tensorflow.python.training.server_lib.ClusterSpec object at 0x7f3f6053dcc0>, '_experimental_distribute': None, '_task_type': 'worker', '_is_chief': True, '_device_fn': None, '_evaluation_master': '', '_num_ps_replicas': 0, '_tf_random_seed': None, '_save_summary_steps': 100, '_keep_checkpoint_every_n_hours': 10000, '_log_step_count_steps': 100, '_protocol': None, '_train_distribute': <tensorflow.contrib.distribute.python.mirrored_strategy.MirroredStrategy object at 0x7f3f9865ef60>, '_global_id_in_cluster': 0}

Наконец, обучаем Estimator, передав аргументы input_fn и steps:

keras_estimator.train(input_fn=input_fn, steps=10)
INFO:tensorflow:Device is available but not used by distribute strategy: /device:XLA_CPU:0
WARNING:tensorflow:Not all devices in DistributionStrategy are visible to TensorFlow session.
INFO:tensorflow:Calling model_fn.
INFO:tensorflow:Done calling model_fn.
INFO:tensorflow:Warm-starting with WarmStartSettings: WarmStartSettings(ckpt_to_initialize_from='/tmp/model_dir/keras/keras_model.ckpt', vars_to_warm_start='.*', var_name_to_vocab_info={}, var_name_to_prev_var_name={})
INFO:tensorflow:Warm-starting from: ('/tmp/model_dir/keras/keras_model.ckpt',)
INFO:tensorflow:Warm-starting variable: dense_24/kernel; prev_var_name: Unchanged
INFO:tensorflow:Warm-starting variable: dense_24/bias; prev_var_name: Unchanged
INFO:tensorflow:Warm-starting variable: dense_23/bias; prev_var_name: Unchanged
INFO:tensorflow:Warm-starting variable: dense_23/kernel; prev_var_name: Unchanged
INFO:tensorflow:Create CheckpointSaverHook.
INFO:tensorflow:Graph was finalized.
INFO:tensorflow:Running local_init_op.
INFO:tensorflow:Done running local_init_op.
INFO:tensorflow:Saving checkpoints for 0 into /tmp/model_dir/model.ckpt.
INFO:tensorflow:loss = 0.7566509, step = 0
INFO:tensorflow:Saving checkpoints for 10 into /tmp/model_dir/model.ckpt.
INFO:tensorflow:Finalize system.
INFO:tensorflow:Loss for final step: 0.7137328.

<tensorflow.python.estimator.estimator.Estimator at 0x7f4099bbbb70>