tf.keras.models.save_model 保存模型必须显式指定 save_format="tf" 并传入目录路径,含自定义对象需同步提供 custom_objects;加载必须用 tf.keras.models.load_model 且再次传入 custom_objects,否则报错。

用 tf.keras.models.save_model 保存模型,不是 model.save() 的所有重载都等价
直接调用 model.save("path/to/model") 默认行为取决于模型类型和 TensorFlow 版本:Keras 模型在 TF 2.4+ 中默认保存为 SavedModel 格式,但若传入 save_format="h5" 或后缀为 .h5,就会走 HDF5 路径——这会导致后续无法用 tf.keras.models.load_model 正确加载为 SavedModel(尤其含自定义层、符号张量或 tf.function 的模型)。稳妥做法是显式指定格式:
-
tf.keras.models.save_model(model, "my_model", save_format="tf")—— 强制输出 SavedModel 目录 - 路径必须是**目录名**(不能带
.h5或.pb后缀),例如"./saved_model_dir",内部会生成assets/、variables/和saved_model.pb - 若模型含自定义对象(如自定义层、损失函数),需同时传入
custom_objects=...参数,否则保存虽成功,加载时会报ValueError: Unknown layer
加载 SavedModel 必须用 tf.keras.models.load_model,不能用 tf.saved_model.load 直接当 Keras 模型用
tf.saved_model.load("path/to/model") 返回的是一个 ConcreteFunction 或模块化签名对象,它没有 .predict()、.fit() 等 Keras 接口,也无法直接参与训练流程。只有 tf.keras.models.load_model 才能重建完整的 Keras 模型实例(含权重、结构、编译配置):
- 加载时若原模型用了自定义对象,必须再次传入
custom_objects,且键名要和定义时一致,比如{"MyCustomLayer": MyCustomLayer} - 如果只关心推理,且模型有明确签名(如
"serving_default"),可用loaded = tf.saved_model.load("path"); infer = loaded.signatures["serving_default"],但这返回的是纯函数,输入需是tf.Tensor,不支持 numpy 数组或 batched list - 加载后的 Keras 模型默认处于 inference 模式;若需继续训练,确认它已编译(
loaded.compile(...)),否则调.fit()会报RuntimeError: The model needs to be compiled before calling fit
保存/加载时 shape 不匹配或 dtype 报错,大概率是输入签名没对齐
SavedModel 在保存时会固化输入张量的 shape 和 dtype(尤其是通过 model.predict() 首次调用后自动推导,或显式用 tf.TensorSpec 定义签名)。加载后若喂入不同 shape 的数据(如训练时 batch size=32,推理时送入 batch=1 但未设 None 维度),会触发 InvalidArgumentError: Input to reshape is a tensor with X values, but the requested shape has Y。
- 保存前确保模型输入层 shape 含动态维度,例如
Input(shape=(None, 128))或Input(shape=(None, None, 3)),避免写死 batch 维度 - 更可靠的方式是在保存时显式指定签名:
tf.keras.models.save_model(model, "my_model", signatures=model.call.get_concrete_function(tf.TensorSpec(shape=[None, 224, 224, 3], dtype=tf.float32))) - 加载后检查输入签名:
loaded.signatures["serving_default"].structured_input_signature,对比你实际输入的数据结构
跨 Python 或 TF 版本加载失败,重点查 saved_model.pb 兼容性边界
SavedModel 格式本身向后兼容(高版本 TF 可加载低版本保存的模型),但反向不保证。TF 2.8 保存的模型在 TF 2.5 上可能因 opset 升级而报 Op type not registered;Python 版本差异通常不影响,但若模型里硬编码了 3.9 特有的语法(如带括号的字面量表达式),则加载时会因 custom_objects 导入失败间接报错。
- 生产部署建议固定 TF 版本,并在 CI 中用目标环境验证加载逻辑
- 不要依赖
tf.__version__字符串做条件分支,SavedModel 内部不存 Python 版本信息,只存计算图与变量值 - 若必须降级加载,唯一可行路径是:用原 TF 版本加载 → 重新
save_model→ 在低版本中加载新保存的模型
SavedModel 的“透明性”是假象——它看似封装完整,实则把输入约束、自定义依赖、版本隐含假设全打包进二进制文件里。最容易被忽略的是签名固化时机和 custom_objects 的两次一致性:保存时没传,可能侥幸成功;加载时漏传,必报错,而且错误信息往往不指明缺哪个 key。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











