motionbert模型量化后精度损失

我来帮你分析这个 MotionBERT 量化精度损失问题。先搜索社区中相关的量化案例和解决方案。

根据你的问题描述和日志分析,这是典型的 Transformer 类模型量化精度损失问题,特别是 Softmax 算子在量化后表现不佳。结合社区已有案例,给出以下解决方案:

核心结论

Softmax 是量化不友好算子,在 Transformer 架构中多层累积会导致严重精度损失。你遇到的抖动和余弦相似度低(<0.9)是典型症状。


解决方案(按优先级排序)

方案 1:Softmax 保持 FP32 计算(推荐首选)

从你的日志看到,Softmax 已被指定为 int16 计算:

The input of node /blocks_st.0/attn_s/Softmax are set to : int16
The output of node /blocks_st.0/attn_s/Softmax are set to : int16

修改 YAML 配置,将 Softmax 算子强制为 FP32:

model_parameters:
  onnx_model: ./motionbert_lite_120.onnx
  march: bayes-e
  working_dir: motionbert_lite_model_output
  # 添加 node_info 配置,将 Softmax 保持 FP32
  node_info:
    /blocks_st.0/attn_s/Softmax:
      ON: CPU  # 或 BPU,但保持 FP32
      InputType: float32
      OutputType: float32
    /blocks_st.0/attn_t/Softmax:
      ON: CPU
      InputType: float32
      OutputType: float32
    /blocks_ts.0/attn_s/Softmax:
      ON: CPU
      InputType: float32
      OutputType: float32
    /blocks_ts.0/attn_t/Softmax:
      ON: CPU
      InputType: float32
      OutputType: float32
    /Softmax:
      ON: CPU
      InputType: float32
      OutputType: float32
    /Softmax_1:
      ON: CPU
      InputType: float32
      OutputType: float32
    /Softmax_2:
      ON: CPU
      InputType: float32
      OutputType: float32

参考案例:社区中 量化 ViT 时 Softmax 掉点严重 的帖子明确指出:“Softmax 本身就量化不友好,建议 FP32 计算”。


方案 2:增加校准数据量 + 优化校准策略

你目前使用 50 条校准数据,对于 MotionBERT 这种时序模型可能不足。

改进步骤

# 1. 增加校准数据到 200-500 条(覆盖更多动作场景)
# 2. 调整校准参数
calibration_parameters:
  cal_data_dir: ./calibration_data_120
  cal_data_type: float32
  calibration_type: default  # 或尝试 'kl'
  max_percentile: 0.99995    # 当前是 0.99999,可尝试降低
  per_channel: true

校准数据要求

  • 覆盖完整动作空间(静止、快速运动、遮挡等场景)
  • 确保 2D 关键点输入分布与真实推理场景一致
  • 检查校准数据前处理是否与推理时完全对齐

方案 3:调整 int16 算子策略

从日志看到部分 MatMul 算子不支持 int16:

The input0 of Node(name:/blocks_st.0/attn_t/MatMul, type:MatMul) does not support data type: int16

建议

  1. 不要强制指定过多算子为 int16,让工具链自动选择
  2. 移除 YAML 中对 Attention 相关算子的 int16 强制配置
  3. 仅对确实需要高精度的算子(如坐标回归头)使用 int16

方案 4:QAT(量化感知训练)

如果 PTQ 调优后精度仍不满足要求,考虑 QAT:

# 使用 horizon_plugin_pytorch 进行 QAT
from horizon_plugin_pytorch.quantization import prepare_qat, convert

# 1. 定义 QAT 配置
qconfig = {
    'default': {'activation': {'dtype': 'int8'}, 'weight': {'dtype': 'int8'}},
    'op_specific': {
        'Softmax': {'activation': {'dtype': 'float32'}},  # Softmax 保持 FP32
        'MatMul': {'activation': {'dtype': 'int16'}}      # 关键算子用 int16
    }
}

# 2. 准备模型
model = prepare_qat(model, qconfig)

# 3. 微调训练(需要原训练数据集)
# ... 训练代码 ...

# 4. 导出 QAT 模型
model = convert(model)
torch.onnx.export(model, ...)

参考:社区有 QAT 之 qconfig 使用指南J5 算法工具链 int16 配置方式 精华帖。


快速排查清单

# 1. 验证浮点模型精度
hb_mapper --config config_float.yaml  # 不量化,验证 ONNX 精度

# 2. 分层对比量化前后输出
# 在 YAML 中开启 layer_out_dump
model_parameters:
  layer_out_dump: true

# 3. 检查量化报告
cat motionbert_lite_model_output/motionbert_lite_quant_info.json
# 重点关注余弦相似度 < 0.95 的算子

# 4. 板端验证
# 使用 HB_ONNXRuntime 在开发机验证 quantized ONNX
# 确认精度损失发生在转换阶段还是板端部署阶段

预期效果

方案 预计提升 实施难度
Softmax 改 FP32 余弦相似度 0.9+
增加校准数据 稳定性提升
QAT 接近浮点精度 高(需训练)

建议先尝试方案 1,通常能解决 80% 的 Softmax 量化问题。如果仍有抖动,再结合方案 2 和 4。

需要进一步帮助可以补充:

  1. 当前使用的工具链版本
  2. 量化后具体精度指标(如 MPJPE 误差)
  3. 是否已在开发机验证过 quantized_model.onnx