你好!这是一个非常关键的问题,很多开发者在初次使用工具链时都会产生这个疑惑。
核心结论
HBRuntime 和 HB ONNX Runtime 是同一个库的不同称呼,但关键在于模型格式和运行环境的区别。
1. 库的关系
| 名称 | 说明 |
|---|---|
| HBRuntime | Python 包名 (horizon_tc_ui.hb_runtime 或 horizon_nn) |
| HB ONNX Runtime | 指支持 ONNX 模型推理的 HBRuntime 后端 |
| HBRuntime (C++) | 底层 C++ 推理引擎 |
本质是同一个推理引擎,只是根据加载的模型格式不同,内部调用不同的执行路径。
2. 关键区别:模型格式决定推理后端
from horizon_tc_ui.hb_runtime import HBRuntime
# 情况 1:加载 ONNX 模型(包括 calibrated_model.onnx)
sess = HBRuntime("calibrated_model.onnx")
# → 内部使用 ONNX Runtime 后端(CPU/GPU)
# → 需要在 x86 服务器或板端 CPU 上运行
# → 不能发挥 BPU 加速
# 情况 2:加载 HBM 模型(BPU 专用格式)
sess = HBRuntime("model.hbm")
# → 内部使用 BPU Runtime 后端
# → 必须在 S100P 板端运行
# → 发挥 BPU 加速
3. 为什么 calibrated_model.onnx 无法正常运行?
根据你的描述,问题可能出在以下几点:
原因 1:运行环境不匹配
calibrated_model.onnx包含HzCalibration节点,这是地平线工具链插入的特殊校准节点- 这些节点只能在地平线定制的 ONNX Runtime中执行
- 如果你用标准 ONNX Runtime (
onnxruntime-gpu) 加载,会报错或输出错误
正确做法:
# 必须使用地平线的 HBRuntime 加载
from horizon_tc_ui.hb_runtime import HBRuntime
sess = HBRuntime("calibrated_model.onnx")
output = sess.run(sess.output_names, input_feed)
原因 2:输入数据预处理不匹配
calibrated_model.onnx可能已经插入了预处理节点(归一化、颜色空间转换)- 如果你再次手动预处理,会导致双重处理,输出异常
排查方法:
# 检查 YAML 配置中是否有 preprocess 相关配置
cat your_config.yaml | grep -A 10 "model_parameters"
# 检查模型输入节点名称
from horizon_tc_ui.hb_runtime import HBRuntime
sess = HBRuntime("calibrated_model.onnx")
print("输入节点:", sess.input_names)
print("输出节点:", sess.output_names)
原因 3:校准数据不足或分布异常
- 如果校准数据太少或分布不均匀,某些节点的量化参数(scale/threshold)会计算异常
- 导致
HzCalibration节点输出错误
排查方法:
# 使用 PTQ Debug 工具检查校准数据
import horizon_nn.debug as dbg
node_message = dbg.get_sensitivity_of_nodes(
model_or_file='./calibrated_model.onnx',
calibrated_data='./calibration_data/',
metrics=['cosine-similarity'],
verbose=True
)
4. 正确的验证流程
# 步骤 1:在 x86 服务器上验证 original_float 和 optimized_float
python3 << EOF
from horizon_tc_ui.hb_runtime import HBRuntime
import numpy as np
# 加载原始模型
sess_orig = HBRuntime("original_float_model.onnx")
sess_opt = HBRuntime("optimized_float_model.onnx")
# 准备输入(注意:不要重复预处理)
input_data = np.load("input.npy") # 已经是预处理后的数据
input_feed = {sess_orig.input_names[0]: input_data}
# 推理
output_orig = sess_orig.run(sess_orig.output_names, input_feed)
output_opt = sess_opt.run(sess_opt.output_names, input_feed)
# 对比
diff = np.abs(output_orig[0] - output_opt[0]).max()
print(f"original vs optimized 最大差异:{diff}")
EOF
# 步骤 2:验证 calibrated_model(需要校准数据)
python3 << EOF
from horizon_tc_ui.hb_runtime import HBRuntime
import numpy as np
sess_calib = HBRuntime("calibrated_model.onnx")
input_data = np.load("calibration_data/input1/0.npy") # 使用校准数据
input_feed = {sess_calib.input_names[0]: input_data}
output_calib = sess_calib.run(sess_calib.output_names, input_feed)
print(f"calibrated_model 输出形状:{output_calib[0].shape}")
print(f"calibrated_model 输出范围:[{output_calib[0].min()}, {output_calib[0].max()}]")
EOF
# 步骤 3:在板端验证 HBM 模型
# 将模型和测试数据拷贝到 S100P 板端
scp model.hbm input.npy root@<board_ip>:/data/
# 在板端运行
ssh root@<board_ip>
python3 << EOF
from horizon_tc_ui.hb_runtime import HBRuntime
import numpy as np
sess_hbm = HBRuntime("model.hbm")
input_data = np.load("input.npy")
input_feed = {sess_hbm.input_names[0]: input_data}
output_hbm = sess_hbm.run(sess_hbm.output_names, input_feed)
print(f"HBM 模型输出形状:{output_hbm[0].shape}")
EOF
5. 关于 optimized_float_model.onnx 精度损失
你提到从 0.809 降到 0.778,这确实不正常。可能原因:
原因 1:算子融合改变了计算顺序
- 浮点运算不满足结合律,
(a + b) + c ≠ a + (b + c) - 某些模型对数值误差非常敏感(如 BatchNorm、LayerNorm)
原因 2:预处理节点被插入
- 检查 YAML 中是否配置了
mean_value、scale_value - 如果配置了,
optimized_float_model会自动插入预处理节点 - 你的测试代码可能重复预处理了
验证方法:
# 检查模型结构差异
import onnx
orig_model = onnx.load("original_float_model.onnx")
opt_model = onnx.load("optimized_float_model.onnx")
print("原始模型节点数:", len(orig_model.graph.node))
print("优化模型节点数:", len(opt_model.graph.node))
# 检查输入节点名称是否变化
print("原始模型输入:", [i.name for i in orig_model.graph.input])
print("优化模型输入:", [i.name for i in opt_model.graph.input])
6. 推荐排查路径
# 1. 确认使用 HBRuntime 加载所有 ONNX 模型
# 2. 检查输入数据是否经过正确预处理(不要重复)
# 3. 使用 PTQ Debug 工具分析 calibrated_model
hmct-debugger runall ./calibrated_model.onnx ./calibration_data --save_dir ./debug_results
# 4. 查看累积误差曲线,判断是激活量化还是权重量化问题
# 5. 根据敏感度分析,对敏感节点设置 int16 或 run_on_cpu
7. 相关社区资源
- PTQ 精度 Debug 工具详解
- original_float/calibrated/quantized 模型区别
- 天工在线支持 - 可直接上传模型工程获取官方技术支持
下一步建议
- 确认你使用的是
horizon_tc_ui.hb_runtime而不是标准onnxruntime - 检查 YAML 配置中的预处理参数,确保输入数据一致性
- 运行 PTQ Debug 工具,定位敏感节点
- 如问题仍未解决,建议将模型转换工程(含 YAML、ONNX、校准数据)打包,发帖或联系天工支持
需要我帮你进一步分析具体的错误日志或 Debug 结果吗?