LLM 推理的 Prefill 和 Decode

LLM 推理不是一锤子买卖。从你输入提示词到模型吐出最后一个 token,中间经历了两个本质不同的阶段:Prefill 和 Decode。搞清楚这两者的区别,是理解所有推理优化技术的起点。

Prefill(预填充)是处理输入的阶段。模型接收整段提示词,一次性完成所有 token 的计算。这个阶段是并行的——所有 token 同时参与矩阵乘法,GPU 的算力被充分利用。打个比方,就像搬家公司派了一整车人来,同时搬所有箱子,效率拉满。

输入 Prompt → GPU 并行计算所有 tokens → KV Cache → 输出

Decode(解码)是生成输出的阶段。模型一个接一个地生成 token,每次只生成一个。这个阶段是串行的,每个新 token 都依赖前一个 token 的输出。更关键的是,每次生成的计算量很小,瓶颈不在计算,而在内存带宽。GPU 大部分时间在等数据从显存搬到计算单元。

Step 1: 读取所有 KV Cache → 计算 → 生成 token_1
Step 2: 读取所有 KV Cache → 计算 → 生成 token_2
Step 3: 读取所有 KV Cache → 计算 → 生成 token_3
        ↑_____________________________________↑
        每一步都要读取,内存带宽是瓶颈

这两个阶段的性能特征差异巨大。Prefill 是算力受限(compute-bound),GPU 算力越强越快。Decode 是内存带宽受限(memory-bound),显存带宽才是决定因素。

用具体数字说话:一个 7B FP16 模型,权重约占 14GB 显存。每次 Decode step 都要把这 14GB 从显存搬到计算单元。A100 的 HBM 带宽是 2 TB/s,理论极限是 14GB ÷ 2TB/s = 7ms/token,也就是约 140 tok/s。这就是 Decode 阶段的硬上限,跟算力无关,纯粹是内存带宽决定的。

正是因为 Decode 阶段的这个硬上限,才催生了各种优化技术。

理解这个区别有什么用?它直接解释了为什么需要「键值缓存(KV Cache)」——避免 Decode 阶段重复计算前面 token 的中间结果。解释了为什么需要「分页注意力(PagedAttention)」——解决 KV Cache 在显存中的碎片化管理问题。也解释了「前缀缓存(Prefix Caching)」的价值——利用多个请求共享相同系统提示词的特点,减少 Prefill 阶段的重复计算。

当你看到某个推理框架宣称优化了性能,第一个问题就该问:它优化的是 Prefill 还是 Decode?是减少了计算量,还是提高了内存带宽的利用率?搞清楚这个,就能判断这个优化是否真的有意义。

MN-Core L 系列芯片的 3D stacked DRAM 设计,本质上就是在解决 Decode 阶段的内存带宽瓶颈。当算力不再是瓶颈,内存带宽就成了制约推理速度的关键。这也是为什么 Preferred Networks 要专门招聘 LLM Serving Engine Engineer——硬件需要软件层面的深度配合才能发挥全部潜力。


如何诊断你的推理瓶颈

理解概念之后,更重要的是应用到实践中。你可以通过以下步骤判断你的推理服务瓶颈在哪里:

1. 监控 GPU 利用率和显存带宽

# NVIDIA GPU 监控
nvidia-smi dmon -s u -d 1  # GPU 利用率
nvidia-smi dmon -s p -d 1  # 显存带宽

2. 分析请求特征

3. 优化策略选择

下一篇讲「键值缓存(KV Cache)」,这个 LLM 推理中最重要也最容易被忽视的机制。


参考文献:

相关文章