Как сохранить, загружать и развернуть модели с использованием TensorFlow SaveModel

Как сохранить, загружать и развернуть модели с использованием TensorFlow SaveModel

30 июля 2025 г.

Обзор контента

  • Создание сохраненной модели из кераса
  • Запуск сохраненной модели в Tensorflow Aerding
  • Формат SaveedModel на диске
  • Сохранение пользовательской модели
  • Загрузка и использование пользовательской модели
  • Основная точная настройка
  • Общая точная настройка
  • Указание подписей во время экспорта
  • Прото-рассеивание
  • Загрузите сохранение модели в C ++
  • Детали интерфейса командной строки SavedModel
  • Установите CLI SaveedModel
  • Обзор команд
  • Показать команду
  • запустить команду

SaveedModel содержит полную программу тензора, включая обученные параметры (т.е.tf.VariableS) и вычисления. Это не требует, чтобы исходный код создания моделей запускался, что делает его полезным для обмена или развертывания сTfliteВTensorflow.jsВTensorflow Aerding, илиTensorflow Hub.

Вы можете сохранить и загрузить модель в формате SaveedModel, используя следующие API:

  • Низкий уровеньtf.saved_modelAPI. Этот документ описывает, как подробно использовать этот API.
    • Сохранять:tf.saved_model.save(model, path_to_dir)
    • Нагрузка:model = tf.saved_model.load(path_to_dir)
  • Высокий уровеньtf.keras.ModelAPI. Обратиться кКерас спасение и сериализуется руководствоПолем
  • Если вы просто хотите сэкономить/загружать веса во время тренировки, см.Руководство по контрольным точкамПолем

Осторожность:Модели TensorFlow - это код, и важно быть осторожным с ненадежным кодом. Узнайте больше вИспользуя тензорфлоу безопасноПолем

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

Deprecated: For Keras objects, it's recommended to use the new high-level .keras format and tf.keras.Model.export, as demonstrated in the guide here. The low-level SavedModel format continues to be supported for existing code.

Для быстрого введения в этом разделе экспортирует предварительно обученную модель керас и служит с ним запросами классификации изображений. Остальная часть руководства заполнит подробности и обсуждает другие способы создания SaveedModels.

import os
import tempfile

from matplotlib import pyplot as plt
import numpy as np
import tensorflow as tf

tmpdir = tempfile.mkdtemp()

physical_devices = tf.config.list_physical_devices('GPU')
for device in physical_devices:
  tf.config.experimental.set_memory_growth(device, True)

file = tf.keras.utils.get_file(
    "grace_hopper.jpg",
    "https://storage.googleapis.com/download.tensorflow.org/example_images/grace_hopper.jpg")
img = tf.keras.utils.load_img(file, target_size=[224, 224])
plt.imshow(img)
plt.axis('off')
x = tf.keras.utils.img_to_array(img)
x = tf.keras.applications.mobilenet.preprocess_input(
    x[tf.newaxis,...])

Вы используете изображение Grace Hopper в качестве примера, и модель классификации изображений, предварительно обученной Keras, так как его проще в использовании. Пользовательские модели тоже работают и подробно рассказываются позже.

labels_path = tf.keras.utils.get_file(
    'ImageNetLabels.txt',
    'https://storage.googleapis.com/download.tensorflow.org/data/ImageNetLabels.txt')
imagenet_labels = np.array(open(labels_path).read().splitlines())

pretrained_model = tf.keras.applications.MobileNet()
result_before_save = pretrained_model(x)

decoded = imagenet_labels[np.argsort(result_before_save)[0,::-1][:5]+1]

print("Result before saving:\n", decoded)

Лучший прогноз для этого изображения - «военная форма».

mobilenet_save_path = os.path.join(tmpdir, "mobilenet/1/")
tf.saved_model.save(pretrained_model, mobilenet_save_path)

Переэскушечный путь следует соглашению, используемому Tensorflow Forming, где последний компонент Path (1/Здесь) номер версии для вашей модели - он позволяет таким инструментам, как Tensorflow, служить рассуждением об относительной свежесть.

Вы можете загрузить сохраненную модель обратно в Python сtf.saved_model.loadИ посмотрите, как классифицируется изображение адмирала Хоппера.

loaded = tf.saved_model.load(mobilenet_save_path)
print(list(loaded.signatures.keys()))  # ["serving_default"]

Импортированные подписи всегда возвращают словаря. Для настройки имен подписей и ключей выходного слова, см.Указание подписей во время экспортаПолем

infer = loaded.signatures["serving_default"]
print(infer.structured_outputs)

Запуск вывода из SaveedModel дает тот же результат, что и исходная модель.

labeling = infer(tf.constant(x))[pretrained_model.output_names[0]]

decoded = imagenet_labels[np.argsort(labeling)[0,::-1][:5]+1]

print("Result after saving and loading:\n", decoded)

Запуск сохраненной модели в Tensorflow Aerding

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

УвидетьTensorflow Учебник для отдыхадля примера сквозного проведения тензора.

Формат SaveedModel на диске

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

ls {mobilenet_save_path}

Аsaved_model.pbФайл хранит фактическую программу TensorFlow или модель, а также набор именованных подписей, каждый из которых идентифицирует функцию, которая принимает тензоры и производит тензорные выходы.

Сохраненные модели могут содержать несколько вариантов модели (множественныеv1.MetaGraphDefs, отождествляется с--tag_setфлагsaved_model_cli), но это редко. API, которые создают несколько вариантов модели, включаютtf.Estimator.experimental_export_all_saved_modelsи в TensorFlow 1.xtf.saved_model.BuilderПолем

saved_model_cli show --dir {mobilenet_save_path} --tag_set serve

Аvariablesкаталог содержит стандартную тренировочную контрольную точку (см.Руководство по обучению контрольных точек)

ls {mobilenet_save_path}/variables

АassetsКаталог содержит файлы, используемые на графике TensorFlow, например, текстовые файлы, используемые для инициализации словарных таблиц. Это не используется в этом примере.

Спасенные модели могут иметьassets.extraСправочник для любых файлов, не используемых на графике TensorFlow, например, информация для потребителей о том, что делать со SavedModel. Сам TensorFlow не использует этот каталог.

Аfingerprint.pbФайл содержитОтпечаток пальцаиз сохраненной модели, которая состоит из нескольких 64-битных хэшей, которые уникально идентифицируют содержимое сохраненной модели. API отпечатков пальцев в настоящее время экспериментально, ноtf.saved_model.experimental.read_fingerprintможно использовать для чтения отпечатка пальца SaveedModel вtf.saved_model.experimental.Fingerprintобъект.

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

tf.saved_model.saveподдерживает сохранениеtf.Moduleобъекты и его подклассы, какtf.keras.Layerиtf.keras.ModelПолем

Давайте посмотрим на пример сохранения и восстановленияtf.ModuleПолем

class CustomModule(tf.Module):

  def __init__(self):
    super(CustomModule, self).__init__()
    self.v = tf.Variable(1.)

  @tf.function
  def __call__(self, x):
    print('Tracing with', x)
    return x * self.v

  @tf.function(input_signature=[tf.TensorSpec([], tf.float32)])
  def mutate(self, new_v):
    self.v.assign(new_v)

module = CustomModule()

Когда вы сохраняетеtf.Module, любойtf.Variableатрибуты,tf.function-Корированные методы, иtf.ModuleS, найденные через рекурсивное обход, сохраняются. (СмУчебное пособие по контрольно -пропускному пунктуДля получения дополнительной информации об этом рекурсивном обходе.) Однако любые атрибуты, функции и данные Python теряются. Это означает, что когдаtf.functionСохраняется, код Python не сохранен.

Если код Python не сохранен, как SaveDmodel узнает, как восстановить функцию?

Вкратце,tf.functionРаботает путем отслеживания кода Python, чтобы создать бетонную функцию (оболочка вокругtf.Graph) При сохраненииtf.function, вы действительно спасаетеtf.functionКэш бетонных функций.

Чтобы узнать больше о отношениях междуtf.functionи конкретные функции, см.TF.Function GuideПолем

module_no_signatures_path = os.path.join(tmpdir, 'module_no_signatures')
module(tf.constant(0.))
print('Saving model...')
tf.saved_model.save(module, module_no_signatures_path)

Загрузка и использование пользовательской модели

Когда вы загружаете сохраненную модель в Python, всеtf.Variableатрибуты,tf.function-Корированные методы, иtf.Modules восстановлены в той же структуре объекта, что и исходные сохраненныеtf.ModuleПолем

imported = tf.saved_model.load(module_no_signatures_path)
assert imported(tf.constant(3.)).numpy() == 3
imported.mutate(tf.constant(2.))
assert imported(tf.constant(3.)).numpy() == 6

Потому что код Python не сохраняется, вызываяtf.functionС новой входной подписью потерпит неудачу:

imported(tf.constant([3.]))

ValueError: Could not find matching function to call for canonicalized inputs ((,), {}). Only existing signatures are [((TensorSpec(shape=(), dtype=tf.float32, name=u'x'),), {})].

Основная точная настройка

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

optimizer = tf.keras.optimizers.SGD(0.05)

def train_step():
  with tf.GradientTape() as tape:
    loss = (10. - imported(tf.constant(2.))) ** 2
  variables = tape.watched_variables()
  grads = tape.gradient(loss, variables)
  optimizer.apply_gradients(zip(grads, variables))
  return loss

for _ in range(10):
  # "v" approaches 5, "loss" approaches 0
  print("loss={:.2f} v={:.2f}".format(train_step(), imported.v.numpy()))

Общая точная настройка

SaveedModel из Keras предоставляетБолее подробная информациячем равнина__call__Для рассмотрения более продвинутых случаев тонкой настройки. Tensorflow Hub рекомендует предоставить следующее, если применимо, в SavedModels, разделенных с целью точной настройки:

  • Если модель использует отсевание или другой метод, при которой прямой проход отличается между обучением и выводом (например, нормализацией пакетов),__call__Метод принимает дополнительную, а также на питонеtraining=аргумент, который по умолчаниюFalseно может быть настроен наTrueПолем
  • Рядом с__call__Атрибут, есть.variableи.trainable_variableАтрибуты с соответствующими списками переменных. Переменная, которая была первоначально обучена, но должна быть заморожена во время точной настройки, опущена из.trainable_variablesПолем
  • Ради карт, таких как кера, которые представляют собой регулялизации веса в качестве атрибутов слоев или подмоделей, также может быть.regularization_lossesатрибут. Он содержит список функций с нулевым аргументом, значения которых предназначены для дополнения к общей потерь.

Возвращаясь к первоначальному примеру Mobilenet, вы можете увидеть некоторые из них в действии:

loaded = tf.saved_model.load(mobilenet_save_path)
print("MobileNet has {} trainable variables: {}, ...".format(
          len(loaded.trainable_variables),
          ", ".join([v.name for v in loaded.trainable_variables[:5]])))

trainable_variable_ids = {id(v) for v in loaded.trainable_variables}
non_trainable_variables = [v for v in loaded.variables
                           if id(v) not in trainable_variable_ids]
print("MobileNet also has {} non-trainable variables: {}, ...".format(
          len(non_trainable_variables),
          ", ".join([v.name for v in non_trainable_variables[:3]])))

Указание подписей во время экспорта

Инструменты, такие как Tensorflow Forming иsaved_model_cliможет взаимодействовать с SavedModels. Чтобы помочь этим инструментам определить, какие конкретные функции использовать, вам необходимо указать подписи обслуживания.tf.keras.ModelS автоматически указывает на обслуживающие подписи, но вам придется явно объявить подпись для наших пользовательских модулей.

Важный:Если вам не нужно экспортировать свою модель в среду, отличную от Tensorflow 2.x с Python, вам, вероятно, не нужно явно экспортировать подписи. Если вы ищете способ обеспечения входной подписи для определенной функции, см.input_signatureаргументtf.functionПолем

По умолчанию, в пользовательскомtf.ModuleПолем

assert len(imported.signatures) == 0

Чтобы объявить подпись, укажите конкретную функцию, используяsignaturesКварг. При указании одной подписи его подпись будет'serving_default', который сохраняется как постояннаяtf.saved_model.DEFAULT_SERVING_SIGNATURE_DEF_KEYПолем

module_with_signature_path = os.path.join(tmpdir, 'module_with_signature')
call = module.__call__.get_concrete_function(tf.TensorSpec(None, tf.float32))
tf.saved_model.save(module, module_with_signature_path, signatures=call)

imported_with_signatures = tf.saved_model.load(module_with_signature_path)
list(imported_with_signatures.signatures.keys())

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

module_multiple_signatures_path = os.path.join(tmpdir, 'module_with_multiple_signatures')
signatures = {"serving_default": call,
              "array_input": module.__call__.get_concrete_function(tf.TensorSpec([None], tf.float32))}

tf.saved_model.save(module, module_multiple_signatures_path, signatures=signatures)

imported_with_multiple_signatures = tf.saved_model.load(module_multiple_signatures_path)
list(imported_with_multiple_signatures.signatures.keys())

По умолчанию имена выходных тензоров довольно общие, какoutput_0Полем Чтобы управлять именами выходов, измените вашиtf.functionЧтобы вернуть словарь, который отображает выходные имена на выходы. Названия входов получены из имен функции Python.

class CustomModuleWithOutputName(tf.Module):
  def __init__(self):
    super(CustomModuleWithOutputName, self).__init__()
    self.v = tf.Variable(1.)

  @tf.function(input_signature=[tf.TensorSpec(None, tf.float32)])
  def __call__(self, x):
    return {'custom_output_name': x * self.v}

module_output = CustomModuleWithOutputName()
call_output = module_output.__call__.get_concrete_function(tf.TensorSpec(None, tf.float32))
module_output_path = os.path.join(tmpdir, 'module_with_output_name')
tf.saved_model.save(module_output, module_output_path,
                    signatures={'serving_default': call_output})

imported_with_output_name = tf.saved_model.load(module_output_path)
imported_with_output_name.signatures['serving_default'].structured_outputs

Прото-рассеивание

Примечание:Эта функция будет частью релиза TensorFlow 2.15. В настоящее время доступно в ночной сборке, которую вы устанавливаете CQANpip install tf-nightlyПолем

Из -за пределов реализации Protobuf размеры прото не могут превышать 2 ГБ. Это может привести к следующим ошибкам при попытке сохранить очень большие модели:

ValueError: Message tensorflow.SavedModel exceeds maximum protobuf size of 2GB: ...

google.protobuf.message.DecodeError: Error parsing message as the message exceeded the protobuf limit with type 'tensorflow.GraphDef'

Если вы хотите сохранить модели, которые превышают предел 2 ГБ, вам нужно сохранить, используя новую опцию протокопта:

tf.saved_model.save(
  ...,
  options=tf.saved_model.SaveOptions(experimental_image_format=True)
)

Больше информации можно найти вРуководство по библиотеке Proto Splitter /Полем

Загрузите сохранение модели в C ++

The C++ version of the SavedModel погрузчикПредоставляет API для загрузки сохраненной модели с пути, позволяя SessionOptions и Runoptions. Вы должны указать теги, связанные с загруженным графом. Загруженная версия SaveedModel называется SaveDmodelbundle и содержит метаграфдеф и сеанс, в который он загружается.

const string export_dir = ...
SavedModelBundle bundle;
...
LoadSavedModel(session_options, run_options, export_dir, {kSavedModelTagTrain},
               &bundle);

Детали интерфейса командной строки SavedModel

Вы можете использовать интерфейс командной строки SavedModel (CLI) для проверки и выполнения SaveedModel. Например, вы можете использовать CLI для проверки моделиSignatureDefс CLI позволяет быстро подтвердить, что входной тензор dtype и форма соответствуют модели. Более того, если вы хотите проверить свою модель, вы можете использовать CLI для проверки здравомыслия, передавая входные входы в различных форматах (например, экспрессии Python), а затем получая выход.

Установите CLI SaveedModel

Вообще говоря, вы можете установить TensorFlow любым из следующих двух способов:

  • Установив предварительно построенный бинар Tensorflow.
  • Построив тензорфлоу из исходного кода.

Если вы установили TensorFlow через предварительно построенный двойной бинар TensorFlow, то CLI SaveedModel уже установлен на вашей системе в PathNamebin/saved_model_cliПолем

Если вы построили TensorFlow из исходного кода, вы должны запустить следующую дополнительную команду, чтобы построитьsaved_model_cli:

$ bazel build //tensorflow/python/tools:saved_model_cli

Обзор команд

CLI SaveedModel поддерживает следующие две команды на SaveedModel:

  • show, который показывает вычисления, доступные из SaveedModel.
  • run, который запускает вычисление из SaveedModel.

showкомандование

SaveedModel содержит один или несколько вариантов модели (технически,v1.MetaGraphDefS), идентифицированные их метками. Чтобы обслуживать модель, вы можете задаться вопросом, что заSignatureDefS находится в каждом варианте модели, и каковы их входы и выходы. АshowКоманда позвольте вам исследовать содержимое сохраненной модели в иерархическом порядке. Вот синтаксис:

usage: saved_model_cli show [-h] --dir DIR [--all]
[--tag_set TAG_SET] [--signature_def SIGNATURE_DEF_KEY]

Например, в следующей команде показаны все доступные теги в SavedModel:

$ saved_model_cli show --dir /tmp/saved_model_dir
The given SavedModel contains the following tag-sets:
serve
serve, gpu

На следующей команде показаны все доступныеSignatureDefКлючи для набора тегов:

$ saved_model_cli show --dir /tmp/saved_model_dir --tag_set serve
The given SavedModel `MetaGraphDef` contains `SignatureDefs` with the
following keys:
SignatureDef key: "classify_x2_to_y3"
SignatureDef key: "classify_x_to_y"
SignatureDef key: "regress_x2_to_y3"
SignatureDef key: "regress_x_to_y"
SignatureDef key: "regress_x_to_y2"
SignatureDef key: "serving_default"

Если естьнесколькоТеги В наборе тега необходимо указать все теги, каждый тег, разделенный запятой. Например:

$ saved_model_cli show --dir /tmp/saved_model_dir --tag_set serve,gpu

Чтобы показать все входы и выходы tensorinfo для конкретногоSignatureDef, пройти вSignatureDefключ кsignature_defвариант. Это очень полезно, когда вы хотите узнать значение ключа тензора, DTYPE и форма входных тензоров для выполнения графика вычисления позже. Например:

$ saved_model_cli show --dir \
/tmp/saved_model_dir --tag_set serve --signature_def serving_default
The given SavedModel SignatureDef contains the following input(s):
  inputs['x'] tensor_info:
      dtype: DT_FLOAT
      shape: (-1, 1)
      name: x:0
The given SavedModel SignatureDef contains the following output(s):
  outputs['y'] tensor_info:
      dtype: DT_FLOAT
      shape: (-1, 1)
      name: y:0
Method name is: tensorflow/serving/predict

Чтобы показать всю доступную информацию в SaveedModel, используйте--allвариант. Например:

$ saved_model_cli show --dir /tmp/saved_model_dir --all
MetaGraphDef with tag-set: 'serve' contains the following SignatureDefs:

signature_def['classify_x2_to_y3']:
  The given SavedModel SignatureDef contains the following input(s):
    inputs['inputs'] tensor_info:
        dtype: DT_FLOAT
        shape: (-1, 1)
        name: x2:0
  The given SavedModel SignatureDef contains the following output(s):
    outputs['scores'] tensor_info:
        dtype: DT_FLOAT
        shape: (-1, 1)
        name: y3:0
  Method name is: tensorflow/serving/classify

...

signature_def['serving_default']:
  The given SavedModel SignatureDef contains the following input(s):
    inputs['x'] tensor_info:
        dtype: DT_FLOAT
        shape: (-1, 1)
        name: x:0
  The given SavedModel SignatureDef contains the following output(s):
    outputs['y'] tensor_info:
        dtype: DT_FLOAT
        shape: (-1, 1)
        name: y:0
  Method name is: tensorflow/serving/predict

runкомандование

ВызватьrunКоманда для запуска вычисления графика, передачи входов, а затем отображения (и опционально сохранения) выходов. Вот синтаксис:

usage: saved_model_cli run [-h] --dir DIR --tag_set TAG_SET --signature_def
                           SIGNATURE_DEF_KEY [--inputs INPUTS]
                           [--input_exprs INPUT_EXPRS]
                           [--input_examples INPUT_EXAMPLES] [--outdir OUTDIR]
                           [--overwrite] [--tf_debug]

АrunКоманда предоставляет следующие три способа передачи входов в модель:

  • --inputsОпция позволяет вам передавать Numpy Ndarray в файлах.
  • --input_exprsОпция позволяет вам передавать экспрессию Python.
  • --input_examplesопция позволяет вам пройтиtf.train.ExampleПолем

--inputs

Чтобы передавать входные данные в файлах, укажите--inputsвариант, который принимает следующий общий формат:

--inputs <INPUTS>

гдеВходные данныеявляется одним из следующих форматов:

  • <input_key>=<filename>
  • <input_key>=<filename>[<variable_name>]

Вы можете пройти несколькоВходные данныеПолем Если вы передаете несколько входов, используйте полуколон, чтобы разделить каждый изВходные данныеПолем

saved_model_cliИспользованиеnumpy.loadЧтобы загрузитьимя файлаПолем Аимя файламожет быть в любом из следующих форматов:

  • .npy
  • .npz
  • Формат рассола

А.npyФайл всегда содержит Numpy Ndarray. Следовательно, при загрузке из.npyФайл, содержимое будет напрямую назначено указанному тензору ввода. Если вы указалиvariable_nameс этим.npyФайл,variable_nameбудет проигнорировано, и будет выпущено предупреждение.

При загрузке из.npz(ZIP) файл, вы можете при желании указатьvariable_nameЧтобы идентифицировать переменную в файле ZIP для загрузки для клавиши входного тензора. Если вы не указалиvariable_name, CLI SaveedModel проверяет, что в файл ZIP включен только один файл и загружается его для указанного ключа ввода -тензора.

При загрузке из файла маринозов, если нетvariable_nameуказывается в квадратных скобках, что бы ни находилось внутри файла рассола, будет передано в указанный ключ входного тензора. В противном случае, CLI SaveedModel предполагает, что в файле Pickle хранится словарь, а значение, соответствующееvariable_nameбудет использоваться.

--input_exprs

Чтобы пройти входы через экспрессии Python, укажите--input_exprsвариант. Это может быть полезно, когда у вас нет файлов данных.SignatureDefс Например:

`<input_key>=[[1],[2],[3]]`

В дополнение к выражениям Python, вы также можете выполнить функции Numpy. Например:

`<input_key>=np.ones((32,32,3))`

(Обратите внимание, чтоnumpyмодуль уже доступен вам какnp.)

--input_examples

Чтобы пройтиtf.train.ExampleВ качестве входных данных укажите--input_examplesвариант. Для каждого ключа ввода он требует списка словаря, где каждый словарь является экземпляромtf.train.ExampleПолем Клавиши словаря - это функции, а значения - это списки значений для каждой функции. Например:

`<input_key>=[{"age":[22,24],"education":["BS","MS"]}]`

Сохранить вывод

По умолчанию CLI SaveedModel записывает вывод в Stdout. Если каталог передается--outdirвариант, выходы будут сохранены как.npyФайлы, названные в честь вывода тензорных клавиш в данном каталоге.

Использовать--overwriteперезаписать существующие выходные файлы.

Первоначально опубликовано наTensorflowВеб -сайт, эта статья появляется здесь под новым заголовком и имеет лицензию в CC на 4.0. Образцы кода, разделенные по лицензии Apache 2.0.


Оригинал
PREVIOUS ARTICLE
NEXT ARTICLE