量化基础:量化定义、量化类型与量化参数
2.1 什么是量化:从连续域到离散域的映射
在深度学习推理中,模型权重和激活值通常以 FP32(32位浮点数)存储。FP32 能表达约 10⁻⁴⁵ 到 10³⁸ 的动态范围,精度极高,但代价是内存占用大、计算吞吐低。vLLM 等推理引擎在服务大模型时,显存带宽往往比算力更早成为瓶颈——每个 token 生成都需要读取全部权重,权重位宽直接决定显存读取量。
量化的本质是:用低精度整数(如 INT8、INT4)近似表示高精度浮点数,同时尽量保留原始数值的分布信息。数学上,这是一个从实数域 ℝ 到有限整数集合 ℤ 的映射:
量化:x_q = clamp(round(x / scale) + zero_point, q_min, q_max)
反量化:x ≈ (x_q - zero_point) × scale
其中 scale 控制映射的步长(浮点数),zero_point 控制映射的偏移(整数),q_min/q_max 是目标整数类型的表示范围(如 INT8 为 [-128, 127])。量化过程必然引入舍入误差和截断误差,但大模型权重通常呈现近似正态分布,绝大多数值集中在均值附近,因此合理的量化方案可以将精度损失控制在可接受范围内。
2.2 量化类型:PTQ 与 QAT
根据量化过程发生在训练前还是训练后,量化分为两大类:训练后量化(PTQ, Post-Training Quantization)和量化感知训练(QAT, Quantization-Aware Training)。两者在精度、成本和适用场景上有显著差异。
| 对比维度 | PTQ(训练后量化) | QAT(量化感知训练) |
|---|---|---|
| 是否需要训练 | 不需要,直接对预训练模型量化 | 需要,在训练/微调过程中模拟量化 |
| 所需数据 | 少量校准数据(几百张样本) | 完整训练数据集 |
| 精度损失 | 较大(尤其低比特时) | 较小,可恢复大部分精度 |
| 计算成本 | 分钟级~小时级 | 需要完整训练周期 |
| 适用场景 | 快速部署、无训练资源 | 精度敏感、长期部署 |
PTQ 流程
- 校准(Calibration):从训练集或真实推理数据中采样少量代表性样本,前向传播收集每层激活值的分布统计(min/max、百分位数、KL散度等)。
- 计算量化参数:根据收集的统计量,为每个张量(权重或激活)计算最优的
scale和zero_point。 - 量化与验证:将 FP32 权重转换为 INT8/INT4,在验证集上评估精度,必要时调整校准策略。
QAT 流程
- 在模型中插入伪量化节点(fake-quant),前向传播时模拟量化-反量化过程。
- 反向传播时使用直通估计器(STE, Straight-Through Estimator),将舍入操作的梯度近似为恒等映射,使梯度能够正常回传。
- 训练若干 epoch 后,模型权重逐渐适应量化噪声,最终移除伪量化节点,导出真正的低精度模型。
quantization 参数指定量化方法(如 awq、gptq、fp8),这些方法本质上都是 PTQ 的变体,区别在于校准策略和量化粒度(per-tensor / per-channel / per-group)。
2.3 量化参数:scale 与 zero-point 的深入剖析
scale 和 zero_point 是量化的两个核心参数,它们共同定义了浮点数到整数的仿射变换。理解这两个参数是掌握所有量化算法的基础。
scale(缩放因子)
scale 是一个正浮点数,表示整数中每个单位对应的浮点数值大小。计算公式为:
scale = (r_max - r_min) / (q_max - q_min)
其中 r_max 和 r_min 是原始浮点数据的最大值和最小值(或根据分布截断后的边界),q_max 和 q_min 是量化后整数的取值范围。scale 越小,量化精度越高,但能表示的浮点范围也越小。
zero-point(零点偏移)
zero_point 是一个整数,表示浮点数值 0 映射到哪个整数。它的作用是确保浮点 0 能被精确表示——这在神经网络中至关重要,因为 padding、ReLU 输出等大量场景都涉及 0 值。计算公式为:
zero_point = clamp(round(-r_min / scale) + q_min, q_min, q_max)
对于对称量化(symmetric),zero_point = 0,即浮点 0 映射到整数 0;对于非对称量化(asymmetric),zero_point 通常不为 0,可以更充分地利用整数表示范围。
量化粒度
量化参数可以按不同粒度计算,粒度越细,精度越高,但计算开销也越大:
- Per-tensor:整个张量共享一组 scale/zero_point,最简单但精度最低。
- Per-channel:每个输出通道独立计算参数,常用于权重量化,精度显著提升。
- Per-group:将通道进一步分组(如每 128 个元素一组),是 GPTQ、AWQ 等主流方法的默认选择。
# 伪代码:per-group 量化参数计算
for group in groups:
r_min = min(group)
r_max = max(group)
scale[group] = (r_max - r_min) / (q_max - q_min)
zero_point[group] = round(-r_min / scale[group]) + q_min
2.4 案例:以 Llama-7B 为例的 INT8 PTQ 实践
假设我们要对 Llama-7B 进行 INT8 权重量化,使用 per-channel 粒度。具体步骤如下:
- 加载模型:使用 HuggingFace Transformers 加载 FP32 预训练权重。
- 校准数据收集:从 C4 数据集中随机采样 128 条文本,每条截断为 512 token。
- 逐层量化:对每个 Linear 层的权重矩阵,按输出通道计算 scale 和 zero_point。
- 替换算子:将 FP32 的
torch.nn.Linear替换为支持 INT8 的量化版本(如bitsandbytes的Linear8bitLt)。 - 验证精度:在 WikiText-2 上计算困惑度(perplexity),对比量化前后差异。
2.5 复盘:量化方案选择的决策要点
在实际项目中,选择量化方案需要综合考虑以下因素:
- 精度敏感度:如果模型用于医疗、金融等对错误容忍度极低的场景,优先选择 QAT 或高比特量化(FP8/INT8);如果只是普通对话场景,INT4 配合 GPTQ/AWQ 通常足够。
- 硬件支持:不同 GPU 对低精度计算的支持不同。例如,A100 支持 INT8 Tensor Core,但 INT4 需要依赖反量化到 INT8 再计算;H100 则原生支持 FP8。
- 推理引擎兼容性:vLLM 对 GPTQ、AWQ、FP8 等有专门优化,而某些量化格式可能需要额外的 kernel 支持,否则无法发挥加速效果。
- 部署成本:QAT 需要训练资源和时间,PTQ 则几乎零成本。对于快速迭代的项目,PTQ 是首选。