量化
量化是推理优化里唯一能同时降显存、降带宽、甚至提算力的手段。它的核心问题只有一个:用几位表示一个数。
这一篇按「W{A}{B}」这套命名法组织 —— A 是激活位宽、B 是权重位宽。这个记号比按方法名罗列清楚得多,因为它直接说明「动了哪一半」。
先看命名法
| 记号 | 做了什么 | 代表方法 |
|---|---|---|
| W16A16 | 什么都没量(BF16 基线) | — |
| W8A16 / W4A16 | 只量权重,激活保持 BF16 | GPTQ、AWQ、bitsandbytes NF4 |
| W8A8 | 权重与激活都量到 INT8 | SmoothQuant、LLM.int8 |
| W4A8 | 权重 4 bit + FP8 激活 | TensorRT-LLM 支持 |
| W4A4 | 极致 | QuaRot、Atom |
一条选型判据(比「哪个方法更好」有用得多):
权重侧优先看显存与带宽,激活侧优先看算力。
- weight-only 在 memory-bound 场景赢 —— 单请求、长上下文(Decode 阶段就是这种形态,见 01-推理性能指标与瓶颈定位)
- W8A8 在 compute-bound 场景赢 —— 大 batch、短上下文
所以「量化能不能加速」的答案是取决于你的瓶颈在哪一侧,不是一个固定结论。
W{A}{B} 这个记号直接说明「动了哪一半」,选型看瓶颈在哪一侧:
权重侧:优先看显存与带宽
│
┌─────────────────────┴─────────────────────┐
▼ ▼
W4A16 / W8A16 W8A8 / W4A8
只量权重,激活保持 BF16 权重与激活都量
│ │
在 memory-bound 场景赢 在 compute-bound 场景赢
单请求、长上下文 大 batch、短上下文
(Decode 阶段就是这种形态) (Prefill 阶段是这种形态)
⇒ 「量化能不能加速」的答案取决于你的瓶颈在哪一侧,不是固定结论三种量化算法:GPTQ、AWQ 与 SmoothQuant
GPTQ(ICLR 2023)
基于二阶信息逐层量化。 用 Hessian 近似确定量化每个权重时的最优补偿策略,并把量化误差「传播」到后续权重中。该文报告可在数小时内把 OPT-175B / BLOOM-176B 压到 3–4 bit 而精度几乎不受影响 —— 它建立了 LLM 量化的工程基准,后续方法多以它为比较对象。
工程参数(vLLM 实现):
| 参数 | 含义 | 典型值 |
|---|---|---|
group_size | 多少权重共享一个 scale | 32 / 64 / 128 |
desc_act | 是否按激活顺序重排 | 布尔 |
bits | 位宽 | 4 或 8 |
AWQ(MLSys 2024 最佳论文)
核心发现:只需保护约 1% 的关键权重,就能实现近乎无损的 4-bit。 按激活值的大小识别重要权重,先用缩放因子保护它们再量化。
与 GPTQ 的差别是取向上的:
| GPTQ | AWQ | |
|---|---|---|
| 依据 | 二阶信息(Hessian 近似) | 激活统计 |
| 风格 | 逐层二阶优化 | 更直觉、更快、硬件更友好 |
| group_size | 32–128 | 通常更大(64–128) |
| 精度一致性 | 基准 | 多数评测中更一致 |
当前 GPU 生产服务的首选 4-bit 方案是 AWQ + Marlin。
SmoothQuant(ICML 2023):把难度搬走
Weight-only 之外的路线:权重与激活都量到 INT8(W8A8),难点是激活里的 outlier —— 少数极大值会把整个张量的量化尺度撑坏。
SmoothQuant 的解法是一次数学等价变换:把量化的难度从激活端迁移到权重端。
两边相乘后仍然是原来的
该文数据:OPT-66B 上精度损失 0.6%,推理加速 1.56×,显存减半。已在 TensorRT-LLM 与 vLLM 原生集成,是生产级 INT8 部署的标准路径。
SmoothQuant 的等价变换:把量化的难度从激活端迁到权重端
难点:激活里有 outlier(少数极大值把整个张量的量化尺度撑坏)
变换前: Y = X · W
↑ ↑
难量化 好量化
等价变换:
Y = ( X · diag(s)⁻¹ ) · ( diag(s) · W )
└── 激活被缩小 ──┘ └── 权重被放大 ──┘
两边相乘后仍然是原来的 XW ⇒ 数学等价,且无需训练
⇒ 激活更好量了,代价由权重承担(而权重本来就好量)
该文数据:OPT-66B 上精度损失 0.6%,推理加速 1.56×,显存减半KV Cache 量化
与权重量化解耦,单独对 K/V 下手:KIVI 做到 2-bit;FP8 KV Cache 是 Hopper 上的常规选择。
它的收益直接来自 10-KV Cache 与推理优化 的结论:Decode 是带宽受限的,而 KV Cache 能占总显存的 50%–80%。
别把两者绑在一起量化
权重 INT4 与 KV bf16 是可以共存的(它们是解耦的)。该文在 2k 上下文评测,而 32k+ 时 INT4 权重 + 量化 KV 会在 needle-in-haystack 这类任务上明显退化。
判据:只有在目标上下文长度上实测过,才量化 KV。
低比特浮点:FP8 与 NVFP4
| 格式 | 硬件 | 粒度 |
|---|---|---|
| FP8(E4M3 / E5M2) | Hopper、Ada(cc ≥ 8.9)、Blackwell | per-tensor / per-token / per-group |
| NVFP4(FP4 E2M1) | Blackwell(SM 10.0+) | per-16 值 micro-block + per-tensor FP8 缩放 |
FP8 是 Ada 及以上 GPU 的默认精度选择 —— DeepSeek-V3/R1、Kimi-K2 等模型已原生支持 FP8 训练与推理。
激活量化的三种粒度(vLLM 实现里可配):
| 粒度 | 特点 |
|---|---|
| per-tensor | 整个张量一个 scale,内存开销最低 |
| per-token | 每个 token 一个 scale,对 outlier token 更友好 |
| per-block | 折中 |
精度要匹配,不要混搭
在 H100 上只开 --kv-cache-dtype fp8 而权重留 bf16,比两者单独都差约 10% 吞吐 —— 因为 K 投影的输出每一步都要被降位转换一次。
要开就一起开,或都不开。
Kernel 比算法更决定速度
这一条最容易被忽略:同一份 AWQ 量化权重,换 kernel 能差 61%。
Marlin kernel 的做法是把反量化与矩阵乘法融合进一个 kernel —— 绕过 L1 走 async-copy、用共享内存双缓冲。它让 INT4 权重拿到接近理想的 4× 加速。
实测(Qwen2.5-32B,H200,batch=1,输入 256 / 输出 512 token):
| 方案 | 吞吐(tok/s) | 相对基线 |
|---|---|---|
| Baseline(BF16) | 461 | 1.0× |
| Marlin-AWQ | 741 | 1.61× |
| Marlin-GPTQ | 712 | 1.54× |
| bitsandbytes(NF4) | 168 | 0.36× |
| GGUF Q4_K_M | 93 | 0.20× |
Marlin 的静默回退陷阱
vLLM 只在 group_size 匹配(128 或 -1)且 shape 对齐时才走 Marlin,否则回退到慢 3–4 倍的 kernel,而且不给警告。
症状是「我的 4-bit 模型比 fp16 还慢」。 查法是启动日志里有没有 Using Marlin kernel;没有就用 group_size=128 重量化。
表里 GGUF 那 93 tok/s 也是同一类问题的另一面 —— GGUF 是为 llama.cpp 设计的格式,在 vLLM 栈里没有优化过的 kernel。
同一份 AWQ 量化权重换 kernel 后的吞吐(Qwen2.5-32B / H200 / batch=1):
1.0× ┤ Baseline(BF16) ████████████████ 461 tok/s
│
1.61× ┤ Marlin-AWQ ██████████████████████████ 741
1.54× ┤ Marlin-GPTQ █████████████████████████ 712
│
0.36× ┤ bitsandbytes(NF4) ██████ 168
0.20× ┤ GGUF Q4_K_M ███ 93
└──────────────────────────────────────────▶ tok/s
⇒ 同一份权重,最好与最差差 8 倍 —— kernel 的选择比算法本身更要紧
静默回退陷阱:vLLM 只在 group_size 匹配(128 或 -1)且 shape 对齐时才走
Marlin,否则回退到慢 3–4 倍的 kernel,而且不给警告。
症状是「我的 4-bit 模型比 fp16 还慢」;查法:启动日志里有没有
Using Marlin kernelvLLM 生态里的格式支持
| 方法 | 位宽 | 加载方式 | 硬件门槛 |
|---|---|---|---|
| AWQ + Marlin | W4A16 | --quantization awq(自动用 Marlin) | Turing+ |
| GPTQ / GPTQModel | W4A16、W3 | --quantization gptq | Volta+(兼容面最广) |
| compressed-tensors | W4A16 / W8A8 / FP8 | 自动检测,无需 flag | Turing – Blackwell |
| FP8(E4M3) | W8A8 FP8 | --quantization fp8 或自动 | Ada / Hopper / Blackwell |
| INT8 W8A8 | W8A8 | compressed-tensors 自动 | Turing+ |
| AutoRound | W4A16、INT2–4 | compressed-tensors 自动 | 含 CPU |
| bitsandbytes NF4 | W4A16 | --quantization bitsandbytes | Volta–Hopper |
| GGUF | Q4–Q8 | 插件 | 实验性 |
compressed-tensors 是值得记的一条:它由 neuralmagic(Red Hat)与 vLLM 项目联合开发,把量化元数据存进 checkpoint 的 quantization_config 字段,vLLM 读 checkpoint 就自动加载 —— 不需要任何额外 flag。
配套的量化工具是 llm-compressor,一个工具覆盖 W4A16 / W8A8-INT8 / FP8:
from llmcompressor.transformers import oneshot
from llmcompressor.modifiers.quantization import GPTQModifier
recipe = GPTQModifier(scheme="W4A16", targets="Linear", ignore=["lm_head"])
oneshot(model="Qwen/Qwen3-30B-A3B", dataset="open_platypus", recipe=recipe,
output_dir="...", max_seq_length=2048, num_calibration_samples=512)MoE 模型的特殊建议:在 cc ≥ 8.9 的卡上优先用 FP8 block-wise —— 它无需校准数据、官方支持最好。FP8 per-tensor 在 Qwen3-MoE 上有已知的维度不匹配问题。
五个坑
| 坑 | 表现与判据 |
|---|---|
| 长上下文退化 | 该文只在 2k 评测;32k+ 时 INT4 在 needle-in-haystack 上掉 3–5 分。在目标上下文长度上实测 |
| 数学与代码任务格外敏感 | GSM8K / HumanEval 对权重噪声异常敏感(示例:fp16 55 分 → INT4-GPTQ 48 分);chat / 摘要几乎无损。要跑自己任务的评测,不能只看困惑度 |
| 校准集污染 | 用 C4(99% 英文)校准中文模型 → MMLU 正常但中文输出乱码。多语言模型要用覆盖目标语言的混合校准集 |
| LoRA 与量化混用 | QLoRA 的正确做法是 adapter 保持 bf16、只量 base。把 bf16 LoRA 合并进 GPTQ base 再重量化会退化 |
| kernel 静默回退 | 见上一节 |
量化「不必然加速」
硬件没有对应低精度 kernel、或计算图频繁做量化-反量化时,延迟可能不降反升。评估量化必须同时报模型大小、延迟、内存、精度四项变化。
这条在端侧同样成立 —— 见 07-端侧推理。
相关
- 01-推理性能指标与瓶颈定位 —— Decode 的带宽瓶颈是 weight-only 加速的来源
- 10-KV Cache 与推理优化 —— KV Cache 量化针对的那块显存
- 01-数值计算与精度 —— FP8 / FP4 的指数位与尾数位,以及低精度累加
- 06-vLLM 部署、参数与服务特性 ——
--quantization参数的用法 - 02-NVIDIA GPU 架构演进:Volta 到 Blackwell —— FP8 与 NVFP4 的硬件代际
参考
- https://arxiv.org/abs/2210.17323
- https://arxiv.org/abs/2306.00978
- https://arxiv.org/abs/2211.10438
- https://docs.vllm.ai/en/latest/features/quantization/
- https://github.com/vllm-project/llm-compressor
- https://github.com/IST-DASLab/marlin
- https://arxiv.org/abs/2402.02750
- 这三处数字来自第三方技术博客与评测(JarvisLabs 的 Qwen2.5-32B / H200 基准、vLLM 源码走读),属于二手整理,引用前建议按 vLLM 官方文档复核:https://thakicloud.com/tech-blog/en/llmops/llm-quantization-vllm-serving-unsloth | https://deepwiki.com/tenstorrent/vllm/3.4-quantization-strategies | https://dineshblog.com/blog/session-dl-067-quantization
YJ