量化感知训练(QAT):让模型学会“低精度生存”
各位同学,咱们接着聊量化。上一章讲了PTQ,也就是训练后量化。说白了就是模型训练完了,我们直接拿它去转精度。这个方法快是快,但精度损失有时候让人头疼。我自己的经验是,对于一些大模型或者对精度极其敏感的任务,PTQ往往不够用。
那怎么办?让模型自己学会适应低精度。这就是量化感知训练,简称QAT。
QAT原理:模拟量化过程
QAT的核心思想其实很简单——在训练过程中,假装模型已经被量化了。你想想看,模型在训练时用的是FP32,推理时突然变成INT8,这中间肯定有落差。就像你一直开自动挡,突然让你开手动挡,肯定要熄火几次。
QAT的做法是:在训练的前向传播中,插入一些“伪量化节点”,让模型提前感受INT8的精度限制。这样训练出来的模型,到了推理阶段转INT8,就不会那么“水土不服”了。
我遇到过这样一个项目:一个图像分类模型,PTQ后精度掉了2.3个点,怎么调都回不去。后来换成QAT,只用了3个epoch的微调,精度损失就降到了0.4%。嗯,这就是“让模型提前适应”的力量。
伪量化节点(FakeQuant)
伪量化节点,英文叫FakeQuant,是QAT中最核心的组件。它到底干了什么?
说白了,FakeQuant就是一个“模拟器”。它在FP32的数值上,模拟了量化-反量化的完整过程:
# 伪量化的数学过程
# 1. 量化:将FP32映射到INT8
q = round(clamp(x / scale + zero_point, q_min, q_max))
# 2. 反量化:将INT8映射回FP32
x_hat = (q - zero_point) * scale
# 输出:x_hat 仍然是FP32,但已经包含了量化误差
注意看,FakeQuant的输入和输出都是FP32。它只是在中间走了一个“量化-反量化”的流程,把量化误差注入到前向传播中。这样反向传播时,梯度就能感知到量化带来的影响。
关键点:FakeQuant在反向传播时,使用直通估计器(STE)来处理round函数的梯度。简单说就是:round函数的梯度近似为1,让梯度能顺利回传。这是QAT能工作的数学基础。
QAT训练流程
QAT的训练流程,我一般分三步走。每一步都有它的讲究:
- 预训练一个FP32模型:先用常规方法训练一个高精度的FP32模型。这一步不能省,底子要打好。
- 插入FakeQuant节点:在模型的权重和激活值后面,都插入FakeQuant节点。注意,不是所有层都需要量化。比如第一层和最后一层,我建议保留FP32,否则精度损失会很大。
- 微调训练:用较小的学习率(通常是原学习率的1/10到1/100),继续训练几个epoch。让模型学会在量化误差下保持精度。
这里有个坑,我曾经踩过:微调时学习率设太大,结果模型直接崩了,精度比PTQ还差。后来我学乖了,学习率从1e-5开始,慢慢往上调。
我的建议:QAT的微调epoch数不用太多,3-5个epoch通常就够了。太多反而可能过拟合。我一般会在验证集上监控精度,一旦精度不再提升就停止。
BN折叠技术
BN折叠,这是QAT中一个容易被忽视但极其重要的技术。为什么需要它?
你想想看,训练时BN层是独立存在的,但推理时BN层会被融合到卷积层中。如果不做处理,QAT训练出来的模型,在推理时BN的参数和量化参数之间会产生不匹配。
BN折叠的做法是:在QAT训练之前,先把BN层的参数“折叠”进卷积层的权重和偏置中。这样训练时就不再有独立的BN层,而是直接训练“卷积+BN”的等效参数。
# BN折叠的数学原理
# 原始卷积+BN:
# y = gamma * (conv(x) - mu) / sqrt(var + eps) + beta
# 折叠后:
# w_folded = gamma * w / sqrt(var + eps)
# b_folded = gamma * (b - mu) / sqrt(var + eps) + beta
# 这样,前向传播就变成了:
# y = conv_folded(x) # 不再需要BN层
我刚开始做QAT时,没做BN折叠,结果模型在训练集上精度很好,一到推理就崩。查了两天才发现是BN的问题。从那以后,BN折叠就成了我QAT流程中的标配。
注意:BN折叠后,模型的训练和推理行为会更一致。但折叠后的模型,不能再使用原始的BN更新方式。所以一般是在FP32预训练完成后,先做BN折叠,再插入FakeQuant节点,最后进行QAT微调。
总结一下
QAT的核心就三件事:
- FakeQuant节点:模拟量化误差,让模型提前适应
- 微调训练:用低学习率让模型学会在INT8下工作
- BN折叠:消除训练和推理之间的行为差异
说实话,QAT比PTQ麻烦不少,需要更多的调参和训练时间。但当你遇到PTQ搞不定的场景时,QAT往往能给你惊喜。我个人习惯是:先试PTQ,如果精度损失超过1%,再上QAT。这样既省时间,又能保证效果。
下一章,咱们聊聊TensorRT的实战部署。到时候我会拿一个完整的模型,从PTQ到QAT,再到TensorRT加速,走一遍完整的流程。敬请期待。