In [ ]:
#@title Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

Keras

Note: Вся информация в этом разделе переведена с помощью русскоговорящего Tensorflow сообщества на общественных началах. Поскольку этот перевод не является официальным, мы не гарантируем что он на 100% аккуратен и соответствует официальной документации на английском языке. Если у вас есть предложение как исправить этот перевод, мы будем очень рады увидеть pull request в tensorflow/docs репозиторий GitHub. Если вы хотите помочь сделать документацию по Tensorflow лучше (сделать сам перевод или проверить перевод подготовленный кем-то другим), напишите нам на docs-ru@tensorflow.org list.

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

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

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

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

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


In [ ]:
# Используй pyyaml если будешь сохранять в формате YAML
!pip install pyyaml

In [ ]:
import tensorflow.compat.v1 as tf

from tensorflow.keras import layers

print(tf.VERSION)
print(tf.keras.__version__)

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

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

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

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

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

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


In [ ]:
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 с настройкой конфигурации каждого слоя:


In [ ]:
# Создаем сигмоидный слой:
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))

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

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

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


In [ ]:
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

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


In [ ]:
# Настраиваем регрессию модели, используем среднеквадратическое отклонение
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{:.external} для обучения и оценки моделей. Модель будет "подстраиваться" под тренировочные данные при помощи метода fit:


In [ ]:
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)

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

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

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


In [ ]:
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))

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

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


In [ ]:
# Инициализируем пробную инстанцию датасета:
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)

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

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


In [ ]:
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)

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

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

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


In [ ]:
data = np.random.random((1000, 32))
labels = np.random.random((1000, 10))

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

model.evaluate(dataset, steps=30)

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


In [ ]:
result = model.predict(data, batch_size=32)
print(result.shape)

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

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

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

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

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

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

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


In [ ]:
# Возвращает тензор-"заполнитель", который мы используем в качестве примера
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)

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


In [ ]:
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)

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

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

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

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

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


In [ ]:
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)

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


In [ ]:
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)

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

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

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

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


In [ ]:
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)

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


In [ ]:
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)

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

Функция обратного вызова 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 своей модели:


In [ ]:
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))

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

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

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


In [ ]:
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'])

In [ ]:
# Сохраняем веса в контрольную точку формата TensorFlow
model.save_weights('./weights/my_model')

# Восстанавливаем состояние модели,
# требуется использование модели с точно такой же архитектурой
model.load_weights('./weights/my_model')

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


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

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

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

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

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

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


In [ ]:
# Сериализация модели в формат JSON
json_string = model.to_json()
json_string

In [ ]:
import json
import pprint
pprint.pprint(json.loads(json_string))

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


In [ ]:
fresh_model = tf.keras.models.model_from_json(json_string)

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


In [ ]:
yaml_string = model.to_yaml()
print(yaml_string)

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


In [ ]:
fresh_model = tf.keras.models.model_from_yaml(yaml_string)

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

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

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


In [ ]:
# Создаем простую модель
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')

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.


In [ ]:
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)

Совет: используй 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 на одном устройстве.

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


In [ ]:
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()

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


In [ ]:
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 как в следующем примере:


In [ ]:
strategy = tf.contrib.distribute.MirroredStrategy()
config = tf.estimator.RunConfig(train_distribute=strategy)

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


In [ ]:
keras_estimator = tf.keras.estimator.model_to_estimator(
  keras_model=model,
  config=config,
  model_dir='/tmp/model_dir')

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


In [ ]:
keras_estimator.train(input_fn=input_fn, steps=10)