4. 模型量化原理(下):量化感知训练(QAT)与训练后量化(PTQ)实战对比

上一节我们把量化的数学原理和对称/非对称这些基础概念讲透了。今天咱们直接上硬菜——两种主流量化方案的实战对比。说白了,就是回答一个问题:我到底该用PTQ还是QAT?

我个人习惯是,先跑PTQ看看效果。如果精度掉得不多,那就直接用PTQ,省时省力。但如果模型对精度特别敏感,比如人脸识别或者自动驾驶场景,那QAT几乎是绕不开的。嗯,咱们一步步来看。

4.1 训练后量化(PTQ):拿来就用的“快刀手”

PTQ的全称是Post-Training Quantization,翻译过来就是“训练完了再量化”。你模型已经训好了,权重都固定了,我直接拿过来做量化校准。这就像你做好了一锅汤,出锅前再调个味。

PTQ的核心流程:

  1. 加载预训练好的浮点模型(FP32)
  2. 准备一小批校准数据(通常几百张图片就够了)
  3. 跑一遍前向推理,统计每一层激活值的分布
  4. 根据统计结果计算量化参数(scale和zero_point)
  5. 把权重和激活值都量化到INT8

我在项目中遇到过最典型的场景:一个分类模型,FP32精度92.3%,直接PTQ量化到INT8后精度掉到了91.8%。只掉了0.5个点,但推理速度翻了将近3倍。这种收益,你说香不香?

关键点:PTQ不需要重新训练模型,也不需要访问原始训练数据(只需要少量校准数据)。这是它最大的优势。

4.2 量化感知训练(QAT):精度保卫战的“终极武器”

QAT就不一样了。它是在训练过程中就“模拟”量化效果,让模型自己去适应量化带来的精度损失。说白了,就是让模型提前知道“我以后要被量化了,你们各层都给我悠着点”。

QAT的核心流程:

  1. 在浮点模型中插入伪量化节点(FakeQuantize)
  2. 用原始训练数据继续训练(通常是微调几个epoch)
  3. 训练过程中,前向传播走量化路径,反向传播走浮点路径
  4. 训练完成后,移除伪量化节点,导出真正的INT8模型

这里有个细节很多人会忽略:QAT训练时,权重更新用的是浮点梯度,但前向计算用的是量化后的值。这个“伪量化”操作,说白了就是在前向时把浮点数先量化再反量化,模拟出量化误差。

我的经验:QAT一般只需要微调3-5个epoch就够了。我曾经试过一个BERT模型,PTQ掉精度2.3%,QAT微调4个epoch后,精度只掉了0.4%。这个差距在工业界就是“能用”和“不能用”的区别。

4.3 实战对比:PTQ vs QAT,到底选哪个?

咱们直接上表格,一目了然。

对比维度 PTQ(训练后量化) QAT(量化感知训练)
是否需要训练 不需要 需要微调
是否需要原始训练数据 仅需少量校准数据 需要完整训练数据
精度损失 通常0.5%~2% 通常0.1%~0.5%
部署时间 几分钟到几小时 几小时到几天
适用场景 大模型、精度不敏感任务 小模型、精度敏感任务
实现复杂度 中高

你想想看,如果你的模型有10亿参数,跑一次PTQ可能只需要1小时。但跑一次QAT,光数据加载和训练就得花好几天。所以我的建议是:先PTQ,精度达标就用PTQ;不达标再上QAT。

4.4 代码实战:用PyTorch实现PTQ和QAT

光说不练假把式。咱们直接上代码,看看PTQ和QAT在PyTorch里到底怎么实现。

4.4.1 PTQ实现(训练后量化)

import torch
import torch.quantization as quant

# 加载预训练模型(FP32)
model = torch.load('resnet18_fp32.pth')
model.eval()

# 配置量化后端
model.qconfig = quant.get_default_qconfig('fbgemm')

# 准备量化(插入观察器)
model_prepared = quant.prepare(model, inplace=False)

# 用校准数据跑一遍前向(这里用dummy数据演示)
with torch.no_grad():
    for i in range(100):
        dummy_input = torch.randn(1, 3, 224, 224)
        model_prepared(dummy_input)

# 真正执行量化
model_quantized = quant.convert(model_prepared, inplace=False)

# 保存INT8模型
torch.save(model_quantized.state_dict(), 'resnet18_int8_ptq.pth')
print("PTQ量化完成!")

这段代码看着简单,但有个坑:校准数据一定要有代表性。我曾经见过有人用随机噪声做校准,结果量化后精度直接崩了。校准数据最好是从验证集里随机抽的,能覆盖模型常见的输入分布。

4.4.2 QAT实现(量化感知训练)

import torch
import torch.quantization as quant

# 加载预训练模型
model = torch.load('resnet18_fp32.pth')
model.train()

# 配置QAT
model.qconfig = quant.get_default_qat_qconfig('fbgemm')

# 准备QAT(插入伪量化节点)
model_prepared = quant.prepare_qat(model, inplace=False)

# 继续微调(通常3-5个epoch)
optimizer = torch.optim.SGD(model_prepared.parameters(), lr=1e-4)
criterion = torch.nn.CrossEntropyLoss()

for epoch in range(5):
    for images, labels in train_loader:
        optimizer.zero_grad()
        outputs = model_prepared(images)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()
    print(f"Epoch {epoch+1} 完成")

# 训练完成后,转换为INT8模型
model_prepared.eval()
model_quantized = quant.convert(model_prepared, inplace=False)

# 保存
torch.save(model_quantized.state_dict(), 'resnet18_int8_qat.pth')
print("QAT量化完成!")

避坑指南:我曾经在QAT训练时忘记把模型切换到train模式,结果伪量化节点没生效,微调了10个epoch精度一点没变。记住:QAT训练时用model.train(),转换时用model.eval()。

4.5 核心知识体系:一张图看懂量化方案选择

下面这张图是我自己总结的量化方案选择决策树,帮你快速判断该用PTQ还是QAT。

量化方案选择决策树 FP32模型 先跑PTQ,看精度是否达标 精度达标 ✅ 直接用PTQ,快速部署 精度不达标 ❌ 考虑上QAT 使用QAT微调3-5个epoch 精度通常可恢复至接近FP32 INT8模型部署 INT8模型部署 建议:先PTQ后QAT,用最小成本换取最大收益

4.6 实战中的“坑”与“避坑指南”

做量化部署这么多年,我踩过的坑比走过的路还多。挑几个典型的说说。

  • 校准数据太少:PTQ时我只用了10张图片做校准,结果量化后模型直接“失明”了。后来改成500张,效果立马正常。建议至少用几百张有代表性的数据。
  • QAT学习率太大:我一开始用1e-3的学习率做QAT微调,结果模型直接训飞了。QAT的学习率一般要比原始训练小10倍,1e-4到1e-5比较稳妥。
  • 忽略BN层融合:量化前一定要把BN层和卷积层融合,否则量化误差会放大。PyTorch的torch.quantization.fuse_modules可以帮你做这个。
  • 硬件差异:同一个INT8模型,在x86上用fbgemm后端,在ARM上用qnnpack后端,精度表现可能不一样。部署前一定要在目标硬件上验证。

我的小技巧:如果你不确定该用PTQ还是QAT,可以先用PTQ跑一遍,然后对比FP32和INT8的精度。如果精度差在1%以内,PTQ就够了。如果超过2%,建议上QAT。这个“1%阈值”是我在多个项目中总结出来的经验值,你可以根据自己的业务场景调整。

4.7 总结:量化不是银弹,但它是性价比最高的优化手段

PTQ和QAT,一个快但精度略低,一个慢但精度高。没有绝对的好坏,只有合不合适的场景。

我个人建议的落地路径是:先PTQ快速验证,精度达标就收工;不达标再上QAT微调。这样既不会在PTQ上浪费太多时间,也不会一上来就投入QAT的高成本。

量化这件事,说白了就是用一点点精度损失,换取数倍的推理加速和内存节省。在AI芯片部署的实战中,这几乎是性价比最高的优化手段了。

核心要点回顾:

  • PTQ:不需要训练,仅需校准数据,速度快,精度损失0.5%~2%
  • QAT:需要微调,精度损失0.1%~0.5%,适合精度敏感场景
  • 先PTQ后QAT,用最小成本换取最大收益
  • 校准数据要有代表性,QAT学习率要调小
专注资料整理