💡 6. 量化方法分类
大模型的量化方法主要分为两个大类:
✅ 6.1 训练后量化(Post-Training Quantization, PTQ)
📌 定义:
PTQ 是指在模型 训练完成后,直接对其参数(权重和激活值)进行量化处理,不再参与额外训练。
📌 特点:
- 无需重新训练 → 操作简单、效率高
- 风险在于:模型在训练时并未考虑量化误差
- 一般适合 8位量化(INT8)或高精度量化场景
📊 PTQ 两种主要形式:
① 静态量化(Static Quantization)
- 所需信息:
- 模型权重
- 一小部分代表性的 校准数据集
- 实施流程:
- 校准集输入模型
- 收集激活值分布
- 离线计算比例因子(scale)和零点(zero-point)
- 生成固定量化参数,部署时直接使用
- ✅ 优势:执行时无需再做计算,效率高
- ⚠️ 缺点:量化误差不易自适应处理,精度可能略低
② 动态量化(Dynamic Quantization)
- 所需信息:
- 模型权重
- 推理时动态输入
- 实施流程:
- 每当有新输入传入模型
- 实时根据该 batch 的激活值动态计算 scale 和 zero-point
- ✅ 优势:精度通常比静态高,尤其适合动态输入变化大的模型(如 LLM)
- ⚠️ 缺点:每个 batch 需计算,推理时开销略高
🔍 对比总结:
方面 | 静态量化 | 动态量化 |
---|---|---|
激活值处理 | 使用校准集离线计算参数 | 实时根据输入动态计算 |
精度 | 稍低 | 更高 |
计算开销 | 更低,推理快 | 略高,推理需实时计算 |
应用场景 | 移动端、嵌入式设备等 | LLM、对话系统等复杂模型 |
✅ 6.2 量化感知训练(Quantization-Aware Training, QAT)
📌 定义:
QAT 是在训练/微调阶段,就引入“伪量化”模块,让模型提前“感知”量化所带来的误差,从而学习对这种误差的鲁棒性。
🧠 核心机制:
- 前向传播时将 FP32 模拟量化为 INTx(如 INT4)
- 反向传播仍使用 FP32 进行梯度更新
- 训练中加入 scale / zero-point 的学习
📌 特点:
- 损失函数中真实考虑了量化误差
- 精度优于 PTQ,尤其在低位宽(如 INT4)下表现更稳定
- 适用于对精度要求极高的部署场景
🔁 举个流程例子:
[Step 1] FP32权重 → 伪量化为INT4 → 前向传播
[Step 2] 模拟量化误差 → 反向传播更新参数
[Step 3] 权重渐渐适应INT4表示 → 精度损失变小
📌 示例图:
原始训练: FP32 → 推理INT4,性能下降
QAT训练: 模拟INT4 → 模型学会适应INT4 → 精度维持
✅ 优势:
- 精度高,尤其适用于 4位及以下 的极限量化
- 抗量化误差能力强
⚠️ 缺点:
- 增加训练/微调开销
- 实施更复杂(需要支持 QAT 的框架)
📌 总体对比总结:
方法类型 | 是否需要重新训练 | 精度表现 | 实施难度 | 适用位宽 | 典型应用 |
---|---|---|---|---|---|
PTQ(静态) | 否 | 中等 | 简单 | INT8 | 移动端模型压缩 |
PTQ(动态) | 否 | 中上 | 中等 | INT8 | LLM 推理部署 |
QAT | 是 | 最佳 | 较高 | INT4 及以下 | 高端设备、低精度部署 |
✨ 总结一句话:
PTQ 简单快捷、适合部署,而 QAT 精度更强、适合极低位宽模型的真实上线。
太好了,你现在已经掌握了很多量化基础!那我们来深入讲解 ✅ 6.2 量化感知训练(QAT) 的详细 流程与关键原理,从 动机 到 核心组件,再到 训练细节 和 部署方式,一次讲透 💡
✅ 什么是 QAT(Quantization-Aware Training)?
QAT 是在模型训练或微调阶段引入“伪量化(Fake Quantization)”操作,使模型在训练过程中提前**“感知”量化误差**,从而提升其在推理阶段的低精度表现能力(如 INT8、INT4)。
🚀 为什么需要 QAT?
问题 | QAT 解决方案 |
---|---|
PTQ 忽略量化误差,精度下降 | QAT 把误差纳入训练目标 |
INT4/INT2 精度损失太大 | QAT 更鲁棒,更适配低比特部署 |
激活值分布难以建模 | QAT 训练时自动学习出稳定特征 |
🔁 QAT 的整体流程(图示 + 步骤)
步骤概览:
┌────────────┐
│ 原始模型(FP32)│
└──────┬─────┘
↓
[Step 1] 注入伪量化模块(FakeQuant)
↓
[Step 2] 前向传播时进行伪量化(模拟INT表示)
↓
[Step 3] 反向传播时仍用FP32计算梯度
↓
[Step 4] 模型学会对量化误差做出“适配性调整”
↓
[Step 5] 训练结束后,导出真实量化模型(INT8/INT4)
🧠 每一步详解
🔹 Step 1:注入伪量化节点(FakeQuant Modules)
在权重(Weight)和激活值(Activation)前后加上伪量化模块(比如 PyTorch 的 FakeQuantize
):
- 对权重做模拟量化(INT8 → 再转回 FP32)
- 对激活值同样进行模拟量化
这一步保证前向传播模拟的是推理时真实量化的效果!
🔹 Step 2:前向传播中的“伪量化”
- 模拟将 FP32 数值按 INTx 精度截断
[
q = \text{round}\left(\frac{x}{s}\right) \times s
] - 权重和激活值都执行这一步
- 效果是:损失函数中已经反映了量化误差
举例:原本 FP32 权重为
1.76
,在 INT8 伪量化后变为1.75
,这是训练中的“噪声”
🔹 Step 3:反向传播保留浮点精度训练
- 虽然前向用了量化值
- 但反向传播仍用 FP32 精度更新参数(对性能有利)
这种技术称为 Straight Through Estimator(STE)
即:量化操作是不可导的,但我们近似地让它“通过”反向传播。
🔹 Step 4:训练过程中学习适配量化误差
- 模型会自动调整权重值、激活值的分布,使其更适合低精度表示
- 比如:
- 把容易被截断的值收缩到范围内
- 避免“narrow minima”(窄极小值)
✅ 最终,模型对量化误差不敏感,部署后精度更高!
🔹 Step 5:导出部署模型(真实量化)
- 训练完成后,导出为真实的 INTx 模型(不是伪量化)
- 权重存为 INT8,激活值可按部署框架支持动态/静态方式量化
🧪 举例说明:以 Linear 层为例
# PyTorch 示例
import torch
from torch.quantization import QuantStub, DeQuantStub, prepare_qat, convert
class QATModel(torch.nn.Module):
def __init__(self):
super().__init__()
self.quant = QuantStub() # 模拟量化输入
self.fc = torch.nn.Linear(128, 64)
self.relu = torch.nn.ReLU()
self.dequant = DeQuantStub() # 模拟反量化输出
def forward(self, x):
x = self.quant(x)
x = self.fc(x)
x = self.relu(x)
x = self.dequant(x)
return x
# QAT流程
model = QATModel()
model.qconfig = torch.quantization.get_default_qat_qconfig('fbgemm') # 指定QAT配置
prepare_qat(model, inplace=True) # 插入伪量化模块
# 🔁 开始训练
for epoch in range(epochs):
for batch in data_loader:
output = model(batch)
loss = criterion(output, label)
loss.backward()
optimizer.step()
# 导出量化模型
quantized_model = convert(model.eval(), inplace=False)
🧭 什么时候用 QAT?
场景 | 是否推荐使用 QAT |
---|---|
追求极致精度(INT4/INT2) | ✅ 强烈推荐 |
高端服务器部署 | ✅ 推荐 |
嵌入式设备部署 | ✅ 推荐 |
快速部署、精度容忍高 | ❌ 可用 PTQ 代替 |
📌 总结要点
内容 | 说明 |
---|---|
核心目标 | 在训练中让模型适应量化误差 |
技术原理 | 前向模拟量化 + 反向FP32梯度更新(STE) |
精度表现 | 通常显著优于 PTQ,尤其在 INT4 以下 |
实施工具 | PyTorch QAT、TensorFlow QAT、HuggingFace Optimum |