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.

In [ ]:
#@title MIT License
#
# Copyright (c) 2017 François Chollet
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.

Сохранение и загрузка моделей

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

Прогресс обучения моделей можно сохранять во время и после обучения: тренировку можно возобновить с того места, где ты остановился. Это обычно помогает избежать долгих бесперервыных сессий обучения. Сохраняя модель, ты также можешь поделиться ею с другими, чтобы они могли воспроизвести результаты ее работы. Большинство практиков машинного обучения помимо самой модели и использованных техник также публикуют:

  • Код, при помощи которого обучалась модель
  • Тренировочные веса, или параметры модели

Публикация этих данных помогает другим понять как работает модель, а также они смогут проверить как она ведет себя с новыми данными.

Внимание! Будь осторожен с кодом, которому ты не доверяешь. Обязательно прочти Как использовать TensorFlow безопасно?

Варианты

Существуют разные способы сохранять модели TensorFlow - все зависит от API, которые ты использовал в своей модели. В этом уроке используется tf.keras, высокоуровневый API для построения и обучения моделей в TensorFlow. Для всех остальных подходов читай руководство по TensorFlow Сохраняй и загружай модели или Сохранение в Eager.

Настройка

Настроим и импортируем зависимости

Установим и импортируем TensorFlow и все зависимые библиотеки:


In [ ]:
!pip install h5py pyyaml

Загрузим датасет

Мы воспользуемся датасетом MNIST для обучения нашей модели, чтобы показать как сохранять веса. Ускорим процесс, используя только первые 1000 образцов данных:


In [ ]:
import os

import tensorflow.compat.v1 as tf

from tensorflow import keras

tf.__version__

In [ ]:
(train_images, train_labels), (test_images, test_labels) = tf.keras.datasets.mnist.load_data()

train_labels = train_labels[:1000]
test_labels = test_labels[:1000]

train_images = train_images[:1000].reshape(-1, 28 * 28) / 255.0
test_images = test_images[:1000].reshape(-1, 28 * 28) / 255.0

Построим модель

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


In [ ]:
# Возвращает короткую последовательную модель
def create_model():
  model = tf.keras.models.Sequential([
    keras.layers.Dense(512, activation=tf.nn.relu, input_shape=(784,)),
    keras.layers.Dropout(0.2),
    keras.layers.Dense(10, activation=tf.nn.softmax)
  ])

  model.compile(optimizer=tf.train.AdamOptimizer(),
                loss=tf.keras.losses.sparse_categorical_crossentropy,
                metrics=['accuracy'])

  return model


# Создадим модель
model = create_model()
model.summary()

Сохраняем контрольные точки

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

Эту задачу выполняет функция обратного вызова tf.keras.callbacks.ModelCheckpoint. Эта функция также может быть настроена при помощи нескольких аргументов.

Использование функции

Обучим нашу модель и передадим ей функцию ModelCheckpoint:


In [ ]:
checkpoint_path = "training_1/cp.ckpt"
checkpoint_dir = os.path.dirname(checkpoint_path)

# Создадим контрольную точку при помощи callback функции
cp_callback = tf.keras.callbacks.ModelCheckpoint(checkpoint_path,
                                                 save_weights_only=True,
                                                 verbose=1)

model = create_model()

model.fit(train_images, train_labels,  epochs = 10,
          validation_data = (test_images,test_labels),
          callbacks = [cp_callback])  # передаем callback обучению

Это создаст одну совокупность файлов контрольных точек TensorFlow, которые обновлялись в конце каждой эпохи:


In [ ]:
!ls {checkpoint_dir}

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

Также мы оценим точность новой модели на проверочных данных. Необученная модель будет лишь изредка угадывать правильную категорию обзоров фильмов (точность будет около 10%):


In [ ]:
model = create_model()

loss, acc = model.evaluate(test_images,  test_labels, verbose=2)
print("Необученная модель, точность: {:5.2f}%".format(100*acc))

А теперь загрузим веса из контрольной точки и проверим еще раз:


In [ ]:
model.load_weights(checkpoint_path)
loss,acc = model.evaluate(test_images,  test_labels, verbose=2)
print("Восстановленная модель, точность: {:5.2f}%".format(100*acc))

Параметры вызова контрольной точки

У callback функции есть несколько параметров, которые дают контрольным точкам уникальные имена, а также корректируют частоту сохранения.

Обучим новую модель и укажем параметр чтобы сохранять контрольные точки через каждые 5 эпох:


In [ ]:
# Укажем эпоху в имени файла (переведем ее в строки при помощи `str.format`)
checkpoint_path = "training_2/cp-{epoch:04d}.ckpt"
checkpoint_dir = os.path.dirname(checkpoint_path)

cp_callback = tf.keras.callbacks.ModelCheckpoint(
    checkpoint_path, verbose=1, save_weights_only=True,
    # Сохраняем веса через каждые 5 эпох
    period=5)

model = create_model()
model.fit(train_images, train_labels,
          epochs = 50, callbacks = [cp_callback],
          validation_data = (test_images,test_labels),
          verbose=0)

Теперь посмотрим на получившиеся контрольные точки и выберем последнюю:


In [ ]:
! ls {checkpoint_dir}

In [ ]:
latest = tf.train.latest_checkpoint(checkpoint_dir)
latest

Помни: по умолчанию TensorFlow сохраняет только 5 последних контрольных точек.

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


In [ ]:
model = create_model()
model.load_weights(latest)
loss, acc = model.evaluate(test_images,  test_labels, verbose=2)
print("Восстановленная модель, точность: {:5.2f}%".format(100*acc))

Как выглядят эти файлы?

Код выше сохраняет веса модели как совокупность контрольных точек - форматированных файлов, которые содержат только обученные веса в двоичном формате. Они включают в себя:

  • Один или несколько шардов (shard, пер. "Часть данных"), в которых хранятся веса твоей модели
  • Индекс, который указывает какие веса хранятся в каждом шарде

Если ты обучаешь модель на одном компьютере, то тогда у тебя будет всего один шард, оканчивающийся на .data-00000-of-00001

Сохраняем веса вручную

Выше мы посмотрели как загружать веса в модель.

Сохранять веса вручную так же просто, просто воспользуйся методом Model.save_weights:


In [ ]:
# Сохраняем веса
model.save_weights('./checkpoints/my_checkpoint')

# Восстанавливаем веса
model = create_model()
model.load_weights('./checkpoints/my_checkpoint')

loss,acc = model.evaluate(test_images,  test_labels, verbose=2)
print("Восстановленная модель, точность: {:5.2f}%".format(100*acc))

Сохраняем модель целиком

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

Сохранять рабочую модель полностью весьма полезно. Например, ты можешь потом восстановить ее в TensorFlow.js (HDF5, Сохраненные модели) и затем обучать и запускать ее в веб-браузерах, или конвертировать ее в формат для мобильных устройств, используя TensorFlow Lite (HDF5, Сохраненные модели)

Сохраняем в формате HDF5

В Keras есть встроенный формат для сохранения модель при помощи стандарта HDF5. Для наших целей сохраненная модель будет использована как единый двоичный объект blob.


In [ ]:
model = create_model()

# Используй keras.optimizer чтобы восстановить оптимизатор из файла HDF5
model.compile(optimizer=keras.optimizers.Adam(),
              loss=tf.keras.losses.sparse_categorical_crossentropy,
              metrics=['accuracy'])

model.fit(train_images, train_labels, epochs=5)

# Сохраним модель полностью в единый HDF5 файл
model.save('my_model.h5')

Теперь воссоздадим модель из этого файла:


In [ ]:
# Воссоздадим точно такую же модель, включая веса и оптимизатор:
new_model = keras.models.load_model('my_model.h5')
new_model.summary()

Проверим ее точность:


In [ ]:
loss, acc = new_model.evaluate(test_images,  test_labels, verbose=2)
print("Восстановленная модель, точность: {:5.2f}%".format(100*acc))

Данная техника сохраняет все:

  • Веса модели
  • Конфигурацию (ее структуру)
  • Параметры оптимизатора

Keras сохраняет модель путем исследования ее архитектуры. В настоящее время он не может сохранять оптимизаторы TensorFlow из tf.train. В случае их использования нужно скомпилировать модель еще раз после загрузки. Таким образом ты получишь параметры оптимизатора.

Сохраняем как saved_model

Обрати внимание: этот метод сохранения моделей tf.keras является экспериментальным и может измениться в будущих версиях.

Построим новую модель:


In [ ]:
model = create_model()

model.fit(train_images, train_labels, epochs=5)

Создадим saved_model:


In [ ]:
saved_model_path = tf.contrib.saved_model.save_keras_model(model, "./saved_models")

Сохраненные модели будут помещены в папку и отмечены текущей датой и временем в названии:


In [ ]:
!ls saved_models/

Загрузим новую модель Keras из уже сохраненной:


In [ ]:
new_model = tf.contrib.saved_model.load_keras_model(saved_model_path)
new_model

Запустим загруженную модель:


In [ ]:
# Оптимизатор не был восстановлен, поэтому мы укажим новый
new_model.compile(optimizer=tf.train.AdamOptimizer(),
              loss=tf.keras.losses.sparse_categorical_crossentropy,
              metrics=['accuracy'])

loss, acc = new_model.evaluate(test_images,  test_labels, verbose=2)
print("Загруженная модель, точность: {:5.2f}%".format(100*acc))

Что дальше?

Это был короткий урок по сохранению и загрузке своих моделей при помощи tf.kers.

  • В руководстве по tf.keras рассказывается подробнее о том, как можно сохранять и загружать модели при помощи tf.keras

  • Статья Сохраняй в Eager рассказывает как сохранять модель во время Eager Execution

  • В руководстве Сохраняй и загружай модели содержится подробный урок обо всех низкоуровневых деталях сохранения моделей TensorFlow