motionbert模型量化后精度损失

:magnifying_glass_tilted_left: 问题分析

虽然 Softmax 已移到 CPU,但问题已转移到其他敏感算子。从新日志看到:

节点 余弦相似度 问题
/blocks_ts.4/attn_t/Softmax 0.688 :cross_mark: 严重损失
/blocks_st.3/attn_t/Softmax 0.754 :cross_mark: 严重损失
/blocks_st.3/attn_t/v_linear/MatMul 0.869 :cross_mark: v_linear 量化敏感
/blocks_st.3/mlp_t/act/Mul_1 0.812 :cross_mark: 激活函数量化损失
/blocks_st.3/mlp_t/fc2/MatMul 0.813 :cross_mark: 深层 FC 层
/norm/ReduceMean 0.824 :cross_mark: 归一化层

核心原因

  1. 50 条校准数据严重不足(时序模型需要 300-500 条)
  2. Attention 的 v_linear 对量化极敏感(仍用 int8)
  3. 深层网络误差累积(layer 3-4 恶化明显)
  4. max_percentile=0.99999 过高,放大了异常值影响

:hammer_and_wrench: 紧急解决方案(按优先级执行)

步骤 1:修改 YAML 配置(关键算子用 int16)

# config_final.yaml
model_parameters:
  onnx_model: ./motionbert_lite_120.onnx
  march: bayes-e
  working_dir: motionbert_lite_model_output_final
  layer_out_dump: true
  
  node_info:
    # ========== 所有 Attention 的 v_linear 强制 int16(最关键)==========
    /blocks_st.0/attn_s/v_linear/MatMul:
      ON: BPU
      InputType: int16
      OutputType: int16
    /blocks_st.0/attn_t/v_linear/MatMul:
      ON: BPU
      InputType: int16
      OutputType: int16
    /blocks_st.1/attn_s/v_linear/MatMul:
      ON: BPU
      InputType: int16
      OutputType: int16
    /blocks_st.1/attn_t/v_linear/MatMul:
      ON: BPU
      InputType: int16
      OutputType: int16
    /blocks_st.2/attn_s/v_linear/MatMul:
      ON: BPU
      InputType: int16
      OutputType: int16
    /blocks_st.2/attn_t/v_linear/MatMul:
      ON: BPU
      InputType: int16
      OutputType: int16
    /blocks_st.3/attn_s/v_linear/MatMul:
      ON: BPU
      InputType: int16
      OutputType: int16
    /blocks_st.3/attn_t/v_linear/MatMul:
      ON: BPU
      InputType: int16
      OutputType: int16
    /blocks_st.4/attn_s/v_linear/MatMul:
      ON: BPU
      InputType: int16
      OutputType: int16
    /blocks_st.4/attn_t/v_linear/MatMul:
      ON: BPU
      InputType: int16
      OutputType: int16
    # blocks_ts 层同理配置所有 v_linear...
    
    # ========== 深层 MLP 层用 int16 ==========
    /blocks_st.3/mlp_s/fc1/MatMul:
      ON: BPU
      InputType: int16
      OutputType: int16
    /blocks_st.3/mlp_s/fc2/MatMul:
      ON: BPU
      InputType: int16
      OutputType: int16
    /blocks_st.3/mlp_t/fc1/MatMul:
      ON: BPU
      InputType: int16
      OutputType: int16
    /blocks_st.3/mlp_t/fc2/MatMul:
      ON: BPU
      InputType: int16
      OutputType: int16
    /blocks_st.4/mlp_s/fc1/MatMul:
      ON: BPU
      InputType: int16
      OutputType: int16
    /blocks_st.4/mlp_s/fc2/MatMul:
      ON: BPU
      InputType: int16
      OutputType: int16
    /blocks_st.4/mlp_t/fc1/MatMul:
      ON: BPU
      InputType: int16
      OutputType: int16
    /blocks_st.4/mlp_t/fc2/MatMul:
      ON: BPU
      InputType: int16
      OutputType: int16
    
    # ========== 输出头保持 int16 ==========
    /head/MatMul:
      ON: BPU
      InputType: int16
      OutputType: int16

calibration_parameters:
  cal_data_dir: ./calibration_data_120
  cal_data_type: float32
  calibration_type: kl  # 改用 KL 散度
  max_percentile: 0.9999  # 从 0.99999 降低到 0.9999
  per_channel: true

步骤 2:增加校准数据(必须执行)

# 50 条对时序模型远远不够,生成 300-500 条
# 覆盖:静止、慢速、快速、遮挡、不同视角

# 示例脚本
python3 generate_calibration_data.py \
  --input_dir ./original_dataset \
  --num_samples 400 \
  --output_dir ./calibration_data_400 \
  --cover_all_actions \
  --sequence_length 120

# 修改 YAML 中的校准数据路径
calibration_parameters:
  cal_data_dir: ./calibration_data_400

步骤 3:重新量化并验证

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

# 检查关键算子相似度
cat motionbert_lite_model_output_final/motionbert_lite_quant_info.json | \
  grep -E "v_linear|Softmax|mlp_t/fc2"

# 预期 v_linear 相似度应提升到 0.95+

:bar_chart: 预期效果对比

指标 当前 步骤 1 后 步骤 1+2 后
v_linear 相似度 0.86-0.87 0.95+ 0.98+
深层 MLP 相似度 0.81-0.85 0.90+ 0.95+
Softmax 相似度 0.68-0.75 0.90+ 0.98+
最终输出相似度 0.998944 0.9995+ 0.9998+
关键点抖动 明显 减轻 基本消除

:warning: 如果仍不满足(QAT 方案)

如果 PTQ 调优后仍有抖动,QAT 是必经之路

# QAT 配置示例
from horizon_plugin_pytorch.quantization import QConfig, prepare_qat

qconfig = QConfig(
    activation={'dtype': 'int8'},
    weight={'dtype': 'int8'},
    op_specific={
        'MatMul': {
            'activation': {'dtype': 'int16'},  # Attention 层用 int16
            'weight': {'dtype': 'int8'}
        },
        'Softmax': {'activation': {'dtype': 'float32'}},  # Softmax 用 FP32
    }
)

model = prepare_qat(model, qconfig)
# 微调 5-10 个 epoch
# ...
model = convert(model)

参考社区精华帖:


:red_question_mark: 需要确认

  1. 当前板端 MPJPE 误差:浮点模型 vs 量化模型各是多少?
  2. 抖动具体表现:帧间位置跳变幅度(毫米)?
  3. 是否有原训练数据集:可用于 QAT 微调?

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