4. 训练后量化(PTQ):校准数据集、精度损失分析、混合精度量化
训练后量化,简称PTQ,是咱们部署模型时的「第一道防线」。说白了,就是模型训练完了,我们直接把它从FP32转成INT8或者更低精度。我个人觉得,PTQ比QAT(量化感知训练)省心太多了——不需要回炉重训,数据集也不用重新标注,成本低到令人发指。
但问题来了:为什么有些模型PTQ之后精度掉得像瀑布,有些却几乎不掉?这里面的门道,我们来拆开看看。
4.1 校准数据集:选错了,后面都是白搭
校准数据集的目的是「摸清」模型各层的激活值分布。你想想看,如果你不知道数据长什么样,怎么确定缩放因子?
选多少张图?不是越多越好。我记得有一次项目,团队用了10000张图做校准,结果精度反而不如512张的版本。为什么?因为数据量太大,分布被「平均化」了,极端值被淹没,量化后反而容易溢出。
我的经验: 分类模型推荐 500~2000 张,检测和分割模型可以稍多,2000~5000 张。关键不是数量,是这些样本要能代表你真实的推理数据分布。
选哪些数据?
- 覆盖各类别: 不要全是「猫」,要混进「狗」、「车」、「房子」
- 包含难样本: 低光照、模糊、遮挡的样本,能暴露量化误差
- 避免离群值: 纯白噪点图或者全黑图,会让校准结果崩掉
我见过一个案例,有人拿验证集做校准,精度掉1.2%,换了个更均匀的数据采样,精度只掉0.3%。差距就在这里。
4.2 精度损失分析:到底是谁在拖后腿
模型量化后精度掉了,你第一反应是什么?我刚开始做的时候,到处找原因,调参数调半天没效果。后来摸出门道了:逐层对比。
把量化前后每一层的输出拉出来,算一下余弦相似度或者相对误差。你会发现——
- 80%的层误差 < 1%,这些层随便量化
- 15%的层误差在 1%~5%,需要关注
- 5%的层误差 > 5%,就是这些「害群之马」把整个模型拖垮了
避坑指南: 我曾经遇到过一层卷积,误差居然高达 34%。找了一整天才发现,那层的输入分布极度不平衡 —— 99%的值集中在 [-0.1, 0.1],剩下1%却跑到 [-50, 50]。标准 MinMax 量化完全失效。后来换成了 KL 散度校准,误差降到 2.1%。
| 方法 | 原理 | 适用场景 | 我的推荐评级 |
|---|---|---|---|
| MinMax | 取激活值的最小最大值 | 分布均匀、无严重离群值的层 | ⭐⭐ |
| KL 散度 | 最小化量化前后分布差异 | 大多数情况,通用性好 | ⭐⭐⭐⭐ |
| Percentile | 截断头尾一定比例的值 | 存在离群值时表现优秀 | ⭐⭐⭐⭐⭐ |
| MSE | 最小化均方误差 | 对精度敏感的层 | ⭐⭐⭐ |
我个人习惯的做法:先用 Percentile 校准作为基础方案——我一般取 99.9% 的截断,然后再对误差超过 2% 的层单独调。
4.3 混合精度量化:该放手时就放手
不是所有层都适合量化到 INT8。有些层天生倔强,你一量化它就崩。那就别硬来,给它保留 FP16 或者 FP32。
哪些层容易出问题?
- 第一层和最后一层: 输入输出层对精度最敏感,我通常直接保留 FP32
- 残差连接中的加法层: 误差会累积,尤其是 ResNet、Transformer 的结构
- Bottleneck 层: 维度压缩再恢复,量化误差会被放大
- 注意力机制中的 Softmax: 输出范围 [0,1],但极度不均匀,量化后容易丢失小概率信息
来看看实际配置:
# 假设用的 NVIDIA TensorRT 或者 ONNX Runtime
# 混合精度策略示例
sensitive_layers = [
"conv1", # 第一层 -> FP32
"fc_out", # 最后一层 -> FP32
"res_add_*", # 所有残差加法 -> FP16
"softmax_*" # 注意力 Softmax -> FP16
]
# 其余层自动选择 INT8
根据我的项目数据,一个标准的 ResNet-50 用混合精度量化后,精度损失可以从 1.8% 降到 0.3%,推理速度只慢 5%。这笔账,太划算了。
核心思路: 混合精度量化的本质不是「暴力压缩」,而是「精细化修剪」。该保的地方保,该压的地方压。你用精度损失最小的 20% 层扛起 FP32 的开销,换来剩下 80% 层极致加速。
4.4 PTQ实战步骤:从配置到验证
- 准备校准数据: 从训练集中均匀采样 1000~2000 张,确保覆盖全类别
- 运行校准: 前向传播一次,收集各层激活值分布
- 计算缩放因子: 根据你选的校准方法(推荐 Percentile 99.9%),得到 scale 和 zero_point
- 模拟量化: 在意 INT8 forward 上跑一遍,收集每层量化误差
- 误差分析: