推理为什么比训练还贵
很多人以为大模型的成本主要在训练,其实上线后推理才是长期开销。训练是一次性投入,推理是每天每用户都在花钱。一个 7B 模型 FP16 加载就要 14GB 显存,每秒生成几十个 token,用户一多,显卡根本排不过来。
推理慢的原因有两个:一是模型权重本身占显存,二是自回归解码必须一个 token 一个 token 生成,没法并行。这两个问题分别对应两条优化路线:量化解决权重显存,KV Cache 和批处理解决解码效率。
推理优化的本质不是「让模型算得更快」,而是「让同一张卡同时服务更多用户、每次生成更省显存」。
- 权重量化把 FP16 权重压到 INT8 甚至 INT4,显存减半甚至更多,精度损失很小。
- KV Cache缓存历史注意力键值,避免每步重算,但随上下文线性增长。
- PagedAttentionvLLM 的核心技术,把 KV Cache 分页管理,消除显存碎片。
- 连续批处理动态拼接不同请求,让显卡始终跑满不空闲。
权重量化:从 FP16 到 INT8
FP16 是半精度浮点数,每个权重占 16 位。量化就是把它压成 8 位整数(INT8)或者 4 位整数(INT4),显存直接减半甚至砍到四分之一。代价是数值精度降低,但实际测试发现,大模型对量化非常鲁棒——INT8 几乎不掉点,INT4 在大多数任务上也能用。
# 常见量化方式对比
# FP16:原始精度,显存最大
# INT8:对称量化,精度损失极小,显存减半
# INT4:分组量化,显存降到四分之一,适合消费级部署
# 用 bitsandbytes 加载量化模型示例
from transformers import BitsAndBytesConfig, AutoModelForCausalLM
quant_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_compute_dtype="float16",
)
model = AutoModelForCausalLM.from_pretrained(
"Qwen/Qwen2.5-7B",
quantization_config=quant_config,
)
量化不是越激进越好。如果你的场景是代码生成或者数学推理,对精度敏感,建议用 INT8;如果只是客服问答或者文案生成,INT4 完全够用。
KV Cache:解码阶段的隐形开销
大模型生成第二个 token 时,理论上需要把前面所有 token 重新过一遍注意力。KV Cache 把每一层的 Key 和 Value 向量缓存下来,生成新 token 时只算新 token 的 Q,和缓存的 K/V 做注意力,不用重算历史。
但 KV Cache 不是免费的。它的大小随上下文长度线性增长:一个 7B 模型,32 层、每头 128 维、32 头,缓存 4096 个 token 就要占好几个 GB。上下文越长,KV Cache 占得越多,多并发时显存直接爆掉。
- 分页管理像操作系统虚拟内存一样把 KV Cache 分成块,消除碎片。
- 量化 KV把 KV 也量化到 INT8,进一步省显存。
- 滑动窗口只保留最近 N 个 token 的缓存,长上下文场景可控。
vLLM 与 PagedAttention
vLLM 是目前最流行的开源推理框架。它的核心创新是 PagedAttention:把 KV Cache 像操作系统的虚拟内存一样分页管理。每个请求的 KV Cache 不必连续存放,按需分配物理块,逻辑上连续就行。
# 用 vLLM 启动一个 OpenAI 兼容服务
# 安装:pip install vllm
# 启动:
# python -m vllm.entrypoints.openai.api_server \
# --model Qwen/Qwen2.5-7B \
# --quantization bitsandbytes \
# --max-model-len 8192 \
# --gpu-memory-utilization 0.9
# 调用和 OpenAI API 完全兼容
from openai import OpenAI
client = OpenAI(base_url="http://localhost:8000/v1", api_key="dummy")
resp = client.chat.completions.create(
model="Qwen/Qwen2.5-7B",
messages=[{"role":"user","content":"你好"}],
)
PagedAttention 解决了 KV Cache 的显存碎片问题。在传统方式下,每个请求预分配最大长度的连续显存,实际用不完就浪费;分页后按需分配,显存利用率从百分之三四十提到百分之九十以上。
连续批处理与调度
除了显存,显卡的算力利用率也是问题。如果一次只处理一个请求,GPU 大量算力空闲。连续批处理(Continuous Batching)就是把不同用户的请求动态拼到一批里,一个请求做完了立刻塞下一个,GPU 永远跑满。
| 技术 | 解决的问题 | 效果 |
|---|---|---|
| 权重量化 | 权重显存大 | 显存减半到四分之一 |
| KV Cache | 避免重算历史 | 解码提速 10 倍以上 |
| PagedAttention | KV 显存碎片 | 显存利用率翻倍 |
| 连续批处理 | GPU 算力空闲 | 吞吐量翻几倍 |
选型与调优经验
实际部署时,选择路线的顺序是:先确定并发量和上下文长度,再决定量化级别;单卡小模型直接用 vLLM 起服务,多卡大模型考虑张量并行或者专家并行;监控指标看吞吐、延迟和显存利用率三个数。
常见的坑:开了量化但没开 KV Cache 量化,长上下文还是爆显存;batch size 设太大导致 OOM;max-model-len 设太长浪费显存。每次调整一个参数,看监控变化。
从单卡到服务化
单机跑通之后,下一步是服务化:前面加负载均衡,后面多卡扩展;加请求队列和优先级;做监控告警,记录每个请求的延迟和 token 数。推理优化不是一次性的事,要跟着流量和模型版本持续调。
推理优化的终极目标不是「每张卡跑多快」,而是「每用户每 token 花多少钱」。把成本压到最低,大模型应用才能真正规模化。