2、模型量化基础:什么是量化?—— 从FP32到INT8,精度损失与速度提升的数学原理

好,咱们正式开始聊量化。

说实话,我第一次接触量化的时候,脑子里就一个想法:把32位浮点数硬塞进8位整数里,这玩意儿靠谱吗?

后来在项目里被逼着做了一次,才发现——嗯,真香。

2.1 量化的本质:用更少的比特,表达差不多的数

量化,说白了就是降低数值的表示精度

模型里存的权重和激活值,默认都是FP32(32位浮点数)。每个数占4个字节。一个BERT模型几亿参数,光存权重就得好几百MB。

INT8呢?每个数只占1个字节。一下子省了75%的内存。

但问题来了——FP32能表示的范围和精度,INT8根本比不了。你想想看,FP32有大约2^32种取值,INT8只有256种。这中间的差距,就是量化要解决的矛盾。

核心思想:用有限的整数格子,去“覆盖”浮点数原本的分布范围。只要覆盖得好,精度损失就能控制在可接受范围内。

2.2 量化映射:从浮点到整数的数学桥梁

怎么把FP32变成INT8?不是直接截断,而是做一个线性映射

公式很简单:

Q = round( (F - zero_point) / scale )

反过来,反量化:

F = Q * scale + zero_point

这里有两个关键参数:

  • scale(缩放因子):决定每个整数格子代表多大的浮点范围
  • zero_point(零点):浮点0对应哪个整数

举个例子。假设你的权重范围是[-1.0, 1.0],要映射到INT8的[-128, 127]:

  • scale = (1.0 - (-1.0)) / (127 - (-128)) = 2.0 / 255 ≈ 0.00784
  • zero_point = 0(浮点0正好对应整数0)

那么浮点0.5量化后就是:round(0.5 / 0.00784) ≈ 64。

我的经验:zero_point不一定非得是0。如果浮点分布不对称,比如权重集中在[-0.5, 2.0],那zero_point就得偏移。我在一个语音模型里遇到过这种情况,当时没调zero_point,结果精度直接掉了2个点。

2.3 精度损失从哪来?—— 两个“凶手”

量化一定会丢精度,这是数学上注定的。但丢多少,取决于两个因素:

2.3.1 舍入误差

INT8只有256个格子,浮点值落在两个格子之间时,只能就近取整。这个“四舍五入”就是误差来源。

举个例子:

  • 浮点值0.00392,量化后是1
  • 浮点值0.00393,量化后还是1
  • 但这两个浮点值其实差了0.00001

这种误差在单次计算中微乎其微,但经过几十层网络累积,就可能影响最终结果。

2.3.2 截断误差

浮点分布总有“尾巴”。比如权重范围是[-1.2, 1.1],但INT8只能表示[-1.0, 1.0](假设scale固定)。那-1.2和1.1就被截断了。

截断的后果比舍入更严重。因为被截断的值直接变成了边界值,信息完全丢失。

避坑指南:我曾经在一个目标检测模型里,因为没处理好激活值的截断,导致小目标直接检测不到了。后来发现是激活值分布有长尾,截断后把微弱信号全丢了。解决办法是——用KL散度去找到最优的截断阈值,而不是简单用min/max。

2.4 速度提升的数学原理

为什么INT8比FP32快?不是因为它“小”,而是因为硬件对整数运算更友好

运算类型 FP32 INT8 速度提升
乘法 需要浮点乘法器 整数乘法器 2-4倍
加法 需要浮点加法器 整数加法器 2-3倍
内存访问 32位/次 8位/次 4倍
缓存利用率 显著提升

你看,乘法快了,加法快了,内存搬运也快了。三者叠加,推理速度翻倍是常有的事。

我个人的习惯是:先看内存带宽是不是瓶颈。如果是,量化带来的收益会特别明显。我在一个NLP模型上试过,FP32推理时GPU利用率只有40%,量化到INT8后直接飙到85%。

2.5 量化误差的数学分析

咱们稍微深入一点。量化误差可以建模为:

E_quant = E_round + E_clip

其中:

  • E_round:舍入误差,均匀分布在[-0.5 * scale, 0.5 * scale]之间
  • E_clip:截断误差,取决于分布尾部被砍掉多少

理论上,如果浮点分布是均匀的,舍入误差的期望是0。但实际中,权重和激活值往往服从高斯分布或拉普拉斯分布,这就导致舍入误差不是均匀的——中间密集区域误差小,尾部稀疏区域误差大。

所以,量化策略的核心就是:找到scale和zero_point,让整体误差最小

我建议:别一上来就搞复杂的量化算法。先用简单的min-max量化跑一遍,看看精度损失。如果损失在1%以内,那就直接用。如果损失大,再考虑KL散度、百分位法等更精细的策略。我在一个项目里,min-max量化只掉了0.3%的精度,完全够用,省了三天调参时间。

2.6 量化粒度:粗一点还是细一点?

量化不是对整个模型一刀切。你可以选择不同的粒度:

  • 逐张量量化:整个权重矩阵共用一个scale和zero_point。简单,但精度损失大。
  • 逐通道量化:每个输出通道单独算scale和zero_point。精度好,但计算量稍大。
  • 逐组量化:把通道分成小组,每组独立量化。折中方案。

我个人的经验是:卷积层用逐通道量化,全连接层用逐张量量化。卷积层的通道间差异大,逐通道能保住精度;全连接层的权重分布相对均匀,逐张量就够了。

2.7 小结:量化不是魔法,是工程

量化不是什么黑科技。它就是用精度换速度,但换多少、怎么换,需要你根据模型和数据去调。

记住三点:

  1. 量化误差来自舍入和截断,截断更致命
  2. 速度提升来自整数运算和内存效率
  3. 量化粒度要因地制宜,别一刀切

下一章,咱们会聊具体的量化方法——训练后量化(PTQ)和量化感知训练(QAT)。到时候我会拿一个实际模型,手把手带你走一遍流程。

嗯,量化这事儿,上手了就会发现,没那么可怕。