权重量化:INT8/INT4 量化原理、训练后量化与量化感知训练
量化,说白了就是把模型里的高精度数字(比如 FP32)换成低精度数字(比如 INT8 或 INT4)。你想想看,一个 FP32 的浮点数占 4 个字节,换成 INT8 就只占 1 个字节,模型体积直接缩到四分之一。这对部署在手机、边缘设备上的场景来说,简直是救命稻草。
我个人习惯把量化分成两类:训练后量化和量化感知训练。前者简单粗暴,后者精细调优。咱们一个一个说。
量化原理:从 FP32 到 INT8 的映射
量化的核心公式其实很简单:
q = round(r / s) + z
其中 r 是原始的浮点数,s 是缩放因子(scale),z 是零点偏移(zero point),q 就是量化后的整数。反过来,反量化就是:
r = (q - z) * s
嗯,这里要注意:s 和 z 怎么选?这直接决定了量化精度。
我在项目中遇到过一种情况:某个层的权重分布特别不均匀,大部分值集中在 0 附近,但有几个离群点特别大。如果用全局的 min/max 来算 scale,那大部分有效信息都会被压缩到几个整数上,精度损失惨重。后来我改用 KL 散度校准,让 scale 尽量覆盖 99.9% 的数据,效果好了很多。
关键点:量化不是简单的截断,而是寻找最优的映射关系。不同的校准方法(MinMax、KL、MSE)会带来不同的精度表现。
INT8 量化 vs INT4 量化
INT8 量化是目前工业界的主流。为什么?因为大部分硬件(CPU、GPU、NPU)都对 INT8 做了深度优化,计算速度能提升 2-4 倍,而精度损失通常控制在 1% 以内。
INT4 量化呢?更激进。模型体积再减半,但精度损失也更大。我试过在某个 NLP 模型上做 INT4 量化,结果准确率掉了 5 个点,直接没法用。后来加了量化感知训练才勉强拉回来。
| 量化类型 | 位宽 | 模型压缩比 | 典型精度损失 | 适用场景 |
|---|---|---|---|---|
| FP32 | 32 bit | 1x | 0% | 训练、高精度推理 |
| INT8 | 8 bit | 4x | < 1% | 大多数推理场景 |
| INT4 | 4 bit | 8x | 1-5% | 极端资源受限场景 |
我的建议:如果硬件支持 INT8,优先用 INT8。INT4 更适合那些对精度要求不高、但对体积和功耗极其敏感的场景,比如智能手表上的唤醒词检测。
训练后量化(Post-Training Quantization, PTQ)
PTQ 是最省事的量化方式。模型训练完,直接拿一批校准数据跑一遍,统计出每层的 scale 和 zero point,然后量化。整个过程不需要重新训练,几分钟搞定。
我曾经在一个图像分类项目上试过 PTQ,校准数据只用了 100 张图片,结果精度只掉了 0.3%。当时心里还挺美,觉得量化不过如此。直到后来做目标检测模型,PTQ 直接让 mAP 掉了 3 个点,我才意识到 PTQ 不是万能的。
PTQ 的流程大致如下:
- 准备校准数据集(几百张图片或几百条文本就够了)
- 用 FP32 模型跑一遍校准数据,收集每层的激活值分布
- 根据分布计算 scale 和 zero point
- 将权重和激活值量化到 INT8/INT4
- 验证量化后的模型精度
避坑指南:我曾经犯过一个错误——校准数据跟训练数据分布不一致。比如训练数据是白天场景,校准数据却用了大量夜景图片,结果量化后的模型在白天场景下精度崩了。校准数据一定要能代表真实推理场景的数据分布。
量化感知训练(Quantization-Aware Training, QAT)
QAT 就复杂多了。它在训练过程中模拟量化操作,让模型自己去适应低精度带来的误差。说白了,就是让模型「提前知道」自己将来要被量化,从而调整权重分布,减少精度损失。
QAT 的核心是伪量化节点(Fake Quantization Node)。这些节点在前向传播时模拟量化-反量化的过程,让梯度能正常回传。反向传播时,直通估计器(STE)会绕过量化函数的不可导点,让训练继续下去。
# 伪量化操作的简化实现
def fake_quantize(x, scale, zero_point, bit_width=8):
# 量化
q = torch.round(x / scale + zero_point)
# 截断到有效范围
q = torch.clamp(q, 0, 2**bit_width - 1)
# 反量化
x_q = (q - zero_point) * scale
return x_q
我在一个语音识别模型上做过对比:PTQ 让词错误率(WER)从 8% 升到了 11%,而 QAT 只升到了 8.5%。虽然 QAT 训练时间多了 3 天,但精度提升是实打实的。
什么时候用 QAT?当 PTQ 的精度损失超过你的容忍阈值时。一般来说,如果 PTQ 损失 < 1%,直接用 PTQ 就够了。如果损失 > 2%,建议上 QAT。
量化粒度:逐层 vs 逐通道
量化粒度也是个讲究。逐层量化(per-tensor)是整个层共用一个 scale,简单但精度差。逐通道量化(per-channel)是每个输出通道单独算 scale,精度更好,但计算量也更大。
我个人的经验是:权重用逐通道量化,激活值用逐层量化。权重分布在不同通道之间差异很大,逐通道能保留更多信息。激活值分布相对均匀,逐层量化就够了,还能省点计算资源。
量化后的性能收益
量化带来的收益不仅仅是模型体积变小。更关键的是计算速度的提升。INT8 的矩阵乘法在硬件上比 FP32 快 2-4 倍,内存带宽占用也大幅降低。对于大模型来说,内存带宽往往是瓶颈,量化直接缓解了这个问题。
我记得有一次部署一个 BERT 模型到手机端。FP32 版本推理一次要 800ms,量化到 INT8 后直接降到 200ms,用户终于不用等得抓狂了。
小技巧:量化后别忘了做一次精度验证。有时候某些层对量化特别敏感,可以单独把这些层保留为 FP32,其他层量化。这种混合精度量化在工程实践中很常见。
本章知识体系
下面这张图帮你理清权重量化的核心脉络:
量化这条路,说白了就是在精度和效率之间找平衡。PTQ 快但可能掉精度,QAT 精度好但训练成本高。具体选哪个,取决于你的业务场景和硬件限制。
我个人建议:先试 PTQ。如果精度损失在可接受范围内,那就直接用。如果不行,再上 QAT。别一上来就搞 QAT,那是在浪费时间和算力。
一句话总结:量化是模型部署的必修课。INT8 是当前最优解,INT4 是未来方向。PTQ 是入门,QAT 是进阶。掌握这两者,你就能在绝大多数场景下把模型塞进资源受限的设备里。
公众号:蓝海资料掘金营,微信deep3321