深色模式
模型量化基础 INT8/FP8/GGUF
摘要:量化是把 16 位权重压到 8/4 位以省显存、提吞吐的关键杠杆。本文区分 PTQ 与 QAT,对比 INT8、FP8、INT4(AWQ/GPTQ)、GGUF 的精度-内存-吞吐权衡,说明为什么"量化不等于一定更快",并给出 vLLM / llama.cpp 的可复制配置与容量/成本估算。适用版本:原理通用,具体精度/速度数字标注
[版本相关]与[未实测]。
核心概念:量化在量化什么
量化把权重(有时含激活)从 FP32/FP16 降到低比特(INT8、FP8、INT4 等)。本质是映射:
text
量化: q = round(x / scale) + zero_point
反量化: x' ≈ (q - zero_point) × scale1
2
2
按对象分两类:
| 类别 | 量化对象 | 特点 | 适用 |
|---|---|---|---|
| 权重量化(Weight-only) | 仅权重 | 省显存,推理时实时反量化;计算省带宽 | LLM 部署主流(AWQ/GPTQ/GGUF) |
| 权重+激活(W8A8/FP8) | 权重与激活 | 整数/低精计算,需校准激活范围 | 高吞吐、硬件依赖 |
PTQ vs QAT
- PTQ(训练后量化):直接量化已训练模型,可选小校准集定 scale。快、便宜、无需重训——几乎所有人都用它。
- QAT(量化感知训练):训练时模拟量化让模型适应,低比特质量更好但需一次训练。仅在 PTQ 在目标比特损失过大时考虑。
关键认知:量化省的是"带宽"不是"算力"
LLM 解码(decode)是显存带宽瓶颈:每生成一个 token 要读一遍全部权重。权重减半,读的字节减半,吞吐近似翻倍。但 prefill(长输入计算)是算力瓶颈,单纯权重量化收益小。所以"量化=更快"只在带宽受限的解码 + 有对应内核时才成立。
架构与原理:方法谱系
| 格式 | 比特 | 相对 FP16 内存 | 质量损失 | 典型用途 |
|---|---|---|---|---|
| FP16/BF16 | 16 | 1× | 无 | 训练、精度敏感服务 |
| FP8 (E4M3) | 8 | ~0.5× | 近零(H100/H200) | 现代 GPU、高吞吐 |
| INT8 | 8 | ~0.5× | 很低 | 广泛硬件支持 |
| INT4 (AWQ/GPTQ) | 4 | ~0.25× | 低(多数任务 1–3%) | 成本受限 GPU 服务 |
| GGUF Q4_K_M 等 | ~4–5 | ~0.25–0.3× | 低 | CPU / llama.cpp / 本地 |
| INT3/INT2 | 2–3 | <0.2× | 高,常不可用 | 研究/极端约束 |
FP8 不是"更小号的 FP16"
FP8 有 E4M3(精度高)与 E5M2(范围大)两种子格式,指数/尾数分配不同,需要专门的 per-tensor scale 管理。它靠 Hopper+(H100/H200)原生张量核支持才高效,老旧 GPU 上无收益。
生产实践:选哪个
- 有 H100/H200(Hopper+):优先 FP8(权重或 KV cache),近无损且吞吐高。
- 普通 NVIDIA GPU 想省显存:AWQ INT4(vLLM 首选,配 Marlin 内核才快)。
- 本地/CPU/Ollama:GGUF q4_K_M 或 q5_K_M 默认。
- 代码/数学/推理模型:优先 INT8 或 FP8,INT4 对这类任务掉得更多。
- GPTQ 仅在某模型没有 AWQ 预量化版时作为兼容兜底。
量化"反直觉"陷阱
AWQ 若无 Marlin 等优化内核,反而比 FP16 慢——因为硬件要先反量化 INT4 回 FP16 再做矩阵乘,开销超过带宽节省。量化提速需同时满足:(a) 带宽受限的解码,(b) 硬件/内核支持量化算子(Marlin on NVIDIA、FP8 原生 on H100)。务必在你的真实硬件上 benchmark,不要假设量化=更快。
操作步骤:落地配置
vLLM 跑 AWQ INT4(GPU 服务)
bash
# 需先取得 AWQ 量化权重(AutoAWQ 生成,约 10–30 分钟/7B)[未实测:时长随硬件]
pip install vllm autoawq
vllm serve TheBloke/Llama-3-8B-Instruct-AWQ \
--quantization awq \
--max-model-len 81921
2
3
4
5
2
3
4
5
llama.cpp / Ollama 跑 GGUF(CPU/本地)
bash
# 下载对应 GGUF(如 q4_K_M),用 ollama 或直接 llama.cpp
ollama run llama3.1:8b-instruct-q4_K_M
# 或
./llama-server -m models/llama-3-8b-q4_K_M.gguf -c 81921
2
3
4
2
3
4
生成 AWQ(你有原始权重时)
python
from awq import AutoAWQForCausalLM
model = AutoAWQForCausalLM.from_pretrained("meta-llama/Llama-3-8B")
model.quantize("calibration_data/") # 用代表你真实 prompt 的校准集,别用随机维基
model.save_quantized("llama-3-8b-awq")1
2
3
4
2
3
4
验证
bash
# 1. 质量:在你的业务评测集(非公开 benchmark)上对比量化前后通过率
# IFEval/MT-Bench(指令遵循)、GSM8K/MATH(推理)、你的红队集(安全)
# 2. 速度:vLLM 自带 benchmark
python -m vllm.entrypoints.openai.api_server --model ... &
python benchmarks/benchmark_serving.py --model ... --num-prompts 100
# 3. 显存:nvidia-smi 观察权重+KV 占用是否达标1
2
3
4
5
6
2
3
4
5
6
校准集决定成败
校准数据要代表你的真实 prompt 分布,而非随机维基百科。激活离群值(早期层可达正常 50–100×)会毁掉量化——SmoothQuant(激活侧)、AWQ 显著通道检测正是为此。量化后必须跑真实评测,perplexity 是弱指标,会掩盖行为回归。
回滚与清理
量化版本与权重强绑定
- 量化格式(AWQ/GPTQ/GGUF)与推理框架内核版本绑定,升级 vLLM/llama.cpp 后重测。
- 保留 FP16 原始权重以便回滚;量化产物用 digest 锁定。
- 混合精度(敏感层保持高精度)是常见做法,回滚时连同配置一起还原。
故障排查
| 现象 | 可能原因 | 排查 |
|---|---|---|
| 量化后变慢 | 无优化内核(如 AWQ 无 Marlin) | 上 Marlin/FP8 原生;或退回 FP16 |
| 质量骤降 | 校准集不代表/离群值 | 换代表性质校准集;试 AWQ 而非 GPTQ |
| OOM 仍在 | 只量化权重,KV 未动 | 叠加 FP8 KV cache(见上下文窗口篇) |
| 输出乱码 | 格式/内核不匹配 | 确认框架支持该量化格式版本 |
安全与合规
量化相关风险
- 质量回归导致安全行为变化:量化可能微妙改变拒答/对齐行为,红队测试必须纳入回归。
- 数据泄露:自托管量化模型若暴露未授权访问,等同权重与可能的微调数据出域;加鉴权与网络隔离。
- 成本失控:量化后吞吐提升可能诱使放开限流被刷量,仍需配额与告警。
- 供应链:第三方预量化权重(如社区 GPTQ/AWQ)来源需核验哈希,避免投毒。
成本与性能:容量与账
以 P 十亿参数模型估算权重显存(再加 KV/激活 15–25%):
| 精度 | 字节/参数 | 7B | 70B |
|---|---|---|---|
| FP16 | 2 | 14 GB | 140 GB |
| INT8/FP8 | 1 | 7 GB | 70 GB |
| INT4 (AWQ) | 0.5 | 3.5 GB | 35 GB |
关键结论:70B 在 FP16 需 ~140 GB(四卡),INT4 约 35 GB——单张 80GB H100 即可带合理 KV cache。这正是一张卡与四张卡的成本之差。[版本相关:具体数字随 head_dim/层数浮动]
成本公式(自托管):GPU 小时成本 ≈ 卡数 × 单价 × 时长 ÷ 利用率。例如 8×A100 80GB 约 $2–3/卡·小时 [未实测:随云厂商/时段],用 INT4 把 70B 从四卡压到一卡,长期推理成本可降数倍。量化提速(解码带宽受限时):INT8 ≈ 1.5–2×,INT4 ≈ 3–4×,FP8 类似 INT8 且精度更好。