4. 量化方法
聊到具体怎么下手做量化,你会发现市面上就两条主流路:训练后量化(PTQ)和量化感知训练(QAT)。说白了,一个是对训练好的模型直接动手,另一个是让模型在训练过程中就学会适应低精度。
我刚开始接触量化那会儿,也觉得QAT听起来更高级,肯定效果更好。但实际项目做多了才发现——没有银弹。选哪个,完全看你的场景、资源和容忍度。
一句话总结:PTQ是快刀斩乱麻,QAT是慢工出细活。前者适合快速部署,后者适合精度敏感场景。
4.1 训练后量化(PTQ)—— 拿来就用
PTQ的思路很直接:模型已经训练好了,我拿一小部分数据跑一遍推理,统计出每层激活值和权重的分布范围,然后算出缩放因子和零点,直接完成量化。
你想想看,这就像你做好了一锅汤,出锅前尝一口,觉得咸淡刚好,然后直接分装。整个过程不需要重新开火。
我的经验:PTQ最爽的地方在于——你不需要原始训练代码,不需要训练环境,甚至不需要懂模型内部结构。拿一个ONNX或Caffe模型,跑几百张图片的校准集,半小时就能出量化结果。
PTQ的核心步骤
- 准备校准数据集——通常几百到几千张样本,覆盖典型场景即可
- 前向传播收集统计量——记录每层激活值的min/max或直方图
- 计算量化参数——根据统计量确定scale和zero_point
- 转换权重和激活——将浮点数值映射到INT8/INT4
- 验证精度——对比量化前后的指标差异
这里有个关键点:校准数据集的质量直接影响量化效果。我在一个安防项目里踩过坑——用了1000张白天场景的图片做校准,结果模型在夜间场景下精度直接掉了5个点。后来把校准集改成白天黑夜各一半,问题就解决了。
PTQ的优缺点
| 优势 | 劣势 |
|---|---|
| 无需训练,部署极快 | 大模型或小模型精度损失可能较大 |
| 不需要原始训练数据(少量校准数据即可) | 对异常值敏感,分布偏移时效果差 |
| 计算资源要求低,CPU都能跑 | 无法恢复因量化丢失的信息 |
| 适合快速迭代和实验 | 某些层(如Depthwise Conv)量化后精度下降明显 |
注意:PTQ不是万能的。我曾经在MobileNetV3上做PTQ,INT8量化后精度掉了3%。后来换成QAT,精度只掉了0.5%。如果你的模型本身就很紧凑(比如轻量级网络),PTQ可能hold不住。
4.2 量化感知训练(QAT)—— 让模型学会适应
QAT的思路完全不同。它在训练过程中就模拟了量化行为——在模型里插入伪量化节点(Fake Quantize Node),前向传播时把浮点值量化再反量化,让模型在反向传播时感知到量化误差,从而调整权重去适应这种精度损失。
说白了,就是让模型在娘胎里就学会怎么在低精度下好好干活。
QAT的工作流程
- 加载预训练浮点模型
- 在关键位置插入伪量化节点——通常在权重和激活之后
- 使用原始训练数据继续训练——通常需要几个epoch的微调
- 冻结量化参数——训练完成后固定scale和zero_point
- 移除伪量化节点,导出INT8模型
这里有个细节:QAT训练时用的学习率要比正常训练小很多。我一般设置成原始学习率的1/10到1/100,不然模型容易震荡。
伪量化节点到底干了什么?
伪量化节点做的事情很简单:
# 伪量化操作示意
def fake_quantize(x, scale, zero_point, bit_width=8):
# 量化
x_int = torch.round(x / scale + zero_point)
# 钳制到有效范围
x_int = torch.clamp(x_int, 0, 2**bit_width - 1)
# 反量化(模拟量化后的精度损失)
x_fake = (x_int - zero_point) * scale
return x_fake
你看,前向传播时它做了量化再反量化,引入了量化误差。但反向传播时,它用的是直通估计器(STE)——直接把梯度传过去,忽略量化操作的不可导性。这样模型就能正常更新权重了。
我的习惯:QAT微调时,我会先用PTQ跑一遍,看看哪些层精度掉得厉害。然后针对这些层单独调整量化配置,或者给它们分配更多的比特数。这样比全模型QAT更高效。
4.3 PTQ vs QAT:怎么选?
这个问题没有标准答案。我根据项目经验总结了一个决策矩阵:
| 场景 | 推荐方法 | 原因 |
|---|---|---|
| 快速原型验证 | PTQ | 几分钟出结果,够用就行 |
| 大模型(ResNet-50以上) | PTQ | 模型冗余度高,量化损失小 |
| 轻量级模型(MobileNet、SqueezeNet) | QAT | 模型紧凑,PTQ容易崩 |
| 精度要求极高(医疗、金融) | QAT | 能多挽回0.5%就值得 |
| 没有训练数据/训练环境 | PTQ | QAT需要完整训练流程 |
| 部署到边缘设备(INT4/混合精度) | QAT | 低比特量化PTQ几乎不可用 |
我个人习惯是:先PTQ,再决定要不要QAT。PTQ如果精度损失在可接受范围内(比如1%以内),那就直接用PTQ,省时省力。如果PTQ掉点太多,再上QAT。
一个真实案例:去年我做一个人脸识别模型,ResNet-50 backbone,PTQ后精度掉了0.8%,客户能接受,直接上线。但另一个项目是MobileNetV2做手势识别,PTQ后精度掉了4.2%,完全不能用。后来用QAT微调了3个epoch,精度恢复到只掉0.3%。
4.4 混合方案:PTQ + 部分QAT
有没有折中方案?有。我经常用的一种策略是:
- 大部分层用PTQ——快速搞定
- 敏感层用QAT微调——针对性修复
怎么找敏感层?很简单:逐层做PTQ,看哪一层量化后精度掉得最多。然后只对这些层做QAT微调,其他层保持PTQ结果。
这样做的好处是:训练时间只有全QAT的1/5,但精度恢复效果接近全QAT的80%。我在好几个项目里都用这招,效果不错。
避坑指南:我曾经在一个项目里偷懒,PTQ后精度掉了2%,我觉得还行就直接部署了。结果上线后用户反馈在某些场景下识别率明显下降。后来排查发现,那些场景的数据分布和校准集差异很大。所以——校准集一定要覆盖真实部署场景,不然PTQ就是自欺欺人。
4.5 小结
PTQ和QAT不是对立关系,而是工具链上的两个选项。PTQ是快车道,适合大多数场景;QAT是精细活,适合精度敏感或低比特场景。我的建议是:先跑PTQ,看结果,再决定要不要上QAT。别一上来就QAT,那是在浪费算力。