为什么量化
LLM 的权重大部分是 16-bit 浮点。把它们压成 8-bit / 4-bit,显存和带宽同时减半乃至四分之一:
| 精度 | 字节/参数 | Llama-70B 权重大小 | 能装到 |
|---|---|---|---|
| FP32 | 4 | 280 GB | 4×A100-80G |
| FP16 / BF16 | 2 | 140 GB | 2×A100-80G |
| FP8 | 1 | 70 GB | 1×H100-80G |
| INT8 | 1 | 70 GB | 1×A100-80G |
| INT4 (AWQ/GPTQ) | 0.5 | 35 GB | 1×A100-40G ✓ |
| INT3 | 0.375 | 26 GB | 消费级 RTX 3090 ✓ |
权重小了,每次 decode 从 HBM 读进寄存器的字节数也小,memory-bound 的 decode 阶段吞吐会变快——这是很多人误解的,量化不只省显存,还能加速。
四种主流量化方案
AWQ (Activation-aware Weight Quantization)
原理
观察到不同 channel 的权重重要性不同(激活大的 channel 更敏感),给敏感 channel 保留更多精度,其他 channel 激进量化到 INT4。
精度
通常掉 0.5-1 个百分点,大模型上几乎看不出差距。
推理速度
vLLM 上 AWQ INT4 decode 吞吐比 FP16 快 1.3-1.8×(因为带宽压力小)。
GPTQ
原理
逐层量化,每层解一个最小化量化误差的最小二乘问题(用 Hessian 近似),把 INT4 精度压到极致。
精度
和 AWQ 差不多,70B+ 大模型上两者 PPL 差 < 0.1。
特点
量化过程要用 128 条校准数据,耗时几分钟到几十分钟。社区已有海量预量化模型(TheBloke 系列)。
FP8
原理
8-bit 浮点(E4M3 或 E5M2),Hopper 架构(H100)原生硬件支持,几乎无精度损失。
硬件
H100 / H200 / L40S 才能跑出最大收益;A100 只能软件模拟 FP8,吞吐提升有限。
精度
通常掉 < 0.2 个百分点,生产首选。
BitsAndBytes
原理
运行时量化,加载原始 FP16 权重到显存时按 block 量化成 NF4(normal float 4-bit)或 INT8。
特点
不用预先生成量化模型,任何 HF 模型都能直接量化加载。吞吐比 AWQ / GPTQ 慢一些,但开发调试方便。
选型建议
| 场景 | 推荐方案 | 为什么 |
|---|---|---|
| H100 / H200 生产 | FP8 | 硬件原生,几乎无精度损失,吞吐最佳 |
| A100 / L40S 生产 | AWQ INT4 | vLLM 对 AWQ kernel 优化好,吞吐 > GPTQ |
| 消费级(3090 / 4090) | GPTQ INT4 | 社区模型多,TheBloke 一抓一把 |
| 快速 PoC / 没预量化版 | BnB NF4 | 直接加载任意 HF 模型 |
| 对精度极敏感 | FP8 / INT8 | 别用 INT4 |
vLLM 加载量化模型
AWQ 示例
vllm serve TheBloke/Llama-2-70B-Chat-AWQ \
--quantization awq \
--dtype half \
--gpu-memory-utilization 0.95
单张 A100-80GB 装下 70B + KV cache,吞吐比 HF FP16(要 4 张卡)还快——一个顶四。
GPTQ 示例
vllm serve TheBloke/Mixtral-8x7B-Instruct-v0.1-GPTQ \ --quantization gptq \ --dtype half
FP8 示例(H100)
vllm serve neuralmagic/Meta-Llama-3-70B-Instruct-FP8 \ --quantization fp8 \ --dtype auto
Neural Magic 发布的 FP8 模型已针对 vLLM 优化,直接拉下来能跑。
BnB 运行时量化
vllm serve meta-llama/Llama-3-8B-Instruct \ --quantization bitsandbytes \ --load-format bitsandbytes
自己量化一个模型:llm-compressor
社区没有现成量化版?用 Neural Magic 开源的 llm-compressor 自己压一个:
from llmcompressor.transformers import oneshot from llmcompressor.modifiers.quantization import GPTQModifier from datasets import load_dataset from transformers import AutoModelForCausalLM, AutoTokenizer MODEL = "meta-llama/Llama-3.1-8B-Instruct" model = AutoModelForCausalLM.from_pretrained(MODEL, device_map="auto", torch_dtype="auto") tok = AutoTokenizer.from_pretrained(MODEL) # 128 条校准样本 ds = load_dataset("HuggingFaceH4/ultrachat_200k", split="train_sft").select(range(128)) oneshot( model=model, dataset=ds, recipe=GPTQModifier(targets="Linear", scheme="W4A16", ignore=["lm_head"]), max_seq_length=2048, num_calibration_samples=128, ) model.save_pretrained("Llama-3.1-8B-Instruct-W4A16") tok.save_pretrained("Llama-3.1-8B-Instruct-W4A16")
一张 A100 量化 8B 约 15 分钟,产物直接能给 vLLM 加载。
KV cache 也能量化
权重量化解决了模型本身,KV cache 还是 FP16,长序列照样占大头。vLLM 支持 KV cache 量化到 FP8:
vllm serve meta-llama/Llama-3-8B-Instruct \ --kv-cache-dtype fp8
KV 显存减半,能装双倍并发。精度几乎无感。H100 上还可以用 fp8_e5m2。
精度 vs 吞吐 benchmark
Llama-3-70B 在 4×A100 vs 1×A100-AWQ 上的实测:
| 配置 | MMLU | 吞吐 token/s | 月成本(AWS) |
|---|---|---|---|
| 4×A100-80G FP16 | 79.2 | 2800 | $11,000 |
| 2×A100-80G FP8 | 79.0 | 3200 | $5,500 |
| 1×A100-80G AWQ-INT4 | 78.5 | 3600 | $2,800 |
| 1×A100-40G AWQ-INT4 | 78.5 | 2400 | $1,900 |
同精度下 AWQ 反而比 FP16 吞吐高,因为它 memory-bound 的瓶颈小了——这是违反直觉但实测反复验证的结论。
量化的"禁区"
- Embedding 和 lm_head 通常不量化(精度敏感,占比小),AWQ/GPTQ 工具默认 ignore
- RoPE 和 LayerNorm 跳过
- MoE 模型的专家路由 有陷阱,建议用社区专门优化过的量化版(如 Mixtral-W4A16-MarlinExperts)
- Tool-calling / JSON 结构化输出 在 INT4 下偶尔变差,生产 critical path 还是建议 FP8
本章小结
- 量化不只省显存,还加速 decode——memory-bound 被缓解
- H100 → FP8,A100 → AWQ-INT4,消费级 → GPTQ,PoC → BnB
- vLLM 一个
--quantization参数搞定,加载 TheBloke / neuralmagic 预量化模型即可 - 自己量化用 llm-compressor,8B 模型 15 分钟出炉
- KV cache 再量化到 FP8 能装双倍并发
- 精度掉点通常 < 1 个点,70B AWQ vs FP16 MMLU 只差 0.7