1、绪论
1.1 保存、序列化以及导出模型的概念
- 保存 (Save): 将模型保存到磁盘或其他存储介质中,以便将来使用。
- 序列化 (Serialize): 将模型(通常是一个复杂的对象或数据结构)转换为一个可以存储或传输的格式(如JSON、XML、二进制等)。序列化是保存模型的关键步骤,因为它将模型转换为一个可以持久化或在网络中传输的格式。
- 导出 (Export): 将模型从一种格式或系统转换为另一种格式或系统,以便在其他环境或工具中使用。例如,将TensorFlow模型导出为ONNX格式,以便在PyTorch或其他框架中使用。
在机器学习和深度学习中,这三个步骤通常是保存和重用模型的重要流程。
1.2 Keras 的组建及存储
Keras模型由多个组件组成:
- 架构或配置,它指定了模型包含哪些层以及这些层是如何连接的。
- 一组权重值(模型的“状态”)。
- 一个优化器(通过编译模型来定义)。
- 一组损失和指标(通过编译模型来定义)。
Keras API 将所有这些组件保存在一个统一的格式中,标记为.keras扩展名。这是一个zip归档文件,包含以下内容:
- 基于JSON的配置文件(config.json):记录模型、层和其他可追踪对象的配置。
- 基于H5的状态文件,例如model.weights.h5(对于整个模型),包含层的目录键及其权重。
- JSON格式的元数据文件,存储如当前Keras版本等信息。
2、存储和加载模型
保存模型的方式如下
model = ... # Get model (Sequential, Functional Model, or Model subclass)
model.save('path/to/location.keras') # The file needs to end with the .keras extension
加载模型则按照以下的方式进行
model = keras.models.load_model('path/to/location.keras')
2.1 设置
import numpy as np
import keras
from keras import ops
2.2 保存模型
本节讨论如何将整个模型保存到一个单一的文件中。该文件将包含:
- 模型的架构/配置
- 模型的权重值(在训练过程中学习得到的)
- 模型的编译信息(如果调用了compile()方法)
- 优化器及其状态(如果有的话,这允许你从上次中断的地方重新开始训练)
使用Keras的API进行保存操作
可以使用model.save()
或keras.models.save_model()
(两者等效)来保存模型。之后,你可以使用keras.models.load_model()
来重新加载模型。
在Keras 3中,唯一支持的格式是“Keras v3”格式,使用.keras扩展名。
def get_model():
# Create a simple model.
inputs = keras.Input(shape=(32,))
outputs = keras.layers.Dense(1)(inputs)
model = keras.Model(inputs, outputs)
model.compile(optimizer=keras.optimizers.Adam(), loss="mean_squared_error")
return model
model = get_model()
# Train the model.
test_input = np.random.random((128, 32))
test_target = np.random.random((128, 1))
model.fit(test_input, test_target)
# Calling `save('my_model.keras')` creates a zip archive `my_model.keras`.
model.save("my_model.keras")
# It can be used to reconstruct the model identically.
reconstructed_model = keras.models.load_model("my_model.keras")
# Let's check:
np.testing.assert_allclose(
model.predict(test_input), reconstructed_model.predict(test_input)
)
2.3 自定义对象的保存和加载
本节讨论在Keras保存和重新加载自定义层、函数和模型时的基本工作流程。
2.3.1 保存操作
当保存包含自定义对象的模型时,例如一个继承自Layer
的子类,此时,就必须在对象类上定义一个get_config()
方法。如果传递给自定义对象构造函数(__init__()
方法)的参数不是Python对象(即除了基本类型如整数、字符串等以外的任何东西),那么你还需要在from_config()
类方法中显式地反序列化这些参数。
get_config()
方法用于返回一个表示层配置的字典。这个字典在保存模型时会与模型的配置一起存储,并且可以用于后续从配置重新创建该层。
from_config()
类方法用于根据配置字典重新创建层实例。它应该使用字典中的值来设置层的属性,并返回一个新的层实例。
在自定义层和模型中使用get_config()
和from_config()
方法时,你需要确保:
get_config()
方法返回一个包含所有必要信息的字典,以便能够重新创建层或模型。from_config()
类方法能够使用get_config()
返回的字典来重新创建层或模型的实例。
此外,如果在脚本中使用了自定义的损失函数、指标函数或优化器,并且它们被作为模型的编译参数(通过compile()
方法传递),再保存时还需要确保这些函数可以在模型保存和重新加载时正确导入。这通常意味着需要将这些函数定义在单独的模块中,并在模型保存和加载的脚本中导入它们。
通过遵循这些步骤,可以确保包含自定义对象的Keras模型能够正确地保存和重新加载。
class CustomLayer(keras.layers.Layer):
def __init__(self, sublayer, **kwargs):
super().__init__(**kwargs)
self.sublayer = sublayer
def call(self, x):
return self.sublayer(x)
def get_config(self):
base_config = super().get_config()
config = {
"sublayer": keras.saving.serialize_keras_object(self.sublayer),
}
return {
**base_config, **config}
@classmethod
def from_config(cls, config):
sublayer_config = config.pop("sublayer")
sublayer = keras.saving.deserialize_keras_object(sublayer_config)
return cls(sublayer, **config)
2.3.2 加载操作
保存的.keras文件是轻量级的,并且不存储自定义对象的Python代码。因此,要重新加载模型,load_model
需要通过以下方法之一访问所使用的任何自定义对象的定义:
- 注册自定义对象,
- 在加载时直接传递自定义对象,或
- 使用自定义对象作用域
以下是每种工作流程的示例:
注册自定义对象
这是推荐的方法,因为自定义对象注册大大简化了保存和加载代码。通过在自定义对象的类定义中添加 @keras.saving.register_keras_serializable
装饰器,可以将对象全局注册到主列表中,以便 Keras 在加载模型时能够识别该对象。
# Clear all previously registered custom objects
keras.saving.get_custom_objects().clear()
# Upon registration, you can optionally specify a package or a name.
# If left blank, the package defaults to `Custom` and the name defaults to
# the class name.
@keras.saving.register_keras_serializable(package="MyLayers")
class CustomLayer(keras.layers.Layer):
def __init__(self, factor):
super().__init__()
self.factor = factor
def call(self, x):
return x * self.factor
def get_config(self):
return {
"factor": self.factor}
@keras.saving.register_keras_serializable(package="my_package", name="custom_fn")
def custom_fn(x):
return x**2
# Create the model.
def get_model():
inputs = keras.Input(shape=(4,))
mid = CustomLayer(0.5)(inputs)
outputs = keras.layers.Dense(1, activation=custom_fn)(mid)
model = keras.Model(inputs, outputs)
model.compile(optimizer="rmsprop", loss="mean_squared_error")
return model
# Train the model.
def train_model(model):
input = np.random.random