跳转至

五十:LLM推理两阶段:Prefill 和 Decode

来源:http://mp.weixin.qq.com/s?__biz=MzYyNTk3Njg1NA==&mid=2247484656&idx=1&sn=698d5e530f3487c0fcfcfe0d1307d148&chksm=f01eb789c7693e9f1c1bd5ff80d4e4835ccf24f8f2f4311b706510fc994af920168972229c4d#rd

1. 学习范围

本日主题是大模型自回归推理的两个阶段:Prefill 和 Decode。 本日覆盖: - 自回归生成的基本流程。

  • Prefill 阶段的输入、输出、计算特征和显存行为。

  • Decode 阶段的输入、输出、计算特征和显存行为。

  • 两阶段复杂度差异。

  • KV cache 在两阶段中的作用。

  • TTFT、TPOT、吞吐、延迟与两阶段的关系。

  • 工程调度、批处理、长上下文和性能优化。

2. 自回归推理流程

Decoder-only LLM 的生成是自回归的。给定 prompt token 序列,模型先处理完整 prompt,然后每次生成一个新 token,并把新 token 追加到上下文中。 流程:

prompt tokens x_1 ... x_n
  -> prefill
  -> logits for next token
  -> sample y_1
  -> decode step 1
  -> sample y_2
  -> decode step 2
  -> ...
Prefill 处理 prompt,Decode 逐 token 生成输出。二者的计算形态不同,是推理性能分析的基础。

3. Prefill 阶段定义

Prefill 阶段也叫 prompt processing。它把用户输入的 prompt 一次性送入模型,计算每一层的隐藏状态,并为 prompt 中所有 token 生成 KV cache。 输入:

batch_size = B
prompt_length = S
tokens shape = [B, S]
输出: - 下一 token 的 logits。

  • 每层每个 prompt token 的 K/V cache。

Prefill 的核心任务是“读入上下文并建立缓存”。

4. Decode 阶段定义

Decode 阶段逐步生成新 token。每一步通常只输入上一轮生成的一个 token,同时读取历史 KV cache,与全部历史 token 做注意力,再生成下一个 token。 单步输入:

tokens shape = [B, 1]
past_kv length = S + t
单步输出: - 当前步 logits。

  • 新 token 对应的 K/V cache。

Decode 的核心任务是“基于已有缓存逐 token 续写”。

5. 两阶段的关键差异

Prefill 和 Decode 的差异:

Prefill: 一次处理 S 个 prompt token,计算密集,易并行。
Decode: 每步处理 1 个新 token,依赖历史 KV,内存访问密集。
Prefill 的矩阵乘法规模大,GPU 利用率通常更高。Decode 每步计算较小,但要频繁读取越来越长的 KV cache,因此更容易受内存带宽和调度开销限制。

6. Attention 在 Prefill 中的计算

在 Prefill 中,模型对 prompt 序列做 causal self-attention。每个 token 只能看自己之前的 token。 若序列长度为 S,注意力矩阵大小约为:

[B, H, S, S]
计算复杂度近似:

O(B * H * S^2 * d_head)
因为所有 prompt token 一起处理,Prefill 可以充分利用并行矩阵运算。

7. Attention 在 Decode 中的计算

Decode 单步只处理一个 query token,但要与历史所有 key/value 做注意力。 第 t 个生成步的注意力形状近似:

Q: [B, H, 1, d_head]
K: [B, H, S+t, d_head]
V: [B, H, S+t, d_head]
Attention scores: [B, H, 1, S+t]
单步复杂度约为:

O(B * H * (S+t) * d_head)
总 Decode 成本随生成长度增长而增加。

8. KV cache 的作用

如果没有 KV cache,Decode 每生成一个 token 都要重新计算全部历史 token 的 K/V,成本极高。 KV cache 保存每层历史 token 的 key 和 value:

past_k: [B, H_kv, seq_len, d_head]
past_v: [B, H_kv, seq_len, d_head]
有了 KV cache,Decode 只需要计算新 token 的 K/V,然后追加到缓存中,并读取历史缓存做 attention。

9. Prefill 中的 KV 写入

Prefill 会为 prompt 中所有 token 计算 K/V 并写入 KV cache。这个过程通常是连续批量写入,适合大矩阵计算。 写入规模与以下因素成正比: - batch size。

  • prompt length。

  • layer 数。

  • KV head 数。

  • head dimension。

  • 数据类型字节数。

长 prompt 的 Prefill 会显著增加 KV cache 初始占用。

10. Decode 中的 KV 追加

Decode 每生成一个 token,就为该 token 计算每层 K/V 并追加到 KV cache。 Decode 中 KV cache 的长度从 S 增长到 S + output_len。因此输出越长,显存占用越高,后续 token 的注意力读取成本也越高。

11. Prefill 的性能特征

Prefill 通常是 compute-bound 或较强计算密集,因为矩阵乘法规模大,GPU 更容易跑满。 影响 Prefill 性能的因素: - prompt length。

  • batch size。

  • 模型参数量。

  • attention 实现。

  • tensor parallel。

  • FlashAttention。

  • 输入长度分布。

Prefill 直接影响 TTFT, Time To First Token。

12. Decode 的性能特征

Decode 通常更 memory-bound,因为每步只处理少量 token,但要读取大量 KV cache。 影响 Decode 性能的因素: - KV cache 大小。

  • batch size。

  • 并发请求数。

  • 生成长度。

  • 内存带宽。

  • KV cache 管理方式。

  • batch 调度。

  • speculative decoding 等优化。

Decode 直接影响 TPOT, Time Per Output Token。

13. TTFT

TTFT 是 Time To First Token,即从请求到第一个输出 token 出现的时间。 TTFT 主要由以下部分组成:

queue time + prompt tokenization + prefill compute + first decode/sample
长 prompt、排队等待和低效 Prefill 都会增加 TTFT。

14. TPOT

TPOT 是 Time Per Output Token,即生成阶段平均每个输出 token 的耗时。 TPOT 主要受 Decode 阶段影响:

TPOT ~= total decode time / number of generated tokens
TPOT 越低,流式输出越快。Decode 优化通常目标是降低 TPOT 和提升 token throughput。

15. 吞吐与延迟

推理服务同时关注吞吐和延迟。 - 延迟:单个请求等多久。

  • 吞吐:单位时间生成多少 token 或完成多少请求。

Prefill 优化常改善 TTFT,Decode 优化常改善 TPOT 和输出吞吐。批处理可以提升吞吐,但可能增加排队延迟。

16. Prefill 批处理

Prefill 批处理将多个请求的 prompt 一起处理,提高 GPU 利用率。挑战是不同请求 prompt 长度不同,需要 padding 或 ragged batch。 问题: - padding 浪费。

  • 长 prompt 拖慢短 prompt。

  • Prefill 计算量波动大。

  • 与 Decode 请求混合调度困难。

17. Decode 批处理

Decode 批处理把多个请求的下一 token 生成放在同一批中。由于每个请求只生成一个 token,decode batch 需要动态维护活跃序列。 挑战: - 请求长度不同。

  • 有些序列提前结束。

  • 新请求不断加入。

  • KV cache 大小不同。

  • batch 形状不断变化。

Continuous batching 就是为了解决动态请求调度问题。

18. Prefill 与 Decode 的资源冲突

Prefill 计算密集,Decode 内存访问密集。二者混合在同一 GPU 上时可能相互影响。 典型问题: - 大 Prefill 阻塞 Decode,导致流式输出卡顿。

  • Decode 请求占用 KV cache,限制 Prefill batch。

  • 调度不当导致 TTFT 或 TPOT 抖动。

现代推理系统会设计 prefill/decode 调度策略,甚至做 prefill-decode disaggregation。

19. 长上下文影响

长上下文对 Prefill 和 Decode 都有影响: - Prefill attention 成本随 prompt length 二次增长。

  • KV cache 显存随上下文长度线性增长。

  • Decode 每步读取更长 KV cache,TPOT 上升。

  • 请求更容易触发显存不足。

因此长上下文推理需要 KV 管理、分页、滑动窗口、压缩或稀疏注意力等技术。

20. 常见优化方向

Prefill 优化: - FlashAttention。

  • prompt chunking。

  • tensor parallel。

  • prefix caching。

  • prefill batching。

Decode 优化: - KV cache 优化。

  • PagedAttention。

  • continuous batching。

  • speculative decoding。

  • quantized KV cache。

  • attention sinks / sliding window。

21. 面试表达要点

解释 Prefill/Decode 时建议先说流程,再说计算差异,再说指标。 简洁表达:

Prefill 是一次性处理 prompt 并建立 KV cache,计算密集,影响 TTFT。
Decode 是逐 token 生成,每步读取历史 KV cache,内存带宽敏感,影响 TPOT。

22. 参考资料

  • Main stages of auto-regressive decoding: https://aiexpjourney.substack.com/p/main-stages-of-auto-regressive-decoding

  • Prefill 和 Decode 计算量分析: https://zhuanlan.zhihu.com/p/1900479313331073118

  • Hugging Face KV cache documentation: https://huggingface.co/docs/transformers/main/en/kv_cache

  • vLLM PagedAttention documentation: https://docs.vllm.ai/en/stable/design/paged_attention.html

            预览时标签不可点
    

    <div class="