深度分析:问题不在 Softmax 本身
从新量化报告看到关键问题:
1. Softmax 相似度两极分化
| Softmax 节点 | 相似度 | 问题 |
|---|---|---|
/blocks_st.0/attn_s/Softmax |
1.000010 |
正常 |
/blocks_st.0/attn_t/Softmax |
1.000109 |
正常 |
/blocks_ts.1/attn_t/Softmax |
0.853005 |
严重损失 |
/blocks_st.2/attn_t/Softmax |
0.832161 |
最严重 |
/blocks_ts.2/attn_t/Softmax |
0.842229 |
严重损失 |
2. 真正问题:Softmax 输入已量化损失
/blocks_st.1/attn_t/v_linear/MatMul → 0.946226 (int8)
↓ 量化损失传递
/blocks_st.1/attn_t/Softmax → 0.930826 (float) ❌
/blocks_ts.1/attn_t/v_linear/MatMul → 0.928596 (int8)
↓ 量化损失传递
/blocks_ts.1/attn_t/Softmax → 0.853005 (float) ❌
Softmax 虽然在 CPU 上跑 float32,但输入数据已经是量化后的 int8!
3. 误差累积曲线
Layer 0: 0.999+ ✅
Layer 1: 0.97-0.99 ⚠️ (v_linear 开始掉点)
Layer 2: 0.92-0.95 ❌ (v_linear 跌破 0.93)
终极解决方案
方案 A:保护 Attention 的 V 投影层(最关键)
# config_attention_fp16.yaml
model_parameters:
onnx_model: ./motionbert_lite_120.onnx
march: bayes-e
working_dir: motionbert_lite_model_output_v2
layer_out_dump: true
node_info:
# ========== 所有 Softmax 保持 CPU + float32 ==========
/blocks_st.0/attn_s/Softmax:
ON: CPU
InputType: float32
OutputType: float32
/blocks_st.0/attn_t/Softmax:
ON: CPU
InputType: float32
OutputType: float32
# ...(所有 Softmax 节点同上)
# ========== 关键:所有 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_ts.0/attn_s/v_linear/MatMul:
ON: BPU
InputType: int16
OutputType: int16
/blocks_ts.0/attn_t/v_linear/MatMul:
ON: BPU
InputType: int16
OutputType: int16
/blocks_ts.1/attn_s/v_linear/MatMul:
ON: BPU
InputType: int16
OutputType: int16
/blocks_ts.1/attn_t/v_linear/MatMul:
ON: BPU
InputType: int16
OutputType: int16
/blocks_ts.2/attn_s/v_linear/MatMul:
ON: BPU
InputType: int16
OutputType: int16
/blocks_ts.2/attn_t/v_linear/MatMul:
ON: BPU
InputType: int16
OutputType: int16
# ========== 可选:q_linear 和 k_linear 也保持 int16 ==========
/blocks_st.1/attn_t/q_linear/MatMul:
ON: BPU
InputType: int16
OutputType: int16
/blocks_st.1/attn_t/k_linear/MatMul:
ON: BPU
InputType: int16
OutputType: int16
# ========== 输出头保持 int16 ==========
/Concat:
ON: BPU
InputType: int16
OutputType: int16
/Concat_1:
ON: BPU
InputType: int16
OutputType: int16
/Concat_2:
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: kl # 改用 KL 散度
max_percentile: 0.9999 # 从 0.99999 降低到 0.9999
per_channel: true
方案 B:增加校准数据(必须配合方案 A)
# 50 条对时序 Transformer 模型严重不足
# 准备 300-500 条校准数据
# 校准数据生成要点:
# 1. 覆盖完整动作空间(静止、行走、跑步、跳跃等)
# 2. 包含遮挡场景
# 3. 包含不同视角
# 4. 确保 2D 关键点输入分布与真实推理一致
python3 generate_calib_data.py \
--num_samples 300 \
--cover_actions all \
--output_dir ./calibration_data_300
方案 C:降低 max_percentile(立即见效)
当前配置 max_percentile: 0.99999 过于激进,导致异常值影响校准:
calibration_parameters:
max_percentile: 0.9999 # 从 0.99999 降低
# 或进一步降低到 0.9998 测试
验证步骤
# 1. 应用新配置重新量化
hb_mapper --config config_attention_fp16.yaml
# 2. 检查 v_linear 层相似度是否提升
cat motionbert_lite_model_output_v2/motionbert_lite_quant_info.json | grep "v_linear/MatMul"
# 预期:从 0.92-0.94 提升到 0.97+
# 3. 检查 Softmax 输入前置节点
cat motionbert_lite_model_output_v2/motionbert_lite_quant_info.json | grep -B2 "Softmax"
# 4. 板端测试抖动
# 录制连续 100 帧,计算关键点位置标准差
预期效果
| 指标 | 当前 | 方案 A 后 | 方案 A+B 后 |
|---|---|---|---|
| v_linear 相似度 | 0.92-0.94 | 0.96+ | 0.98+ |
| 低分 Softmax | 0.83-0.85 | 0.95+ | 0.98+ |
| 关键点抖动 | 明显 | 减轻 | 基本消除 |
如果仍不满足
QAT 是最终手段,参考社区精华帖:
请先执行方案 A(保护 v_linear)+ 方案 C(降低 max_percentile),这通常能解决 90% 的 Transformer 量化抖动问题。
需要我帮你生成完整的 YAML 配置文件吗?