本站内容由 AI 生成,可能存在错误。如发现问题,欢迎到 GitHub Issues 反馈。

Prefill vs Decode 阶段

Prefill vs Decode 阶段

更新于 2026-04-23

简介:LLM 推理不是一步完成的

当你向 ChatGPT 提问时,你会注意到两个明显不同的阶段:

  1. 等待片刻 — 模型在处理你的完整输入(prompt)
  2. 逐字输出 — 模型开始一个接一个地生成 token

这两个阶段对应着 LLM 推理中的两个根本不同的计算过程:Prefill(预填充)Decode(解码)。它们不仅在功能上不同,在计算特性上也截然相反 — 一个是 compute-bound(计算密集),另一个是 memory-bound(内存带宽密集)。

理解这两个阶段的区别,是理解 LLM 服务性能优化的基础。

LLM 推理两阶段概览LLM 推理的两个阶段Prefill并行处理所有 prompt tokensDecode逐 token 自回归生成用户体验⏳ 等待首个 token (TTFT)用户体验▶️ 流式输出 tokens (TPS)两阶段的计算特性完全不同:Compute-bound vs Memory-bound

Prefill 阶段:并行处理 Prompt

Prefill 阶段的任务是处理用户输入的完整 prompt,为生成阶段做准备。

Prefill 阶段并行处理流程Prefill:并行处理所有 Prompt Tokenst1t2t3t4t5N 个 tokens同时输入QKV 投影GEMMN×N Attention全注意力矩阵FFNGEMMKV Cache填充 N 条N×N 注意力矩阵一次性填充GEMM (Matrix × Matrix):Compute-Bound

工作流程

假设 prompt 有 nn 个 token,Prefill 阶段会:

  1. 将所有 nn 个 token 同时送入模型
  2. 对每一层 Transformer,计算所有 token 的 Query、Key、Value
  3. 执行完整的 Self-Attention:每个 token 关注所有之前的 token
  4. 生成并缓存 KV Cache — 后续 Decode 阶段将复用这些缓存
  5. 输出第一个生成 token

计算特性

Prefill 的核心计算是大规模矩阵乘法。以一层 Transformer 的 QKV 投影为例:

Q=XWQ,K=XWK,V=XWVQ = X \cdot W^Q, \quad K = X \cdot W^K, \quad V = X \cdot W^V

其中 XX 的形状为 (n×d)(n \times d),每个权重矩阵 WQ,WK,WVW^Q, W^K, W^V 的形状均为 (d×d)(d \times d)。以单个投影(如 Q=XWQQ = X \cdot W^Q)为例,这是一个经典的矩阵-矩阵乘法(GEMM),计算量为:

FLOPs=2×n×d×d=2nd2\text{FLOPs} = 2 \times n \times d \times d = 2nd^2

需要加载的数据量(权重矩阵)约为:

Bytes=d2×sizeof(dtype)\text{Bytes} = d^2 \times \text{sizeof(dtype)}

因此 Arithmetic Intensity(算术强度,即每加载一字节数据执行的浮点运算次数)为:

AIprefill=2nd2d2×sizeof(dtype)=2nsizeof(dtype)\text{AI}_{\text{prefill}} = \frac{2nd^2}{d^2 \times \text{sizeof(dtype)}} = \frac{2n}{\text{sizeof(dtype)}}

以 FP16 为例(2 bytes),当 prompt 长度 n=1024n = 1024 时:

AIprefill=2×10242=1024 FLOPs/Byte\text{AI}_{\text{prefill}} = \frac{2 \times 1024}{2} = 1024 \text{ FLOPs/Byte}

这个值非常高!远超现代 GPU 的计算-带宽比(如 A100 的约 312 FLOPs/Byte),意味着 Prefill 是 compute-bound — GPU 的算力是瓶颈,而非内存带宽。

GEMM (Prefill) vs GEMV (Decode)

Prefill 做矩阵×矩阵 (GEMM),Decode 做向量×矩阵 (GEMV)。关键差异在于数据复用率

Prefill (GEMM)
(4×6) × (6×6)
输入 (4×6)
×
权重 (6×6)

权重的每列被 4 行复用 → 数据复用率高

GPU 核心
88%
Decode (GEMV)
(1×6) × (6×6)
输入 (1×6)
×
权重 (6×6)

权重的每列只被 1 行用一次 → 加载即丢弃

GPU 核心
25%

关键特征

  • 所有 token 并行处理:充分利用 GPU 并行能力
  • 大矩阵运算(n×d)×(d×d)(n \times d) \times (d \times d) 的 GEMM 操作,GPU 擅长处理
  • 高算术强度:计算量远大于数据搬运量
  • GPU 利用率高:通常可以达到较高的 MFU(Model FLOPs Utilization)

Decode 阶段:自回归逐 Token 生成

Prefill 完成后,模型进入 Decode 阶段,开始逐个生成新 token。

Decode 阶段逐 token 生成流程Decode:逐 Token 自回归生成t1 个 token新输入QKV 投影GEMV1×N Attnquery vs KV CacheFFNGEMV采样 token→ 下一步1×N 注意力KV Cache+1循环直到 EOSGEMV (Matrix × Vector):Memory-Bound

工作流程

每个 Decode 步骤:

  1. 取上一步生成的 单个 token 作为输入
  2. 计算该 token 的 Query、Key、Value
  3. 将新的 K、V 追加到 KV Cache 中
  4. 用新 token 的 Query 与完整 KV Cache 做 Attention
  5. 通过 FFN 层,输出下一个 token 的概率分布
  6. 采样得到下一个 token,重复以上过程

计算特性

Decode 的核心计算退化为向量-矩阵乘法(GEMV)。以 QKV 投影为例:

q=xWQq = x \cdot W^Q

其中 xx 的形状为 (1×d)(1 \times d)WW 的形状为 (d×d)(d \times d)。计算量为:

FLOPs=2×1×d×d=2d2\text{FLOPs} = 2 \times 1 \times d \times d = 2d^2

需要加载的数据量不变 — 仍然要加载整个权重矩阵 WW

Bytes=d2×sizeof(dtype)\text{Bytes} = d^2 \times \text{sizeof(dtype)}

Arithmetic Intensity:

AIdecode=2d2d2×sizeof(dtype)=2sizeof(dtype)\text{AI}_{\text{decode}} = \frac{2d^2}{d^2 \times \text{sizeof(dtype)}} = \frac{2}{\text{sizeof(dtype)}}

以 FP16 为例:

AIdecode=22=1 FLOPs/Byte\text{AI}_{\text{decode}} = \frac{2}{2} = 1 \text{ FLOPs/Byte}

仅为 1 FLOPs/Byte!远低于 GPU 的计算-带宽比,意味着 Decode 是 memory-bound — 内存带宽是瓶颈,GPU 大量算力被闲置,等待数据加载。

Attention 部分同样是 memory-bound

Decode 时的 Attention 计算也面临同样的问题。新 token 的 query 向量 qq 需要与 KV Cache 中所有 SS 个 key 做点积:

FLOPs=2×S×dk(点积 + 缩放)\text{FLOPs} = 2 \times S \times d_k \quad (\text{点积 + 缩放})

而需要从显存加载的 KV Cache 大小为:

Bytes=2×S×dk×sizeof(dtype)(K 和 V 各一份)\text{Bytes} = 2 \times S \times d_k \times \text{sizeof(dtype)} \quad (\text{K 和 V 各一份})

Arithmetic Intensity:

AIattn=2Sdk2Sdk×sizeof(dtype)=1sizeof(dtype)=0.5 FLOPs/Byte (FP16)\text{AI}_{\text{attn}} = \frac{2Sd_k}{2Sd_k \times \text{sizeof(dtype)}} = \frac{1}{\text{sizeof(dtype)}} = 0.5 \text{ FLOPs/Byte (FP16)}

极低的算术强度。随着序列长度 SS 增长,KV Cache 线性增大,加载开销也线性增加。

关键特征

  • 每步仅处理 1 个 token:无法利用 GPU 大规模并行能力
  • 向量-矩阵运算(1×d)×(d×d)(1 \times d) \times (d \times d) 的 GEMV 操作
  • 低算术强度:数据搬运量与计算量同阶
  • GPU 利用率极低:大部分时间在等待内存读取

对比图:两阶段的计算流程

Prefill vs Decode 阶段对比Prefill 阶段处理完整 Prompt(并行)输入: n 个 token 同时处理token₁token₂token₃...tokenₙ矩阵 x 矩阵 (GEMM)(n x d) x (d x d) = n x dFull Self-Attention (n x n)生成完整 KV Cache输出: 第一个 tokenCompute-boundAI = 2n / sizeof(dtype) (FP16 下约 1024)GPU 算力是瓶颈,利用率高决定 TTFT (Time To First Token)Decode 阶段自回归生成(逐 token)输入: 1 个 tokennew token向量 x 矩阵 (GEMV)(1 x d) x (d x d) = 1 x dQuery x KV Cache (1 x S)追加到 KV Cache (S → S+1)输出: 下一个 token重复直到结束Memory-boundAI = 2 / sizeof(dtype) (FP16 下仅 1)内存带宽是瓶颈,GPU 算力闲置决定 TPS (Tokens Per Second)

上图清晰展示了两个阶段的核心区别:

  • Prefill 将所有 prompt token 并行送入模型,执行大规模矩阵乘法,是 compute-bound 操作
  • Decode 每步仅处理一个 token,执行向量-矩阵乘法并读取完整 KV Cache,是 memory-bound 操作

Compute-bound vs Memory-bound:Arithmetic Intensity 分析

Roofline 模型

要理解为什么 Prefill 和 Decode 的瓶颈不同,需要借助 Roofline 模型。Roofline 模型描述了硬件的两个关键参数之间的关系:

  • 峰值算力 π\pi(FLOPs/s):GPU 每秒可执行的最大浮点运算次数
  • 峰值带宽 β\beta(Bytes/s):GPU 显存每秒可传输的最大数据量

两者的比值定义了计算-带宽平衡点

I=πβ(FLOPs/Byte)I^* = \frac{\pi}{\beta} \quad (\text{FLOPs/Byte})

对于 NVIDIA A100(SXM,FP16 Tensor Core):

IA100=312 TFLOPS2039 GB/s153 FLOPs/ByteI^*_{A100} = \frac{312 \text{ TFLOPS}}{2039 \text{ GB/s}} \approx 153 \text{ FLOPs/Byte}

判断规则

  • 如果操作的 Arithmetic Intensity AI>I\text{AI} > I^*,则该操作是 compute-bound
  • 如果 AI<I\text{AI} < I^*,则该操作是 memory-bound
I* = 156 FLOP/BMemory-boundCompute-boundPrefillDecode (bs=1)Arithmetic Intensity (FLOP/Byte, log)Throughput (TFLOPS, log)
Decode: AI = 1.0 FLOP/B → ⚠️ Memory-bound (带宽瓶颈) | Prefill: AI ≈ 2048 FLOP/B → ✅ Compute-bound

两阶段的 Arithmetic Intensity 对比

指标Prefill (nn tokens)Decode (1 token)
线性层 FLOPs2nd22nd^22d22d^2
线性层 Bytesd2×sizeofd^2 \times \text{sizeof}d2×sizeofd^2 \times \text{sizeof}
AI (线性层, FP16)nn11
Attention FLOPsO(n2dk)O(n^2 d_k)O(Sdk)O(S \cdot d_k)
Attention BytesO(n2+ndk)O(n^2 + nd_k)O(Sdk)O(S \cdot d_k)
AI (Attention, FP16)较高0.5\approx 0.5
瓶颈类型Compute-boundMemory-bound

以 A100 为例(I153I^* \approx 153),prompt 长度 n=512n = 512

  • Prefill:AI 512153\approx 512 \gg 153,compute-bound。GPU 算力被充分利用
  • Decode:AI 1153\approx 1 \ll 153,memory-bound。GPU 只利用了约 1/1530.65%1/153 \approx 0.65\% 的峰值算力

这就是为什么 Decode 效率如此之低 — GPU 的绝大部分算力都在空转,等待数据从显存搬运过来。

Batch Size 的影响

增加 batch size BB 可以提升 Decode 的算术强度。当同时为 BB 个请求做 Decode 时:

AIdecode, batched=2Bd2d2×sizeof(dtype)=2Bsizeof(dtype)=B (FP16)\text{AI}_{\text{decode, batched}} = \frac{2Bd^2}{d^2 \times \text{sizeof(dtype)}} = \frac{2B}{\text{sizeof(dtype)}} = B \text{ (FP16)}

权重矩阵只需加载一次,但为 BB 个请求分别计算,计算量乘以 BB。当 BIB \geq I^*(A100 上 B153B \geq 153)时,Decode 也能变成 compute-bound。

但实际中有两个限制:

  1. KV Cache 显存:每个请求的 KV Cache 会占用大量显存,限制了可用的 batch size
  2. 延迟约束:batch 太大会增加单个请求的延迟

这正是 GQA/MQA 等 KV Cache 压缩技术的重要性所在 — 缩小 KV Cache 后可以支持更大的 batch size,从而提升 Decode 阶段的效率。

实际性能影响:TTFT vs TPS

两个阶段分别对应不同的用户体感指标:

TTFT — Time To First Token

定义:从用户发送请求到收到第一个生成 token 的时间。

TTFT 主要由 Prefill 阶段决定。影响因素:

  • Prompt 长度:prompt 越长,Prefill 计算量越大,TTFT 越高
  • GPU 算力:Prefill 是 compute-bound,更快的 GPU 直接缩短 TTFT
  • Prefill 计算量与 prompt 长度近似线性(Attention 部分是二次的,但通常 FFN 主导)

TPS — Tokens Per Second

定义:Decode 阶段每秒生成的 token 数量。

TPS 由 Decode 阶段决定。影响因素:

  • 内存带宽:Decode 是 memory-bound,带宽越高 TPS 越快
  • 模型大小:参数越多,每步需要加载的权重越多
  • KV Cache 大小:序列越长,Attention 步骤加载的数据越多

数值估算

以 LLaMA-2 7B(约 14×10914 \times 10^9 bytes FP16)在 A100 上为例:

Decode TPS 估算(memory-bound,忽略 KV Cache):

TPS带宽模型大小=2039 GB/s14 GB146 tokens/s\text{TPS} \approx \frac{\text{带宽}}{\text{模型大小}} = \frac{2039 \text{ GB/s}}{14 \text{ GB}} \approx 146 \text{ tokens/s}

实际受 KV Cache 加载、内核启动开销等因素影响,真实值通常在 100-130 tokens/s 左右(batch size = 1)。

Prefill 速度估算(compute-bound):

tokens/s峰值 TFLOPS2×参数量=312×10122×7×10922,286 tokens/s\text{tokens/s} \approx \frac{\text{峰值 TFLOPS}}{2 \times \text{参数量}} = \frac{312 \times 10^{12}}{2 \times 7 \times 10^9} \approx 22{,}286 \text{ tokens/s}

即 Prefill 处理 prompt 的吞吐量可以达到 Decode 的 100 倍以上 — 这就是为什么你感受到”等一下后快速输出”而不是”均匀缓慢输出”。

优化方向

针对两个阶段不同的计算特性,业界发展出了不同的优化策略:

优化方向概览两阶段的优化方向技术原理效果Flash AttentionPrefill 显存优化SRAM 分块HBM O(n²)→O(n)Speculative DecodingDecode 加速小模型大模型验证多步合并验证KV Cache Compression显存压缩GQA/INT8GQA / 量化 Cache

Prefill 优化

  • Flash Attention:虽然 Prefill 整体是 compute-bound,但标准 Attention 实现会将 n×nn \times n 的中间矩阵反复写入/读回 HBM,产生大量不必要的显存访问。Flash Attention 通过分块在 SRAM 中完成 softmax 和矩阵乘,避免中间矩阵落盘,将 Attention 部分的 HBM 访问从 O(n2)O(n^2) 降至 O(n)O(n)
  • Tensor Parallelism:将矩阵运算分布到多个 GPU,提升 compute-bound 操作的吞吐量
  • 量化(Quantization):使用 INT8/FP8 降低精度,在相同硬件上获得更高的有效算力

Decode 优化

  • KV Cache 压缩:GQA、MQA 减少 KV Cache 大小,降低内存带宽需求
  • Speculative Decoding(推测解码):用小模型快速”猜”多个 token,再用大模型一次验证,将多步 Decode 合并为一次 Prefill-like 的并行验证
  • Continuous Batching:动态组 batch,提升 GPU 利用率

混合优化

  • Chunked Prefill:将长 prompt 分块处理,在 Prefill 的间隙穿插 Decode 步骤,避免长 prompt 的 Prefill 阻塞其他请求的 Decode
  • Disaggregated Serving(分离式推理):将 Prefill 和 Decode 部署到不同的硬件上 — Prefill 用计算密集型 GPU,Decode 用高带宽设备

推荐学习资源

如果你想更深入地学习 LLM 推理优化,以下是我们精选的资源:

经典论文

  • Kwon et al.《Efficient Memory Management for Large Language Model Serving with PagedAttention》 — vLLM 核心论文(SOSP 2023),提出用类似 OS 虚拟内存的方式管理 KV Cache,实现近零浪费。是理解现代 LLM serving 内存管理的核心论文。
  • Lilian Weng《Large Transformer Model Inference Optimization》 — 系统性综述 Transformer 推理优化方法,涵盖蒸馏、量化、剪枝、稀疏化、架构优化等,是推理优化领域的最佳综述之一。

博客与教程(图文并茂)

  • kipply《Transformer Inference Arithmetic》推理性能分析的经典博文。从第一性原理推导 LLM 推理延迟,详解 KV Cache 机制、模型并行、batch size 影响、FLOPS 计算、memory bandwidth bound vs compute bound 的判断方法。
  • Patrick von Platen / Hugging Face《Optimizing your LLM in production》 — 涵盖低精度推理(8-bit/4-bit)、Flash Attention、KV Cache 优化(MQA/GQA)、位置编码等,包含详细的内存计算和加速比数据,实操性强。
  • Anyscale《How continuous batching enables 23x throughput in LLM inference》 — 详解 continuous batching 机制,对比 static batching 的吞吐量差异(高达 23 倍),benchmark 了 HF TGI、vLLM、Ray Serve 等框架的实际性能。
  • Finbarr Timbers《How is LLaMa.cpp possible?》 — 分析 LLM 在消费级硬件上推理的可行性原理。通过数学推导展示 memory bandwidth 是瓶颈、量化如何大幅降低内存需求。含不同设备(A100/M1/M2)的性能计算对比。

总结

概念说明
Prefill 阶段并行处理完整 prompt,生成 KV Cache,compute-bound
Decode 阶段自回归逐 token 生成,读取 KV Cache,memory-bound
Arithmetic IntensityPrefill: 2nsizeof\frac{2n}{\text{sizeof}} (高) vs Decode: 2sizeof\frac{2}{\text{sizeof}} (低)
Roofline 模型AI >π/β> \pi / \beta 为 compute-bound,反之为 memory-bound
TTFTTime To First Token,由 Prefill 决定
TPSTokens Per Second,由 Decode 决定
核心矛盾Decode 的 AI 远低于硬件平衡点,GPU 算力严重浪费

核心直觉:LLM 推理的两个阶段就像”备菜”和”上菜”。Prefill 像厨师同时处理所有食材(并行、计算密集),速度取决于厨师的刀工速度(GPU 算力)。Decode 像服务员一道道上菜(串行、带宽密集),速度取决于厨房到餐桌的传送带速度(内存带宽)。理解这个区别,是理解一切 LLM 推理优化技术的起点。