根据你的日志和现象,这是典型的 CPU/BPU 异构量化误差累积问题。*_quantized_model.onnx 是理想量化模拟,.bin 是板端实际运行,两者在 BPU<->CPU 切换时的反量化/重量化逻辑差异会导致误差累积。
问题定位步骤
1. 使用 hb_verifier 分阶段对比
# 分 Subgraph 对比,定位误差来源
hb_verifier \
--original_model lraspp_99_torch110.onnx \
--quantized_model lraspp_99_torch110_3_quantized_model.onnx \
--bin_model lraspp_99_torch110_3.bin \
--calibration_data ../hb_calibration_data1_f32 \
--layer_wise_compare \
--output_dir verifier_output
重点关注输出中 Cosine Similarity 骤降 的层,通常是 BPU->CPU 或 CPU->BPU 的切换点。
2. 检查日志中的关键信息
从你的日志看,有几个风险点:
| 风险点 | 说明 |
|---|---|
| 8 个子图切分 | Subgraph_0 ~ Subgraph_7,每次切换都有量化误差 |
| ScatterND/Where 在 CPU | 对输入精度极其敏感,前级 BPU 反量化误差会导致索引错误 |
| Conv_170/171 强制 int16 | 可能与前后级 int8 数据格式不匹配 |
| segmentation 输出 L1 Distance=83.29 | 误差过大,说明语义分支有严重问题 |
优化方案
方案 A:减少 CPU/BPU 切换(推荐优先尝试)
将语义分割分支的关键算子全部放到 CPU 或全部放到 BPU:
model_parameters:
node_info: {
# 方案 A1:关键路径全部 CPU
"Conv_170": {'ON': 'CPU'},
"Conv_171": {'ON': 'CPU'},
"Add_172": {'ON': 'CPU'},
"Concat_178": {'ON': 'CPU'},
"Conv_179": {'ON': 'CPU'},
"Sigmoid_230": {'ON': 'CPU'},
"ScatterND_337": {'ON': 'CPU'},
"ScatterND_414": {'ON': 'CPU'},
"Where_263_add": {'ON': 'CPU'},
"Where_340_add": {'ON': 'CPU'},
}
或
model_parameters:
node_info: {
# 方案 A2:关键路径全部 BPU(需要算子支持)
"ScatterND_337": {'ON': 'BPU'}, # 如支持
"ScatterND_414": {'ON': 'BPU'},
"Where_263_add": {'ON': 'BPU'},
"Where_340_add": {'ON': 'BPU'},
}
方案 B:敏感算子使用 INT16
model_parameters:
node_info: {
# 将语义分支相关算子全部配置为 int16
"Conv_170": {'ON': 'BPU', 'InputType': 'int16', 'OutputType': 'int16'},
"Conv_171": {'ON': 'BPU', 'InputType': 'int16', 'OutputType': 'int16'},
"Add_172": {'ON': 'BPU', 'InputType': 'int16', 'OutputType': 'int16'},
"Concat_178": {'ON': 'BPU', 'InputType': 'int16', 'OutputType': 'int16'},
"Conv_179": {'ON': 'BPU', 'InputType': 'int16', 'OutputType': 'int16'},
"Sigmoid_230": {'ON': 'BPU', 'InputType': 'int16', 'OutputType': 'int16'},
}
方案 C:改进校准策略
calibration_parameters:
calibration_type: 'kl' # 从 max 改为 kl
per_channel: True
max_percentile: 0.9999
# 增加校准数据多样性(建议 200-500 张)
cal_data_dir: '../hb_calibration_data_enhanced_f32'
方案 D:检查校准数据质量
# 验证校准数据统计分布
import numpy as np
cal_files = glob('../hb_calibration_data1_f32/*.bin')
for f in cal_files[:10]:
data = np.fromfile(f, dtype=np.float32).reshape(1, 5, 360, 640)
print(f"{f}: mean={data.mean():.4f}, std={data.std():.4f}, "
f"min={data.min():.4f}, max={data.max():.4f}")
# 检查 5 个通道的分布是否合理
for c in range(5):
ch_data = data[0, c, :, :]
print(f" Channel {c}: mean={ch_data.mean():.4f}, std={ch_data.std():.4f}")
排查清单
- 使用
hb_verifier --layer_wise_compare定位误差最大的 Subgraph - 尝试将
ScatterND/Where相关算子全部放到 CPU - 尝试将校准方法从
max改为kl - 增加校准数据数量到 200+,确保覆盖不同场景
- 检查校准数据的 5 个通道(RGB + radar_range + radar_valid_mask)预处理是否与推理时完全一致
- 尝试移除
Conv_170/171的强制 int16 配置,让工具自动选择
参考文档
建议先从方案 A开始,减少 CPU/BPU 切换次数,通常能解决大部分此类问题。有进展欢迎反馈!