跳转至

第 13 章 线性注意力与状态空间模型

第 12 章仍保留「每个被选中的位置有一份 K、V」——历史可以很长,只是不每次算全。这一章走第二条路:不再为每个历史 token 留一份缓存,而把已经读过的内容压进一块大小固定的状态里。生成时只更新这块状态,显存不再随长度线性涨,计算也可以做到近线性。

第 0 章说过:这很像 RNN 回来了。当年 Transformer 淘汰 RNN 的两条理由——训练难并行、固定状态装不下——这里会还回一条、留住一条。还回的是训练并行;留住的正是本章最后的天花板,也是第 14 章必须混合的原因。

13.1 标准注意力贵在哪,线性化动哪一刀

标准因果注意力在位置 \(t\) 要拿当前的 \(q_t\) 去和过去所有 \(k_1,\ldots,k_t\) 比相似度,softmax 之后再加权 \(v\)。softmax 卡在中间,逼得实现里常常出现与 \(n^2\) 相关的工作(FlashAttention 把它藏进 SRAM,但渐近复杂度仍在)。

若相似度能写成「先映射再内积」,而不走那层 softmax:

\[ \operatorname{sim}(q,k)=\phi(q)^\top\phi(k), \]

那么求和次序可以换。直觉上:不必先造整张「query×key」大表,可以先把历史的 \(\phi(k_i)v_i^\top\) 累加成一块矩阵状态,再用当前的 \(\phi(q_t)\) 去读它。

因果情形下,位置 \(t\) 可以维护

\[ S_t=\sum_{i\le t}\phi(k_i)v_i^\top,\qquad z_t=\sum_{i\le t}\phi(k_i), \]
\[ y_t= \frac{\phi(q_t)^\top S_t} {\phi(q_t)^\top z_t+\epsilon}. \]

\(S_t\) 的形状是 \(d_k\times d_v\),\(z_t\) 是 \(d_k\) 维——大小与序列长度无关。分母是归一化;讨论「矩阵乘法可交换」时有人会暂时略去它,那只是直觉,不是完整算法。全序列视角下,这等价于先形成与长度无关的中间量再与 \(\phi(Q)\) 相乘,计算从 \(O(n^2d)\) 落到大约 \(O(nd_kd_v)\)。

生成时不再需要 KV Cache,只维护这份状态。随 \(n\) 线性涨的缓存和按 \(n^2\) 涨的 Prefill,在这条路上一起被拿掉。

13.2 说白了:RNN 换了一身衣服

固定大小的状态、每来一个 token 更新一次、下一步只依赖状态——这就是第 0.5 节的 RNN 画像。线性注意力 / 现代状态空间模型,是把这幅画像重新接到 Transformer 积木上:前面仍有投影、后面仍接 FFN,中间的「序列混合」换成状态更新。

当年两条判决,今天的答案是:

旧判决 现在
训练不能并行,必须逐步走 已缓解:分块并行 + parallel scan(见下)
固定状态装不下任意长历史的细节 仍成立:见 13.6

分块并行是让这条路重新可训的关键工程:块内用类似注意力的并行写法算局部贡献,块间只传递状态;再配合结合律上的 parallel scan,避免 Python 式 for-loop 逐步更新。没有这条,线性模型会再次输在训练吞吐上,论文好看也落不了地。

13.3 必须会「忘」:从固定衰减到选择性

最朴素的累加——所有历史无差别地加进 \(S_t\)——很快被噪声塞满,语言建模质量会明显差于标准注意力。这条线上的进步,很大程度是在回答:怎么忘。

固定衰减(RetNet 等)。 让越远的历史乘上随距离变小的系数,像指数遗忘。实现简单、好并行;衰减快慢与当前内容无关——不重要的噪声和关键的闭馆规则,按距离一视同仁。

输入相关的选择性(Mamba 一族)。 让遗忘强弱、写入强弱由当前输入决定:模型可以学「这句是硬约束,多留一会儿;这句是寒暄,快忘」。效果上台阶,代价是算子复杂,往往需要专门 CUDA kernel 才有训练 / 推理效率。

统一写成离散状态更新:

\[ h_t=A_t h_{t-1}+B_t x_t,\qquad y_t=C_t h_t. \]

固定衰减里 \(A_t\) 基本不看内容;选择性 SSM 让 \(A_t,B_t,C_t\)(或其等价参数化)依赖 \(x_t\)。训练期能并行,是因为这类仿射更新满足结合律,可用 parallel scan,而不是逐步启动解释器循环。

走到这一步,思想已经和 LSTM 的门控同源:差别主要在形状是否贴合现代 GPU、以及能否与注意力层混编进同一座 decoder 栈。

13.4 delta rule:不要只会加,要会改

累加式更新还有一个结构性毛病:同一个 key 反复出现时,信息会叠在一起,状态里留下一团糊。更像「日记只追加、从不订正」。

delta rule 换了一种写入:先读出状态里对该 key 的当前预测,减去旧贡献,再写入新值——定向修改,而不是盲目追加。一种常见写法:

\[ \hat v_t=S_{t-1}^\top k_t, \qquad S_t=S_{t-1}+\beta_t\,k_t(v_t-\hat v_t)^\top. \]

\(\hat v_t\) 是「按现在的状态,这个 key 对应什么 value」;残差 \(v_t-\hat v_t\) 只写入还没对齐的部分;\(\beta_t\in[0,1]\) 控制更新幅度。若状态已经正确,更新接近零;若同一 key 对应的事实变了(行程从周二改到周一),它沿该 key 的方向改写。

DeltaNet 是这一规则的代表实现。需要「更新已知事实」的任务上,它往往比纯累加更稳——这正是多轮行程助手常发生的事:用户改口之后,旧槽位不该继续投票。

13.5 GDN:门控决定忘多少,delta 决定怎么写

把 13.3 的选择性遗忘和 13.4 的误差改写接在一起,就是 Gated DeltaNet(GDN)一类设计:先决定旧记忆留多少,再按预测误差写入。 它是线性路线上常被拿来当主干层的强形态之一;第 16 章读旗舰配置时,若看到门控 delta / 同类线性层,应能回溯到这条演化线,而不是当成突然冒出的品牌模块。

抽象骨架可以写成:先衰减,再 delta:

\[ \widetilde S_{t-1}=\alpha_t\odot S_{t-1}, \qquad S_t=\widetilde S_{t-1} +\beta_t k_t\left(v_t-\widetilde S_{t-1}^{\top}k_t\right)^\top. \]

\(\alpha_t\) 管保留,\(\beta_t\) 管写入深度。头切分、归一化、参数从哪些投影出来,各家不同;「选择性遗忘 + 按误差改写」是共同骨架。

演化顺序建议记成:

线性注意力(固定状态,可换序)
    → 加遗忘 / 选择性(会忘)
    → 加 delta(会改)
    → 门控 + delta(GDN 一类)

13.6 天花板:固定状态做不了无损精确检索

状态再聪明,容量也是 \(O(d_k d_v)\) 量级的一块(再乘头数等常数)。信息一旦写进去,就和别的历史挤在同一套参数里,属于有损压缩。

因此,凡是要逐字复现远处细节的任务——大海捞针、长代码里的精确变量名、合同里的某一条款原文——纯线性 / 纯 SSM 栈往往系统性地弱于「仍保留每 token KV」的注意力。这不是调参没调好,而是信息瓶颈:你无法保证从固定大小的状态里无损解出任意历史 token。

对照第 12 章:

历史怎么放 典型失败
稀疏注意力 仍存(或按窗口截断)KV,计算时少看 漏选:该看的块没点到
线性 / 状态 压进固定状态 压坏:看过但抠不回原文级细节

稀疏与线性都能压长序列成本,失败模式不同。纯线性模型很难单独成为通用对话主栈;工业界更常见的是大部分层用线性扛长度,少数层保留精确注意力做回看——第 14 章的主题。

13.7 和 Mamba、RWKV 这些名字怎么对齐

读论文时会碰到不同出身:

  • 线性注意力:从 softmax 注意力出发,换相似度、换求和次序。
  • 状态空间模型(SSM / Mamba):从控制理论的状态方程出发,加上选择性与硬件友好扫描。
  • RWKV 等:显式时间衰减 + 类 RNN 写法,训练可并行。

落到实现,大家越来越像同一族:固定(或缓增长)状态 + 输入相关的更新 / 遗忘 + 可并行训练的扫描或分块。Mamba-2 等工作甚至直接讨论与线性注意力的对偶。第一册不必在谱系树上纠缠;看到「线性循环层」「状态混合」「GDN / Mamba 层」,先问三句:状态多大?会不会选择性遗忘?有没有和全注意力混用?

13.8 行程助手里怎么想象这条路

全程线性栈:显存按「层数 × 状态大小」走,贴一百页攻略也不再按 token 堆 KV——这是产品侧最诱人的点。但若闭馆规则只在第 67 页出现一次,又没有精确回看层,状态里可能只剩下「好像和寺庙开放时间有关」的模糊痕迹,生成时改成「建议周一去」这种自信的错。

因此工程上更常见的画像是:线性层负责把对话「推着往前走」,偶尔插入的注意力层负责「翻回原件核对」。如何插、插多少,留给第 14 章;本章先把线性侧的能力与不能做什么钉死。

动手

手写一版最小 DeltaNet 前向:状态初始化、逐 token 的读出–减旧–写新;有余力再写分块版本。在一个「记住并回答远处某个键」的合成任务上,对比它与标准注意力的召回;再测「同一 key 中途改值」时,累加式与 delta 式谁更能跟上。


核心问答

Q1:线性注意力为什么不需要 KV Cache? 历史已被累进固定形状的状态;推理只需带着状态走,不必再存每个 token 的 K、V。显存与序列长度脱钩,是它相对第 7、12 章最不同的优势。

Q2:它和 Mamba 是一回事吗? 出身不同,形态高度趋同。现在常统称线性循环 / 状态混合层。读配置时按「状态 + 选择性 + 是否混合注意力」理解即可。

Q3:delta rule 解决了什么? 减少重复写入造成的糊状叠加;对「事实被更新」更友好。它提高固定容量的使用效率,并不取消容量上限。

Q4:又快又省,为什么不全用它? 精确检索弱。固定状态是有损压缩。现代通用模型的主流答案是混合:线性层扛成本,少数标准(或稀疏)注意力层保回看——见第 14 章。

Q5:怎么快速判断一篇线性注意力论文的成色? 两件事:有没有在大海捞针 / 精确召回上给数字(回避的多半是弱项);有没有分块并行或 scan 的训练效率(训不动就落不了地)。再看它是否诚实讨论与注意力混合,而不是暗示「从此不再需要 KV」。