Многоразовые сохраненные модели

Введение

TensorFlow Hub, помимо прочих ресурсов, содержит сохраненные модели для TensorFlow 2. Их можно загрузить обратно в программу на Python с помощью obj = hub.load(url) [ подробнее ]. Возвращаемый obj является результатом выполнения tf.saved_model.load() (см. руководство по сохраненным моделям TensorFlow). Этот объект может иметь произвольные атрибуты, которые могут быть объектами tf.functions, tf.Variables (инициализированными из их предварительно обученных значений), другими ресурсами и, рекурсивно, другими подобными объектами.

На этой странице описывается интерфейс, который должен быть реализован загруженным obj для повторного использования в программе TensorFlow на Python. Сохраненные модели, соответствующие этому интерфейсу, называются многократно используемыми сохраненными моделями (Reusable SavedModels ).

Повторное использование означает построение более крупной модели на основе объекта obj , включая возможность его тонкой настройки. Тонкая настройка подразумевает дальнейшее обучение весов загруженного объекта obj в рамках окружающей модели. Функция потерь и оптимизатор определяются окружающей моделью; obj определяет только отображение входных активаций на выходные (прямой проход), возможно, с использованием таких методов, как Dropout или пакетная нормализация.

Команда TensorFlow Hub рекомендует реализовывать интерфейс Reusable SavedModel во всех объектах SavedModel, предназначенных для повторного использования в указанном выше смысле. Многие утилиты из библиотеки tensorflow_hub , в частности hub.KerasLayer , требуют, чтобы объекты SavedModel реализовывали этот интерфейс.

Связь с SignatureDefs

Этот интерфейс, в части tf.functions и других функций TF2, отделен от сигнатур SavedModel, которые доступны с TF1 и продолжают использоваться в TF2 для инференса (например, при развертывании SavedModels на TF Serving или TF Lite). Сигнатуры для инференса недостаточно выразительны для поддержки тонкой настройки, и tf.function предоставляет более естественный и выразительный API на Python для повторно используемой модели.

Связь с библиотеками для построения моделей

Многократно используемая сохраненная модель (Reusable SavedModel) использует только примитивы TensorFlow 2, независимо от какой-либо конкретной библиотеки для построения моделей, такой как Keras или Sonnet. Это облегчает повторное использование в различных библиотеках для построения моделей, исключая зависимость от исходного кода построения модели.

Для загрузки многократно используемых сохраненных моделей в любую библиотеку построения моделей потребуется некоторая адаптация. В Keras загрузку обеспечивает hub.KerasLayer , а встроенная функция сохранения в формате SavedModel в Keras была переработана для TF2 с целью предоставления расширенного варианта этого интерфейса (см. RFC от мая 2019 года).

Связь со специфическими для задачи "Общими API сохраненных моделей"

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

Определение интерфейса

Атрибуты

Многоразовая сохраненная модель (Reusable SavedModel) — это сохраненная модель TensorFlow 2, в которой obj = tf.saved_model.load(...) возвращает объект, обладающий следующими атрибутами.

  • __call__ . Обязательно. Функция tf.function, реализующая вычисления модели («прямой проход») в соответствии с приведенной ниже спецификацией.

  • variables : Список объектов tf.Variable, содержащий все переменные, используемые при любом возможном вызове __call__ , включая как обучаемые, так и необучаемые.

    Этот список можно опустить, если он пуст.

  • trainable_variables : Список объектов tf.Variable, для всех элементов которых v.trainable истинно. Эти переменные должны быть подмножеством variables . Это переменные, которые будут обучаться при тонкой настройке объекта. Создатель SavedModel может исключить некоторые переменные, которые изначально были обучаемыми, чтобы указать, что их не следует изменять во время тонкой настройки.

    Этот список можно опустить, если он пуст, в частности, если SavedModel не поддерживает тонкую настройку.

  • regularization_losses : Список функций tf.functions, каждая из которых принимает ноль входных данных и возвращает один скалярный тензор с плавающей запятой. Для тонкой настройки пользователю SavedModel рекомендуется включать их в качестве дополнительных членов регуляризации в функцию потерь (в простейшем случае без дальнейшего масштабирования). Как правило, они используются для представления регуляризаторов весов. (Из-за отсутствия входных данных эти функции tf.functions не могут выражать регуляризаторы активности.)

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

Функция __call__

Восстановленный объект SavedModel obj имеет атрибут obj.__call__ , который представляет собой восстановленную функцию tf.function и позволяет вызывать obj следующим образом.

Краткое содержание (псевдокод):

outputs = obj(inputs, trainable=..., **kwargs)

Аргументы

Аргументы следующие.

  • При наличии пакета входных активаций SavedModel имеется один обязательный позиционный аргумент. Его тип — один из следующих:

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

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

  • В параметре training может быть необязательный ключевой аргумент, принимающий логическое значение Python, True или False . По умолчанию используется False . Если модель поддерживает тонкую настройку и если ее вычисления различаются между двумя вариантами (например, как в случае с Dropout и пакетной нормализацией), это различие реализуется с помощью этого аргумента. В противном случае этот аргумент может отсутствовать.

    Функция __call__ не обязана принимать в качестве аргумента training тензорные значения. При необходимости для переключения между ними tf.cond() является обязанностью вызывающей стороны.

  • Создатель SavedModel может выбрать вариант с добавлением дополнительных необязательных kwargs в виде определенных имен.

    • Для аргументов в виде тензоров создатель SavedModel определяет допустимые типы данных и формы. tf.function принимает значение по умолчанию Python для аргумента, который отслеживается с помощью входных данных tf.TensorSpec. Такие аргументы можно использовать для настройки числовых гиперпараметров, участвующих в __call__ (например, коэффициент отсеивания).

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

Восстановленная функция __call__ должна предоставлять трассировки для всех допустимых комбинаций аргументов. Переключение training между True и False не должно изменять допустимость аргументов.

Результат

outputs вызова obj могут быть следующие параметры:

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

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

Именованные вызываемые функции

Многократно используемая сохраненная модель может предоставлять несколько частей модели описанным выше способом, помещая их в именованные подобъекты, например, obj.foo , obj.bar и так далее. Каждый подобъект предоставляет метод __call__ и вспомогательные атрибуты, касающиеся переменных и т. д., специфичные для этой части модели. В приведенном выше примере это будут obj.foo.__call__ , obj.foo.variables и так далее.

Обратите внимание, что данный интерфейс не охватывает подход добавления простой функции tf.function напрямую как tf.foo .

Предполагается, что пользователи многократно используемых сохраненных моделей будут обрабатывать только один уровень вложенности ( obj.bar , но не obj.bar.baz ). (В будущих версиях этого интерфейса может быть разрешена более глубокая вложенность, а также может быть отменено требование о том, чтобы сам объект верхнего уровня был вызываемым.)

Заключительные замечания

Связь с API, используемыми в процессе обработки.

В этом документе описывается интерфейс класса Python, который состоит из примитивов, таких как tf.function и tf.Variable, сохраняющих свои свойства при сериализации с помощью tf.saved_model.save() и tf.saved_model.load() . Однако этот интерфейс уже присутствовал в исходном объекте, переданном в tf.saved_model.save() . Адаптация к этому интерфейсу позволяет обмениваться частями модели между API построения модели в рамках одной программы TensorFlow.