☰
INT8量化实战:从矩阵乘、校准到QAT与LLM量化落地
2026/10/1 23:47:51 网站建设 项目流程

模型上线之后,真正让人头疼的往往不是网络结构本身,而是"精度掉了一点、延迟却卡在瓶颈"这种不上不下的状态。FP32 跑得动但太慢,FP16 快是快,可有些老硬件根本不认;于是 INT8 成了绕不开的一站。这篇就围绕INT8 矩阵乘、校准、QAT 与 LLM 量化这条主线,把量化从"为什么能压"到"怎么落地"讲透。适合已经能把模型跑起来、准备做推理优化的同学,也适合被显存和延迟卡过脖子、想搞清楚量化到底动了哪些手脚的工程师。我会尽量把原理、参数、踩坑点都摊开讲,读完你应该能自己判断:这个模型该不该量化、用哪种量化、校准集怎么选、掉点之后往哪查。

1. 量化到底在压什么:从浮点到定点的账本

1.1 一个生活化类比:把米尺换成厘米尺

浮点数就像一把可以无限细分的软尺,你想量多细都行,代价是每次读数都要现算;定点数则像一把刻度固定的硬尺,刻度之间只能取整,但读起来飞快。量化的本质,就是把这把"软尺"换成"硬尺",并且约定好刻度代表多少真实长度。

数学上,最常用的线性量化(affine quantization)长这样:

real_value ≈ scale × (quantized_value - zero_point)

其中scale是浮点缩放因子,zero_point是整数零点偏移。反过来说,把一个 FP32 值x量化成 INT8:

q = round(x / scale) + zero_point

round之后还要 clamp 到[-128, 127](有符号)或[0, 255](无符号)。这一步 clamp 就是精度损失的来源——超出范围的值会被"削平",也就是饱和(saturation)。

1.2 对称量化与非对称量化,差的不只是一个零点

对称量化强制zero_point = 0,量化范围关于 0 对称,通常取[-127, 127]。非对称量化允许零点偏移,范围可以是[-128, 127]任意映射。

类型零点典型范围适用场景计算开销
对称0[-127, 127]权重、激活分布近似对称低,可省去零点修正
非对称可调[-128, 127]激活全为正(如 ReLU 后)略高,需处理零点

为什么权重常用对称量化?因为权重通常以 0 为中心近似对称分布,强制零点为 0 能省掉一大堆补偿计算,硬件实现更简单。而激活经过 ReLU 之后全是非负的,如果还用对称量化,一半的整数范围就浪费了,这时候非对称量化更划算。

1.3 per-tensor、per-channel、per-group:粒度越细越准,也越贵

  • per-tensor:整个张量共用一个 scale,最省,但离群值会拖累整体精度。
  • per-channel:每个输出通道一个 scale,卷积和线性层常用,精度明显提升。
  • per-group:把通道再分组,每组一个 scale,LLM 量化里非常常见(比如 group_size=128)。

粒度选择的经验是:权重量化尽量用 per-channel 或 per-group,激活量化因为运行时动态统计成本高,多数场景还是 per-tensor。这个取舍后面讲 LLM 量化时还会反复提到。

2. INT8 矩阵乘为什么能快:硬件视角的拆解

2.1 从 FP32 MAC 到 INT8 MAC,省在哪

矩阵乘的核心是乘加运算(MAC)。FP32 的一个 MAC 需要完整的浮点乘法器和加法器,功耗和面积都大。INT8 的 MAC 可以用定点乘法器实现,位宽只有 8 位,同样面积的芯片能塞进更多运算单元。

以常见的推理加速器为例,INT8 的峰值算力通常是 FP32 的 4 倍甚至更多,原因有三:

  1. 乘法器位宽从 32 位降到 8 位,面积和功耗大幅下降;
  2. 数据搬运量减少 4 倍,内存带宽压力骤降;
  3. 累加可以用 INT32 完成,避免频繁的浮点归一化。

注意:INT8 的加速收益高度依赖硬件是否原生支持。如果硬件没有 INT8 指令,框架会退化成"反量化成 FP32 再算",那不但不快,反而更慢。上线前一定要确认目标硬件的指令集支持情况。

2.2 量化矩阵乘的完整计算链路

假设权重W和激活X都量化成 INT8,各自有 scale 和 zero_point:

W ≈ s_w × (W_q - z_w) X ≈ s_x × (X_q - z_x)

那么:

Y = W · X ≈ s_w × s_x × (W_q - z_w) · (X_q - z_x)

展开后:

(W_q - z_w) · (X_q - z_x) = W_q · X_q - z_w · ΣX_q - z_x · ΣW_q + z_w · z_x · N

其中N是累加维度长度。可以看到,真正的 INT8 矩阵乘只需要算W_q · X_q这一项,其余都是对结果的修正项。如果是对称量化(z_w = z_x = 0),修正项全部消失,只剩一个干净的 INT8 矩阵乘加一个统一的 scale 缩放。

这就是为什么工程上偏爱对称量化的深层原因——它让硬件路径最短。

2.3 累加溢出:INT8 乘 INT8 为什么用 INT32 累加

两个 INT8 相乘,结果范围是[-128×127, 127×127],约[-16256, 16129],已经超出 INT16 的安全范围。如果累加维度是 1024,最坏情况累加值会到千万级别,必须用 INT32 才能不溢出。

实际实现里,累加器通常是 INT32,算完再乘上s_w × s_x反量化回浮点。这个"INT8 乘、INT32 累加、最后统一缩放"的模式,是几乎所有 INT8 推理内核的标准套路。

3. 校准:量化精度的第一道生死线

3.1 校准在做什么,为什么不能省

训练后量化(PTQ)不需要重新训练,但它需要知道激活值的动态范围,才能算出合理的 scale。这个"统计激活范围"的过程就是校准。

校准的核心问题是:用什么样的数据、统计什么样的范围。范围估小了,大量激活被 clamp,精度崩;范围估大了,有效量化位数被浪费,精度也掉。这是一个两头不讨好的平衡。

3.2 校准集怎么选:不是随便丢几百张图就行

校准集的选择有几个实操原则:

  • 数量:通常 100 到 500 个样本足够,太多收益递减,太少统计不稳。
  • 分布:必须覆盖真实推理时可能遇到的输入分布。如果线上有长尾场景,校准集里也要有。
  • 预处理:校准集的预处理必须和推理时完全一致,包括归一化、resize、通道顺序。这一点极其容易出错。

我踩过的一个坑:校准集用了训练集的中心裁剪,但推理时用的是全图 resize,结果激活分布对不上,量化后 mAP 掉了 6 个点。排查了半天才发现是预处理不一致。

3.3 几种主流校准算法对比

算法原理优点缺点
Min-Max取激活的全局最小最大值简单、覆盖全对离群值极敏感
Moving Average Min-Max滑动平均历史 min/max更平滑仍需处理离群值
KL 散度最小化量化前后分布差异精度好计算慢
Percentile取分位数截断抗离群值分位数需调
MSE最小化量化误差平方和平衡性好需搜索

KL 散度校准是 TensorRT 的经典方案,它通过搜索一个截断阈值,让量化后的分布尽量逼近原始分布。Percentile 校准则更直接,比如取 99.99% 分位,把极端离群值直接砍掉。

提示:如果发现量化后某些层误差特别大,先看这一层的激活是不是有极端离群值。很多情况下,单独给这一层换校准算法或调分位数,比全局换算法更有效。

3.4 逐层敏感度分析:找出不能量化的那几层

不是所有层都适合量化。第一层卷积、最后的分类头、以及某些带特殊激活的层,往往对量化特别敏感。做法是逐层做敏感度分析:每次只把一层保持 FP32,其余量化,看精度变化。

精度恢复明显的层,就加入"量化白名单"跳过。这个流程在 PyTorch 里可以用torch.ao.quantization的 observer 配合自定义配置实现,在 TensorRT 里则通过 layer-wise 的精度对比工具完成。

4. QAT:当 PTQ 掉点太多时的救命方案

4.1 QAT 的核心思想:把量化误差"演"给训练看

PTQ 的问题是量化误差在训练结束后才引入,模型没机会适应。QAT(Quantization-Aware Training)在训练前向传播里插入伪量化节点(fake quantize),模拟量化的舍入和截断,让模型在训练中就"感受"到量化误差,从而调整权重去补偿。

伪量化的公式就是前面那个:

q = round(clamp(x / scale, -128, 127)) x_fake = (q - zero_point) × scale

注意前向是量化后的值,反向传播时因为round不可导,用的是 STE(Straight-Through Estimator),直接把梯度原样传过去。

4.2 QAT 的典型流程与关键参数

一个标准的 QAT 流程:

  1. 加载预训练 FP32 模型;
  2. 插入伪量化节点,配置哪些层量化、用什么粒度;
  3. 用较小学习率微调若干 epoch;
  4. 冻结量化参数(scale、zero_point),导出量化模型。

关键参数上,学习率通常设为原始训练的 1/100 到 1/10,epoch 数不用多,几个 epoch 往往就够。学习率太大反而会把预训练权重带偏。

4.3 QAT 与 PTQ 的取舍:什么时候值得多花这些功夫

维度PTQQAT
训练成本无需要微调
精度一般更好
落地速度快慢
适用场景大模型、冗余度高小模型、精度敏感

经验判断:如果 PTQ 掉点在 1 个点以内,直接用 PTQ;掉 1 到 3 个点,先试敏感度分析跳过几层;掉超过 3 个点,或者模型本身很小(比如移动端检测网络),那就上 QAT。

4.4 QAT 实操中的几个隐蔽坑

  • BN 层融合:QAT 前一定要把 BN 融进卷积,否则量化节点和 BN 的顺序会出问题。
  • 伪量化节点的位置:放在激活函数前还是后,结果差别很大,要按框架推荐来。
  • 导出后的验证:QAT 训练时用的是伪量化,导出的是真量化,两者数值可能有细微差异,必须用真实量化模型再跑一遍验证集。

5. LLM 量化:当模型大到装不下的时候

5.1 LLM 量化的特殊难点

LLM 量化和 CNN 量化完全不是一个难度级别。核心难点在于:

  • 激活离群值:LLM 的激活里存在极少数数值特别大的通道(outlier),这些离群值会把 per-tensor 的 scale 撑得很大,导致其他正常值量化后精度全丢。
  • 权重分布不均:不同通道的权重范围差异大,per-tensor 量化效果差。
  • 显存瓶颈:LLM 参数量巨大,量化首先是为了省显存,其次才是提速。

5.2 权重量化:GPTQ、AWQ 与 GGUF 的路线差异

方案核心思路特点
GPTQ逐层做二阶误差补偿精度好,量化需校准数据
AWQ保护重要权重通道推理快,对激活离群值友好
GGUF多种量化等级可选部署方便,适合端侧

GPTQ 的思路是逐层量化,每量化一列权重,就用剩余未量化的权重去补偿误差,本质是一个带 Hessian 信息的贪心算法。AWQ 则观察到"不是所有权重都同等重要",通过激活幅度识别出重要通道,对这些通道保留更高精度。

5.3 激活量化的硬骨头:SmoothQuant 与离群值处理

激活量化比权重量化难得多。SmoothQuant 的核心 trick 是把激活的量化难度"迁移"一部分到权重上:对激活除以一个平滑因子s,对权重乘以s,因为数学上Y = (X/s) · (W·s)等价,但激活的离群值被压平了,权重的量化难度增加有限。

这个思路很巧妙,本质是用权重的"余量"去换激活的"平滑"。实际调参时,s的选择依赖对激活和权重幅度的统计,通常按通道计算。

5.4 KV Cache 量化:被低估的显存大户

长上下文场景下,KV Cache 的显存占用可能超过模型权重本身。KV Cache 量化通常用 INT8 甚至 INT4,但要注意:

  • Key 的分布比 Value 更集中,量化更友好;
  • Value 的离群值更多,需要更细的粒度;
  • 量化 KV Cache 对生成质量的影响在长序列上会被放大。

注意:KV Cache 量化一定要在长上下文场景下验证,短序列测不出问题,长序列上可能直接崩。

6. 量化落地的完整检查清单与踩坑复盘

6.1 上线前的验证流程

量化模型不能只看"能不能跑",要有一套完整验证:

  1. 数值一致性:量化模型和 FP32 模型在同一输入下的输出差异,逐层对比;
  2. 精度指标:在完整验证集上跑任务指标,不只看 loss;
  3. 性能实测:在目标硬件上测延迟和吞吐,别信理论算力;
  4. 边界输入:极端输入、全零输入、超大输入都要测,看会不会溢出或异常。

6.2 常见掉点原因速查表

现象可能原因排查方向
整体掉点均匀校准集分布不对检查预处理、样本覆盖
个别层误差大该层有离群值敏感度分析、换校准算法
输出全错scale 计算溢出检查是否有 NaN/Inf
速度没提升硬件不支持 INT8确认指令集、算子融合
长序列崩KV Cache 量化过激放宽 KV 量化精度

6.3 我踩过的几个真实坑

第一个坑是校准集预处理不一致,前面提过,掉了 6 个点。第二个坑是导出 ONNX 时忘了把伪量化节点正确转换,结果导出的模型还是 FP32,白忙一场。第三个坑最隐蔽:某个版本的推理框架对 per-channel 量化的支持有 bug,per-tensor 正常,per-channel 结果全乱,换版本才解决。

这些坑的共同点是:量化的问题往往不在量化算法本身,而在数据流和工具链的衔接处。所以每次量化上线,我都会把"数据预处理一致性"和"导出后数值验证"当成必查项。

6.4 一个可复用的量化决策流程

最后给一个我常用的决策路径:

  • 先跑 PTQ,看掉点;
  • 掉点可接受,直接上线,省事;
  • 掉点偏大,做逐层敏感度分析,跳过敏感层;
  • 还不行,上 QAT 微调;
  • LLM 场景,权重优先用 GPTQ/AWQ,激活用 SmoothQuant,KV Cache 按需量化。

这套流程不保证每次都最优,但能覆盖绝大多数场景,避免一上来就上最重的方案。

量化这件事,说到底是在精度、速度、显存三者之间找平衡点,没有银弹。我个人的体会是,先把校准和验证这两件事做扎实,比盲目追求更激进的量化等级有用得多。很多时候,一个干净的校准集加上逐层敏感度分析,就能把 PTQ 的精度拉回到可用范围,根本用不着上 QAT。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询