外观
权重量化与混合精度
概念定义:攻 decode 阶段带宽墙的最强武器
LLM 推理在 decode 阶段是 memory-bound——每生成一个 token 都要把整个模型权重从 HBM 读一遍。**权重量化(weight-only quantization)**就是专门为此设计:把权重压到 INT4/INT8(4 倍/2 倍字节减少),激活仍用 FP16/BF16(精度无损),就能让 decode 吞吐 3-4 倍。
理解 weight-only 的两个关键认知:
- 它只压权重,不压激活——因为激活只占小头(一次前向只算当前 token 的几 KB),权重才是大头(70B 模型 140GB);
- 它专攻 decode,prefill 受益有限——prefill 是 compute-bound,减字节不直接换速度;decode 是 memory-bound,减字节直接换速度。
权重量化是当前 LLM 推理的事实标准——vLLM、TensorRT-LLM、llama.cpp 都内置支持。
一、weight-only 的基本套路
text
原始: W (FP16) × X (FP16) → Y (FP16) # decode 阶段带宽瓶颈
量化: W (INT4) → dequant → W' (FP16) × X (FP16) → Y
↑
反量化在算 matmul 前即时完成关键问题:反量化(dequant)放在哪里?两种主流做法:
| 方案 | 流程 | 优势 | 劣势 |
|---|---|---|---|
| 离线反量化 | W INT4 → W FP16(推理前一次性反量化) | 实现简单 | 显存没省,速度没快——反例 |
| 在线反量化 + 融合 kernel | 在 matmul 内部即时反量化每组权重 | 显存省 4 倍,带宽省 4 倍 | kernel 要手写优化(Marlin) |
不要"离线反量化"
"先把 INT4 权重反量化回 FP16 再推理"是新手最常踩的坑——那样显存没省(还是要存 FP16),速度还慢了(多一步反量化)。真正的 weight-only 必须用融合 kernel——反量化算在 matmul 内部,每读一组 INT4 立刻反量化立刻算,权重全程留在 INT4 状态。Marlin kernel 就是为此而生。
二、GPTQ:Hessian 二阶补偿
核心思想
GPTQ(Frantar et al., 2023)是 INT4 权重量化精度最高的算法之一。它的核心:按列顺序量化权重,每量化一列就用 Hessian 信息调整剩余列补偿误差。
数学原理:
text
量化误差最小化:minimize || W × X - Q × X ||²
其中 X 是校准数据,X × X^T ≈ H(Hessian 矩阵)GPTQ 用一种基于二阶信息(Hessian)的贪心算法——逐列量化,每量化完一列就把误差用 Hessian 加权投影到剩余列,让后续列补偿已发生的误差。这种"补偿式"量化让累积误差最小。
工程实现
python
# AutoGPTQ 简化使用流程
from auto_gptq import AutoGPTQForCausalLM, BaseQuantizeConfig
quant_config = BaseQuantizeConfig(
bits=4,
group_size=128,
desc_act=False, # 是否按 Hessian 排序
)
model = AutoGPTQForCausalLM.from_pretrained("llama-2-70b")
model.quantize(calibration_data, quant_config)
model.save_quantized("llama-2-70b-gptq-4bit")优势与局限
- 优势:INT4 精度极佳(<1% loss),兼容性广(几乎所有 LLM 都有 GPTQ 版本);
- 局限:量化过程慢(要跑校准 + Hessian 计算,70B 模型要几小时),kernel 速度略逊 AWQ。
三、AWQ:保护显著权重
核心思想
AWQ(Lin et al., 2023)的核心观察:LLM 中有 1% 的"显著权重"(salient weights)对精度起决定性作用——通常是激活幅度大的通道对应的权重。如果能保住这部分权重,其他 99% 的权重量化精度损失可以忽略。
但"保护 1% 的权重"该怎么实现?AWQ 用了一个聪明技巧:等价缩放。
text
原始: Y = W × X
等价变换: Y = (W / s) × (s · X) = W' × X'
↑ ↑
缩放后的权重 缩放后的激活通过对激活幅度大的通道乘以 s > 1(让显著权重的相对值变小,落到 INT4 量化范围更友好区段),等价地把 X 的对应通道除以 s——这样数学上等价,但显著权重在量化时损失更小。
为什么 AWQ 比 GPTQ 快
AWQ 的量化过程是无需 Hessian 的轻量搜索——只在权重大小上观察激活幅度,几百次前向就能定出每组的 scale。kernel 实现也更高效——AWQ kernel(vLLM 实现)和 GPTQ Marlin 在同等精度下 AWQ 速度通常领先 10-30%。
工程实现
python
# AutoAWQ 简化使用流程
from awq import AutoAWQForCausalLM
from transformers import AutoTokenizer
model = AutoAWQForCausalLM.from_pretrained("llama-2-70b")
tokenizer = AutoTokenizer.from_pretrained("llama-2-70b")
quant_config = {"w_bit": 4, "q_group_size": 128, "zero_point": True}
model.quantize(tokenizer, quant_config)
model.save_quantized("llama-2-70b-awq-4bit")四、GPTQ vs AWQ:实战对比
| 维度 | GPTQ | AWQ |
|---|---|---|
| 核心算法 | Hessian 二阶补偿 | 显著权重保护 + 等价缩放 |
| 量化时间 | 慢(70B 几小时) | 快(30-60 分钟) |
| INT4 精度 | <1% loss | <1% loss(相当) |
| kernel 速度 | Marlin kernel 优化后接近 AWQ | 原生更快 |
| 生态 | AutoGPTQ、vLLM、TensorRT-LLM | AutoAWQ、vLLM、TensorRT-LLM |
| 微调友好度 | LoRA 加在量化权重上稍麻烦 | LoRA 加在量化权重上更顺 |
| 校准数据需求 | 128-1024 条 | 128-512 条 |
选哪个
- 追求极致精度 + 算力不紧:GPTQ + Marlin kernel;
- 追求部署速度 + LoRA 微调:AWQ(当前社区主流推荐);
- H100+ 卡:FP8(不需要量化算法,原生支持,精度无损);
- 追求极致压缩:W4A16 + 2:4 稀疏(叠加剪枝)。
五、混合精度组合:选型矩阵
权重量化 + 激活量化的不同组合,应对不同瓶颈特性:
| 组合 | 权重 | 激活 | 显存压缩 | decode 速度 | prefill 速度 | 精度损失 | 适用 |
|---|---|---|---|---|---|---|---|
| W16A16(基线 FP16) | FP16 | FP16 | 1× | 1× | 1× | 0 | 基线 |
| W8A16 | INT8 | FP16 | 2× | ~1.5× | ~1× | <0.5% | 中等压缩、精度优先 |
| W4A16 | INT4 | FP16 | 4× | ~3-4× | ~1× | 1-3% | decode 主流 |
| W8A8 | INT8 | INT8 | 2× | ~2× | ~2× | 1-5% | prefill 密集 |
| W4A8 | INT4 | INT8 | 4×(权重)+2×(激活) | ~3× | ~2× | 3-8% | 平衡但精度风险 |
| W4A4 | INT4 | INT4 | 4×+4× | ~4× | ~4× | 5-15% | 极致算力,精度差 |
| FP8 W8A8 | FP8 | FP8 | 2× | ~2× | ~2× | <1% | H100+ 旗舰 |
| FP4 W4A4 | FP4 | FP4 | 4× | ~4× | ~4× | 2-5% | B200 Blackwell |
decode 优先 W4A16,prefill 优先 W8A8
- W4A16 是当前在线 LLM 服务的事实标准——decode 是带宽墙,权重量化直接 4 倍加速,激活 FP16 不影响计算(反正算力闲置 99%);
- W8A8 适合 prefill 密集场景(如离线批处理)——prefill 是 compute-bound,激活也压成 INT8 才能让 Tensor Core INT8 算力(989 TF × 2 = 1978 TOPS)跑满;
- W4A4 极致但风险大——激活 INT4 在 LLM 上精度很难保,慎用。
六、混合精度策略:哪些层要保 FP16
不是所有层都能量化到 INT4 而不损精度。敏感层要保留 FP16,这是混合精度(mixed precision)的核心:
| 层 | 量化建议 | 原因 |
|---|---|---|
| Final LayerNorm | FP16 | 输出分布对量化极敏感 |
| Attention softmax | FP16 | 概率分布量化后失真严重 |
| Embedding | FP16 或 INT4 都可 | 量化影响小,看显存 |
| LM head(output projection) | FP16 | 输出 logits,量化影响 next-token 分布 |
| Q/K/V projection | INT4 OK | 中间表示,量化误差被后层吸收 |
| FFN matmul | INT4 OK | 同上 |
混合精度不是"省事"——是必需
统一量化所有层到 INT4 在 70B 以上模型经常翻车(精度退化 5%+),保留 3-5 个敏感层 FP16 几乎无损(<1% loss)。AutoGPTQ 和 AutoAWQ 都支持 layer-wise mixed precision 配置——配好 YAML 文件就行。
七、Marlin kernel:W4A16 的极致融合
痛点
W4A16 的朴素实现:
text
1. 从 HBM 读 INT4 权重 → SRAM
2. unpack INT4 → INT8 → FP16(在 SRAM 内)
3. 用 FP16 算 matmul
4. 写回 HBM这每一步都在 SRAM 里——但 1+2+3 是分三个独立 kernel 写的,每一步的中间张量都要写回 HBM 再读回来,反量化的好处被 HBM 往返吃光。
Marlin 的做法
Marlin(Frantar et al., 2024)把"读 INT4 → unpack → 反量化 → matmul"全融合进一个 kernel:
- 权重在 SRAM 内即时反量化——一次 HBM 读,全程不写回;
- warp-level 分块 + shared memory tiling——把 SRAM 用满;
- async memcpy——HBM 读和 SRAM 算并行流水线;
- INT4 → FP16 转换用 SIMD——一行 CUDA 指令把 8 个 INT4 解成 8 个 FP16。
效果:W4A16 在 A100/H100 上的 matmul 算力从朴素实现的 ~30 TFLOPS 拉到 ~150-200 TFLOPS——5-7 倍提升。
主流实现
- GPTQ Marlin:vLLM 默认 kernel,GPTQ 量化模型用;
- AWQ Marlin:vLLM AWQ 模型用,速度比 AWQ 原生 kernel 快 30%+;
- exllama:早期 INT4 kernel,已被 Marlin 取代;
- TensorRT-LLM 内核:NVIDIA 自家实现,性能与 Marlin 接近但闭源。
详见算子融合与自定义核。
八、权衡与取舍
- 算法选 GPTQ 还是 AWQ:精度相当,AWQ kernel 速度领先——主流选 AWQ;极致精度选 GPTQ + Marlin;
- bit 数选 4 还是 8:decode 优先 W4A16;prefill 密集 W8A8;H100+ 直接 FP8;
- group size 选 32/64/128:越小精度越好但元数据越多——INT4 主流 128,INT8 不需要分组;
- 要不要混合精度:70B 以上模型强烈建议,保留 final norm / softmax / lm_head 几个敏感层 FP16;
- 要不要 LoRA 叠加:量化模型 + LoRA 是微调 LLM 的甜点方案——AWQ + LoRA 兼容性更好,详见实践指南。
延伸阅读
- 量化基础——量化的通用原理与算法全景
- 算子融合与自定义核——Marlin kernel 的底层原理
- 显存层次与带宽墙——为什么 weight-only 是 decode 神器
- 剪枝与稀疏化——稀疏 INT4 权重的叠加
- 知识蒸馏——压缩三件套的训练侧武器
- vLLM 案例研究——AWQ/GPTQ Marlin 的工业实现
- llama.cpp 案例研究——CPU/边缘上的 GGUF 量化
- TensorRT 案例研究——FP8/INT8 在 NVIDIA 栈的实现
参考资料
- Frantar et al. GPTQ: Accurate Post-Training Quantization for Generative Pre-trained Transformers(ICLR 2023) —— GPTQ 原始论文
- Lin et al. AWQ: Activation-aware Weight Quantization for LLM Compression and Acceleration(MLSys 2024) —— AWQ 原始论文
- Frantar & Alistarh. Marlin: Mixed-Precision Auto-Regressive Parallel Inference Engine(2024) —— Marlin kernel 论文
- AutoGPTQ GitHub —— GPTQ 工程实现
- AutoAWQ GitHub —— AWQ 工程实现
- vLLM Quantization Documentation —— 各类量化在 vLLM 中的使用