You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Keras SavedModel添加自定义资产的正确方法与加载报错解决

我需要向saved_model中添加任意自定义资产,例如用于将标签索引映射到对应名称的文本文件/JSON文件。此前我一直通过手动方式将资产保存到{saved_model_path}/assets/custom_asset.txt路径下。

近期我了解到tf.saved_model.Asset似乎是更简洁规范的实现方式,相关测试代码如下:

checkpoint = tf.train.Checkpoint()
checkpoint.my_filename = tf.saved_model.Asset('some_file.txt')

# 常规模型保存逻辑
model.save(saved_model_path)

# 保存tf.saved_model.Asset
tf.saved_model.save(checkpoint, saved_model_path)

按上述方式操作后,模型看似保存正常,自定义资产也按预期出现在{saved_model}/assets目录中,但实际存在明显异常:

  • 使用saved_model_cli检查模型时,得到的签名等信息与未保存自定义可追踪对象的同模型检查结果存在差异;
  • 模型加载失败,报错信息如下:

# 尝试在独立进程中加载模型
model = tf.keras.models.load_model(path)

>>> Traceback (most recent call last):
  File "/Users/rsilveira/dev/ddm-ml-classifieds-recommender/tf_model_exporter.py", line 80, in <module>
    load(_saved_model_path)
  File "/Users/rsilveira/dev/ddm-ml-classifieds-recommender/tf_model_exporter.py", line 67, in load
    model = tf.keras.models.load_model(path)
  File "/Users/rsilveira/dev/ddm-ml-classifieds-recommender/.venv/lib/python3.8/site-packages/keras/utils/traceback_utils.py", line 67, in error_handler
    raise e.with_traceback(filtered_tb) from None
  File "/Users/rsilveira/dev/ddm-ml-classifieds-recommender/.venv/lib/python3.8/site-packages/keras/saving/saved_model/load.py", line 466, in _revive_from_config
    obj, self._proto.nodes[node_id], node_id)
IndexError: list index (62) out of range
问题

是否存在TensorFlow原生的标准方式,可实现未直接挂载到模型上的自定义资产的保存?

可复现代码
from tensorflow.keras.layers import Input, Dense
from tensorflow.keras import Model
import tensorflow as tf
import numpy as np
from tensorflow.data import Dataset
from tensorflow.keras.metrics import SparseCategoricalAccuracy
from tensorflow.keras.losses import SparseCategoricalCrossentropy

# 构建测试模型
def build_model():
    i = Input(shape=(5,))
    fc = Dense(5, activation='relu')(i)
    softmax = Dense(5, activation='softmax', name='Softmax')(fc)

    return Model(inputs=i, outputs=softmax)

# 初始化并训练模型
model = build_model()
opt = tf.keras.optimizers.Adam(learning_rate=0.003)

model.compile(optimizer=opt,
    metrics=[SparseCategoricalAccuracy()],
    loss=SparseCategoricalCrossentropy(from_logits=False))

# 构造测试数据
_ds = Dataset.from_tensor_slices((np.random.rand(10, 5), np.random.randint(0, 5, 10)))

model.fit(_ds.batch(32), epochs=3)

saved_model_path = "./test_saved_model"
# 第一次保存模型
model.save(saved_model_path)

some_file = 'some_file.txt'
with open(some_file, "w") as f:
    f.write("test asset")
checkpoint = tf.train.Checkpoint()
checkpoint.my_filename = tf.saved_model.Asset(some_file)
# 第二次向同路径保存Checkpoint
tf.saved_model.save(checkpoint, saved_model_path)

# 加载模型时报错
model = tf.keras.models.load_model(saved_model_path)

答案

错误原因

两次向同一路径执行SavedModel写入操作是问题根源。第二次执行tf.saved_model.save(checkpoint, saved_model_path)时,会直接覆盖第一次model.save()生成的完整模型结构,最终路径下存储的是仅包含资产引用的空Checkpoint对象,而非携带自定义资产的可用模型,必然出现节点索引不匹配、签名错乱、加载失败的问题。

原生标准实现方案

TensorFlow原生支持自定义资产保存,有两种完全合规的实现方式,不需要额外hack:

  1. 挂载为模型可追踪属性(官方推荐方案)
    tf.saved_model.Asset的核心设计就是自动识别为可追踪依赖,只要将资产赋值给被保存对象(模型/层/Checkpoint等)的非内置属性,保存时框架会自动将资产文件复制到SavedModel的assets目录,不需要单独执行额外保存操作。
    正确代码示例:

    # 模型训练完成后,为模型添加自定义资产属性
    model.label_map = tf.saved_model.Asset("label_map.json")
    
    # 一次性保存整个模型,资产会自动同步到assets目录
    model.save(saved_model_path)
    
    # 加载模型后可直接读取资产路径
    loaded_model = tf.keras.models.load_model(saved_model_path)
    asset_path = loaded_model.label_map.asset_path.numpy().decode("utf-8")
    

    注意:给模型添加资产属性时,不要使用save、load、layers这类Keras模型已经占用的内置属性名,避免属性冲突。

  2. 手动复制资产到assets目录(无挂载需求时使用)
    如果不想将资产作为模型属性暴露,可以在模型保存完成后,直接将自定义资产文件复制到{saved_model_path}/assets/目录下。这种操作完全符合SavedModel的目录规范,框架加载模型时不会校验assets目录下的用户自定义文件,不会破坏模型签名、也不会引发加载错误,后续推理时直接从assets目录读取对应文件即可。


内容的提问来源于stack exchange,提问作者rodrigo-silveira

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.03 01:45:43