为什么推理优化越来越重要
训练一次大模型成本高,但跑起来之后每天都要服务大量用户,长期来看推理成本远高于训练成本。一个 70B 模型如果用 FP16 直接跑,单卡 A100 80G 都装不下,更不用说提供低延迟服务。所以推理优化不是锦上添花,而是落地的前提。
下面整理几个工程上最常用、收益最显著的优化方向。
1. KV Cache 是性能的核心
Transformer 自回归生成时每生成一个 token 都要重新计算所有历史 token 的 K 和 V,这是 O(n²) 的浪费。KV Cache 把之前算过的 K/V 缓存下来,每步只算新 token 的 K/V,复杂度降到 O(n)。
但 KV Cache 本身会吃巨量显存:一个 13B 模型、序列长度 4K、batch 16,KV Cache 就要十几 GB。所以衍生出一系列优化:
- PagedAttention(vLLM 提出):把 KV Cache 按"页"管理,避免连续显存碎片化,吞吐能提 2-4 倍
- GQA / MQA:让多个 Query Head 共享同一组 K/V Head,KV Cache 大小直接砍几倍,Llama 3 就用了 GQA
- 量化 KV Cache:把 KV Cache 从 FP16 量化到 INT8 甚至 INT4,显存减半但精度损失很小
2. 量化:用精度换显存和速度
权重量化的核心思路是:模型权重是 FP16 (16 bit),但实际有效信息可能只需要 4 bit 就能表达。常见方案:
| 方案 | 位宽 | 特点 |
|---|---|---|
| GPTQ | 4 bit | 训练后量化,精度高,主流方案 |
| AWQ | 4 bit | 保留重要权重通道为高精度,效果略好于 GPTQ |
| GGUF (llama.cpp) | 2-8 bit | CPU/Metal 友好,本地部署首选 |
| FP8 | 8 bit | H100 原生支持,精度损失极小 |
实测 4 bit 量化的 70B 模型在大部分中文任务上和 FP16 差距不到 1 个百分点,但显存占用从 140G 降到 35G,单卡 A100 即可部署。
3. 投机采样:用小模型加速大模型
Speculative Decoding 的思路非常巧妙:让一个小模型(draft model)连续生成 n 个候选 token,再用大模型一次性并行验证这 n 个 token,接受其中前 k 个正确的。
这样大模型一次 forward 能产生多个 token,平均 latency 降低 2-3 倍,且输出和直接用大模型完全一致(数学上等价)。
限制是小模型需要和大模型分布接近,否则接受率太低反而变慢。Llama 3 8B + Llama 3 70B 是经典搭配。
4. Continuous Batching
传统批处理:等齐 N 个请求再一起跑,最快的请求要等最慢的请求结束才能拿到结果。
Continuous Batching(也叫 In-flight Batching):每生成完一个 token 就检查队列,结束的请求出队、新请求入队,永远保持 batch 满载。vLLM、TGI、TensorRT-LLM 都用这个调度策略。
效果是吞吐能提 2-10 倍,尤其在请求长度差异大的场景。
5. 编译优化与图融合
把 PyTorch 的动态图编译成静态图能省下解释器开销。常用工具:
- torch.compile:PyTorch 2.0 内置,开箱即用,对常规模型有 20-50% 加速
- TensorRT-LLM:NVIDIA 官方,性能最强但写起来复杂
- vLLM:综合方案,工程友好,社区活跃
实践中 vLLM 是大部分团队的默认选择 —— 不是单项最快,但综合性能、易用性、社区支持最佳。
写在最后
推理优化没有银弹,需要根据业务场景组合:
- 延迟敏感(如对话):优先 Speculative Decoding + GQA
- 吞吐敏感(如批量摘要):优先 Continuous Batching + 量化
- 显存吃紧(消费级 GPU):优先 GGUF 量化 + KV Cache 量化
下一篇会写 vLLM 的具体部署和调优经验。