修复策略总览:量化感知训练、部分量化、混合精度与校准优化

模型量化后精度掉了,怎么办?

别慌。这几乎是每个做量化的工程师都会遇到的坎。我刚开始接触量化时,也天真地以为跑完校准就万事大吉,结果模型精度直接掉了 5 个点,被业务方追着问了一周。

后来我总结出一套修复策略。说白了,就是四个方向:量化感知训练(QAT)、部分量化、混合精度量化、校准数据集优化。今天我把它们掰开揉碎讲清楚。

核心观点:没有万能药。修复策略的选择取决于你的模型结构、精度损失程度、以及部署硬件的支持情况。
量化精度损失修复策略总览 精度损失修复策略 量化感知训练 部分量化 混合精度量化 校准数据集优化 插入伪量化节点 反向传播模拟 敏感层保留 FP32 逐层精度评估 权重 FP16 + 激活 INT8 按算子粒度混合 数据分布对齐 样本多样性 实际项目中,这四种策略经常组合使用。比如:先用校准数据集优化,再对敏感层做混合精度。

1. 量化感知训练(QAT)

QAT 是目前修复精度最有效的手段之一。它的思路很简单:在训练过程中模拟量化误差,让模型自己学会适应。

具体做法是在计算图中插入伪量化节点(Fake Quantize Node)。前向传播时,这些节点模拟 INT8 的舍入和截断行为;反向传播时,梯度仍然用浮点精度更新。这样模型在训练中就「见过」量化噪声了,部署时切换到真实量化,精度损失会小很多。

我的经验:QAT 不是从头训练。通常的做法是:先浮点预训练 → 加载预训练权重 → 插入伪量化节点 → 用较小学习率(1e-5 到 1e-6)微调几个 epoch。微调太多反而会过拟合。

我曾经在一个语义分割模型上试过,直接 PTQ 后 mIoU 掉了 4.2%。用 QAT 微调了 3 个 epoch,精度只掉了 0.3%。效果很明显,但代价是训练时间增加了。

# PyTorch 中启用 QAT 的典型流程
import torch.quantization as quant

# 准备模型
model = MyModel()
model.load_state_dict(torch.load('float_model.pth'))
model.train()

# 插入伪量化节点
model.qconfig = quant.get_default_qat_qconfig('fbgemm')
quant.prepare_qat(model, inplace=True)

# 微调
for epoch in range(3):
    for data, target in train_loader:
        optimizer.zero_grad()
        output = model(data)
        loss = criterion(output, target)
        loss.backward()
        optimizer.step()

# 转换为量化模型
model.eval()
quant.convert(model, inplace=True)
注意:QAT 需要训练数据和计算资源。如果你的模型已经部署上线,没有训练环境,那这条路就走不通了。这时候可以考虑后面的策略。

2. 部分量化(Partial Quantization)

不是所有层都对量化敏感。有些层量化后精度几乎不变,有些层一量化就崩。部分量化的思路就是:只量化那些「皮实」的层,敏感层保留浮点。

怎么找敏感层?我一般用两种方法:

  • 逐层精度分析:每次只量化一个层,观察精度变化。变化大的就是敏感层。
  • 激活值分布检查:如果某层的激活值分布特别宽(比如范围超过 [-10, 10]),量化后信息损失会很大。

我记得有一次做 NLP 模型量化,Embedding 层量化后精度直接崩了。后来我把 Embedding 层单独保留 FP32,其他层全部 INT8,精度几乎无损。

层类型 量化敏感度 建议策略
Conv2d(深度可分离) 低 可量化
Linear(全连接) 中 视情况量化
Embedding 高 建议保留 FP32
BatchNorm 低 可量化
LayerNorm 高 建议保留 FP32
Attention(Softmax 附近) 高 建议保留 FP32

3. 混合精度量化(Mixed Precision)

混合精度和部分量化有点像,但更细粒度。部分量化是「层级别」的,混合精度可以做到算子级别甚至通道级别。

举个例子:一个 Conv2d 层,权重用 INT8,激活用 INT16,或者权重用 FP16,激活用 INT8。不同硬件支持的混合精度组合不一样。

我建议你优先关注权重和激活的位宽组合:

  • W8A8:标准 INT8 量化,大部分硬件支持。
  • W4A8:权重用 INT4,激活用 INT8。适合存储受限的场景。
  • W8A16:权重 INT8,激活 INT16。适合激活值分布宽的模型。
  • FP16 + INT8:权重 FP16,激活 INT8。某些 GPU 上效率很高。
关键点:混合精度的难点在于硬件支持。不是所有芯片都支持 W4A8 或 W8A16。选策略前,先查清楚目标硬件的量化指令集。

4. 校准数据集优化

这个策略最容易被忽略,但往往成本最低、效果最明显。

校准数据集是用来确定量化参数(scale 和 zero_point)的。如果校准数据分布和真实数据分布不一致,量化参数就会偏,精度自然掉。

我踩过这个坑。有一次做图像分类量化,用了 500 张 ImageNet 验证集做校准,精度掉了 2%。后来换成 2000 张训练集,精度只掉了 0.5%。

优化校准数据集,我总结了三条原则:

  1. 样本量要够:一般建议 500-2000 张,太少统计不稳定。
  2. 覆盖所有类别:每个类别至少 10-20 张,避免分布偏移。
  3. 包含边界样本:比如低光照、高噪声、极端角度。这些样本能拉大量化范围,减少截断误差。
一个小技巧:如果校准后精度不理想,可以尝试用 KL 散度或 MSE 来评估校准集和验证集的数据分布差异。差异大的话,优先调整校准集。

策略对比与选择

四种策略各有适用场景。我整理了一张对比表,方便你快速决策:

策略 精度修复效果 实施成本 适用场景
量化感知训练(QAT) ★★★★★ 高(需要训练) 有训练环境,精度要求极高
部分量化 ★★★★ 中(需要逐层分析) 模型结构复杂,部分层敏感
混合精度量化 ★★★★ 中高(依赖硬件) 硬件支持混合精度指令
校准数据集优化 ★★★ 低(只需换数据) 校准集分布偏差大

实际项目中,我通常的流程是:先优化校准数据集(成本最低),如果精度还不够,再做逐层分析找敏感层(部分量化),最后才考虑 QAT。混合精度量化一般放在硬件适配阶段做。

避坑提醒:我曾经在一个项目中,花了两周调 QAT 参数,精度死活上不去。后来发现是校准集里混入了 30% 的噪声样本。换掉校准集后,精度直接恢复。所以,先检查数据,再调模型。

好了,这四种策略的框架就讲到这里。后面几章我会逐一深入,带你看代码实现和实际案例。记住,修复精度损失不是一锤子买卖,而是一个迭代过程。多试、多对比、多记录,慢慢你就有感觉了。