3. 模型量化基础:INT8/INT4量化原理、对称与非对称量化、量化感知训练

量化这个话题,说白了就是把模型从浮点数世界拽到整数世界。为什么要这么干?因为整数运算快、省带宽、省功耗。我在做边缘端部署时,一个模型从FP32压到INT8,推理速度能翻3-4倍,功耗直接砍半。今天我们就聊聊量化的核心原理和实战要点。

3.1 量化原理:从浮点到整数的映射

量化的本质就是一个线性映射。我们把浮点数的范围映射到整数的表示范围上。比如INT8,取值范围是[-128, 127](有符号)或[0, 255](无符号)。

数学上很简单:

Q = round(r / S) + Z

其中:

  • r 是原始浮点值
  • S 是缩放因子(scale)
  • Z 是零点偏移(zero point)
  • Q 是量化后的整数值

反量化就是逆过程:

r = (Q - Z) × S

嗯,这里要注意:S 和 Z 是量化参数,它们决定了映射的精度。S越小,精度越高,但能表示的范围越小。这是个典型的精度-范围权衡。

核心指标:量化误差 = |r - r̂|,其中r̂是反量化后的值。误差主要来自舍入操作。

3.2 对称量化 vs 非对称量化

这两种方式我都在项目中用过。简单说:

  • 对称量化:Z = 0,浮点0映射到整数0。范围对称,[-α, α] 映射到 [-127, 127](INT8有符号)。
  • 非对称量化:Z ≠ 0,浮点0可以映射到任意整数。范围灵活,[min, max] 映射到 [0, 255](INT8无符号)。
特性 对称量化 非对称量化
零点偏移 Z = 0 Z ≠ 0
实现复杂度 低(乘法少) 高(需要额外减法)
精度利用率 低(可能浪费范围) 高(完全利用范围)
适用场景 权重分布对称(如ReLU后) 权重分布不对称(如sigmoid输出)
硬件友好度 高(很多硬件只支持对称) 低(需要额外逻辑)

我个人习惯:权重用对称量化,激活值用非对称量化。为什么?权重分布通常接近对称(均值为0),对称量化不会损失太多精度。激活值分布往往偏斜(比如ReLU后全是非负),非对称量化能更好地利用整数范围。

实战技巧:我在部署MobileNet时发现,如果激活值也用对称量化,精度掉了2.3%。换成非对称量化后,只掉了0.7%。这个差距在敏感任务上很要命。

3.3 INT8 vs INT4:精度与效率的博弈

INT4量化是近两年的热点。它比INT8更激进:

  • INT8:256个量化级别,精度损失可控,大部分模型都能接受
  • INT4:16个量化级别,精度损失大,但带宽和计算量再减半

我曾经在语音识别模型上试过INT4,结果WER(词错误率)从8.5%飙到了15.2%。后来改用混合精度——敏感层用INT8,非敏感层用INT4——才把WER压回9.1%。

指标 INT8 INT4
量化级别 256 16
存储压缩比(vs FP32) 4× 8×
典型精度损失 < 1% 1-5%
硬件支持 广泛(CPU/GPU/NPU) 有限(部分NPU/专用加速器)
推荐场景 通用部署 资源极度受限

避坑指南:我曾经在图像超分模型上直接用INT4量化,结果输出图像全是色块。后来发现是激活值范围太大,量化步长S太大导致信息丢失。解决方案:先做激活值裁剪(clipping),把异常大值截断,再量化。

3.4 量化感知训练(QAT)

量化感知训练,说白了就是在训练过程中模拟量化误差,让模型学会适应量化。和训练后量化(PTQ)不同,QAT把量化操作插入计算图,反向传播时通过直通估计器(STE)传递梯度。

QAT的核心流程:

  1. 插入伪量化节点:在权重和激活值后面加fake_quant操作
  2. 前向传播:用量化后的值计算,但梯度还是浮点的
  3. 反向传播:STE把梯度直接通过量化节点(忽略舍入操作)
  4. 更新参数:浮点权重在后台更新,量化参数(S, Z)也同步更新
# 伪代码:QAT中的fake_quant
def fake_quantize(x, scale, zero_point, num_bits=8):
    # 量化
    q = torch.round(x / scale + zero_point)
    # 截断到整数范围
    q = torch.clamp(q, 0, 2**num_bits - 1)
    # 反量化(模拟量化误差)
    x_hat = (q - zero_point) * scale
    return x_hat

# 前向时用x_hat,反向时梯度直接通过

关键参数:QAT的学习率通常比正常训练小10倍。我一般用1e-5起步,否则权重更新太快,量化参数跟不上。

QAT和PTQ的对比:

维度 PTQ(训练后量化) QAT(量化感知训练)
是否需要训练 否 是(需要少量微调)
精度恢复能力 有限 强(可接近FP32精度)
部署时间 几分钟 几小时到几天
适用模型 大模型、鲁棒模型 小模型、精度敏感模型
典型精度损失 0.5-2% < 0.5%

我个人建议:先跑PTQ看看精度损失。如果损失在可接受范围内,直接用PTQ,省时省力。如果损失太大,再上QAT。我在部署YOLOv5时,PTQ掉了1.8%的mAP,QAT微调了3个epoch后只掉了0.3%。

3.5 量化参数校准

量化参数S和Z怎么确定?需要校准数据集。校准过程:

  • 收集统计量:跑几百到几千张图片,记录每层激活值的min/max或分布
  • 选择量化范围:可以用min/max,也可以用百分位(比如99.9%分位)
  • 计算S和Z:根据选定的范围计算缩放因子和零点

校准方法对比:

方法 原理 优点 缺点
MinMax 用实际min/max 简单、无超参 对异常值敏感
Percentile 用指定分位值 抗异常值 需要调分位参数
KL散度 最小化量化前后分布差异 精度最优 计算量大
MSE 最小化均方误差 平衡精度和计算 需要搜索最优范围

我的经验:校准集大小选500-1000张就够了。太多反而可能过拟合到校准集的分布。另外,校准集要和实际部署场景的数据分布一致,否则量化参数会偏。

3.6 量化部署实战流程

最后,给一个我常用的量化部署流程:

  1. 模型准备:导出FP32模型,确保计算图固定(没有动态shape)
  2. 校准:用校准集跑一遍,收集每层的激活值统计量
  3. PTQ尝试:先做训练后量化,评估精度损失
  4. 精度检查:如果损失 < 1%,直接部署;否则进入QAT
  5. QAT微调:插入伪量化节点,用低学习率微调3-5个epoch
  6. 导出INT8模型:冻结量化参数,导出为INT8格式
  7. 硬件部署:在目标硬件上跑推理,验证性能和精度

最后提醒:量化不是万能药。有些模型(比如GAN、Transformer)对量化特别敏感。我遇到过BERT量化后精度掉了5%以上,最后只能做混合精度——注意力层用FP16,其他层用INT8。所以,量化策略要因模型而异,别一刀切。

量化部署核心流程 FP32 模型 校准集统计 PTQ 量化 精度达标? QAT 微调 INT8 模型导出 硬件部署验证 是 否 PTQ 优先尝试,精度损失大时回退到 QAT 微调