4. 量化感知训练(QAT):原理介绍,如何在训练中模拟量化误差

好,咱们接着聊量化。上一节讲了PTQ(训练后量化),说白了就是模型训练完了,我们直接拿它去量化。这个方法快,但精度损失有时候让人头疼。那有没有办法让模型自己“学会”适应量化呢?

有,这就是量化感知训练——QAT。

4.1 QAT的核心思想:让模型提前“挨打”

QAT的原理,用一句话概括就是:在训练过程中,假装模型已经被量化了

你想想看,模型在训练时用的是浮点数,精度高得很。但部署到边缘设备上,比如一个Cortex-M4内核的MCU,它只能用INT8甚至INT4去算。这中间的巨大落差,就是精度损失的根源。

QAT的做法很聪明:在前向传播时,插入“伪量化”操作。这个操作会把浮点权重和激活值,先量化成低精度,再反量化回浮点。这样,模型在计算梯度时,就已经“感受”到了量化带来的误差。

我个人习惯把QAT比作“模拟考试”。你平时做练习(训练)时,就用和正式考试(部署)一样的难度和规则。这样上了考场,自然不慌。

核心公式(伪量化操作):

# 伪量化:量化 -> 反量化
q = round(clamp(x / scale, -128, 127)) * scale

这里的 scale 是缩放因子,clamp 把值限制在INT8范围内。整个操作是可微分的,所以梯度能正常回传。

4.2 训练流程:三步走

QAT的训练流程,我一般分三步。嗯,这里要注意,每一步都有坑。

  1. 先预训练一个浮点模型:别一上来就搞QAT。先用常规方法训一个精度达标的浮点模型。这一步是“打地基”。
  2. 插入伪量化节点:在模型的权重和激活值后面,都加上伪量化操作。框架如PyTorch的 torch.quantization 模块,或者TensorFlow的 tf.quantization,都提供了现成的API。
  3. 微调(Fine-tune):用较小的学习率(比如原来的1/10),继续训练几个epoch。让模型适应量化后的数值分布。

我在项目中遇到过一个问题:如果微调的学习率太大,模型会“忘记”之前学到的知识,精度反而下降。所以,学习率一定要小,我一般用1e-5起步。

4.3 模拟量化误差的细节

QAT的精髓,在于如何“模拟”量化误差。这里有几个关键点:

  • 量化范围怎么定? 不是所有值都适合量化。比如激活值,大部分集中在0附近,但偶尔有几个大值。如果按最大值去定scale,那大部分值都会被压缩到很小的区间,精度损失巨大。我建议用滑动平均来统计激活值的范围,而不是直接取最大值。
  • 梯度怎么处理? 伪量化操作里的 round() 函数,梯度是0(因为它是阶梯函数)。这会导致梯度无法回传。怎么办?用直通估计器(STE)。简单说,就是前向传播时用 round(),反向传播时假装 round() 不存在,直接把梯度传过去。

STE的伪代码:

# 前向传播
q = round(x / scale) * scale

# 反向传播(STE)
# 梯度直接跳过 round()
grad_x = grad_q  # 假装 round() 是恒等函数

这个技巧很关键。没有STE,QAT根本训不动。

4.4 实战中的避坑指南

我曾经在一个语音识别模型上做QAT,结果精度比PTQ还差。排查了半天,发现是BN层(Batch Normalization)的问题。

BN层在训练时,会统计均值和方差。但QAT的伪量化操作,会改变数值分布,导致BN层的统计量不准。怎么办?

  • 方案一:冻结BN层。在微调阶段,固定BN层的均值和方差,不更新。
  • 方案二:用GN(Group Normalization)替代BN。GN不依赖batch size,对量化更友好。

我个人更推荐方案一,简单有效。

注意: QAT不是万能的。如果模型本身就很“脆弱”(比如某些轻量级网络),QAT可能也救不回来。这时候,你可能需要重新设计网络结构,或者考虑混合精度量化(部分层用INT8,部分层用FP16)。

4.5 QAT vs PTQ:怎么选?

很多同学问我:到底用QAT还是PTQ?我的建议是:

场景 推荐方法 原因
模型精度很高,量化后损失小 PTQ 快,省事
模型精度一般,量化后损失大 QAT 能挽回1-3%的精度
部署平台对量化敏感(如某些NPU) QAT 让模型提前适应硬件特性
项目时间紧,没时间微调 PTQ QAT需要额外训练时间

说白了,QAT是用训练时间换精度。如果你的模型部署后,精度差得离谱,那QAT值得一试。如果PTQ已经能满足需求,就别折腾了。

4.6 小结

QAT的核心,就是让模型在训练时“体验”量化误差。通过伪量化操作和STE,模型学会了在低精度下依然保持良好性能。

最后提醒一句:QAT不是银弹。它解决的是“量化后精度损失”的问题,但解决不了“模型本身就不行”的问题。先把浮点模型训好,再考虑量化的事。

下一节,我们会聊混合精度量化——怎么在同一个模型里,同时用INT8和FP16,达到精度和速度的平衡。