Skip to content

什么是推理加速

本页速览 推理是把训练好的模型权重变成生产可服务系统的全部工程。本文给出三层定义、与训练的根本差异、四大优化层次、手写最小推理系统(含 KV cache),以及三个实证加速刻度。

什么是推理加速

一句话定义:推理加速(Inference Acceleration)是把训练好的模型权重变成生产可服务、能在延迟与成本约束下吞吐真实流量的系统的全部工程——训练解决"模型会不会",推理解决"模型能不能用得上、用得起、用得稳"。

你写过的最"推理"的代码可能是一行 model.generate(inputs)。拆开看这行代码:它不是在算梯度,而是用一组已经固定下来的参数,对输入做一次前向计算,得到输出。整个推理工程学科的起点,就是这行代码背后的张力:训练算的是 FLOPs 多少,推理算的是访存多贵、batching 多紧、用户等多久。一行 model.generate 在 HuggingFace Transformers 上跑 Llama-2-70B,单请求吞吐约 20 tokens/s;同样的权重,在 vLLM 上能跑到 2000+ tokens/s 的聚合吞吐——100 倍差距不在模型,而在系统

一、定义:从三个层面理解

1. 实用层:做什么

推理系统接收输入(prompt/图像/特征),产出输出(token/标签/分数),但它的独特之处在于它是一项"在线服务"

训练:    数据 + 标签 ──→ 模型权重(离线、批处理、追求总吞吐)
推理:    模型权重 + 输入 ──→ 输出(在线、并发、追求单请求延迟 × 总吞吐)

训练是"在实验室里把模型教会",推理是"把毕业的模型送上岗"。凡是"模型已经训好、要让它对真实流量服务"的场景——聊天 API、搜索排序、推荐召回、图像识别、语音转写——都是推理工程的主场。推理工程师的日常不是调损失函数,而是和延迟、显存、吞吐、 batching、量化打交道。

2. 学术层:从计算图视角的定义

从计算图角度看,推理是在计算图上执行一次前向传播(forward pass),不记录梯度、不更新参数

给定训练好的参数 θ* 和输入 x,推理是计算 y = f(x; θ*) 的过程。其中 f 是模型定义,θ* 是已固定的权重张量集合,x 是新输入。整个过程的算力可以精确刻画为 FLOPs = 2 × P × S(P 为参数量,S 为序列长度,对 Transformer 而言),且对同一 (θ*, x) 结果可复现。

这个定义的力量在于它给出了推理优化的三个可量化目标

目标含义衡量
延迟 (Latency)单请求从输入到首 token / 末 token 的时间TTFT、TPOT、E2E latency(见延迟与吞吐
吞吐 (Throughput)单位时间处理的请求数或 token 数tokens/s、QPS、requests/min
显存占用 (Memory)模型权重 + 激活 + KV cache 占用的显存GB(见访存与带宽

三者构成推理不可能三角——延迟低、吞吐高、显存省通常不可兼得,所有优化都是在这三者之间做权衡。详见Roofline 模型

3. 数学层:访存瓶颈视角

从数学上看,推理优化的核心问题不是"算得快",而是"喂得饱":

一个 Transformer 解码步的算术强度约为 2 × batch × seq_len × hidden_dim(FLOPs)/ 2 × batch × seq_len × hidden_dim × bytes_per_param(访存字节)。当 batch=1、bytes_per_param=2(FP16)时,算术强度约为 1 FLOP/byte——远低于 GPU 的 roofline 拐点(A100 约 100 FLOPs/byte),因此单请求 LLM 推理是**访存瓶颈(memory-bound)**的。

这个结论是推理工程最重要的一个事实:LLM 单请求解码不是在算,而是在等显存把权重和 KV cache 搬到 SM。所有 LLM 推理优化——batching、量化、KV cache 压缩、算子融合——本质上都是在抬高算术强度。详见访存与带宽Roofline 模型

为什么推理"难"?

训练难的根源是算力大、收敛难;推理难的根源是算力分布极不均匀——同一个模型,单请求解码时算术强度 ~1(访存瓶颈),prefill 阶段算术强度 ~100(算力瓶颈),批量推理时又回到算力瓶颈。一套系统要同时把三种 workload 都喂饱,这是推理工程比训练工程更"碎"的根本原因。

二、推理 vs 训练:算力分布、访存特征、batching 差异

推理和训练看似都是"跑神经网络前向",但工程上几乎是两个领域。最关键的三个差异:

1. 算力分布:训练密集均匀,推理稀疏不均

训练一个 epoch 是"对每个样本算一次前向 + 一次反向",反向的算力约是前向的 2 倍,且所有样本同等对待——算力分布均匀且密集,GPU 利用率可以稳定压到 50-60% MFU。

推理完全相反。LLM 推理分两个阶段(详见推理 vs 训练 vs 微调):

  • Prefill 阶段(处理 prompt):算力密集,batch=1 时算术强度也高,GPU 利用率能到 60%+;
  • Decode 阶段(生成 token):每个步只算一个 token,batch=1 时算术强度 ~1,GPU 利用率常常不到 5%。

所以同一个 Llama-2-70B 模型,prefill 一次 1k token prompt 的延迟可能只有 200ms,但 decode 200 个 token 要花 4 秒——decode 才是延迟大头,而 decode 几乎在等显存

2. 访存特征:训练复用权重,推理每次重读

训练时一个 batch 内权重只读一次,算力/访存比由 batch size 抬高;推理 decode 阶段每个 token 都要把全部权重读一遍——70B 模型 FP16 是 140GB,每生成一个 token 就要从 HBM 搬一次 140GB 到 SM,A100 80GB 的 2TB/s 带宽下,单个 token 的访存下限就是 70ms。这就是为什么单请求 LLM 推理的 token/s 上限大致等于 HBM 带宽 / 模型大小——和算力几乎无关。

3. Batching 差异:训练静态,推理连续

训练的 batch size 在一个 step 内是固定的(static batching),可以开到几百上千;推理的请求是用户随时来、长度各不相同的——如果用静态 batching,要么等凑齐 batch(延迟爆炸),要么强制截断(体验崩溃)。这就是 vLLM 的 PagedAttention 与 continuous batching 解决的核心问题:让请求动态加入和退出 batch,把"长度不一的 N 个请求"塞进同一 GPU 一起算,把 decode 的算术强度从 ~1 抬到 ~50+。

完整的训练 vs 推理对照见推理 vs 训练 vs 微调

三、四大优化层次(模型层 / 算子层 / 图层 / 系统层)

推理优化不是某一招,而是一棵四层的优化树。任何"推理加速"手段都可以归到这四层之一:

text
┌─────────────────────────────────────────────────────────────┐
│  系统层  │ batching · scheduling · KV cache · 路由 · 多模型  │
│         │  代表:vLLM continuous batching、PagedAttention     │
├─────────┼───────────────────────────────────────────────────┤
│  图层   │ 算子融合 · 常量折叠 · 死代码消除 · 内存规划          │
│         │  代表:TensorRT graph fusion、ONNX 图优化           │
├─────────┼───────────────────────────────────────────────────┤
│  算子层 │ FlashAttention · 手写 CUDA kernel · 算子融合        │
│         │  代表:FlashAttention-2/3、FlashInfer              │
├─────────┼───────────────────────────────────────────────────┤
│  模型层 │ 量化 · 剪枝 · 蒸馏 · 稀疏化                         │
│         │  代表:GPTQ/AWQ INT4、SmoothQuant、模型蒸馏        │
└─────────┴───────────────────────────────────────────────────┘
        ▲ 上层收益大但门槛高,下层收益直接但需要硬件知识 ▼
        优化顺序应自下而上,但实战中常四层叠加

模型层:把模型本身变小

  • 量化(Quantization):FP16 → INT8/INT4/FP8,直接把权重和访存量砍 2-4 倍,是性价比最高的优化。详见模型量化基础权重 only 与混合精度
  • 剪枝(Pruning):去掉不重要的权重/通道/头,结构化剪枝能真省算力,非结构化需要稀疏核支持。详见剪枝
  • 蒸馏(Distillation):用大模型教小模型,让小模型逼近大模型质量。详见知识蒸馏

算子层:把单个算子写快

  • FlashAttention:把 attention 的中间矩阵分块到 SRAM 计算,避免 HBM 来回读写——单算子 2-4x 加速,是 LLM 推理的标配。详见算子融合
  • 手写 CUDA/Triton kernel:针对自家模型的形状特制核,vLLMSGLang、FlashInfer 都大量使用。
  • 算子融合:把多个相邻算子合并成一个 kernel,减少 kernel launch 与访存。

图层:把整张计算图重排

  • 算子融合(图级):在图层级识别可融合模式(Conv+BN+ReLU、MatMul+Add+GELU),由 TensorRTONNX Runtime 自动完成。
  • 常量折叠:编译期把常量计算掉(如 2 × 3 × x 折成 6 × x)。
  • 内存规划:重排算子顺序、复用激活显存,把峰值显存压下来。详见图优化

系统层:把多请求一起喂饱

  • Continuous batching:让长短不一的请求动态进出 batch,是 vLLM/TGI/SGLang 的核心机制。
  • KV cache 管理:PagedAttention 把 KV cache 像虚拟内存一样分页管理,显存利用率从 20% 拉到 90%+。
  • 投机解码(Speculative Decoding):用小模型/草稿模型先猜几个 token,大模型并行验证,2-6x 加速。详见投机解码案例
  • 多模型路由:简单请求走小模型,复杂请求走大模型,整体成本下降。详见模型服务

四层叠加才是一线生产

真实生产系统不是"选某一层",而是四层叠加。例如一个典型的 Llama-3-70B 服务:底层 H100 FP8(硬件层)→ AWQ INT4 量化(模型层)→ FlashAttention-3 + FlashInfer(算子层)→ TensorRT-LLM 图融合(图层)→ continuous batching + PagedAttention + EAGLE-3 投机解码(系统层)。四层叠加后,单 H100 节点能从 HuggingFace 的 ~20 tokens/s 推到 ~3000 tokens/s——150 倍差距全在工程

四、一个最小推理系统:手写 forward + batched forward + KV cache

剥掉 vLLM 和 transformers 的所有封装,一个能跑的 LLM 推理循环只需要 60 行 Python。这一节我们手写一遍,看清推理工程的三个层次:单请求 forward、batched forward、带 KV cache 的自回归生成

1. 单次前向:最朴素的推理

python
import torch
import torch.nn.functional as F

# 假设 model 是一个已加载好权重的 Transformer(任何框架都可以)
model = load_model("llama-7b", dtype=torch.float16, device="cuda")
input_ids = torch.tensor([[1, 1500, 2500, 980]], device="cuda")  # 一个 prompt

# 最朴素的推理:一次 forward,拿 logits,argmax 出下一个 token
with torch.no_grad():
    logits = model(input_ids)        # [1, seq_len, vocab_size]
    next_token = logits[0, -1].argmax(-1)   # 取最后一个位置的 logits
print(next_token)  # 这就是一个 greedy decode 步

这一步什么都没优化,但它已经暴露了核心问题:每次 forward 都要重新算整个序列的 attention,第 2 个 token 时算了前 1 个,第 3 个 token 时又算了前 2 个——O(N²) 重复计算。对 1000 token 的 prompt 生成 200 个 token,相当于算了 1000 + 1001 + ... + 1200 ≈ 220k 次 attention,而真正需要的新计算只有 200 × (1000 + 200) ≈ 240k——重复率接近一半。

2. 批处理:把多个请求一起算

python
# 三个请求,长度不同,需要 padding 到等长
prompts = [
    [1, 1500, 2500, 980],          # 长度 4
    [1, 980, 2333, 880, 1024, 55], # 长度 6
    [1, 733],                       # 长度 2
]
max_len = max(len(p) for p in prompts)
# 左 padding(attention mask 让模型看不见 pad token)
input_ids = torch.full((3, max_len), pad_id, device="cuda")
attention_mask = torch.zeros(3, max_len, device="cuda")
for i, p in enumerate(prompts):
    input_ids[i, max_len - len(p):] = p
    attention_mask[i, max_len - len(p):] = 1

with torch.no_grad():
    logits = model(input_ids, attention_mask=attention_mask)
    next_tokens = logits[:, -1, :].argmax(-1)  # 三个请求各拿各的 next token

batch=3 时算术强度提升 3 倍——但代价是 padding 浪费、且必须等最慢请求算完。这就是 static batching 的痛点,也是 continuous batching 要解决的。

3. KV cache:避免重复计算

python
# 关键:让模型把每层的 K、V 缓存下来,下一步只算新 token
past_key_values = None
generated = list(prompts[0])  # 复制第一个 prompt 作为已生成序列

for _ in range(20):  # 生成 20 个 token
    input_ids = torch.tensor([[generated[-1]]], device="cuda")  # 只喂新 token
    with torch.no_grad():
        out = model(input_ids, past_key_values=past_key_values, use_cache=True)
    logits = out.logits[:, -1, :]
    past_key_values = out.past_key_values  # 累积 KV cache
    next_token = logits.argmax(-1).item()
    generated.append(next_token)

加了 KV cache 后,每步只算 1 个 token 的前向——算力下降 O(seq_len) 倍,但访存变成每步读整个 KV cache。这是 LLM 推理的最关键数据结构,PagedAttention 就是在它上面做分页管理。

真正动手跑一遍

上面三段代码在任意一个有 GPU 的环境都能跑。建议用 transformersLlamaForCausalLM 试一遍:依次加上 use_cache=False/True、batch=1/4/16,记录每一步的 tokens/s 和显存峰值——你会发现 KV cache 是 LLM 推理的命脉,batch size 是吞吐的命脉。完整的实战流程见从零构建推理服务

五、为什么推理优化"有效":三个实证刻度

"推理优化能加速"不是宣传口号,是可以用公开数据检验的事实。三个里程碑式的实证:

1. TensorRT vs 原生 PyTorch:2-4x

TensorRT 是 NVIDIA 的推理引擎,对同一模型做图融合 + 算子融合 + 精度优化。在 ResNet-50 上,TensorRT INT8 相比 PyTorch FP32 通常 2-4x 吞吐提升;在 BERT-large 上,TensorRT 相比 PyTorch FP16 约 3x 吞吐提升。这个加速不需要改模型、不需要换硬件,纯工程优化。详见TensorRT 案例

2. vLLM PagedAttention:10-20x

2023 年 6 月,UC Berkeley 的 vLLM 论文《Efficient Memory Management for LLM Serving with PagedAttention》发布,核心是把 KV cache 像操作系统的虚拟内存一样分页管理,把显存利用率从 ~20% 拉到 ~90%,同时支持 continuous batching。实测在 Llama-2-70B 上,vLLM 相比 HuggingFace Transformers(FP16)的吞吐提升约 14-24x——这是 LLM 推理工程化的引爆点。详见vLLM 与 PagedAttention

3. EAGLE-3 投机解码:2-6x

2024-2025 年,投机解码(speculative decoding)从理论走向工程。EAGLE 系列用一个小型"草稿头"猜几个 token,大模型并行验证,验证通过的 token 一次性接收。EAGLE-3 在 Llama-3-70B 上实测 2-6x 加速,且不改变输出分布——这是一个"既要又要"的优化。详见投机解码案例

三个刻度叠加起来:原生 PyTorch (1x) → TensorRT (3x) → vLLM (30x) → + EAGLE-3 (90x)。90 倍差距全在工程,模型权重一字未改——这就是推理工程作为独立学科存在的理由。

一个诚实的反面

推理优化的收益是有条件的:量化在敏感模型上会掉点(尤其是 INT4 权重 only 对激活异常值敏感);投机解码在算力已经喂饱时收益小(受 HBM 带宽限制);PagedAttention 在 batch=1 时收益不如大 batch。所有优化都有它的 sweet spot,离开 workload 谈加速倍数都是耍流氓。系统化的陷阱清单见常见陷阱与反模式

六、本手册怎么用

推理加速是工程、算法与硬件三者的交汇,本站按"建立概念 → 理解机制 → 拆解案例 → 动手实践"的顺序组织:

  1. 导读(你在这里):接着读推理 vs 训练 vs 微调切清三种 workload 的边界,用演进简史建立时间线,再用总体架构解剖建立全站地图,最后按学习路径选一条路线对号入座。
  2. 核心知识:从延迟与吞吐访存与带宽Roofline 模型 打下性能分析地基;然后量化剪枝蒸馏 拆模型层;算子融合图优化 拆算子图层;GPU 优化批处理与调度模型服务 拆系统硬件层。
  3. 案例拆解:把抽象概念落到具体引擎——TensorRTONNX RuntimeOpenVINOvLLMTensorRT-LLM投机解码llama.cpp移动端部署Triton Server分布式推理
  4. 动手实践从零构建推理服务渐进式教程基准测试作品集项目引擎对比调优实战设计原则常见陷阱
  5. 随时查阅:术语表硬件入门基准数据精选资源

延伸阅读

参考资料