TensorFlow2.0 Guide 官方教程 学习笔记5- Save and serialize models with Keras

本笔记参照TensorFlow官方教程,主要是对‘Writing custom layers and models with Keras’教程内容翻译和内容结构编排,原文链接:Save and serialize models with Keras

Keras 模型的保存和序列化操作

  • 创建环境(Setup)
  • 一、保存顺序模型或功能模型
    • 1.1 保存整个模型
    • 1.2 输出到已经保存的模型(Export to SavedModel)
    • 1.3 仅保存架构
    • 1.4 仅保存权重
    • 1.5 使用TensorFlow检查点保存权重
  • 二 、保存子类化模型

目录
创建环境(Setup)
第一部分:保存顺序模型或功能模型
1.1保存整个模型
1.2输出到已经保存的模型(Export to SavedModel)
1.3只保存架构
1.4只保存权重
1.5使用TensorFlow检查点只保存权重
第二部分:保存子类模型
本指南的第一部分介绍了顺序模型、使用‘Functional API’构建的模型和顺序模型的保存和序列化。对于这两种类型的模型,保存和序列化API是完全相同的。
保存模型的自定义子类将在“保存子类模型”一节中讨论。本例中的api与顺序模型或功能模型稍有不同。

创建环境(Setup)

from __future__ import absolute_import, division, print_function, unicode_literals

try:
  # %tensorflow_version only exists in Colab.
  %tensorflow_version 2.x
except Exception:
  pass
import tensorflow as tf

tf.keras.backend.clear_session()  # For easy reset of notebook state.

一、保存顺序模型或功能模型

让我们来看下下面的模型:

from tensorflow import keras
from tensorflow.keras import layers

inputs = keras.Input(shape=(784,), name='digits')
x = layers.Dense(64, activation='relu', name='dense_1')(inputs)
x = layers.Dense(64, activation='relu', name='dense_2')(x)
outputs = layers.Dense(10, activation='softmax', name='predictions')(x)

model = keras.Model(inputs=inputs, outputs=outputs, name='3_layer_mlp')
model.summary()

或者,让我们训练这个模型,这样它就有要保存的权重值,以及优化器状态。当然,你也可以保存你从未训练过的模型,但很明显,那样没有乐趣,_

(x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data()
x_train = x_train.reshape(60000, 784).astype('float32') / 255
x_test = x_test.reshape(10000, 784).astype('float32') / 255

model.compile(loss='sparse_categorical_crossentropy',
              optimizer=keras.optimizers.RMSprop())
history = model.fit(x_train, y_train,
                    batch_size=64,
                    epochs=1)
# Save predictions for future checks
predictions = model.predict(x_test)

1.1 保存整个模型

您可以将使用函数API构建的模型保存到单个文件中。以后可以从这个文件重新创建相同的模型,即使您不再能够访问创建模型的代码。这个文件包含:
(1)模型的架构
(2)模型的权重值(训练中学习到的)
(3)模型的训练配置(传递到‘compile’),如果有的话
(4)优化器和它的状态,如果有的话(这样可以让你从停止的地方重新训练)

# Save the model
model.save('path_to_my_model.h5')

# Recreate the exact same model purely from the file
new_model = keras.models.load_model('path_to_my_model.h5')
import numpy as np

# Check that the state is preserved
new_predictions = new_model.predict(x_test)
np.testing.assert_allclose(predictions, new_predictions, rtol=1e-6, atol=1e-6)

# Note that the optimizer state is preserved as well:
# you can resume training where you left off.

1.2 输出到已经保存的模型(Export to SavedModel)

我们还可以将整个模型导出为TensorFlow ‘SavedModel’格式。SavedModel是Tensorflow对象的独立序列化格式,由Tensorflow和Tensorflow实现(Python除外)支持。

# Export the model to a SavedModel
model.save('path_to_saved_model', save_format='tf')

# Recreate the exact same model
new_model = keras.models.load_model('path_to_saved_model')

# Check that the state is preserved
new_predictions = new_model.predict(x_test)
np.testing.assert_allclose(predictions, new_predictions, rtol=1e-6, atol=1e-6)

# Note that the optimizer state is preserved as well:
# you can resume training where you left off.

‘SavedModel’文件包含:
(1)包含模型权重的TensorFlow检查点
(2)包含底层TensorFlow图的SavedModel原型

1.3 仅保存架构

有时,我们只对模型的体系结构感兴趣,不需要保存权重值或优化器。在这种情况下,我们可以通过get_config()方法检索模型的“config”。该配置是一个Python字典,它使您能够重新创建相同的模型——从头开始初始化,而不需要以前在培训期间学到的任何信息。

config = model.get_config()
reinitialized_model = keras.Model.from_config(config)

# Note that the model state is not preserved! We only saved the architecture.
new_predictions = reinitialized_model.predict(x_test)
assert abs(np.sum(predictions - new_predictions)) > 0.

我们也可以从from_json()中使用to_json(),它使用JSON字符串来存储配置,而不是Python字典,这对于将配置保存到磁盘非常有用。

json_config = model.to_json()
reinitialized_model = keras.models.model_from_json(json_config)

1.4 仅保存权重

	有时,我们只对模型的状态(它的权值)感兴趣,而对体系结构不感兴趣。在这种情况下,我们可以通过get_weights()以Numpy数组列表的形式获取权值,并通过set_weights设置模型的状态:
weights = model.get_weights()  # Retrieves the state of the model.
model.set_weights(weights)  # Sets the state of the model.

我们可以联合‘get_config()/from_config()’和‘get_weight()/set_weights()’在相同的状态里创建我们的模型。然而,不像model.save(),这个将不包括训练配置和优化器。在使用模型训练之前,我们需要重新调用‘compile()’

config = model.get_config()
weights = model.get_weights()

new_model = keras.Model.from_config(config)
new_model.set_weights(weights)

# Check that the state is preserved
new_predictions = new_model.predict(x_test)
np.testing.assert_allclose(predictions, new_predictions, rtol=1e-6, atol=1e-6)

# Note that the optimizer was not preserved,
# so the model should be compiled anew before training
# (and the optimizer will start from a blank state).

get_weights()和set_weights(weights)的另一种保存到磁盘的方法是save_weights(fpath)和load_weights(fpath)。下面是将模型保存到磁盘的例子:

# Save JSON config to disk
json_config = model.to_json()
with open('model_config.json', 'w') as json_file:
    json_file.write(json_config)
# Save weights to disk
model.save_weights('path_to_my_weights.h5')

# Reload the model from the 2 files we saved
with open('model_config.json') as json_file:
    json_config = json_file.read()
new_model = keras.models.model_from_json(json_config)
new_model.load_weights('path_to_my_weights.h5')

# Check that the state is preserved
new_predictions = new_model.predict(x_test)
np.testing.assert_allclose(predictions, new_predictions, rtol=1e-6, atol=1e-6)

# Note that the optimizer was not preserved.

记住:最简单的方式是这样的:

model.save('path_to_my_model.h5')
del model
model = keras.models.load_model('path_to_my_model.h5')

1.5 使用TensorFlow检查点保存权重

注意,save_weights可以创建Keras HDF5格式的文件,也可以创建TensorFlow检查点格式的文件。格式是从我们提供的文件扩展名推断出来的:如果它是‘.h5’或者‘.keras’,该框架使用Keras HDF5格式。其它任何东西都默认为检查点。

model.save_weights('path_to_my_tf_checkpoint')

对于总的明确性,可以通过save_format参数显式传递格式,参数可以取值“tf”或“h5”:

model.save_weights('path_to_my_tf_checkpoint', save_format='tf')

二 、保存子类化模型

顺序模型和功能模型是表示层的DAG的数据结构。因此,它们可以安全地序列化和反序列化。
子类模型的不同之处在于它不是一个数据结构,而是一段代码。模型的体系结构是通过调用方法的主体来定义的。这意味着不能安全地序列化模型的体系结构。要加载模型,我们需要访问创建模型的代码(模型子类的代码)。或者,我们可以将这些代码序列化为字节码(例如,通过pickle),但这是不安全的,而且通常是不可移植的。
我们看下面的子类模型,它遵循上面提到的模型中同样的架构:

class ThreeLayerMLP(keras.Model):

  def __init__(self, name=None):
    super(ThreeLayerMLP, self).__init__(name=name)
    self.dense_1 = layers.Dense(64, activation='relu', name='dense_1')
    self.dense_2 = layers.Dense(64, activation='relu', name='dense_2')
    self.pred_layer = layers.Dense(10, activation='softmax', name='predictions')

  def call(self, inputs):
    x = self.dense_1(inputs)
    x = self.dense_2(x)
    return self.pred_layer(x)

def get_model():
  return ThreeLayerMLP(name='3_layer_mlp')

model = get_model()

首先,一个没有被用过的子类模型是不能被保存的。因为子类模型需要在数据上调用来创建权重。在调用模型之前,它不知道应该期望的输入数据的形状和dtype,因此不能创建它的权重变量。您可能还记得,在第一部分的功能模型中,输入的形状和dtype是预先指定的(通过keras.Input(…))——这就是为什么功能模型在实例化后立即具有状态的原因。
让我们来训练这个模型,给它一个状态:

class ThreeLayerMLP(keras.Model):

  def __init__(self, name=None):
    super(ThreeLayerMLP, self).__init__(name=name)
    self.dense_1 = layers.Dense(64, activation='relu', name='dense_1')
    self.dense_2 = layers.Dense(64, activation='relu', name='dense_2')
    self.pred_layer = layers.Dense(10, activation='softmax', name='predictions')

  def call(self, inputs):
    x = self.dense_1(inputs)
    x = self.dense_2(x)
    return self.pred_layer(x)

def get_model():
  return ThreeLayerMLP(name='3_layer_mlp')

model = get_model()
(x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data()
x_train = x_train.reshape(60000, 784).astype('float32') / 255
x_test = x_test.reshape(10000, 784).astype('float32') / 255

model.compile(loss='sparse_categorical_crossentropy',
              optimizer=keras.optimizers.RMSprop())
history = model.fit(x_train, y_train,
                    batch_size=64,
                    epochs=1)

保存子类化模型的推荐方法是使用save_weights创建一个TensorFlow SavedModel检查点,它将包含与模型相关的所有变量的值:
(1)层的权重
(2)优化器状态
(3)与有状态模型指标相关的任何变量(如果有的话)

model.save_weights('path_to_my_weights', save_format='tf')
# Save predictions for future checks
predictions = model.predict(x_test)
# Also save the loss on the first batch
# to later assert that the optimizer state was preserved
first_batch_loss = model.train_on_batch(x_train[:64], y_train[:64])

为了恢复模型,我们需要访问创建这个模型对象的代码。
请注意,为了恢复优化器状态和任何有状态指标的状态,我们应该编译模型(使用与前面完全相同的参数),并在调用load_weights之前对一些数据调用它:

# Recreate the model
new_model = get_model()
new_model.compile(loss='sparse_categorical_crossentropy',
                  optimizer=keras.optimizers.RMSprop())

# This initializes the variables used by the optimizers,
# as well as any stateful metric variables
new_model.train_on_batch(x_train[:1], y_train[:1])

# Load the state of the old model
new_model.load_weights('path_to_my_weights')

# Check that the model state has been preserved
new_predictions = new_model.predict(x_test)
np.testing.assert_allclose(predictions, new_predictions, rtol=1e-6, atol=1e-6)

# The optimizer state is preserved as well,
# so you can resume training where you left off
new_first_batch_loss = new_model.train_on_batch(x_train[:64], y_train[:64])
assert first_batch_loss == new_first_batch_loss

你可能感兴趣的:(TensorFlow,2.0,学习笔记,TensorFlow2.0)