← 人工智能返回顶部

Inference:模型推理原理与性能

LLM Inference 是模型利用已经训练完成的权重,根据输入 Token 自回归生成输出 Token 的过程。

核心概念:

Inference
├── Execution
│   ├── Prefill
│   ├── Decode
│   └── KV Cache
├── Scheduling
│   ├── Batching
│   ├── Continuous Batching
│   └── Chunked Prefill
├── Memory
│   ├── Model Weights
│   ├── KV Cache
│   └── PagedAttention
└── Performance
    ├── TTFT
    ├── TPOT / ITL
    ├── Latency
    └── Throughput

1. Prefill:处理输入 Prompt

Prefill 是推理的初始阶段,负责处理输入 Prompt 并建立 KV Cache。

例如输入包含 2000 个 Token:

Prompt(2000 Tokens)
          ↓
       Prefill
          ├── Token Embedding
          ├── Transformer Layers
          ├── Compute Q / K / V
          ├── Build KV Cache
          └── Generate First-token Logits
          ↓
       First Token

由于 Prompt 的全部 Token 已经存在,模型可以通过 Causal Mask 并行计算多个位置的表示。

主要特点:

  • 输入 Token 数量通常较多。
  • 大规模矩阵运算较多。
  • GPU 并行度高。
  • 通常更偏向 Compute-bound。

Compute-bound

表示执行速度主要受到 GPU 计算能力限制。

例如:

GPU FLOPS 是主要瓶颈
增加计算能力
       ↓
可能提升 Prefill 速度

不过实际性能还取决于序列长度、Batch Size、Attention 实现和内存访问。

Prefill 不一定必须一次处理完整 Prompt,也可以使用 Chunked Prefill 分块执行。

2. Decode:逐 Token 生成

Prefill 产生第一个输出 Token 后,模型继续逐步生成剩余 Token。

自回归生成要求下一个 Token 依赖之前已经生成的 Token。

Previous Generated Token
           ↓
    Compute New Q/K/V
           ↓
  Read Historical KV Cache
           ↓
       Attention
           ↓
          MLP
           ↓
         Logits
           ↓
        Sampling
           ↓
      Next Token

每个 Decode Step 通常只为每条正在生成的序列产生一个新 Token。

Memory-bandwidth-bound

Decode 需要反复读取模型权重,并访问随上下文增长的 KV Cache。

当 Batch 较小时,每轮计算量相对较低,GPU 往往无法充分发挥计算能力。

因此 Decode 通常更容易受到显存带宽限制。

Decode
   ↓
Read Model Weights
Read KV Cache
   ↓
Compute Next Token

当 Batch 增大时,多个请求可以共享一次批处理中的模型权重读取,从而提高计算利用率。

因此 Decode 并不永远是 Memory-bound,较大 Batch 或长上下文可能改变性能瓶颈。

Prefill 与 Decode 对比

对比PrefillDecode
主要任务处理输入 Prompt生成后续 Token
并行度Token 维度并行度较高单条序列逐步生成
计算特点大规模矩阵计算较小的逐步计算
常见瓶颈GPU ComputeMemory Bandwidth
KV Cache创建和填充读取和扩展
主要影响指标TTFTTPOT / ITL

3. KV Cache:缓存 Attention 状态

KV Cache 保存已经处理过的 Token 在各 Transformer Layer 中的 Key 和 Value。

作用是避免每次生成新 Token 时,重新计算所有历史 Token 的 K/V。

Prefill
   ↓
K/V for Prompt Tokens
   ↓
KV Cache
   ↓
Decode Step 1 → Append K/V
   ↓
Decode Step 2 → Append K/V
   ↓
Decode Step 3 → Append K/V

KV Cache 内存估算

对于常见的 Decoder-only Transformer:

M∗KV≈2×L×H∗kv×D×S×B×PM*{\mathrm{KV}} \approx 2 \times L \times H*{kv} \times D \times S \times B \times P

其中:

参数含义
(L)Transformer 层数
(H_kv)KV Head 数
(D)Head Dimension
(S)每条序列缓存的 Token 数
(B)Batch 中的序列数
(P)每个元素的字节数

例如:

32 Layers
8 KV Heads
128 Head Dimension
4096 Cached Tokens
1 Sequence
BF16 = 2 Bytes

理论 KV Cache 大小约为 512 MiB。

这是未考虑分页分配、内存对齐、共享前缀及其他运行时开销的估算。

重要结论:

  • Context Length 越大,KV Cache 通常越大。
  • Batch 中的序列越多,KV Cache 总量通常越大。
  • GQA/MQA 可以降低 KV Cache 大小。
  • KV Cache Quantization 可以进一步减少内存开销。

4. Context Length

Context Length 是模型在当前推理过程中允许使用的上下文 Token 数量上限。

通常:

Input Tokens+Generated Tokens≤Context Limit\text{Input Tokens}+\text{Generated Tokens}\leq\text{Context Limit}

需要注意:

  • 模型架构的理论位置范围不一定等于可靠支持的上下文长度。
  • 推理引擎可能设置更小的 max_model_len。
  • 长上下文通常增加 KV Cache 占用与 Attention 开销。
  • 实际上还可能受到模型精度、RoPE 配置和 GPU 内存限制。

Context Length 影响的是单条请求可以使用的上下文规模,而 Batch Size 影响的是同时处理的请求数量,两者共同决定 KV Cache 压力。

5. Batching:批处理

Batching 是指将多个请求组合起来,在 GPU 上执行计算。

例如:

Request A ──┐
Request B ──┼── GPU Batch
Request C ──┘

优点:

  • 提高 GPU 利用率。
  • 分摊模型权重读取开销。
  • 提高服务器整体吞吐量。

缺点:

  • 可能增加排队等待。
  • 消耗更多 KV Cache 内存。
  • Batch 太大时可能降低单请求响应速度。

Static Batching

传统静态 Batch 通常要求一个 Batch 内的请求作为一组被调度。

不同请求的输入及输出长度可能不同,容易产生 Padding 或等待造成的浪费。

Continuous Batching

Continuous Batching(也称 In-flight Batching)允许请求动态加入或离开正在执行的批次。

Step 1: A B C
Step 2: A B C
Step 3: A   C     ← B 完成
Step 4: A D C     ← D 加入
Step 5:   D C     ← A 完成

核心价值:

  • 请求不需要同时进入。
  • 完成的请求可以立即释放资源。
  • 新请求可以在后续调度步骤加入。
  • 提高 GPU 利用率与服务吞吐量。

Continuous Batching 是 vLLM、SGLang 等现代推理引擎的重要调度机制。

6. Chunked Prefill

长 Prompt 的 Prefill 可能占用大量 GPU 计算资源,从而影响正在 Decode 的请求。

Chunked Prefill 将长 Prompt 拆成多个 Token Chunk 处理。

例如:

Prompt: 4096 Tokens

Chunk 1: 1024
Chunk 2: 1024
Chunk 3: 1024
Chunk 4: 1024

这样调度器可以在多个调度步骤之间安排 Prefill 和 Decode 工作。

GPU Scheduling
       ↓
Decode Batch
       ↓
Prefill Chunk
       ↓
Decode Batch
       ↓
Prefill Chunk

主要目的:

  • 避免长 Prefill 长时间占用计算资源。
  • 减少对其他请求 TPOT 的影响。
  • 提供更灵活的吞吐量与延迟权衡。

但分块也可能增加单条 Prompt 完成 Prefill 的时间,因此需要合理配置调度策略。

vLLM 中 max_num_batched_tokens 等参数可影响每个调度步骤的 Token 预算。

7. PagedAttention

KV Cache 随 Token 数量动态增长。

如果为每个请求预留连续的大块显存,容易出现内存浪费和碎片化。

PagedAttention 将 KV Cache 划分为固定大小的 Block,并通过映射关系管理。

Request A
Logical Blocks
  [0] [1] [2]
   ↓   ↓   ↓
Physical KV Blocks
  [7] [3] [9]

Request B
Logical Blocks
  [0] [1]
   ↓   ↓
Physical KV Blocks
  [2] [5]

主要优势:

  • KV Cache 不需要为每条请求预留完整的连续物理空间。
  • 降低显存碎片化与预留浪费。
  • 更灵活地分配和回收 KV Cache。
  • 可以支持某些 KV Block 共享策略。

PagedAttention 主要解决 KV Cache 内存管理问题,而 Continuous Batching 主要解决请求调度问题。

两者结合可以提高推理服务的并发能力。

8. 推理性能指标

指标含义优化目标
TTFTTime To First Token越低越好
TPOTTime Per Output Token越低越好
ITLInter-token Latency越低越好
Latency请求总耗时越低越好
Throughput单位时间处理的工作量越高越好
Tokens/sToken 处理或生成速度越高越好

TTFT

从请求发出到客户端收到第一个输出 Token 的时间。

Request
   ↓
Queue
   ↓
Prefill
   ↓
First Token

TTFT 包含的不只是 GPU Prefill 时间,还可能包含网络、请求排队、Tokenization 和首次输出传输开销。

TPOT / ITL

TPOT 通常表示生成阶段平均每个后续 Token 所需时间。

常见计算方式:

TPOT=Latency−TTFTN_output−1TPOT=\frac{Latency-TTFT}{N\_{\mathrm{output}}-1}

其中 math\(N\_{\mathrm{output}}>1\)math。

例如:

TTFT = 1.0 s
Total Latency = 5.0 s
Output Tokens = 101

则:

TPOT = 40 ms/token

对应的平均后续生成速度约为 25 tokens/s。

注意:不同 Benchmark 工具对 TPOT、ITL、首 Token 和流式 Chunk 的统计方式可能有差异,比较结果时需要确认定义。

请求从开始到完成的端到端时间。

Request Start
      ↓
Queue + Prefill + Decode + Delivery
      ↓
Request Complete

对于流式生成,请求的总延迟通常可以分解为:

Latency≈TTFT+(N_output−1)×TPOTLatency \approx TTFT+(N\_{\mathrm{output}}-1)\times TPOT

Throughput

服务器单位时间处理的工作量。

常见指标:

Requests/s
Input Tokens/s
Output Tokens/s
Total Tokens/s

其中 Output Tokens/s 通常用于衡量生成吞吐量。

单用户 Tokens/s 与服务器整体 Tokens/s 不是同一个指标。

例如:

  • 单用户速度:30 tokens/s。
  • 服务器同时处理 20 个请求。
  • 服务器整体生成吞吐量可能远高于 30 tokens/s。

但整体吞吐量不会简单地随并发请求数线性增长。

9. Latency 与 Throughput 的权衡

推理服务通常同时追求:

  • 较低的 TTFT。
  • 较低的 TPOT。
  • 较高的 Throughput。
  • 较好的 GPU 利用率。

但这些目标可能互相冲突。

Smaller Batch
     ↓
通常较低的排队与调度开销
     ↓
较低整体吞吐量风险

Larger Batch
     ↓
更高 GPU 利用率
     ↓
更高整体吞吐量
     ↓
可能增加单请求延迟

例如增加并发量:

  • GPU 利用率可能上升。
  • 总 Output Tokens/s 可能上升。
  • Queue Time 也可能上升。
  • TTFT 和 TPOT 可能恶化。

因此不能只关注 Tokens/s。

P50 / P95 / P99

性能评测通常报告延迟分位数。

  • P50:50% 请求的延迟不超过该值。
  • P95:95% 请求的延迟不超过该值。
  • P99:99% 请求的延迟不超过该值。

平均延迟较低并不代表高负载时不存在严重的尾部延迟。

10. 推理性能优化思路

问题可能的优化方向
TTFT 高降低排队时间、优化 Prefill、Prefix Caching
TPOT 高Continuous Batching、Attention Kernel、提高内存效率
KV Cache 显存不足GQA、KV Cache Quantization、PagedAttention
GPU 利用率低调整 Batch Size、Continuous Batching
长 Prompt 影响其他请求Chunked Prefill
模型权重占用过高Weight Quantization
高并发排队严重调整调度参数、增加副本或计算资源

Prefix Caching

如果多个请求具有相同的 Prompt 前缀,可以在满足条件时复用已经计算好的 KV Cache Block。

例如:

Request A:
[System Prompt] + [Question A]

Request B:
[System Prompt] + [Question B]

如果系统能够复用共同的 System Prompt 前缀,就可以减少重复 Prefill 计算。

不过 Prefix Caching 的收益取决于前缀重复率、缓存命中情况和内存容量,并不能保证所有请求都明显加速。

总结

LLM 推理可以用以下结构理解:

Incoming Requests
        ↓
Request Queue / Scheduler
        ↓
Continuous Batching
        │
        ├── Prefill
        │    └── Build KV Cache
        │
        └── Decode
             ├── Read KV Cache
             ├── Generate Token
             └── Extend KV Cache
        ↓
Streaming Response

需要重点掌握的关系:

概念核心理解
Prefill并行处理输入 Prompt,通常更偏计算密集
Decode自回归逐 Token 生成,通常更偏显存带宽密集
KV Cache减少重复计算,但增加显存开销
Continuous Batching动态管理正在处理的请求
Chunked Prefill降低长 Prompt 对其他请求的阻塞
PagedAttention高效分配和管理 KV Cache
TTFT首 Token 响应速度
TPOT后续 Token 的平均生成间隔
Latency单请求端到端耗时
Throughput整个推理服务的处理能力

实际性能测试时,应固定模型、输入输出 Token 长度、硬件和并发条件,否则不同测试结果可能不具备可比性。


参考文档