4、后训练量化:快速部署的捷径—— 校准数据集、KL散度与对称/非对称量化
说到模型部署,我最常被问到的一个问题是:“模型太大,跑不动,怎么办?”
嗯,答案其实不复杂。除了剪枝和蒸馏,还有一个更直接、更暴力的方法——后训练量化(Post-Training Quantization, PTQ)。说白了,就是把模型里的浮点数(FP32)换成整数(INT8)。
你想想看,一个模型从 32 位变成 8 位,体积直接缩到四分之一。推理速度呢?在支持 INT8 的硬件上,能快 2 到 4 倍。我在项目中遇到过好几次,模型精度掉得不多,但速度翻倍,那种感觉真的很爽。
4.1 什么是后训练量化?
后训练量化,就是模型训练完之后,我们直接对权重和激活值做“压缩”。不需要重新训练,也不需要改网络结构。
它的核心思路很简单:找到浮点数的分布范围,然后映射到整数的范围里。
举个例子:
- 原始权重范围:[-1.0, 1.0]
- INT8 范围:[-128, 127]
- 映射公式:
q = round(r / scale) + zero_point
这里的 scale 和 zero_point 就是我们要算的关键参数。
核心要点:后训练量化不需要反向传播,只需要前向推理一次或几次,就能完成量化。所以它特别适合快速部署的场景。
4.2 校准数据集:量化前的“摸底考试”
量化不是随便找个范围就行的。你得知道模型在实际数据上的激活值分布是什么样的。
这就是校准数据集(Calibration Dataset)的作用。
我个人习惯从训练集中抽一小部分数据,大概几百到几千张图片,作为校准集。然后让模型跑一遍前向推理,记录每一层的激活值分布。
为什么要这么做?
- 权重是固定的,可以直接统计范围。
- 激活值是动态的,不同输入会产生不同分布。
- 校准集要尽量覆盖真实场景,否则量化后精度会崩。
小技巧:校准集的数量不用太多。我一般用 500 张图片就够了。太多反而浪费时间,太少又不够稳定。你可以试试 200 到 1000 张之间,效果差别不大。
4.3 KL散度:找到最优的量化范围
校准完数据,我们拿到了激活值的分布。接下来要解决的问题是:怎么选量化范围,才能让精度损失最小?
这里就要请出 KL 散度(Kullback-Leibler Divergence)了。
KL 散度衡量的是两个分布之间的差异。在量化里,我们比较的是:
- 原始浮点数的分布(P)
- 量化后再反量化回来的分布(Q)
我们希望这两个分布越接近越好。KL 散度越小,说明量化损失越小。
具体做法是这样的:
- 统计原始激活值的直方图。
- 尝试不同的截断阈值(比如从最大值往下砍一点)。
- 对每个阈值,计算量化后的分布,再反量化回来。
- 计算 KL 散度,选最小的那个阈值。
为什么不用最大值? 因为激活值里可能有极少数异常大的值。如果直接用最大值做范围,会导致大部分值被压缩到很小的区间里,精度损失反而更大。KL 散度能帮我们“砍掉”这些异常值,找到更合理的范围。
我曾经在一个目标检测模型上试过,直接用最大值量化,mAP 掉了 3 个点。换成 KL 散度校准后,只掉了 0.5 个点。差距还是很明显的。
4.4 对称量化 vs 非对称量化
聊完校准,我们来说说量化的两种基本形式。
4.4.1 对称量化
对称量化,就是量化范围关于 0 对称。公式很简单:
scale = max(|r_max|, |r_min|) / 127
zero_point = 0
q = round(r / scale)
优点:
- 计算简单,不需要 zero_point。
- 硬件实现方便,很多 NPU 只支持对称量化。
缺点:
- 如果数据分布不对称(比如全是正数),会浪费一半的量化范围。
4.4.2 非对称量化
非对称量化允许范围不对称,用 zero_point 来偏移:
scale = (r_max - r_min) / 255
zero_point = round(-r_min / scale)
q = round(r / scale) + zero_point
优点:
- 能充分利用 INT8 的 256 个级别,精度更高。
缺点:
- 多了一个 zero_point,计算稍微复杂一点。
- 某些硬件不支持。
| 对比项 | 对称量化 | 非对称量化 |
|---|---|---|
| zero_point | 固定为 0 | 需要计算 |
| 范围利用率 | 低(数据不对称时) | 高 |
| 硬件支持 | 广泛 | 部分支持 |
| 精度 | 一般 | 更好 |
注意:我在项目中踩过一个坑。当时用非对称量化,精度表现很好。但部署到某款边缘芯片上时,发现它不支持非对称量化,只能重新校准。所以,选哪种方式,一定要先看目标硬件的文档。
4.5 实战建议:如何选择量化策略?
说了这么多,到底该怎么选?我总结了几条经验:
- 权重用对称量化:权重的分布通常比较对称,用对称量化就够了。
- 激活值用非对称量化:激活值经常是 ReLU 后的正数,非对称量化更合适。
- 校准方法优先选 KL 散度:它比 min-max 和 percentile 更稳定。
- 校准集要贴近真实数据:别拿训练集里的纯背景图去校准,模型会“学歪”。
我的习惯:先用默认的对称量化跑一遍,看看精度。如果掉点超过 1%,再换成非对称量化 + KL 散度校准。大部分情况下,这样就能把精度拉回来。
后训练量化,说白了就是一条快速部署的捷径。它不需要你动模型结构,也不需要重新训练。只要校准集选得好,量化策略选得对,精度损失完全可以控制在可接受范围内。
嗯,下一章我们会聊量化感知训练(QAT),那是另一种更精细的玩法。但如果你赶时间,PTQ 绝对是你的首选。