模型量化基础:为什么要做量化、量化的数学原理、精度与速度的权衡、常见量化格式
大家好,我是你们的老朋友。今天我们来聊聊模型量化。
说实话,我刚入行那会儿,对量化这事儿挺不屑的。觉得FP16跑得好好的,干嘛非要折腾成INT8?直到有一次,我负责的一个大模型服务,单卡A100只能塞下一个7B模型,用户一多就OOM。嗯,那会儿我才意识到——量化不是锦上添花,是刚需。
为什么要做量化?
说白了,量化就是给模型“减负”。
你想想看,一个FP32的权重占4个字节,换成INT8只要1个字节。模型体积直接缩到四分之一。推理速度呢?INT8的矩阵乘法在硬件上比FP32快2-4倍。我有个项目,量化后延迟从120ms降到了35ms,用户体验直接起飞。
还有一点——显存。大模型时代,显存就是命。量化能让你的模型在更便宜的卡上跑起来。我个人习惯,部署前先问自己一句:这个模型能不能量化?能的话,为什么不?
- 模型体积缩小(4倍起步)
- 推理速度提升(2-4倍常见)
- 显存占用降低(省钱才是硬道理)
量化的数学原理
量化本质上是把一个高精度数值映射到低精度整数空间。听起来玄乎,其实就一个公式的事。
对称量化
对称量化,就是让零点对齐到0。公式长这样:
q = round(clamp(x / scale, -127, 127))
scale = max(|x|) / 127
这里x是原始浮点数,q是量化后的INT8整数。scale是缩放因子。
我刚开始做量化时,对称量化用得最多。为什么?因为它简单。你不需要管零点偏移,硬件实现也快。但有个坑——如果数据分布不对称,比如ReLU后的激活值全是正数,那对称量化会浪费一半的表示范围。
非对称量化
非对称量化引入了零点偏移z,公式变成:
q = round(clamp((x - min) / scale, 0, 255))
scale = (max - min) / 255
z = round(-min / scale)
你看,多了个z。这个z的作用就是把浮点数的min映射到整数0。这样,即使数据全是正数,也能充分利用INT8的0-255范围。
我曾经在一个BERT模型上做过对比:对称量化后精度掉了1.2%,换成非对称量化只掉了0.3%。嗯,这个差距在敏感任务上可能就是能不能用的区别。
量化精度与推理速度的权衡
这里有个绕不开的话题——精度和速度,你总要牺牲一个。
我画了张图,帮你理清思路:
从图上你能看到:FP32精度最高但最慢,INT4最快但精度掉得厉害。我个人觉得,INT8是目前性价比最高的选择。为什么?因为大多数模型在INT8下精度损失小于1%,但速度能翻倍。
我有个血的教训:曾经为了追求极致速度,把一个翻译模型压到INT4。结果BLEU分数从28掉到了22,用户反馈翻译结果完全没法看。后来我改回INT8,速度只慢了15%,但BLEU回到了27.5。嗯,这个trade-off你得自己掂量。
常见量化格式
现在主流的量化格式就三种:INT8、INT4、FP8。我一个个说。
| 格式 | 位宽 | 表示范围 | 典型精度损失 | 推理加速比 |
|---|---|---|---|---|
| INT8 | 8 bit | -128 ~ 127 | < 1% | 2x - 3x |
| INT4 | 4 bit | -8 ~ 7 | 2% - 5% | 3x - 4x |
| FP8 | 8 bit | 动态范围大 | < 0.5% | 1.5x - 2x |
INT8
INT8是量化界的“老黄牛”。几乎所有硬件都支持,生态最成熟。在vLLM里,我默认就用INT8 W8A16(权重INT8,激活FP16)。效果稳定,部署省心。
INT4
INT4是“激进派”。模型体积能压到FP32的八分之一。但精度损失明显,尤其在小模型上。我建议只在7B以上的大模型上尝试INT4,而且一定要做校准集上的精度验证。
FP8
FP8是“新贵”。H100和AMD MI300都原生支持。它保留了浮点数的动态范围,精度比INT8好,但加速比不如INT8。我个人觉得,FP8是未来的方向,但目前硬件普及度还不够。如果你用的是H100,可以优先考虑FP8。
好了,量化基础就聊到这儿。记住一句话:没有最好的量化格式,只有最适合你场景的格式。动手之前,先想清楚你的瓶颈是显存、延迟还是精度。