量化后.bin的模型与原始.onnx模型精度出现很大偏差,模型输出语义信息和深度信息。

根据你的日志和现象,这是典型的 CPU/BPU 异构量化误差累积问题。*_quantized_model.onnx 是理想量化模拟,.bin 是板端实际运行,两者在 BPU<->CPU 切换时的反量化/重量化逻辑差异会导致误差累积。

:magnifying_glass_tilted_left: 问题定位步骤

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 误差过大,说明语义分支有严重问题

:hammer_and_wrench: 优化方案

方案 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}")

:clipboard: 排查清单

  • 使用 hb_verifier --layer_wise_compare 定位误差最大的 Subgraph
  • 尝试将 ScatterND/Where 相关算子全部放到 CPU
  • 尝试将校准方法从 max 改为 kl
  • 增加校准数据数量到 200+,确保覆盖不同场景
  • 检查校准数据的 5 个通道(RGB + radar_range + radar_valid_mask)预处理是否与推理时完全一致
  • 尝试移除 Conv_170/171 的强制 int16 配置,让工具自动选择

:books: 参考文档

建议先从方案 A开始,减少 CPU/BPU 切换次数,通常能解决大部分此类问题。有进展欢迎反馈!