L大语言模型从理论到实践
阅读 PDF ↗
CHAPTER 30

增量解码

自回归生成每次只增加少量词元,但新的词元需要读取已经形成的上下文。如果每一步重新执行整个前缀,模型会反复计算相同的位置表示。键值缓存利用因果结构保留这些中间结果,把后续计算集中于新增位置;与此同时,缓存随序列增长,成为并发、显存与状态一致性的核心约束。

本章先证明缓存复用的数学条件,再讨论不同注意力结构的容量、分页寻址和前缀共享。第6章《Transformer 网络结构》定义网络层,第37章《长上下文建模》讨论长距离能力。本章侧重执行状态;算子优化和投机生成由第33章《推理计算优化》展开,服务调度由第31章《批处理调度》展开。

30.1预填充及增量解码

两个阶段的输入输出

预填充(Prefill)对已知提示的全部位置执行因果前向,形成各层键和值。增量解码(Incremental Decoding)随后只处理新加入的词元,通过历史缓存读取前缀信息。它改变执行方式,不改变自回归概率分解。

提示包含 \(P\) 个词元,编号 \(0,\ldots,P-1\)。预填充最后位置的输出分布预测第一个生成词元 \(y_0\);采样出 \(y_0\) 后,才把它送入位置 \(P\) 的增量前向,得到预测 \(y_1\) 的分布。因而输出 \(G\) 个词元通常需要一次预填充与 \(G-1\) 次后续单词元前向,而不必为最后一个输出再执行一次模型。1

张量形状

设批次大小 \(B\),隐藏维数 \(d\),层数 \(N\),查询头数 \(h_q\),键值头数 \(h_{kv}\),键维数 \(d_k\),值维数 \(d_v\)。预填充一层有

\[ H\in\mathbb R^{B\times P\times d},\quad Q\in\mathbb R^{B\times h_q\times P\times d_k},\quad K\in\mathbb R^{B\times h_{kv}\times P\times d_k},\quad V\in\mathbb R^{B\times h_{kv}\times P\times d_v}. \tag{30.1}\]

若已经缓存 \(L\) 个词元,新加入 \(q\) 个词元,则 \(Q_{\mathrm{new}}\) 的序列轴为 \(q\)\(K,V\) 的可读取序列轴为 \(L+q\)。单词元解码时 \(q=1\),每个查询头的注意力分数形状为 \([B,1,L+1]\)。实际运行时可采用不同轴顺序或打包布局,逻辑维度不变。

\(g(i)\) 将查询头 \(i\) 映射到其键值头,新增位置 \(r\in\{0,\ldots,q-1\}\) 的注意力为

\[ o_{r,i}=\sum_{j=0}^{L+r} \frac{\exp(\frac{q_{r,i}^{\top}k_{j,g(i)}}{\sqrt{d_k}}+b_{L+r,j})} {\sum_{u=0}^{L+r}\exp(\frac{q_{r,i}^{\top}k_{u,g(i)}}{\sqrt{d_k}}+b_{L+r,u})} v_{j,g(i)}. \tag{30.2}\]

\(b\) 表示合法的位置偏置,旋转位置编码则通常已经作用于查询与键。新块内部仍需因果约束 \(j\le L+r\),不能因为使用缓存而让较早新词元读取较晚新词元。

符号及一致性假设

符号 含义
\(P,G,L,q\) 提示长度、输出词元数、已缓存长度、新增位置数。
\(N,d,h_q,h_{kv},d_k,d_v\) 网络层数、隐藏维数及注意力维度。
\(b_k,b_v\) 单个键或值元素占用的字节数。
\(\mathcal C^{(\ell)}\) \(\ell\) 层的键值缓存及其位置元数据。
\(p_b,\mathcal B\) 每个物理块容纳的词元数与逻辑块到物理块的映射。
\(r_c,d_C,d_R\) 潜变量缓存维数、内容查询/键维数与解耦位置分量维数。

缓存等价的条件

模型参数、适配器、位置规则和可见性规则固定;网络处于推理模式,旧位置的计算不依赖未来词元。层归一化和前馈变换按位置进行,不以不断扩展的整段序列重新计算全局统计。缓存没有被有损修改,并保留与参考全量前向一致的逻辑位置和输入条件。

30.2键值缓存等价性

层级因果性证明

键值缓存(Key-Value Cache,KV Cache)保存各层历史位置的 \(K,V\)。设在长度 \(L\) 的前向中,第 \(\ell\) 层历史位置 \(j<L\) 的隐状态为 \(h_j^{(\ell,L)}\)。现在追加词元扩展为 \(L+q\),需要证明

\[ h_j^{(\ell,L)}=h_j^{(\ell,L+q)},\qquad j<L. \tag{30.3}\]

第一层之前,旧词元及位置编号相同,嵌入相同。假设某层输入的历史状态相同,则其历史 \(Q,K,V\) 相同;因果掩码保证旧位置 \(j\) 只读取 \(0,\ldots,j\),新增位置不进入求和。于是注意力输出相同,逐位置残差、归一化和前馈结果也相同。对层数归纳,式(30.3)成立。

计算新增位置时,使用缓存的历史键值与重新计算整个前缀所得到的历史键值相同,新位置本身按同一公式计算,故新增隐状态与输出分布也相同。这是缓存等价的依据,不是因为历史文本“通常不变”而作出的近似。

历史查询通常不必保存,因为以后只需要新位置发出的查询;历史键和值仍将被后续查询读取。跨层不能只保存最后一层缓存:第 \(\ell\) 层新查询需要第 \(\ell\) 层的历史键值,其表示与其他层不同。

等价性条件

双向编码器旧位置会读取新增文本,通常不能直接沿用这套追加证明。对编码器—解码器模型,如果编码器输出固定,则交叉注意力的编码器键值可以预先计算;若源文本改变,则这些缓存失效。

推理时仍启用随机丢弃、随长度改变位置缩放、修改适配器或依赖全序列统计的操作,都会破坏旧状态不变的前提。量化缓存、选择性淘汰或近似压缩也会引入额外误差,应作为不同执行模式说明。

数学等价不要求不同内核逐位相同。浮点求和顺序、精度与归约布局可能带来误差;输出概率接近时,贪心最大值也可能发生离散分叉。验证应先比较同一输入下的分数或概率,再区分数值误差与掩码、位置错误,不能只凭生成文本相同或不同判断缓存正确性。

例24.1

考虑单层单头、\(d_k=1,d_v=2\) 的构造。前两个位置的缓存为

\[ k_0=0,\ k_1=\log2,\qquad v_0=(1,0),\ v_1=(0,2). \tag{30.4}\]

第三个新位置的查询 \(q_2=1\),新键 \(k_2=\log3\),新值 \(v_2=(3,3)\)。无位置偏置时,分数为 \(0,\log2,\log3\),指数为 \(1,2,3\),归一化权重为 \(\frac{1}{6},\frac{2}{6},\frac{3}{6}\)。所以

\[ o_2=\frac16(1,0)+\frac26(0,2)+\frac36(3,3) =\left(\frac53,\frac{13}{6}\right). \tag{30.5}\]

全量前向会为第三行生成完全相同的分数;缓存前向复用前两行键值即可。它不需要重新计算前两行注意力输出。若错误漏掉新键值,得到 \((\frac{1}{3},\frac{4}{3})\),这不是数值精度差异,而是可见集合改变。

单层增量计算的数据流。新查询读取全部合法键值,历史查询和历史前馈输出不再重算。
图 30.1 单层增量计算的数据流。新查询读取全部合法键值,历史查询和历史前馈输出不再重算。

30.3复杂度及带宽

重复前缀及缓存执行

忽略层数等固定系数,以密集网络常见维度关系计,长度 \(L\) 的全量前向约为 \(O(Ld^2+L^2d)\)。如果生成每个词元都重算整个前缀,\(G\) 次预测消耗约

\[ \sum_{g=0}^{G-1}O\big((P+g)d^2+(P+g)^2d\big). \tag{30.6}\]

使用缓存后,预填充一次,后续 \(G-1\) 次单词元前向各为 \(O(d^2+(P+g)d)\),总量为

\[ O(Pd^2+P^2d)+O\big(Gd^2+(GP+G^2)d\big). \tag{30.7}\]

因此无初始长提示时,朴素重复前缀的注意力累计量可达三次方,而缓存把它降到二次方;单步解码的密集注意力仍随上下文线性增长,不能称为常数时间。

例如提示4个词元、输出3个词元。全量方案分别处理长度4、5、6,累计线性变换位置15个;缓存方案处理4个提示与2个新增位置,共6个。按因果合法分数对计,前者为 \(10+15+21=46\),后者为 \(10+5+6=21\)。这是运算对象计数,不是端到端时间加速比。

缓存容量及计算量

单步解码需要读取历史键值。若主要限制是显存带宽,减少缓存元素有助于降低读取成本;但查询头数不变时,注意力分数与输出仍按查询头计算。预填充可以对许多查询并行执行,单词元解码更容易受参数与缓存读取影响,二者不能共用一个固定吞吐常数。

缓存只避免重算,不会消除新词元的网络层计算,也不会消除全上下文注意力读取。实际耗时还取决于批次、内核复用、页布局、并行通信和工作区;第33章《推理计算优化》讨论算子,第31章《批处理调度》讨论调度。本章容量式不替代实际负载下的延迟分析。

30.4MHA、GQA 及 MQA 的缓存

头共享结构

多头注意力(Multi-Head Attention,MHA)为每个查询头提供独立键值头,\(h_{kv}=h_q\)多查询注意力(Multi-Query Attention,MQA)让所有查询头共享一个键值头,\(h_{kv}=1\)(Shazeer 2019)分组查询注意力(Grouped-Query Attention,GQA)在两者之间按组共享键值(Ainslie 等 2023)

\(h_q\) 能被 \(h_{kv}\) 整除,每组有 \(\frac{h_q}{h_{kv}}\) 个查询头。共享键值并不意味着查询头输出相同,因为各查询向量仍不同,从而产生不同注意力权重。这些是不同参数化结构;不能把已有 MHA 键值头直接丢弃后声称数学等价。转换需要与模型训练方式及质量评估结合。

四个查询头下的键值共享关系。查询头数相同,缓存键值头数依次为4、2、1。
图 30.2 四个查询头下的键值共享关系。查询头数相同,缓存键值头数依次为4、2、1。

统一容量公式

若请求 \(b\) 缓存长度为 \(L_b\),各层同形状,则裸缓存容量为

\[ M_{KV}=N\sum_bL_bh_{kv}(d_kb_k+d_vb_v). \tag{30.8}\]

\(d_k=d_v=d_h,b_k=b_v=b_e\)、所有请求长度 \(L\) 相同时,退化为 \(2NBLh_{kv}d_hb_e\)。它不包含页表、分配碎片、量化比例、临时空间和模型权重。分层采用滑窗或不同头数时,应分别求和。

\(N=32,h_q=32,d_h=128,b_e=2,L=8192,B=1\)。每词元 MHA 缓存为 \(2\times32\times32\times128\times2=524288\) 字节,即512 KiB。GQA 取8个键值头,每词元128 KiB;MQA 每词元16 KiB。于是

结构 键值头数 单请求裸缓存 四请求裸缓存
MHA 32 4 GiB 16 GiB
GQA 8 1 GiB 4 GiB
MQA 1 128 MiB 512 MiB

这里 GiB 为 \(2^{30}\) 字节。相同比例描述缓存容量,不代表模型总显存或吞吐按同样比例变化。

张量并行下,若键值头均匀分片,每卡缓存可相应减少;若键值头少于并行设备数而运行时复制,则不能直接除以并行度。例如 MQA 的一个头可能在多个设备上分别驻留。容量规划需使用实际每卡存储头数,并与模型及内核布局一致。

30.5低秩键值及潜变量缓存

(选修)

联合表示及矩阵吸收

键值头共享减少独立头数,另一种思路是让键和值由低维共同变量生成。对单位置列向量 \(h_t\in\mathbb R^d\),设

\[ c_t=W_Dh_t\in\mathbb R^{r_c},\quad k_{t,i}=U_{K,i}c_t,\quad v_{t,i}=U_{V,i}c_t, \tag{30.9}\]

其中 \(U_{K,i}\in\mathbb R^{d_k\times r_c}\)\(U_{V,i}\in\mathbb R^{d_v\times r_c}\)。不含位置旋转时

\[ q_{t,i}^{\top}k_{j,i}=(U_{K,i}^{\top}q_{t,i})^{\top}c_j. \tag{30.10}\]

可以先把当前查询投到潜空间,再与缓存 \(c_j\) 点积,不必为每个历史位置展开完整键。输出也有

\[ \sum_j a_{t,j,i}v_{j,i}=U_{V,i}\sum_j a_{t,j,i}c_j. \tag{30.11}\]

若第 \(i\) 头输出投影块为 \(O_i\),可进一步合并 \(O_iU_{V,i}\)。这种矩阵吸收(Matrix Absorption)利用线性结合与矩阵乘法结合律,改变计算顺序而保留所定义低秩结构的数学结果。

低秩约束本身不等于任意原始 MHA 的无损压缩。模型若按该结构训练,可以精确执行自身的潜变量形式;若对已有高秩权重作事后低秩近似,则还需分析近似误差。缓存变小也可能增加某些潜空间计算,必须结合维度与执行阶段权衡。

位置旋转的非交换约束

若对完整键加入旋转 \(R_j\),查询也按位置 \(t\) 旋转,则点积为

\[ q_{t,i}^{\top}R_t^{\top}R_jU_{K,i}c_j. \tag{30.12}\]

中间旋转依赖历史位置 \(j\),一般不能用一个与 \(j\) 无关的固定矩阵吸收到当前查询投影中。矩阵通常不交换次序;忽略这一点会把缓存压缩推导变成错误等式。

多头潜在注意力(Multi-Head Latent Attention,MLA)在 DeepSeek-V2 中采用联合键值压缩与解耦位置分量(DeepSeek-AI 2024)。概念上可把分数写为内容项和位置项之和:

\[ s_{t,j,i}=\frac{(q^C_{t,i})^\top U_{K,i}c_j+ (q^R_{t,i})^\top k^R_j}{\sqrt{d_C+d_R}}. \tag{30.13}\]

内容项采用矩阵吸收,旋转位置项单独保留。分母与该结构的查询、键总维度和训练尺度一致,不能任意换成潜变量维数。这里只给出缓存相关关系,具体查询压缩与模型规格应遵循对应架构。

若每层每位置保存一个 \(r_c\) 维潜变量和一个共享 \(d_R\) 维位置键,统一元素字节数 \(b_e\) 时,裸容量为

\[ M_{\mathrm{latent}}=N\sum_bL_b(r_c+d_R)b_e. \tag{30.14}\]

例如取 \(r_c=512,d_R=64,N=32,b_e=2,L=8192\),得到288 MiB。该构造不能直接与不同模型的性能比较;这里只说明缓存由哪些维度决定。

30.6逻辑位置及物理分页

页表不改变注意力位置

分页键值缓存(Paged KV Cache)把序列的连续逻辑位置映射到可不连续的物理块。PagedAttention 将此思路用于模型服务中的缓存管理(Kwon 等 2023)。若每块容纳 \(p_b\) 个词元,逻辑位置 \(t\) 对应

\[ j=\lfloor \frac{t}{p_b}\rfloor,\qquad o=t\bmod p_b, \qquad \mathrm{physical}(t)=(\mathcal B[j],o). \tag{30.15}\]

\(j\) 为逻辑块编号,\(o\) 为块内偏移,\(\mathcal B\) 是请求页表。位置编码仍使用逻辑位置 \(t\),不能使用物理块编号。搬迁一个块只需更新映射与数据位置,不应重新解释序列顺序。

设块大小4、逻辑长度10,页表为 \((7,2,9)\)。位置6映射到物理块2的偏移2,位置9映射到物理块9的偏移1。三个物理块共有12个槽位,最后两位无效,注意力必须根据逻辑长度排除它们。

逻辑块映射到不连续物理块。页表解决存储布局,逻辑位置和有效长度决定模型可见的内容。
图 30.3 逻辑块映射到不连续物理块。页表解决存储布局,逻辑位置和有效长度决定模型可见的内容。

碎片及容量预留

没有共享时,请求长度 \(L_b\) 需要 \(\lceil \frac{L_b}{p_b}\rceil\) 个块,分配槽位与有效长度之差小于 \(p_b\)。对 \(B\) 条请求,尾部内部碎片少于 \(Bp_b\) 个词元槽位。块太大增加尾部浪费,块太小增加页表和寻址开销,选择应结合内核与长度分布。

缓存按需增长减少一次预留最大输出长度的浪费,但不能消除后续增长风险。接纳请求时应考虑未来输出预算及可用块;正在执行的内核读取旧映射期间,块不能被提前回收。页表修改、数据拷贝与设备执行之间需要明确顺序和完成边界。

批内变长

对长度分别为 \(L_1,\ldots,L_B\) 的请求,每个新查询仅能读取自身有效前缀。连续批次中的行号只是当前执行槽位,不能代替稳定请求身份。请求完成后压缩批次、交换行或加入新请求时,缓存映射必须跟随请求,而不能默认沿用原行对应的物理块。

填充到批内最大长度的实现与分页变长实现可以表达同一逻辑计算;前者需要屏蔽无效位置,后者需要正确页表与长度。它们的缓存分配量和算子效率不同,但语义不应改变。

30.7前缀共享及缓存生命周期

计算前缀共享

前缀缓存(Prefix Cache)复用多个请求相同前缀产生的键值。因为旧状态只依赖前面的内容,相同模型、相同逻辑位置与相同条件下的精确词元前缀可以共享。相同的一段后缀若前文不同,深层键值通常不同,不能仅按局部文本重复复用。

共享通常从完整块边界开始。前缀块的身份应绑定前一块身份与本块词元内容,使同一局部块出现在不同前缀后时不被误判为相同计算状态。内容摘要是索引手段,仍需要足够可靠的身份方案与兼容性元数据。

完整命中提示缓存时,若仅保存 \(K,V\),可能没有可直接产生首个新词元的最后隐状态或输出分数。实现可以保留相应输出状态,或重新处理最后一个提示位置并精确控制缓存截断与追加。不能将最后词元再追加一次而造成重复位置,也不能把“所有 KV 已存在”误解为“首词元分布必然已保存”。

引用计数及写时复制

共享块在被多个请求引用时应保持不可变。引用计数(Reference Counting)记录有多少活动使用者持有该物理块;释放一个请求只减少其引用,计数归零后才具备回收条件。若块仍被设备内核读取,还需等待相关执行完成。

当多个分支共享未满块又要追加不同词元时,需要写时复制(Copy-on-Write,CoW):为修改分支分配新块,复制有效前缀,再追加。否则一个请求会覆盖另一个请求的缓存。已满共享块无需复制,后续分支直接分配各自的新块即可。

例如每块4个词元,三条请求共享8个前缀词元,各自拥有3个后续词元。独立存储需要 \(3\times\lceil\frac{11}{4}\rceil=9\) 块;共享后需要2个公共块加3个私有尾块,共5块。有效独特缓存词元为 \(8+3\times3=17\),分配20槽位;节省的是重复前缀,并未减少私有后缀的计算内容。

缓存驻留及淘汰

活动请求使用的缓存不能因“最近没访问”就直接删除。缓存淘汰(Cache Eviction)通常针对没有活动引用但为未来复用保留的块;若要抢占活动请求,应保存可恢复映射并换出,或释放后按同一输入重新计算。前者消耗传输,后者消耗计算,两者的语义与普通缓存命中不同。

缓存可经历空闲、分配写入、可共享驻留、活动引用、无引用可淘汰、回收等状态。取消与超时也必须走释放路径,并以请求资源所有权防止重复递减。前缀复用率高但长期占满显存时,驻留策略会挤压活动解码;如何在任务之间分配资源由调度章节展开。

缓存块生命周期。CoW边表示创建新的私有副本,原共享块仍保持原状态;取消与正常结束都按所有权释放一次引用。未完成的设备访问禁止复用物理存储。
图 30.4 缓存块生命周期。CoW边表示创建新的私有副本,原共享块仍保持原状态;取消与正常结束都按所有权释放一次引用。未完成的设备访问禁止复用物理存储。

算法30.1 前缀缓存的引用与追加

输入为计算身份、词元前缀、请求身份及所需新增容量;输出为请求页表和可继续执行的私有尾部。

  1. 在允许共享的命名空间内查找最长兼容完整前缀,逐块验证计算身份与有效范围,取得引用后固定映射。

  2. 为未命中部分分配块,执行预填充并提交有效长度;只有计算完成的内容可发布为可共享状态。

  3. 每次追加前判断尾块是否有空位及是否被共享;共享且需要修改时先复制有效内容到私有块。

  4. 写入各层新键值,在成功完成后推进逻辑长度;失败时回滚未提交分配,不发布部分完成状态。

  5. 请求终止后按所有权恰好释放一次引用;待无引用且设备使用结束后,块可保留驻留或由淘汰策略回收。

不变量是任何活动页表只能指向兼容且已完成的有效数据,共享块不被原地覆盖,逻辑长度只描述已提交状态。

30.8滑窗、淘汰及位置编码约束

历史状态淘汰条件

模型若原本采用包含当前位置的窗口 \(w\),未来查询只读取最近 \(w\) 个键值,则窗口之外的历史键值不再作为该层的直接输入,可在保持必要元数据的条件下回收。删除全注意力模型的旧键值,则改变式(30.2)的求和集合,是近似策略而非精确缓存管理。

滑窗模型的高层新状态可能包含通过中间位置传递的更早信息。缓存中仅保留最近键值,不等于从原始文本只取最近 \(w\) 个词元重新运行整网:后者可能失去这些键值形成时曾使用的上下文。精确性应相对于相同逐步滑窗计算定义。

混合全局层与滑窗层时,缓存保留范围按层不同。用于前缀匹配的累计逻辑长度也不等于当前驻留位置数,应同时保存历史进度和各层可见范围。

环形存储的逻辑位置

环形缓存(Ring Buffer)用位置 \(t\bmod w\) 复用物理槽位。槽位编号是存储坐标,位置编码仍应使用模型定义的逻辑位置 \(t\)。把槽位0当成绝对位置0,会改变旋转相位或绝对嵌入。

如果缓存保存已经旋转的键,移动物理块不需要重新旋转;若改变逻辑位置,情况不同。纯相对旋转在特定条件下可以通过一致变换分析重定位,但普通网络还包含深层上下文状态,不能只改键相位就宣称任意裁剪与拼接等价。

长度扩展方案若根据当前长度动态修改旋转频率,旧键以及形成旧键的深层状态可能不再对应新规则。最稳妥的缓存复用前提是一次请求内固定位置配置;需要动态改变时应明确重建范围,而不能仅更新配置数字。

30.9缓存身份及隔离

缓存失效依赖

缓存是给定计算条件的中间结果。其身份至少应覆盖权重及结构修订、适配器组合、精度与缓存格式、位置配置、注意力规则、精确前缀和外部条件。对多模态或交叉注意力模型,还需绑定媒体特征、处理器和编码器状态;同样文本标记不保证图像条件相同。

分词器与模板决定如何得到词元前缀,适合在制品身份中统一绑定。温度与采样阈值若仅作用于输出分布而不改变前向,本身不改变已有前缀 KV;但它们影响后续采样结果及恢复随机轨迹,因此仍属于请求生成状态。区分这两类依赖可以避免缓存键过宽或过窄。

模型名称、可变分支名和目录路径不是充分身份。更新模型而继续使用旧缓存会得到混合版本计算;同一个请求在解码中切换修订也不具有普通续算语义。无损搬迁到相同制品通常只改变位置,跨不同缓存布局则需要明确定义格式转换。

多租户共享边界

缓存包含由用户内容计算出的状态,应受请求或授权共享域控制。即使两个租户碰巧拥有相同词元前缀,也不意味着系统已获准共享其私有计算状态。命名空间、前缀来源和授权域应进入查找边界;公共固定前缀可以在明确规则下共享,私有内容不应被摘要命中自动扩大访问范围。

引用计数只保证内存生命周期,不提供权限隔离。缓存命中造成的时间差、日志或错误信息也可能泄露前缀存在性,应避免向无权请求暴露可查询的私有前缀信息。物理块重新分配后,旧内容必须在访问与有效长度上不可见,不能依赖“下次大概会覆盖”。

缓存正确性的三个层次

数学层保证保存的状态等价于相同前缀计算;存储层保证页表、有效长度与生命周期一致;隔离层保证只有授权请求能够复用状态。三者缺一不可,较高命中率不能替代任何一层的正确性。

30.10增量执行过程

算法30.2 带缓存的自回归生成

输入为非空提示、冻结模型、生成上限 \(G>0\)、停止规则与空或兼容前缀缓存;输出为最多 \(G\) 个词元及最终缓存进度。

  1. 确定提示词元、逻辑位置和缓存身份,复用合法前缀并处理未缓存部分,取得提示末位置的输出分布。

  2. 根据生成策略选择下一个词元并记录输出;若达到结束条件或输出上限,终止生成。

  3. 为该新词元分配可写位置,按层计算新查询、键和值,查询所有合法历史位置并完成残差与前馈;提交缓存及逻辑长度。

  4. 从最终层取得下一词元分布,返回步骤2;批内其他请求使用各自页表、长度及终止状态。

  5. 正常结束、取消或失败时释放请求持有的资源;若保留续聊状态,明确缓存是否已经覆盖最后输出词元。

每次循环至多增加一个已输出词元,缓存只覆盖已经执行前向的位置;不把“已采样”误认为“已写入各层 KV”。

时间指标也应遵循阶段语义。首词元延迟从约定入口到首个可见输出,通常包含排队与预填充;后续词元间隔描述增量阶段及其排队、传输影响。若 TTFT 已含排队,端到端时间写为 \(\mathrm{TTFT}+(G-1)\mathrm{TPOT}\),不能重复加排队。缓存命中减少某些预填充计算,但不保证所有请求的首词元延迟同比下降。

30.11缓存计量及服务边界

缓存增长、头共享和容量计数描述状态存储的成本;内核分块、编译与并行效率在后续章节展开。请求身份、模型修订、取消和资源释放决定缓存生命周期与隔离边界。容量算例用于推导字节数,不能称为实测显存或吞吐。


  1. 若服务需要把完整最终回答状态留下用于续聊,可能额外处理最后输出词元。请求返回了多少词元与缓存实际覆盖到哪个位置应分别记录。↩︎

WORKBOOK / 习题

配套习题与解析

先独立作答,再展开参考解析。选修题保留原书标记。

习题 30.1

提示长度为5、输出长度为4,列出每次前向处理的词元位置、产生的预测与最终缓存长度。

展开参考解析

约定生成4个词元后立即停止,不把最后输出再送入模型。预填充处理提示位置0至4,末端logits预测y0,缓存5;随后分别处理y0位置5预测y1、y1位置6预测y2、y2位置7预测y3,缓存依次6、7、8。最终输出4个而缓存8位置;只有为继续生成再物化y3才到9,输出长度不必等于已物化缓存长度。

习题 30.2

逐层证明旧位置隐状态不变,并指出双向注意力在哪一步破坏该证明。

展开参考解析

嵌入与逻辑位置固定时历史层0状态相同。若某层历史输入相同,其QKV相同;因果掩码使旧位置不读取新位置,注意力输出相同,逐位置归一化/前馈与残差也相同。因此逐层历史KV不变。双向注意力的旧行会读新增键,新分母和值改变,归纳在注意力这一步失败。

习题 30.3

改变数值例的新键为 \(\log4\),重新计算权重与输出;说明漏掉自身键值的错误。

展开参考解析

指数质量为1、2、4,总量7;输出 \((\frac{1}{7})(1,0)+(\frac{2}{7})(0,2)+(\frac{4}{7})(3,3)=(\frac{13}{7},\frac{16}{7})\)。漏自身时仍错误得到 \((\frac{1}{3},\frac{4}{3})\),相当于丢失\(\frac{4}{7}\)的分布质量而重新归一,不是精度容差。

习题 30.4

对提示8、输出4,分别计算全量重算与缓存方案的线性处理位置数和因果合法分数对数。

展开参考解析

按最后输出不物化的约定,全量前向长度为8、9、10、11,总线性位置38;缓存为8+1+1+1=11。合法因果分数对:全量 \(36+45+55+66=202\),缓存 \(36+9+10+11=66\)。这是每层每头的逻辑配对,若内核计算被掩码的稠密元素,实际算术计数还会不同。

习题 30.5

设40层、16个 KV 头、键维128、值维64,元素均为2字节,缓存16384词元,计算裸容量。

展开参考解析

每词元字节为 \(40\times16\times(128+64)\times2=245760\);乘16384得4026531840字节,即3.75 GiB。键值维不相等时不能用 \(2d_k\) 替代二者和,分页元数据和预留另计。

习题 30.6

保持32个查询头,比较4个 KV 头与1个 KV 头的容量;解释为什么计算不能简单按容量同比减少。

展开参考解析

固定层、长度、键值维及精度,缓存正比KV头数,4头比1头为4倍。32个查询头仍各产生分数和输出,查询投影与前馈也未按KV头数缩减;广播和矩阵布局影响实际带宽,不能把缓存缩减4倍称为全模型计算缩减4倍。

习题 30.7选修

推导式30.10,并用维度说明 \(U_K\) 不能与任意位置旋转交换。

展开参考解析

\(k_j=U_Kc_j\),则 \(q_t^\mathsf Tk_j=q_t^\mathsf TU_Kc_j=(U_K^\mathsf Tq_t)^\mathsf Tc_j\)\(U_K\in\mathbb R^{d_k\times r_c}\),矩形矩阵不能与任意 \(d_k\times d_k\)旋转交换;例如 \(R_jU_K\)\(U_KR_j\) 后者甚至维度不合法。即使方阵也一般不交换,位置旋转须保持其真实分工。

习题 30.8

块大小8、长度19、页表 \((4,1,7)\),求位置17的物理块和偏移及尾部空位。

展开参考解析

逻辑位置17在第 \(\lfloor\frac{17}{8}\rfloor=2\) 个逻辑块,页表映射为物理块7,偏移1。长度19共分配24槽位,尾部空5槽。物理块编号7不意味着位置编码使用7或57,应保留逻辑时间17。

习题 30.9

四条请求共享16词元前缀、各有5词元后缀、块大小8,计算共享前后块数与尾部碎片。

展开参考解析

独立每请求长度21,需3块,四条共12块;共享16前缀用2公共块,四条5词元尾部各1块,共6块。独立分配96槽位、有效84、尾碎片12;共享分配48槽位、独特有效 \(16+4\times5=36\),尾碎片仍12。节省来自重复前缀,不是所有尾部碎片被消除。

习题 30.10

说明未满共享块追加时为何需要写时复制,以及引用计数归零为何仍可能暂不可回收。

展开参考解析

共享未满块若被一条分支直接写入会影响其他引用者,须分配私有块复制有效内容后追加。引用归零只表示无活动所有者,设备内核可能尚未读完;需等完成事件或安全epoch后复用内存,否则产生异步读写竞态。取消也必须按所有权只减一次。

习题 30.11

区分全注意力历史淘汰、原生滑窗回收、无引用前缀淘汰和活动请求抢占。

展开参考解析

全注意力删历史通常改变模型条件,是近似;原生滑窗删除未来不再可见的键值可保持其逐步计算语义;无引用前缀淘汰只降低未来命中率;活动抢占需换出完整状态或重算后恢复,影响成本和时延。它们不能仅以一个LRU规则统一处理,须明确活动引用与可恢复边界。

习题 30.12

设计缓存身份字段,分别讨论仅改变采样温度、适配器、模板和图像输入时是否可复用。

展开参考解析

键覆盖权重/结构摘要、适配器组合、精度布局、位置/掩码、完整词元前缀、模板处理器和图像特征依赖、共享命名空间。仅温度作用于输出分布时已有KV可复用,但后续采样状态不同;适配器变化一般失效;模板若导致同一实际前缀且其他依赖相同可复用,否则失效;不同图像即便文本标记相同也不能复用其条件KV。

REFERENCES

参考文献

Ainslie, Joshua, James Lee-Thorp, Michiel de Jong, Yury Zemlyanskiy, Federico Lebron, 和 Sumit Sanghai. 2023. 《GQA: Training Generalized Multi-Query Transformer Models from Multi-Head Checkpoints》. 收入 Proceedings of the 2023 Conference on Empirical Methods in Natural Language Processing, 4895–4901. https://doi.org/10.18653/v1/2023.emnlp-main.298.
DeepSeek-AI. 2024. 《DeepSeek-V2: A Strong, Economical, and Efficient Mixture-of-Experts Language Model》. 2024年. https://arxiv.org/abs/2405.04434v5.
Kwon, Woosuk, Zhuohan Li, Siyuan Zhuang, Ying Sheng, Lianmin Zheng, Cody Hao Yu, Joseph E. Gonzalez, Hao Zhang, 和 Ion Stoica. 2023. 《Efficient Memory Management for Large Language Model Serving with PagedAttention》. 2023年. https://arxiv.org/abs/2309.06180.
Shazeer, Noam. 2019. 《Fast Transformer Decoding: One Write-Head is All You Need》. 2019年. https://arxiv.org/abs/1911.02150.

搜索全书

搜索全书正文、习题与解析