s100p 量化部署精度问题

你好!这是一个非常关键的问题,很多开发者在初次使用工具链时都会产生这个疑惑。

核心结论

HBRuntimeHB ONNX Runtime 是同一个库的不同称呼,但关键在于模型格式运行环境的区别。


1. 库的关系

名称 说明
HBRuntime Python 包名 (horizon_tc_ui.hb_runtimehorizon_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) 加载,会报错或输出错误

:white_check_mark: 正确做法

# 必须使用地平线的 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 可能已经插入了预处理节点(归一化、颜色空间转换)
  • 如果你再次手动预处理,会导致双重处理,输出异常

:white_check_mark: 排查方法

# 检查 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 节点输出错误

:white_check_mark: 排查方法

# 使用 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_valuescale_value
  • 如果配置了,optimized_float_model 会自动插入预处理节点
  • 你的测试代码可能重复预处理

:white_check_mark: 验证方法

# 检查模型结构差异
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. 相关社区资源


下一步建议

  1. 确认你使用的是 horizon_tc_ui.hb_runtime 而不是标准 onnxruntime
  2. 检查 YAML 配置中的预处理参数,确保输入数据一致性
  3. 运行 PTQ Debug 工具,定位敏感节点
  4. 如问题仍未解决,建议将模型转换工程(含 YAML、ONNX、校准数据)打包,发帖或联系天工支持

需要我帮你进一步分析具体的错误日志或 Debug 结果吗?