深度学习量化双雄:PTQ 与 QAT 的技术剖析与实战
深度学习量化双雄:PTQ 与 QAT 的技术剖析与实战
写给想把 FP32 模型卷成 INT8 又不掉精度的你。
1 量化的动机
- 体积:FP32 → INT8,模型大小 ×4 倍压缩
- 带宽:内存/显存占用 ×4 倍降低
- 算力:INT8 Tensor Core 峰值 ×4 倍提升
一句话:量化 ≈ 免费午餐。
2 训练后量化(PTQ)
2.1 原理
- 在校准集上跑一次前向,统计 权重/激活 的 min/max(或 99.9 % percentile)。
- 按公式计算 scale 与 zero-point
对称量化(权重常见):
非对称量化(激活常见):scale = max(|w|) / 127 zero_point = 0
scale = (max - min) / 255 zero_point = round(-min / scale)
- 将 scale/zero-point 写入引擎,推理时作为 常量乘子 直接吸收进 kernel,无额外计算。
2.2 粒度
对象 | 推荐粒度 | scale 个数 |
---|---|---|
权重 | per-channel(每输出通道) | OC |
激活 | per-tensor(整张特征图) | 1 |
2.3 一键脚本
trtexec --onnx=model.onnx --int8 \--calibDataDir=./calib_imgs \--saveEngine=model_int8.engine
calib_imgs/
只需原始图片,无标签。- 10 分钟生成可部署引擎。
2.4 优缺点
- ✅ 零训练、零侵入
- ❌ 精度损失 1–3 %,对异常值敏感
3 量化感知训练(QAT)
3.1 原理
在训练图里插入 FakeQuant 节点
w_q = round(clip(w / scale)) * scale
- 前向:模拟量化误差
- 反向:STE 把梯度直接传给 FP32 权重,让网络学会“抗量化”的位置。
3.2 粒度
- 默认:权重 per-channel,激活 per-tensor
- 最新研究:scale/zero-point 亦可 可学习参数,端到端更新。
3.3 PyTorch 30 行示例
import torch, torchvision, torch.quantization as tqmodel = torchvision.models.resnet18(pretrained=True)
model.train()
tq.prepare_qat(model, qconfig=tq.get_default_qat_qconfig('fbgemm'))opt = torch.optim.AdamW(model.parameters(), 1e-4)
for x, y in train_loader:loss(model(x), y).backward()opt.step()torch.jit.save(tq.convert(model.eval()), 'qat.pt')
- 额外训练 1–5 epoch
- 精度损失 <0.5 %
3.4 优缺点
- ✅ 精度几乎无损,支持 4-bit 超低比特
- ❌ 需完整训练集和 GPU 时间
4 选型建议
场景 | 推荐 |
---|---|
模型已训练好,精度要求不苛刻 | PTQ |
精度敏感,可接受再训练 | QAT |
正在训练新模型 | 直接 QAT |
5 技术小结
- scale/zero-point 是编译期常数,推理时 无额外延迟
- PTQ 先上车,QAT 再精雕
量化不再是黑魔法,而是标准化流水线。