课程导入:学习目标、核心概念、整体框架

欢迎来到《PagedAttention机制深度解析》课程。在正式进入技术细节之前,我们需要先建立对整个知识版图的清晰认知。PagedAttention并非一个孤立的算法,而是连接着操作系统虚拟内存管理、GPU硬件架构、大语言模型推理引擎等多个领域的交叉创新。本章将帮助你明确学习目标、掌握核心概念,并构建起贯穿后续29章的整体框架。

1.1 学习目标:从“会用”到“能改”

完成本课程后,你应当具备以下四个层次的能力。这四个层次层层递进,对应着不同的职业角色与工程深度:

层次 能力描述 对应角色
第一层:理解 能清晰解释PagedAttention解决的核心问题(KV Cache碎片化与冗余),并对比其与朴素注意力机制的内存管理差异。 算法工程师
第二层:应用 能在vLLM、SGLang等推理框架中配置相关参数,识别并规避显存溢出(OOM)风险。 推理优化工程师
第三层:分析 能通过Profiling工具观察KV Cache的物理块分配情况,定位吞吐瓶颈。 性能分析专家
第四层:改造 能基于PagedAttention思想,为自定义注意力变体(如GQA、MLA)设计专属的内存管理方案。 系统架构师
学习建议:本课程包含大量代码片段与显存计算示例。建议你准备一个支持CUDA的GPU环境(哪怕只有8GB显存),边学边动手验证。纯理论阅读的效果会打五折。

1.2 核心概念:KV Cache与显存墙

要理解PagedAttention,必须先理解它要解决的问题——KV Cache。在自回归生成过程中,模型需要反复计算注意力分数。为了避免重复计算历史token的Key和Value矩阵,推理引擎会将其缓存在显存中,这就是KV Cache。

KV Cache的大小与序列长度和层数呈线性关系,且增长极快。以LLaMA-7B模型为例,当batch size为1、序列长度为2048时,KV Cache约占显存的1.2GB;当batch size增至32时,仅KV Cache就需要约38GB显存——这已经超过了单张A100(80GB)的一半容量。更棘手的是,KV Cache的显存分配是动态且碎片化的:

  • 预分配浪费:传统方式按最大序列长度预分配连续显存,但实际生成长度往往远小于上限,导致大量显存闲置。
  • 内部碎片:不同序列长度不同,连续分配方式导致显存空洞无法被其他序列利用。
  • 无法共享:并行采样(如beam search)时,多个序列共享前缀,但传统方式无法共享KV Cache,造成重复存储。

PagedAttention的核心思想,正是借鉴操作系统中的虚拟内存分页机制,将KV Cache划分为固定大小的物理块(Block),通过块表(Block Table)实现逻辑地址到物理地址的映射。这样,KV Cache不再需要连续显存,碎片化问题迎刃而解。

PagedAttention 核心思想:逻辑分页 vs 物理块映射 逻辑视图(连续) 逻辑块 0 (Token 0-3) 逻辑块 1 (Token 4-7) 逻辑块 2 (Token 8-11) 逻辑块 3 (Token 12-15) 逻辑块 4 (未分配) 块表 (Block Table) 逻辑块 0 → 物理块 7 逻辑块 1 → 物理块 2 逻辑块 2 → 物理块 5 逻辑块 3 → 物理块 9 逻辑块 4 → NULL 物理显存(非连续) 块 0 空闲 块 1 空闲 块 2 逻辑1 块 3 空闲 块 4 空闲 块 5 逻辑2 块 6 空闲 块 7 逻辑0 块 8 空闲 块 9 逻辑3 块 10 空闲 块 11 空闲 块 12 空闲 块 13 空闲 块 14 空闲 块 15 空闲 物理块无需连续,空闲块可被任意序列复用,块表记录映射关系 对比传统连续分配:物理块 3、4、6、8 等空闲块可被其他序列使用,消除内部碎片

上图展示了PagedAttention的核心映射关系。左侧是某个序列的逻辑视图,它认为自己拥有连续的4个块(逻辑块0-3)。右侧是真实的物理显存,这些块分散在不同的物理地址上。中间的块表记录了逻辑块到物理块的映射。当序列需要访问第5个逻辑块时,只需在块表中新增一条记录,而无需移动已有数据。

1.3 整体框架:课程四大模块

本课程共30章,分为四大模块,每个模块解决一个核心问题。建议你按照顺序学习,因为后续章节会频繁引用前面的概念。

模块一:基础与动机(第1-6章)——回答“为什么需要PagedAttention”。包括KV Cache的显存模型、朴素注意力机制的内存瓶颈、以及传统显存管理的三大缺陷(预分配浪费、内部碎片、无法共享)。

模块二:核心机制(第7-15章)——深入PagedAttention的每一个设计决策。包括块大小选择、块表数据结构、物理块分配与回收算法、以及如何支持beam search中的KV Cache共享。

模块三:工程实现(第16-24章)——聚焦vLLM框架中的实际代码。包括PagedAttention的CUDA kernel实现、与PyTorch的接口设计、显存Profiling工具的使用,以及多GPU场景下的块迁移策略。

模块四:进阶与展望(第25-30章)——探讨PagedAttention的变体与未来。包括与FlashAttention的融合、在MoE模型中的应用、以及面向长序列场景的稀疏分页方案。

1.4 案例场景:一次显存OOM的排查

让我们通过一个真实场景来感受PagedAttention的价值。假设你在部署一个13B参数的对话模型,使用传统的连续显存分配方式:

# 传统方式:预分配最大长度显存
max_seq_len = 2048
batch_size = 8
kv_cache_bytes = batch_size * max_seq_len * num_layers * 2 * head_dim * num_heads * 2  # 约 12.8 GB
# 实际平均生成长度只有 512,浪费了 75% 的显存

当并发请求增多时,显存很快耗尽,服务返回OOM错误。而使用PagedAttention后,KV Cache按需分配:

# PagedAttention方式:按实际长度分配物理块
block_size = 16  # 每个块存储16个token的KV
# 序列A实际长度512 → 分配32个物理块
# 序列B实际长度128 → 分配8个物理块
# 序列C实际长度1024 → 分配64个物理块
# 总显存 = (32+8+64) * block_size * per_block_bytes ≈ 4.2 GB
# 相比传统方式节省约 67% 显存
常见误区:初学者常误以为PagedAttention只是“动态分配显存”的简单实现。实际上,它的核心创新在于块表映射带来的三个额外收益:① 物理块可被任意序列复用(消除外部碎片);② 支持前缀共享(beam search时多个序列共享同一物理块);③ 支持异步预取(通过块表预判未来需要访问的物理块)。这些能力远超简单的“按需分配”。

1.5 本章小结与学习路径

本章我们完成了三件事:明确了四个层次的学习目标(理解、应用、分析、改造);建立了KV Cache与显存墙的核心概念;构建了四大模块的整体框架。现在,你已经具备了进入下一章的基础。

在继续之前,请确保你能回答以下三个问题:

  1. KV Cache的显存占用与哪些参数呈线性关系?为什么说它是“动态且碎片化”的?
  2. PagedAttention借鉴了操作系统的什么机制?块表的作用是什么?
  3. 传统连续分配方式存在哪三大缺陷?PagedAttention分别如何解决?