最稳妥方式是用tf.keras.models.save_model(model, path, save_format="tf"),路径须为无特殊字符的目录名,保存前需确保模型已前向调用、自定义类已注册,并推荐显式指定signatures以适配部署环境。

用 tf.keras.models.save_model() 保存模型最稳妥
直接调用 tf.keras.models.save_model() 是导出 SavedModel 的推荐方式,它自动处理权重、计算图、签名(signatures)和元数据,兼容性最好。不要手动拼接 tf.saved_model.save() 调用,除非你明确需要自定义签名或冻结特定输入输出。
常见错误是传入模型实例后漏掉 save_format='tf'(虽然默认就是 'tf',但显式写出更防误),或路径含中文/空格导致后续加载失败。
- 路径必须是**绝对路径或相对路径中不含特殊字符**,建议用
os.path.join()构造 - 目标目录不能已存在(否则报
FileExistsError),可提前shutil.rmtree()清理 - 若模型含自定义层或损失函数,需确保类已导入且在保存前注册(如用
@tf.keras.utils.register_keras_serializable()) - 保存后检查目录结构:应有
saved_model.pb、variables/和assets/子目录
导出时指定 signatures 才能被非 Keras 环境调用
默认保存的模型只带 __call__ 签名,适合 Python 中用 model(input) 调用;但 TensorFlow Serving、TFLite 或 C++ 推理时,必须提供明确的命名 signature。不设 signature,加载后会报 SignatureDef not found 或无法识别输入输出名。
实操上,用 tf.function + get_concrete_function() 构建签名最可靠:
立即学习“Python免费学习笔记(深入)”;
@tf.function
def serve_fn(x):
return model(x, training=False)
<p>concrete_fn = serve_fn.get_concrete_function(
x=tf.TensorSpec(shape=[None, 224, 224, 3], dtype=tf.float32)
)</p><p>tf.keras.models.save_model(
model,
'my_model',
signatures={'serving_default': concrete_fn}
)-
TensorSpec的shape中None表示 batch 维度可变,务必写对通道数和数据类型 - 签名名(如
'serving_default')会被 TF Serving 默认使用,别随意改 - 若模型有多个输入(如图像+文本),
concrete_fn参数要一一对应,签名字典里可加多个 key
加载 SavedModel 后验证输入输出名是否匹配部署环境
保存完别急着部署,先用 tf.saved_model.load() 加载并打印 signature,确认输入输出张量名与文档或客户端代码一致。名字不匹配是线上推理失败最常见原因——比如训练时叫 'input_1:0',而 Serving 配置里写成 'x' 就会报 KeyError。
快速验证命令:
import tensorflow as tf
loaded = tf.saved_model.load('my_model')
print(list(loaded.signatures.keys())) # 看有哪些 signature
infer = loaded.signatures['serving_default']
print(infer.structured_input_signature) # 看输入名、shape、dtype
print(infer.structured_outputs) # 看输出名和结构- 输出中的
TensorSpec名字(如'output_1')才是实际键名,不是模型层名 - 如果用
tf.keras.models.load_model()加载,它会自动包装为 Keras 模型,但丢失原始 signature 信息,不适合验证部署兼容性 - TF 2.16+ 中
tf.saved_model.load()返回对象不再支持.predict(),必须走signatures调用
导出前关闭 eager execution 无意义,但禁用 jit_compile 可避免某些 OP 不兼容
有人误以为关掉 eager mode 能让 SavedModel 更“静态”,其实 SavedModel 本质就是图模式导出,eager 开关不影响结果。真正要注意的是 jit_compile=True(XLA 加速)可能导致部分算子无法序列化,尤其涉及动态 shape 或控制流时。
- 训练时用了
@tf.function(jit_compile=True),导出前建议重载模型并用jit_compile=False再保存 - 若模型含
tf.py_function,SavedModel 无法跨 Python 版本加载,必须替换成原生 TF OP - CPU/GPU 导出的模型通常可互换,但含 GPU 专属 OP(如某些 cuDNN 卷积)的模型,在纯 CPU 环境加载会失败
导出 SavedModel 看似一步操作,真正卡点往往在 signature 定义是否精准、输入 spec 是否与生产数据对齐、以及自定义逻辑能否脱离 Python 运行时存活——这些细节不验证,模型就只是一堆文件,不是服务。


















