TensorFlow(Keras)模型转ONNX报add_slot属性缺失、UTF-8解码错误求助
问题根因
- 第一个
AttributeError: '_UserObject' object has no attribute 'add_slot'报错:是版本不兼容+模型保存参数不合理共同导致。Keras 2.6版本默认使用model.save()会同时保存优化器、训练过程用到的slot变量等训练相关信息,tf2onnx加载该SavedModel时,优化器对象会被反序列化为无add_slot属性的_UserObject,触发属性不存在报错。 - 第二个
UnicodeDecodeError报错:属于参数传值错误,tf2onnx.convert的--checkpoint参数需要传入后缀为.meta的元图定义文件,你传入的keras_metadata.pb是二进制格式文件,无法按utf-8解析为文本格式的元图定义,因此触发解码错误。
解决方案
- 第一步:重新保存仅包含推理所需信息的模型,保存时关闭优化器、训练轨迹存储:
执行保存的代码调整为:
其中model.save( os.path.join("models", 'modelData'), include_optimizer=False, save_traces=False )include_optimizer=False会排除优化器相关的所有训练态数据,从根源避免add_slot相关报错,save_traces=False可以减少SavedModel的冗余信息,提升转换成功率。 - 第二步:使用SavedModel模式执行转换,建议指定兼容Keras 2.6的ONNX opset版本:
执行命令:python -m tf2onnx.convert --saved-model modelData --output model.onnx --opset 13 - 若上述方案仍报错,可通过显式加载模型生成concrete function的方式转换:
执行转换代码:import tensorflow as tf import tf2onnx # 加载模型时关闭编译,避免加载优化器 model = tf.keras.models.load_model("modelData", compile=False) # 定义输入签名,和你模型的输入shape、dtype保持一致即可 input_signature = [ tf.TensorSpec((None, *input0_shape), dtype=tf.float32, name="input0"), tf.TensorSpec((None, *input1_shape), dtype=tf.float32, name="input1") ] # 转换为ONNX模型 model_proto, _ = tf2onnx.convert.from_keras(model, input_signature=input_signature, opset=13) # 保存模型 with open("model.onnx", "wb") as f: f.write(model_proto.SerializeToString())
问题确认
- 模型保存前需要做特殊处理:仅用于推理转换的模型不需要保存训练相关数据,保存时关闭优化器存储即可。
- 存在版本兼容问题:Keras 2.6的SavedModel序列化格式和旧版tf2onnx的优化器加载逻辑存在兼容冲突,仅保存推理态模型即可规避该问题。
内容的提问来源于stack exchange,提问作者Igor Ševo
相关产品推荐
相关产品推荐

