4. PTQ(训练后量化)
训练后量化,也就是PTQ,是咱们落地推理加速最常用的一招。说白了,就是模型训练完了,我们直接拿它做量化,不用再费劲去搞QAT(量化感知训练)。
我刚开始接触PTQ时,觉得这玩意儿简单——跑一遍校准数据,算个scale和zero_point不就完事了?结果第一次部署到端侧设备,精度直接掉了3个点,被算法同事追着问了一下午。嗯,从那以后我才明白,PTQ里的门道比想象中多得多。
4.1 Calibration数据集:选不对,全白费
Calibration数据集,说白了就是用来“观察”模型激活值分布的。你想想看,量化需要知道每一层输出的数值范围,才能决定怎么映射到INT8。这个观察样本选得不对,量化后的模型就跟瞎子一样。
选Calibration数据集,我总结了三条铁律:
- 覆盖度优先:数据要能代表真实推理场景的分布。比如你做图像分类,别只拿猫的图片去校准,狗、车、风景都得有。我见过一个项目,校准集只用了100张室内场景图,结果模型在户外场景下精度崩了。
- 数量别贪多:一般500~2000张就够了。太多反而让校准过程变慢,而且边际收益递减。我个人习惯用500~1000张,跑起来快,效果也稳。
- 避免极端值:别把全是噪声或者全黑的图片塞进去。极端值会拉大量化范围,导致正常数值的精度被压缩。
4.2 MinMax校准:简单粗暴,但有坑
MinMax是最直观的校准方法。它直接取激活值的最大值和最小值,然后映射到INT8的[-128, 127]范围。
公式很简单:
scale = (max - min) / 255
zero_point = round(-min / scale)
优点很明显:
- 计算量小,跑一遍校准集就能算出来
- 实现简单,几乎零门槛
但坑也很大:
- 对离群点极其敏感。如果校准数据里有一个异常大的值,整个量化范围就被撑大了,正常数值的精度会严重损失。
- 我遇到过最典型的情况:校准集里有一张过曝的图片,激活值里冒出一个200+的异常点。结果MinMax把scale拉得很大,正常0~50的数值只能分到不到64个量化级别,精度直接跳水。
4.3 KL散度校准:更聪明,但更慢
KL散度校准,也叫“相对熵校准”。它的核心思想是:找一个量化后的分布,让它跟原始浮点分布的“差异”最小。
具体做法是:
- 统计原始激活值的直方图(比如2048个bin)
- 尝试不同的阈值T,把直方图截断到T
- 对截断后的分布做量化,再反量化回浮点
- 计算量化前后分布的KL散度
- 选KL散度最小的那个T作为量化阈值
说白了,KL散度校准就是在“精度”和“范围”之间找一个平衡点。它允许丢掉一些极端的离群点,换来更精细的量化粒度。
我个人的经验:
- KL散度校准在大多数场景下比MinMax好,尤其是模型有BatchNorm层或者激活值分布比较集中时。
- 但它的计算量比MinMax大一个数量级。校准1000张图,MinMax可能几秒就搞定,KL散度要跑几十秒甚至几分钟。
- 如果模型层数很深(比如ResNet-152),KL散度校准的时间成本会很高。我建议先跑一次MinMax看看效果,如果精度损失在可接受范围内,就别折腾KL了。
4.4 两种校准方法的对比
| 对比维度 | MinMax | KL散度 |
|---|---|---|
| 计算复杂度 | 低(O(n)) | 高(O(n * bins)) |
| 对离群点敏感度 | 高 | 低(自动截断) |
| 精度保留 | 一般 | 较好 |
| 适用场景 | 快速验证、低精度要求 | 精度敏感、离线校准 |
| 校准时间(1000张图) | ~5秒 | ~30秒~2分钟 |
4.5 实际部署踩坑实录
PTQ部署到端侧或者服务端,坑真的不少。我挑几个印象深刻的说说。
坑一:校准数据跟推理数据分布不一致
这个最致命。我有个项目是做视频检测的,校准集用的是白天场景的图片,结果模型部署到晚上场景的摄像头下,精度直接掉了5个点。后来我重新从全天候数据里抽了校准集,问题才解决。
坑二:量化后的模型在某些层上精度崩了
有时候整体精度看起来还行,但某些层的输出完全乱掉了。我遇到过的情况是:模型里有一个Depthwise卷积层,它的激活值分布特别窄(集中在0附近),MinMax量化后几乎全变成了0。解决办法是:对这类层单独做per-channel量化,或者直接跳过量化。
坑三:硬件对量化参数的支持不一致
不同芯片对scale和zero_point的精度要求不一样。有些芯片只支持对称量化(zero_point=0),有些支持非对称量化。我踩过的一个坑是:在PC上验证时用的非对称量化,部署到某款NPU上才发现它只支持对称量化,结果scale要重新算,折腾了两天。
4.6 PTQ校准流程总览
下面这张图是我自己总结的PTQ校准流程,你可以照着这个步骤来,基本不会出大问题。
4.7 我的建议
如果你刚开始做PTQ,我建议你按这个顺序来:
- 先用MinMax跑一遍,看看精度损失
- 如果精度损失在1%以内,直接部署,别折腾
- 如果精度损失超过1%,换成KL散度再试
- 如果KL散度也不行,考虑per-channel量化或者跳过敏感层
- 最后,一定要用真实推理数据做验证,别只依赖校准集
PTQ这东西,说白了就是“数据决定上限,方法决定下限”。校准数据集选对了,MinMax也能用;选错了,KL散度也救不了。嗯,希望这些经验能帮你少踩几个坑。