如何获取并调试ONNX模型的中间层输入与输出
ONNX模型中间层输入输出调试方案
以下是几种常用的可落地的调试方式,你可以根据自己的场景选择:
1. 修改计算图,将中间张量追加为模型输出
这是最通用、兼容性最好的方案,不需要依赖推理框架的特殊功能,修改后的模型可以在任意支持ONNX的推理引擎上运行,直接拿到中间结果。
操作步骤:
- 先通过Netron打开原始ONNX模型,找到你要调试的节点,记录对应的中间输入/输出张量的名称
- 用
onnx库加载模型,将目标张量添加到模型的输出列表中,重新保存模型 - 正常运行推理,输出结果中就会包含你添加的中间张量值
示例代码:
import onnx import onnxruntime as ort # 加载原始模型 original_model = onnx.load("your_model.onnx") # 填写你从Netron中查到的要调试的张量名,支持同时添加多个 target_inter_tensors = ["conv1_input", "relu3_output"] for tensor_name in target_inter_tensors: # 构造张量的value info,动态维度可以填None tensor_info = onnx.helper.make_tensor_value_info(tensor_name, onnx.TensorProto.FLOAT, None) original_model.graph.output.append(tensor_info) # 保存修改后的模型 onnx.save(original_model, "model_with_intermediate_outputs.onnx") # 推理获取结果 sess = ort.InferenceSession("model_with_intermediate_outputs.onnx") # 构造你的输入数据 input_feed = {"input": your_input_numpy_array} all_outputs = sess.run(None, input_feed) # 输出顺序为:原模型的输出 -> 按你添加顺序排列的中间张量值
2. 使用ONNX Runtime的节点钩子功能,无需修改原模型
如果你不想修改原始模型文件,只是临时调试一次,可以用ONNX Runtime提供的前后钩子接口,在推理过程中自动捕获指定节点的输入输出值。
示例代码:
import onnxruntime as ort # 前置钩子:捕获节点推理前的输入 def pre_hook(node, inputs): # 替换成你要调试的节点名,可从Netron中查询 if node.name == "target_conv_node": print(f"节点 {node.name} 输入:") for idx, inp in enumerate(inputs): print(f"输入{idx}形状:{inp.shape}, 数值范围:{inp.min()} ~ {inp.max()}") return inputs # 后置钩子:捕获节点推理后的输出 def post_hook(node, outputs): if node.name == "target_conv_node": print(f"节点 {node.name} 输出:") for idx, out in enumerate(outputs): print(f"输出{idx}形状:{out.shape}, 数值范围:{out.min()} ~ {out.max()}") return outputs sess = ort.InferenceSession("your_model.onnx") # 注册钩子 sess.set_pre_session_run_hook(pre_hook) sess.set_post_session_run_hook(post_hook) # 正常执行推理即可自动触发钩子 input_feed = {"input": your_input_numpy_array} _ = sess.run(None, input_feed)
3. 静态结构调试用Netron
如果不需要看运行时的数值,只是排查层结构、张量维度、参数配置错误,直接把ONNX模型拖入Netron,点击对应节点就能看到该节点的所有属性、输入输出的名称、形状、数据类型,不需要写代码,非常高效。
注意:以上所有方法都需要你提前获取到目标节点的名称或者对应张量的名称,直接在Netron中点选对应节点就能复制,避免手动拼写错误。
内容的提问来源于stack exchange,提问作者Avinash Singh
相关产品推荐
相关产品推荐

