大模型推理优化实战

“训练靠算力,推理靠优化。一个优秀的推理系统,能让同一张 GPU 服务的用户数翻 10 倍。”

一、为什么推理优化如此重要?

训练大模型需要海量 GPU,但将大模型部署并提供服务同样挑战巨大:

模型 参数量 FP16 显存 推理速度( A100)
GPT-3.5 175B ~350GB ~10 tokens/s
LLaMA-2-70B 70B ~140GB ~8 tokens/s
GPT-4 ~1.8T(MoE) ~800GB

一张 A100 只有 80GB 显存,70B 模型的 FP16 权重需要 140GB,一张卡根本放不下。即便能放下,推理速度太慢也会导致用户体验极差。

推理优化就是在有限的硬件资源下,用更快的速度、更低的成本提供更好的服务

二、KV Cache

2.1 自回归生成的问题

大语言模型生成文本是逐 token 自回归的——每个新 token 的生成都需要 attend 到之前所有的 token:

1
2
生成 "今天天气真" → 需要 attend 到 [今, 天, 天, 气, 真]
生成 "好" → 需要 attend 到 [今, 天, 天, 气, 真, 好] ← 重复计算!

生成 100 个 token,就要重复计算 99+98+…+1 = 4950 次 attention!这是巨大的浪费。

2.2 KV Cache 的原理

KV Cache 的核心思想是缓存已计算过的 Key-Value 矩阵,避免重复计算。

1
2
3
4
5
6
7
8
9
10
11
无 KV Cache:
生成 token_1: 计算 K_1, V_1, attend([K_1], [V_1])
生成 token_2: 计算 K_2, V_2, attend([K_1,K_2], [V_1,V_2])
生成 token_3: 计算 K_3, V_3, attend([K_1,K_2,K_3], [V_1,V_2,V_3])
... 每次都重新计算所有 K, V

有 KV Cache:
生成 token_1: 计算 K_1, V_1, attend([K_1], [V_1])
生成 token_2: 直接使用 [K_1,V_1], 只计算 K_2, V_2, attend([K_1,K_2], [V_1,V_2])
生成 token_3: 直接使用 [K_1,K_2,V_1,V_2], 只计算 K_3, V_3
... 每次只计算当前 token 的 K, V

计算量从 O(n²·L) 降低到 O(n·L),其中 n 是上下文长度,L 是层数。

2.3 KV Cache 的代价

天下没有免费的午餐。KV Cache 的代价是显存占用急剧增加

1
2
3
4
5
KV Cache 显存 ≈ 2 × n_layers × n_heads × head_dim × batch_size × sequence_length × bytes_per_param

对于 70B 模型,batch_size=1, sequence_length=4096:
≈ 2 × 80 × 8 × 128 × 1 × 4096 × 2 bytes (FP16)
≈ 16 GB

这只是单个请求的 KV Cache!并发 100 个请求,就是 1.6TB——远超任何单卡的显存。

所以实际系统中,KV Cache 的管理策略至关重要。

2.4 PagedAttention(vLLM 的核心)

vLLM 提出的 PagedAttention 借鉴了操作系统内存管理的思路——将 KV Cache 分成固定大小的”页”(Page),按需分配,动态扩展。

1
2
3
传统方式:预分配 4096 长度的连续显存,不管用不用
PagedAttention:按 16 tokens 为一页,用多少分多少
类似操作系统的分页内存管理

效果:显存利用率提升 2~4 倍,吞吐量提升 10 倍以上。

三、Continuous Batching

3.1 静态批处理(Static Batching)的问题

早期的推理系统使用静态批处理——将多个请求凑成一个 batch,统一处理。但每个请求的输出长度不同:

1
2
3
请求A:输入10 tokens,输出100 tokens
请求B:输入20 tokens,输出5 tokens
静态批处理:必须等最长的输出完成 → GPU 空转浪费严重

3.2 Continuous Batching(迭代级调度)

Continuous Batching 的思想是迭代级别的动态调度——每次生成一个 token 后,就把已完成生成的请求移出队列,新请求加入。

1
2
3
4
5
时间步 1: [请求A, 请求B, 请求C] → 各生成 1 token
时间步 2: [请求A, 请求B, 请求C] → 各生成 1 token
时间步 3: 请求B 完成 → 移出,加入请求D
时间步 4: [请求A, 请求C, 请求D] → 各生成 1 token
...

效果:GPU 利用率大幅提升,吞吐量提升 10~20 倍。

四、量化(Quantization)

4.1 什么是量化?

量化是将高精度浮点数(FP32/FP16)转换为低精度整数(INT8/INT4/INT2)的过程。

1
2
3
FP32:  1个参数占 4 字节,  175B 模型需要 700GB 显存
INT8: 1个参数占 1 字节, 175B 模型需要 175GB 显存 ← A100 单卡可以装下
INT4: 1个参数占 0.5 字节,175B 模型需要 87.5GB 显存 ← 消费级显卡也能跑

4.2 量化方法对比

方法 精度损失 速度 显存节省 适用场景
FP16(无量化) 基准 基准 基准 精度优先
INT8(对称量化) ~1% 1.5~2x 2x 平衡场景
INT8(非对称量化) ~2% 1.5~2x 2x 追求显存
INT4(GPTQ) ~3-5% 2~4x 4x 低显存
INT4(AWQ) ~2-3% 2~4x 4x 更好的精度
GGUF(Q4_K_M) ~3% 2~4x 4x 本地部署

4.3 量化实践

使用 llama.cpp(GGUF 格式):

1
2
3
4
5
# 下载量化后的 Q4_K_M 模型
wget https://huggingface.co/TheBloke/Llama-2-70B-Chat-GGUF/resolve/main/llama-2-70b-chat.Q4_K_M.gguf

# 运行
./llama-cli -m llama-2-70b-chat.Q4_K_M.gguf -n 2048 -p "请介绍一下北京"

使用 vLLM(AWQ 量化):

1
2
3
4
5
6
7
from vllm import LLM

llm = LLM(
model="lmsys/longchat-7b-16k",
quantization="AWQ",
tensor_parallel_size=2
)

4.4 量化感知训练 vs 训练后量化

  • 训练后量化(PTQ):先训练好模型,再量化。简单高效,但精度损失较大。
  • 量化感知训练(QAT):在训练过程中模拟量化,让模型适应低精度表示。精度更高,但训练成本大。
  • GPTQ / AQAT:介于两者之间,通过校准数据补偿量化误差。

五、推测解码(Speculative Decoding)

5.1 核心思想

大模型生成时,Draft Model(小模型) 快速生成若干个 token,然后 oracle Model(大模型) 并行验证。如果大部分猜对了,就”赚”到了;如果猜错了,就丢弃重来。

1
2
3
Draft Model(7B):一口气猜出 [今, 天, 天, 气, 非, 常, 好] → 7 个 token
Oracle Model(70B):并行验证这 7 个 token,全对 → 白赚 6 个 token(第一个自己猜的)
如果第 5 个错了:接受前 4 个,从第 5 个重新猜

理论加速比:draft model 和 oracle model 的 accept rate 决定加速倍数,通常 2~4 倍。

5.2 适用场景

推测解码最适合 accept rate 高的场景——也就是说,draft model 能猜对大部分的情况。如果两个模型能力差距太大,推测解码反而会更慢。

六、分布式推理

当单个 GPU 放不下模型时,需要张量并行(Tensor Parallelism)

1
2
3
4
5
模型层                    GPU 0        GPU 1        GPU 2        GPU 3
Transformer Layer 0: [W_0:0] [W_0:1] [W_0:2] [W_0:3]
Transformer Layer 1: [W_1:0] [W_1:1] [W_1:2] [W_1:3]
... ↓ ↓ ↓ ↓
AllReduce ←——— AllReduce ←——— AllReduce ←——— AllReduce

每一层的权重矩阵按列切分到多个 GPU,每个 GPU 只计算一部分,最后通过 AllReduce 汇总结果。

vLLM + Tensor Parallelism

1
2
3
4
llm = LLM(
model="meta-llama/Llama-2-70b-hf",
tensor_parallel_size=4 # 用 4 张 GPU
)

七、推理优化工具全家桶

工具 厂商/作者 核心特性
vLLM UC Berkeley PagedAttention, Continuous Batching, 最流行
TensorRT-LLM NVIDIA FP8, INT8, 深度优化, 最佳性能
llama.cpp Georgi Gerganov GGUF 格式, CPU/GPU 混合, 本地部署首选
text-generation-inference HuggingFace 稳定可靠, 与 HF 生态无缝集成
DeepSpeed-Inference Microsoft ZeRO, 多种优化技术
Medusa 推测解码 多 draft head, 2~3x 加速

八、总结

大模型推理优化是一个系统性的工程问题:

  1. KV Cache:避免重复计算 attention,是所有现代推理系统的标配
  2. Continuous Batching:动态批处理,最大化 GPU 利用率
  3. 量化:INT8/INT4 牺牲少量精度,换取 2~4 倍的显存和速度收益
  4. 推测解码:小模型帮大模型”作弊”,在 accept rate 高的场景有奇效
  5. 分布式推理:多卡并行,突破单卡显存限制

实际生产中,通常是以上多种技术组合使用。vLLM 已经将 PagedAttention、Continuous Batching 和量化集成在一起,是目前最推荐的推理方案。


相关文章: