4、训练后量化(PTQ)与量化感知训练(QAT)对比:原理、优缺点、适用场景
在TinyML工作流中,将浮点模型转换为INT8模型是部署到MCU、NPU或低功耗DSP的必经之路。然而,“如何做量化”直接决定了模型体积、推理速度和精度损失。目前业界主流的两条路径分别是训练后量化(Post-Training Quantization, PTQ)和量化感知训练(Quantization-Aware Training, QAT)。两者并非替代关系,而是针对不同项目约束(数据可得性、时间成本、精度敏感度)的工程权衡。本章将从原理、优缺点、适用场景三个维度展开对比,并给出选型决策框架。
上图展示了PTQ与QAT在工程链路中的位置差异:PTQ是“事后转换”,QAT是“训练中模拟”。核心区别在于:PTQ不修改权重,仅通过校准数据确定量化参数;QAT则在训练过程中让网络“适应”量化误差,从而获得更鲁棒的权重分布。下面逐一展开。
4.1 核心原理:PTQ的静态校准与QAT的伪量化模拟
PTQ(训练后量化)的原理非常直接:给定一个已经收敛的浮点模型,使用一小部分代表性数据(通常为训练集的子集,约100~500个样本)作为“校准集”,前向推理时统计每一层激活值的数值范围(min/max、百分位或KL散度),从而确定每个张量的缩放因子(scale)和零点(zero-point)。权重则直接根据其数值范围进行对称或非对称量化。整个过程不进行反向传播,因此计算开销极小,通常几分钟内即可完成。
QAT(量化感知训练)则是在训练阶段就“欺骗”网络:在计算图中插入伪量化节点(FakeQuant),前向传播时对权重和激活执行“量化-反量化”操作(即先量化到INT8再还原为浮点),使得梯度能够通过直通估计器(STE, Straight-Through Estimator)反向传播。这样,网络在更新权重时就会“感知”到量化带来的舍入误差,并主动调整权重分布,使得最终量化后的精度损失最小化。
4.2 优缺点对比:精度、成本、部署灵活性
| 对比维度 | PTQ(训练后量化) | QAT(量化感知训练) |
|---|---|---|
| 精度保持 | 大模型(>10M参数)通常损失 <1%;小模型(<1M参数)可能损失 2~5% | 通常损失 <0.5%,甚至无损;对极小模型(如MobileNetV1)也能保持 >98% 精度 |
| 所需数据 | 仅需少量校准数据(无需标签) | 需要完整带标签训练集,且需重新训练 |
| 计算成本 | CPU上几分钟完成,无需GPU | 需要GPU训练,耗时数小时至数天(取决于模型大小) |
| 实现复杂度 | 调用现成API(如TensorFlow Lite Converter、PyTorch FX)即可 | 需修改训练代码,插入伪量化模块,调整学习率策略 |
| 部署灵活性 | 可随时对任意已训练模型进行量化,无需原始训练环境 | 必须保留训练脚本和数据集,且量化参数与训练绑定 |
| 硬件适配 | 对不支持某些算子的硬件,可回退到浮点层 | 伪量化节点需与目标推理库(如CMSIS-NN、TFLM)对齐 |
从表中可以看出,PTQ的核心优势是“快、省、简单”,但精度风险较高;QAT的核心优势是“准、稳”,但代价是训练资源和时间。实际项目中,通常先尝试PTQ,若精度不达标再升级到QAT。
4.3 案例拆解:关键词唤醒模型(KWS)的量化实战
我们以一个典型的TinyML场景——关键词唤醒(KWS)模型为例,说明PTQ与QAT的选型过程。该模型基于DS-CNN(Depthwise Separable CNN),参数量约40K,输入为40维MFCC特征(时间帧×频带),部署在Cortex-M4F MCU上,Flash预算为100KB,RAM预算为30KB。
初始现象与目标:浮点模型在测试集上准确率为94.2%。目标是将模型量化到INT8后,准确率不低于92.5%(即损失不超过1.7个百分点)。
第一步:PTQ尝试。使用500张无标签校准数据(从训练集随机抽取),采用per-tensor量化(权重和激活均使用对称量化)。转换后模型大小为38KB,Flash占用达标。但在测试集上准确率降至89.6%,损失4.6个百分点,远超目标。
第二步:PTQ调优。将权重改为per-channel量化(每个输出通道独立scale),激活仍为per-tensor。准确率回升至91.8%,仍差0.7个百分点。进一步尝试使用KL散度校准方法(而非min/max),激活分布拟合更准确,准确率提升至92.1%,但依然未达92.5%的阈值。
第三步:QAT升级。由于PTQ已接近目标但未达标,且我们有完整的带标签训练集(约10万条语音),决定采用QAT。具体操作如下:
# 伪代码:QAT训练流程(PyTorch风格)
model = load_pretrained_fp32_model()
qat_model = prepare_qat(model, quant_config) # 插入FakeQuant节点
optimizer = SGD(qat_model.parameters(), lr=1e-4, momentum=0.9)
for epoch in range(10):
for batch in train_loader:
optimizer.zero_grad()
output = qat_model(batch)
loss = cross_entropy(output, label)
loss.backward()
optimizer.step()
# 每2个epoch降低学习率
if epoch % 2 == 0:
scheduler.step()
# 导出INT8模型
converted_model = convert(qat_model, backend='tflite-micro')
训练10个epoch后,QAT模型的INT8量化准确率达到93.8%,超过92.5%的目标。最终部署模型Flash占用36KB,RAM占用24KB,推理延迟从浮点的12ms降至INT8的4.2ms。
风险与代价:QAT训练耗时约3小时(单张GPU),且需要维护训练脚本。此外,QAT训练时使用的学习率必须比正常训练低(通常为原学习率的1/10~1/100),否则权重更新过大导致量化误差放大。
4.4 适用场景与选型决策框架
根据上述原理和案例,我们可以总结出清晰的选型规则:
- 优先选择PTQ的场景:① 模型参数量大于5M;② 只有少量无标签数据;③ 项目周期短(1~2天);④ 硬件支持per-channel量化;⑤ 精度损失容忍度在2%以内。
- 必须选择QAT的场景:① 模型参数量小于500K;② 对精度要求极高(损失<1%);③ 部署的硬件对量化算子支持不完善(如不支持per-channel);④ 有完整的训练pipeline和GPU资源。
- 混合策略:先PTQ快速评估,若精度损失在1%~3%之间,可尝试“部分QAT”——仅对敏感层(如第一层和最后一层)进行量化感知训练,其余层保持PTQ。这能节省约70%的训练时间。
最后,无论选择哪种路径,都必须在目标硬件上做端到端验证。因为不同推理库(TFLite Micro、CMSIS-NN、Glow)对量化算子的实现细节不同,可能导致精度差异。建议在选型时预留20%的精度余量,以应对硬件实现的微小偏差。