Как определить, сохранить и восстановить модели в TensorFlow

Как определить, сохранить и восстановить модели в TensorFlow

11 июня 2025 г.

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

  • Настраивать
  • Модули тензорфлоу
  • Строительные модули
  • В ожидании создания переменных
  • Экономия веса
  • Функции сохранения
  • Создание сохраненной модели

Чтобы сделать машинное обучение в Tensorflow, вам, вероятно, нужно определить, сохранить и восстановить модель.

Модель, абстрактно:

  • Функция, которая вычисляет что -то на тензорах (Вперед)
  • Некоторые переменные, которые могут быть обновлены в ответ на обучение

В этом руководстве вы пройдете под поверхностью керас, чтобы увидеть, как определены модели TensorFlow. Это рассматривает, как Tensorflow собирает переменные и модели, а также как они сохраняются и восстанавливаются.

Настраивать

import tensorflow as tf
import keras
from datetime import datetime

%load_ext tensorboard

2023-10-18 01:21:05.536666: E tensorflow/compiler/xla/stream_executor/cuda/cuda_dnn.cc:9342] Unable to register cuDNN factory: Attempting to register factory for plugin cuDNN when one has already been registered
2023-10-18 01:21:05.536712: E tensorflow/compiler/xla/stream_executor/cuda/cuda_fft.cc:609] Unable to register cuFFT factory: Attempting to register factory for plugin cuFFT when one has already been registered
2023-10-18 01:21:05.536766: E tensorflow/compiler/xla/stream_executor/cuda/cuda_blas.cc:1518] Unable to register cuBLAS factory: Attempting to register factory for plugin cuBLAS when one has already been registered

Модули тензорфлоу

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

Строительные модули

Вот пример очень простогоtf.ModuleЭто работает на скалярном тензоре:

class SimpleModule(tf.Module):
  def __init__(self, name=None):
    super().__init__(name=name)
    self.a_variable = tf.Variable(5.0, name="train_me")
    self.non_trainable_variable = tf.Variable(5.0, trainable=False, name="do_not_train_me")
  def __call__(self, x):
    return self.a_variable * x + self.non_trainable_variable

simple_module = SimpleModule(name="simple")

simple_module(tf.constant(5.0))

2023-10-18 01:21:08.181350: W tensorflow/core/common_runtime/gpu/gpu_device.cc:2211] Cannot dlopen some GPU libraries. Please make sure the missing libraries mentioned above are installed properly if you would like to use GPU. Follow the guide at https://www.tensorflow.org/install/gpu for how to download and setup the required libraries for your platform.
Skipping registering GPU devices...
<tf.Tensor: shape=(), dtype=float32, numpy=30.0>

Модули и, соответственно, слои являются терминологией глубокого обучения для «объектов»: у них есть внутреннее состояние и методы, которые используют это состояние.

В этом нет ничего особенного__call__кроме как вести себя какPython Callable; Вы можете вызвать свои модели с любыми функциями, которые вы пожелаете.

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

Примечание:tf.Moduleбазовый класс для обоихtf.keras.layers.Layerиtf.keras.Model, так что все, что вы здесь сталкиваетесь, также применяется в Керас. По причинам исторической совместимости слои кераса не собирают переменные из модулей, поэтому ваши модели должны использовать только модули или только слои кераса. Однако методы, показанные ниже для осмотра переменных, одинаковы в любом случае.

Подклассомtf.Module, любойtf.Variableилиtf.Moduleэкземпляры, назначенные свойствам этого объекта, автоматически собираются. Это позволяет вам сохранять и загружать переменные, а также создавать коллекцииtf.Moduleс

# All trainable variables
print("trainable variables:", simple_module.trainable_variables)
# Every variable
print("all variables:", simple_module.variables)

trainable variables: (<tf.Variable 'train_me:0' shape=() dtype=float32, numpy=5.0>,)
all variables: (<tf.Variable 'train_me:0' shape=() dtype=float32, numpy=5.0>, <tf.Variable 'do_not_train_me:0' shape=() dtype=float32, numpy=5.0>)

Это пример двухслойной модели линейного слоя, сделанной из модулей.

Сначала плотный (линейный) слой:

class Dense(tf.Module):
  def __init__(self, in_features, out_features, name=None):
    super().__init__(name=name)
    self.w = tf.Variable(
      tf.random.normal([in_features, out_features]), name='w')
    self.b = tf.Variable(tf.zeros([out_features]), name='b')
  def __call__(self, x):
    y = tf.matmul(x, self.w) + self.b
    return tf.nn.relu(y)

А затем полная модель, которая делает два экземпляра слоя и применяет их:

class SequentialModule(tf.Module):
  def __init__(self, name=None):
    super().__init__(name=name)

    self.dense_1 = Dense(in_features=3, out_features=3)
    self.dense_2 = Dense(in_features=3, out_features=2)

  def __call__(self, x):
    x = self.dense_1(x)
    return self.dense_2(x)

# You have made a model!
my_model = SequentialModule(name="the_model")

# Call it, with random results
print("Model results:", my_model(tf.constant([[2.0, 2.0, 2.0]])))

Model results: tf.Tensor([[0.       3.415034]], shape=(1, 2), dtype=float32)

tf.Moduleэкземпляры будут автоматически собираться, рекурсивно, любыеtf.Variableилиtf.Moduleэкземпляры назначены ему. Это позволяет вам управлять коллекциямиtf.ModuleS с одним экземпляром модели, а также сохранить и загружать целые модели.

print("Submodules:", my_model.submodules)

Submodules: (<__main__.Dense object at 0x7f7931aea250>, <__main__.Dense object at 0x7f77ed5b8a00>)

for var in my_model.variables:
  print(var, "\n")

<tf.Variable 'b:0' shape=(3,) dtype=float32, numpy=array([0., 0., 0.], dtype=float32)> 

<tf.Variable 'w:0' shape=(3, 3) dtype=float32, numpy=
array([[-2.8161757, -2.6065955,  1.9061812],
       [-0.9430401, -0.4624743, -0.4531979],
       [-1.3428234,  0.7062293,  0.7874674]], dtype=float32)> 

<tf.Variable 'b:0' shape=(2,) dtype=float32, numpy=array([0., 0.], dtype=float32)> 

<tf.Variable 'w:0' shape=(3, 2) dtype=float32, numpy=
array([[ 1.0474309 , -0.6920227 ],
       [ 1.2405277 ,  0.36411622],
       [-1.6990206 ,  0.762131  ]], dtype=float32)>

В ожидании создания переменных

Возможно, вы заметили здесь, что вы должны определить как входные, так и выходные размеры для слоя. Это такwПеременная имеет известную форму и может быть выделена.

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

class FlexibleDenseModule(tf.Module):
  # Note: No need for `in_features`
  def __init__(self, out_features, name=None):
    super().__init__(name=name)
    self.is_built = False
    self.out_features = out_features

  def __call__(self, x):
    # Create variables on first call.
    if not self.is_built:
      self.w = tf.Variable(
        tf.random.normal([x.shape[-1], self.out_features]), name='w')
      self.b = tf.Variable(tf.zeros([self.out_features]), name='b')
      self.is_built = True

    y = tf.matmul(x, self.w) + self.b
    return tf.nn.relu(y)

# Used in a module
class MySequentialModule(tf.Module):
  def __init__(self, name=None):
    super().__init__(name=name)

    self.dense_1 = FlexibleDenseModule(out_features=3)
    self.dense_2 = FlexibleDenseModule(out_features=2)

  def __call__(self, x):
    x = self.dense_1(x)
    return self.dense_2(x)

my_model = MySequentialModule(name="the_model")
print("Model results:", my_model(tf.constant([[2.0, 2.0, 2.0]])))

Model results: tf.Tensor([[0. 0.]], shape=(1, 2), dtype=float32)

Эта гибкость заключается в том, почему слои TensorFlow часто должны только указывать форму их выходов, например, вtf.keras.layers.Dense, а не вход и выходной размер.

Экономия веса

Вы можете сохранитьtf.Moduleкак обаКонтрольная точкаиСохраняйте модельПолем

Контрольные точки - это просто веса (то есть значения набора переменных внутри модуля и его подмодулей):

chkp_path = "my_checkpoint"
checkpoint = tf.train.Checkpoint(model=my_model)
checkpoint.write(chkp_path)

'my_checkpoint'

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

ls my_checkpoint*

my_checkpoint.data-00000-of-00001  my_checkpoint.index

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

tf.train.list_variables(chkp_path)

[('_CHECKPOINTABLE_OBJECT_GRAPH', []),
 ('model/dense_1/b/.ATTRIBUTES/VARIABLE_VALUE', [3]),
 ('model/dense_1/w/.ATTRIBUTES/VARIABLE_VALUE', [3, 3]),
 ('model/dense_2/b/.ATTRIBUTES/VARIABLE_VALUE', [2]),
 ('model/dense_2/w/.ATTRIBUTES/VARIABLE_VALUE', [3, 2])]

Во время распределенного (мульти-машинового) обучения они могут быть охвачены, поэтому они пронумерованы (например, «00000-of-00001»). В этом случае, однако, есть только один осколок.

Когда вы загружаете модели обратно, вы перезаписываете значения в вашем объекте Python.

new_model = MySequentialModule()
new_checkpoint = tf.train.Checkpoint(model=new_model)
new_checkpoint.restore("my_checkpoint")

# Should be the same result as above
new_model(tf.constant([[2.0, 2.0, 2.0]]))

<tf.Tensor: shape=(1, 2), dtype=float32, numpy=array([[0., 0.]], dtype=float32)>

Примечание:Поскольку контрольно -пропускные пункты лежат в основе длительных тренировочных процессовtf.checkpoint.CheckpointManagerэто вспомогательный класс, который значительно облегчает управление контрольно -пропускными пунктами. СмРуководство по обучению контрольных точекДля получения более подробной информации.

Функции сохранения

TensorFlow может запускать модели без оригинальных объектов Python, как продемонстрированоTensorflow AerdingиTensorflow Lite, даже при загрузке обученной модели изTensorflow Hub.

Tensorflow должен знать, как делать вычисления, описанные на Python, ноБез исходного кодаПолем Для этого вы можете сделатьграфик, который описан вРуководство по введению в графики и функцииПолем

Этот график содержит операции, илиОпс, это реализует функцию.

Вы можете определить график в модели выше, добавив@tf.functionдекоратор, чтобы указать, что этот код должен работать как график.

class MySequentialModule(tf.Module):
  def __init__(self, name=None):
    super().__init__(name=name)

    self.dense_1 = Dense(in_features=3, out_features=3)
    self.dense_2 = Dense(in_features=3, out_features=2)

  @tf.function
  def __call__(self, x):
    x = self.dense_1(x)
    return self.dense_2(x)

# You have made a model with a graph!
my_model = MySequentialModule(name="the_model")

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

print(my_model([[2.0, 2.0, 2.0]]))
print(my_model([[[2.0, 2.0, 2.0], [2.0, 2.0, 2.0]]]))

tf.Tensor([[0.31593648 0.        ]], shape=(1, 2), dtype=float32)
tf.Tensor(
[[[0.31593648 0.        ]
  [0.31593648 0.        ]]], shape=(1, 2, 2), dtype=float32)

Вы можете визуализировать график, отслеживая его в рамках резюме для тензора.

# Set up logging.
stamp = datetime.now().strftime("%Y%m%d-%H%M%S")
logdir = "logs/func/%s" % stamp
writer = tf.summary.create_file_writer(logdir)

# Create a new model to get a fresh trace
# Otherwise the summary will not see the graph.
new_model = MySequentialModule()

# Bracket the function call with
# tf.summary.trace_on() and tf.summary.trace_export().
tf.summary.trace_on(graph=True)
tf.profiler.experimental.start(logdir)
# Call only one tf.function when tracing.
z = print(new_model(tf.constant([[2.0, 2.0, 2.0]])))
with writer.as_default():
  tf.summary.trace_export(
      name="my_func_trace",
      step=0,
      profiler_outdir=logdir)

tf.Tensor([[0. 0.]], shape=(1, 2), dtype=float32)

Запустите Tensorboard, чтобы просмотреть результирующую трассу:

#docs_infra: no_execute
%tensorboard --logdir logs/func

Создание аSavedModel

Рекомендуемый способ обмена полностью обученными моделями - использоватьSavedModelПолемSavedModelСодержит как набор функций, так и набор весов.

Вы можете сохранить только что модель, которую только что обучили следующим образом:

tf.saved_model.save(my_model, "the_saved_model")

INFO:tensorflow:Assets written to: the_saved_model/assets

# Inspect the SavedModel in the directory
ls -l the_saved_model

total 32
drwxr-sr-x 2 kbuilder kokoro  4096 Oct 18 01:21 assets
-rw-rw-r-- 1 kbuilder kokoro    58 Oct 18 01:21 fingerprint.pb
-rw-rw-r-- 1 kbuilder kokoro 17704 Oct 18 01:21 saved_model.pb
drwxr-sr-x 2 kbuilder kokoro  4096 Oct 18 01:21 variables

# The variables/ directory contains a checkpoint of the variables
ls -l the_saved_model/variables

total 8
-rw-rw-r-- 1 kbuilder kokoro 490 Oct 18 01:21 variables.data-00000-of-00001
-rw-rw-r-- 1 kbuilder kokoro 356 Oct 18 01:21 variables.index

Аsaved_model.pbФайлпротокол буферописывая функциональныеtf.GraphПолем

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

Вы можете загрузить модель как новый объект:

new_model = tf.saved_model.load("the_saved_model")

new_model, из загрузки сохраненной модели, является внутренним объектом пользователя TensorFlow без какого -либо знания класса. Это не типаSequentialModuleПолем

isinstance(new_model, SequentialModule)

False

Эта новая модель работает на уже определенных входных подписях. Вы не можете добавить больше подписей в модель, восстановленную, как это.

print(my_model([[2.0, 2.0, 2.0]]))
print(my_model([[[2.0, 2.0, 2.0], [2.0, 2.0, 2.0]]]))

tf.Tensor([[0.31593648 0.        ]], shape=(1, 2), dtype=float32)
tf.Tensor(
[[[0.31593648 0.        ]
  [0.31593648 0.        ]]], shape=(1, 2, 2), dtype=float32)

Таким образом, использованиеSavedModel, вы можете сэкономить веса и графики TensorFlow, используяtf.Module, а затем загрузите их снова.


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


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