motionbert模型量化后精度损失

根据你提供的完整量化日志,我找到了核心问题

:magnifying_glass_tilted_left: 问题诊断

1. Softmax 配置错误(最关键)

从转换日志看到:

node_info:
  '/blocks_st.0/attn_s/Softmax': {'ON': 'BPU', 'InputType': 'int16', 'OutputType': 'int16'}
  '/blocks_st.0/attn_t/Softmax': {'ON': 'BPU', 'InputType': 'int16', 'OutputType': 'int16'}
  ...

但余弦相似度显示

节点 相似度 数据类型 问题
/blocks_st.3/attn_t/Softmax 0.882 float :cross_mark: 严重损失
/blocks_ts.4/attn_t/Softmax 0.877 float :cross_mark: 严重损失
/blocks_st.2/attn_t/Softmax 0.920 float :cross_mark: 严重损失

虽然显示为 float,但输入数据经过了 int16 requantize,导致精度在 Softmax 前已损失。

2. 误差累积严重

blocks_st.0: 0.999+  ✅
blocks_st.1: 0.98-0.99  ⚠️
blocks_st.2: 0.95-0.96  ❌
blocks_st.3: 0.90-0.92  ❌❌  (/blocks_st.3/mlp_t/fc2/MatMul: 0.903864)
blocks_st.4: 继续恶化

3. int16 算子过多

日志显示配置了200+ 个算子为 int16,远超必要范围。


:hammer_and_wrench: 立即执行方案

步骤 1:修改 YAML 配置(最关键)

# config_softmax_fp32.yaml
model_parameters:
  onnx_model: ./motionbert_lite_120.onnx
  march: bayes-e
  working_dir: motionbert_lite_model_output_fp32
  layer_out_dump: true  # 开启分层输出对比
  
  # 关键:所有 Softmax 强制 CPU + float32
  node_info:
    # blocks_st 层 - 所有 Softmax
    /blocks_st.0/attn_s/Softmax:
      ON: CPU
      InputType: float32
      OutputType: float32
    /blocks_st.0/attn_t/Softmax:
      ON: CPU
      InputType: float32
      OutputType: float32
    /blocks_st.1/attn_s/Softmax:
      ON: CPU
      InputType: float32
      OutputType: float32
    /blocks_st.1/attn_t/Softmax:
      ON: CPU
      InputType: float32
      OutputType: float32
    /blocks_st.2/attn_s/Softmax:
      ON: CPU
      InputType: float32
      OutputType: float32
    /blocks_st.2/attn_t/Softmax:
      ON: CPU
      InputType: float32
      OutputType: float32
    /blocks_st.3/attn_s/Softmax:
      ON: CPU
      InputType: float32
      OutputType: float32
    /blocks_st.3/attn_t/Softmax:
      ON: CPU
      InputType: float32
      OutputType: float32
    /blocks_st.4/attn_s/Softmax:
      ON: CPU
      InputType: float32
      OutputType: float32
    /blocks_st.4/attn_t/Softmax:
      ON: CPU
      InputType: float32
      OutputType: float32
    
    # blocks_ts 层 - 所有 Softmax
    /blocks_ts.0/attn_s/Softmax:
      ON: CPU
      InputType: float32
      OutputType: float32
    /blocks_ts.0/attn_t/Softmax:
      ON: CPU
      InputType: float32
      OutputType: float32
    /blocks_ts.1/attn_s/Softmax:
      ON: CPU
      InputType: float32
      OutputType: float32
    /blocks_ts.1/attn_t/Softmax:
      ON: CPU
      InputType: float32
      OutputType: float32
    /blocks_ts.2/attn_s/Softmax:
      ON: CPU
      InputType: float32
      OutputType: float32
    /blocks_ts.2/attn_t/Softmax:
      ON: CPU
      InputType: float32
      OutputType: float32
    /blocks_ts.3/attn_s/Softmax:
      ON: CPU
      InputType: float32
      OutputType: float32
    /blocks_ts.3/attn_t/Softmax:
      ON: CPU
      InputType: float32
      OutputType: float32
    /blocks_ts.4/attn_s/Softmax:
      ON: CPU
      InputType: float32
      OutputType: float32
    /blocks_ts.4/attn_t/Softmax:
      ON: CPU
      InputType: float32
      OutputType: float32
    
    # 顶层 Softmax
    /Softmax:
      ON: CPU
      InputType: float32
      OutputType: float32
    /Softmax_1:
      ON: CPU
      InputType: float32
      OutputType: float32
    /Softmax_2:
      ON: CPU
      InputType: float32
      OutputType: float32
    /Softmax_3:
      ON: CPU
      InputType: float32
      OutputType: float32
    /Softmax_4:
      ON: CPU
      InputType: float32
      OutputType: float32
    
    # 输出头保持 int16(坐标回归需要精度)
    /Concat:
      ON: BPU
      InputType: int16
      OutputType: int16
    /Concat_1:
      ON: BPU
      InputType: int16
      OutputType: int16
    /Concat_2:
      ON: BPU
      InputType: int16
      OutputType: int16
    /Concat_3:
      ON: BPU
      InputType: int16
      OutputType: int16
    /Concat_4:
      ON: BPU
      InputType: int16
      OutputType: int16
    /head/MatMul:
      ON: BPU
      InputType: int16
      OutputType: int16

calibration_parameters:
  cal_data_dir: ./calibration_data_120
  cal_data_type: float32
  calibration_type: default
  max_percentile: 0.99995  # 从 0.99999 降低
  per_channel: true

步骤 2:重新量化

# 使用新配置重新量化
hb_mapper --config config_softmax_fp32.yaml

# 查看新量化报告
cat motionbert_lite_model_output_fp32/motionbert_lite_quant_info.json | grep -A2 "Softmax"

步骤 3:验证分层输出

# 对比浮点模型和量化模型各层输出
import onnxruntime as ort
import numpy as np

# 加载浮点模型
float_session = ort.InferenceSession('motionbert_lite_original_float_model.onnx')
# 加载量化模型
quant_session = ort.InferenceSession('motionbert_lite_quantized_model.onnx')

# 准备测试数据
test_input = np.random.randn(1, 120, 17, 3).astype(np.float32)

# 对比输出
float_output = float_session.run(None, {'input': test_input})[0]
quant_output = quant_session.run(None, {'input': test_input})[0]

cosine_sim = np.dot(float_output.flatten(), quant_output.flatten()) / (
    np.linalg.norm(float_output.flatten()) * np.linalg.norm(quant_output.flatten())
)
print(f"输出余弦相似度:{cosine_sim}")

:bar_chart: 预期效果

指标 当前 修改后预期
Softmax 相似度 0.87-0.92 0.99+
最终输出相似度 0.999567 0.9998+
关键点抖动 明显 基本消除

:warning: 如果仍有问题

方案 B:增加校准数据

# 50 条对时序模型明显不足,建议 200-500 条
# 覆盖不同动作场景:静止、快速运动、遮挡等

# 生成更多校准数据
python3 generate_calibration_data.py --num_samples 300 --output_dir ./calibration_data_300

方案 C:QAT(最后手段)

如果 PTQ 调优后仍不满足,参考社区精华帖:


:red_question_mark: 需要确认

  1. 当前板端部署后 MPJPE 误差是多少?(浮点 vs 量化)
  2. 抖动表现:是时间序列上的帧间抖动,还是单帧精度下降?
  3. 工具链版本hbdk version 3.49.15,确认是否有更新版本

先执行步骤 1 和 2,通常能解决 80% 以上的 Transformer 量化精度问题。完成后请反馈新的量化报告。