根据你提供的完整量化日志,我找到了核心问题:
问题诊断
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 | |
/blocks_ts.4/attn_t/Softmax |
0.877 | float | |
/blocks_st.2/attn_t/Softmax |
0.920 | float |
虽然显示为 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,远超必要范围。
立即执行方案
步骤 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}")
预期效果
| 指标 | 当前 | 修改后预期 |
|---|---|---|
| Softmax 相似度 | 0.87-0.92 | 0.99+ |
| 最终输出相似度 | 0.999567 | 0.9998+ |
| 关键点抖动 | 明显 | 基本消除 |
如果仍有问题
方案 B:增加校准数据
# 50 条对时序模型明显不足,建议 200-500 条
# 覆盖不同动作场景:静止、快速运动、遮挡等
# 生成更多校准数据
python3 generate_calibration_data.py --num_samples 300 --output_dir ./calibration_data_300
方案 C:QAT(最后手段)
如果 PTQ 调优后仍不满足,参考社区精华帖:
需要确认
- 当前板端部署后 MPJPE 误差是多少?(浮点 vs 量化)
- 抖动表现:是时间序列上的帧间抖动,还是单帧精度下降?
- 工具链版本:
hbdk version 3.49.15,确认是否有更新版本
先执行步骤 1 和 2,通常能解决 80% 以上的 Transformer 量化精度问题。完成后请反馈新的量化报告。