13.模型保存-加载

模型保存-加载整个模型

Keras 模型保存为HDF5文件。
(官网建议)不建议使用pickle 或cPickle 来保存Keras 模型。

保存:使用model.save(filepath) 将Keras 模型保存到单个HDF5中。
可以保存以下内容:

  1. 模型的结构,允许重新创建模型
  2. 模型的权重
  3. 训练配置项(损失函数,优化器)
  4. 优化器状态,允许准确地从上次结束的地方继续训练。

代码:
保存

import h5py
model.save('my_model.h5')

加载:

import keras
from keras.models import load_model
import numpy as np
my_model=load_model('my_model.h5') 
import keras.datasets.mnist as mnist   
(train_image,train_lable),(test_image,test_label)=mnist.load_data() #加载数据集

预测举例

test_image = np.expand_dims(test_image,axis=-1)
my_model.evaluate(test_image,test_label)
my_model.predict(test_image[0:2])

模型保存-加载模型结构

保存

from keras.models import model_from_json
my_model_json=model.to_json()
with open('muy_json_model.json','w') as f:
    f.write(my_model_json)

加载:

with open('muy_json_model.json') as f:
    my_json_model = f.read()
from keras.models import model_from_json
model=model_from_json(my_json_model)

看看是不是和以前结构一样:

model.summary()

这里是完成不了my_model.evaluate(test_image,test_label)的,因为没有编译也没有权重,只是一个结构。

模型保存-加载模型训练权重

model.save_weights('my_model_weights.h5') #保存模型权重
model.load_weights('my_model_weights.h5') #加载模型权重

上面是保存所有层的权重
还可以实现保存部分层的权重
但首先要给层取一个名字

model.add(layers.Dense(64,activation='relu',name='D1')) 

给这个层起个名字 叫D1
这时候保存权重的时候会根据名字保存。
然后

model.load_weights('my_model_weights.h5',by_name=True) #加载模型权重

就会按照层的名称加载模型权重了。(保存的时候模型的层的名字要和加载时建立的模型的层的名字一致)

在训练期间保存检查点

在训练期间或者训练结束时自动保存检查点,这样就可以使用经过训练的模型,而无需重新训练模型,或者从上次暂停的地方继续训练,以防训练过程中断。
回调函数:tf.keras.callbacks.ModelCheckpoint 或者keras.callbacks.ModelCheckpoint

keras.callbacks.ModelCheckpoint(
    filepath,        保存路径
    monitor='val_loss',  监控目标
    verbose=0,  是否显示提示
    save_best_only=False, 保存loss最低的权值
    save_weights_only=False, 只保存权重 (false 就是保存整个模型)
    mode='auto',         
    save_freq='epoch',
    **kwargs,
)

怎么保存?

cp_callback=keras.callbacks.ModelCheckpoint(checkpoin_path,save_weights_only=True) #定义保存路径,保存啥什么的
model.fit(train_image,train_label,epochs=3, callbacks=[cp_callback]) #在训练模型的时候使用,就会保存

怎么使用?比如训练中途突然断电或者其他什么原因。
如何恢复这个模型:
首先创建原来的模型,然后编译,然后加载保存了的权重:

model.load_weights(checkpoin_path)
D:\anaconda3\python.exe C:\Users\li\Desktop\新建文件夹\数据\training_outputs\输出.py 2025-07-31 01:02:02.877698: I tensorflow/core/util/port.cc:153] oneDNN custom operations are on. You may see slightly different numerical results due to floating-point round-off errors from different computation orders. To turn them off, set the environment variable TF_ENABLE_ONEDNN_OPTS=0. 2025-07-31 01:02:03.493233: I tensorflow/core/util/port.cc:153] oneDNN custom operations are on. You may see slightly different numerical results due to floating-point round-off errors from different computation orders. To turn them off, set the environment variable TF_ENABLE_ONEDNN_OPTS=0. 2025-07-31 01:02:05.140749: I tensorflow/core/platform/cpu_feature_guard.cc:210] This TensorFlow binary is optimized to use available CPU instructions in performance-critical operations. To enable the following instructions: SSE3 SSE4.1 SSE4.2 AVX AVX2 AVX_VNNI FMA, in other operations, rebuild TensorFlow with the appropriate compiler flags. --- 步骤1: 正在加载数据和【新格式 .keras】模型... --- 加载模型失败: The function of this Lambda layer is a Python lambda. Deserializing it is unsafe. If you trust the source of the config artifact, you can override this error by passing safe_mode=False to from_config(), or calling `keras.config.enable_unsafe_deserialization(). [提示] 如果加载失败,请尝试重新运行一次训练脚本,生成一个新的.keras文件。 进程已结束,退出代码为 1
最新发布
08-01
<think>我们正在处理一个关于Keras Lambda层模型加载错误的问题。错误信息是:“The function of this Lambda layer is a Python lambda. Deserializing it is unsafe.” 这是因为Lambda层使用了Python的lambda函数,而Keras在加载模型时无法安全地反序列化lambda函数。 解决方案通常有以下几种: 1. **避免使用lambda函数**:使用自定义层(继承`Layer`)代替Lambda层。这样,自定义层可以被安全地序列化和反序列化。 2. **在加载模型时提供自定义对象**:如果必须使用Lambda层,可以在加载模型时通过`custom_objects`参数提供该层使用的函数。但是,对于lambda函数,由于它们是匿名的,这种方法可能不可行,因此建议使用方法1。 由于错误信息明确指出使用Python lambda是不安全的,因此最佳实践是使用自定义层。 下面我们将展示如何将Lambda层替换为自定义层。 假设原来的模型使用了Lambda层,例如: ```python from tensorflow.keras.models import Model from tensorflow.keras.layers import Input, Lambda # 原始使用Lambda层的代码示例 input = Input(shape=(...)) # 假设我们使用Lambda层进行一个简单的操作,比如取绝对值 output = Lambda(lambda x: tf.abs(x))(input) model = Model(input, output) ``` 我们可以创建一个自定义层来替代: ```python import tensorflow as tf from tensorflow.keras.layers import Layer class AbsoluteValueLayer(Layer): def __init__(self, **kwargs): super(AbsoluteValueLayer, self).__init__(**kwargs) def call(self, inputs): return tf.abs(inputs) def get_config(self): return super(AbsoluteValueLayer, self).get_config() ``` 然后,在模型中这样使用: ```python input = Input(shape=(...)) output = AbsoluteValueLayer()(input) model = Model(input, output) ``` 这样,当我们保存模型(使用`model.save()`)并重新加载时,就不会出现上述错误。 如果已经有一个使用Lambda层保存模型,并且出现了反序列化错误,那么我们需要在加载模型时提供自定义对象。但是,由于lambda函数是匿名的,我们无法通过名称引用,所以这种方法不适用。因此,我们只能重新构建模型,将Lambda层替换为自定义层,然后重新训练模型,或者从保存的权重中加载权重(前提是模型结构相同)。 步骤: 1. 使用自定义层重新构建模型结构。 2. 使用`model.load_weights()`加载之前保存的权重(注意:保存权重时应该使用`model.save_weights()`,或者从保存的整个模型中提取权重)。 但是,如果之前保存的是整个模型(包括结构和权重),而我们无法加载,那么可能需要先通过代码重新构建模型(使用自定义层),然后使用以下方法加载权重: ```python # 重新构建模型(使用自定义层) model = ... # 构建相同的模型结构,但Lambda层替换为自定义层 # 加载权重 model.load_weights('path/to/weights.h5') ``` 注意:如果原始模型保存为`.h5`文件或SavedModel格式,但包含Lambda层,则直接加载会出错。因此,我们必须在加载时提供自定义对象(如果Lambda层使用的是命名函数而不是lambda表达式,则可以提供该函数)。但是,对于lambda表达式,我们无法提供,因此必须重构模型。 总结:为了避免此类问题,建议在构建模型时避免使用Lambda层,尤其是使用lambda函数。如果必须使用,则使用命名函数(def定义的函数)而不是lambda,并在加载模型时通过`custom_objects`提供该函数。但是,最佳实践是使用自定义层。 下面是一个使用命名函数代替lambda的例子(虽然可以解决,但依然不如自定义层安全,因为函数必须与原始定义完全相同): ```python def my_abs(x): return tf.abs(x) # 在Lambda层中使用 output = Lambda(my_abs)(input) ``` 保存模型后,加载时: ```python model = tf.keras.models.load_model('model.h5', custom_objects={'my_abs': my_abs}) ``` 但是,这种方法要求我们记住所有使用过的函数,并且这些函数必须是可导入的(或者在加载时定义相同的函数)。如果模型要迁移到其他环境,可能会带来不便。 因此,我们强烈推荐使用自定义层。 针对用户的问题,我们建议: 1. 如果可能,修改原始代码,用自定义层替换Lambda层,然后重新训练和保存模型。 2. 如果已经有一个保存模型,并且不想重新训练,可以尝试重新构建模型(用自定义层替换Lambda层),然后加载权重。 注意:如果原始模型使用了多个Lambda层,需要为每个Lambda层创建对应的自定义层。 如果用户遇到的具体错误是由于Lambda层使用了lambda函数,那么按照上述自定义层的方法应该可以解决。 参考引用[1]中提到的是关于KerasTensor不能作为TensorFlow函数输入的错误,但与我们当前的问题无关。引用[2]是关于模型编译的示例,引用[3]是关于多线程下TensorFlow的bug,也与当前问题无关。因此,我们主要根据Keras的文档和最佳实践来给出解决方案。 如果用户需要进一步的帮助,可以提供具体的Lambda层代码,以便我们给出更具体的自定义层实现。 相关问题: 1. 如何自定义Keras层? 2. 在Keras中保存加载模型的最佳实践是什么? 3. 除了Lambda层,还有哪些Keras层在序列化时需要注意?</think>### 解决 Keras Lambda 层模型加载错误 当加载包含 Python `lambda` 函数的 Keras 模型时,会遇到错误 **"The function of this Lambda layer is a Python lambda. Deserializing it is unsafe"**。这是因为 Keras 无法安全序列化匿名函数(lambda)。以下是完整解决方案: #### 📌 根本原因 - Lambda 层使用 Python 的匿名函数 `lambda x: ...`,这些函数无法被序列化 - 模型加载时无法重建原始 lambda 函数的执行环境 - Keras 的安全机制阻止潜在的不安全反序列化 #### ✅ 解决方案(3种方法) **方法1:使用命名函数替代 lambda(推荐)** ```python # 将 lambda 替换为命名函数 def custom_activation(x): return tf.keras.activations.relu(x, alpha=0.1) # 修改模型中的 Lambda 层 model.add(Lambda(custom_activation)) # 替代 lambda x: tf.keras.activations.relu(x, alpha=0.1) ``` **方法2:创建自定义层(更安全)** ```python from tensorflow.keras.layers import Layer class CustomActivation(Layer): def __init__(self, **kwargs): super().__init__(**kwargs) def call(self, inputs): return tf.keras.activations.relu(inputs, alpha=0.1) def get_config(self): return super().get_config() # 在模型中替换 model.add(CustomActivation()) ``` **方法3:加载时提供自定义对象** ```python # 保存模型时需使用命名函数 model.save('model.h5') # 加载时提供函数引用 loaded_model = tf.keras.models.load_model( 'model.h5', custom_objects={'custom_activation': custom_activation} # 与方法1的命名对应 ) ``` #### ⚠️ 注意事项 1. **模型权重兼容性** 修改层结构后需重新训练模型,或使用相同架构加载权重: ```python new_model = create_model() # 使用新层结构 new_model.load_weights('old_weights.h5') # 加载原始权重 ``` 2. **序列化限制** 以下对象无法安全序列化: - 匿名函数(`lambda`) - 局部函数(在另一个函数内定义的函数) - 闭包(引用外部变量的函数) 3. **TensorFlow 版本** 此问题在 TF 2.x 中更常见,因为 Keras 已集成到 TensorFlow 中[^1]。 #### 💡 最佳实践 ```mermaid graph TD A[原始Lambda层] -->|问题| B(加载失败) A -->|解决方案| C[使用命名函数] A -->|解决方案| D[创建自定义层] C --> E[保存模型] D --> E E --> F[加载时提供custom_objects] F --> G[成功加载模型] ``` #### 📚 示例修正 **错误代码:** ```python model.add(Lambda(lambda x: x * 2)) # 引发序列化错误 ``` **修正后:** ```python def double_tensor(x): return x * 2 model.add(Lambda(double_tensor)) # 可序列化 ``` 通过以上方法,可彻底解决 Lambda 层的反序列化问题,确保模型能安全保存加载
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值