线性注意力从头到尾讲清楚:从注意力矩阵到可递推状态
关键不是少算几次乘法,而是把 token-to-token 交互改写成“先写入状态,再由 query 读取”
Linear Attention 的目标是避免显式构造 \(n\times n\) 的注意力矩阵,而是把“每个 query 与所有 key 的交互”改写成“query 读取一个累积状态”。
这句话比“Linear Attention 把复杂度从平方降到线性”更接近本质。复杂度下降只是结果,真正发生的结构变化是:标准 Attention 显式维护 token 与 token 之间的关系,而 Linear Attention 先把所有 key–value 信息写进一个状态,再让 query 从状态中读出结果。
这篇文章从标准 Attention 出发,把这次改写完整推一遍。读完后,你应该能回答四个问题:为什么不能直接先算 \(K^\top V\);归一化需要保存什么额外状态;因果 Linear Attention 为什么像 RNN;以及它用固定状态换走 \(n\times n\) 矩阵时究竟牺牲了什么。
如果只看三句话
- 标准 Attention 是“每个 query 逐个匹配所有 key”,因此会产生 \(n\times n\) 的注意力矩阵。
- 如果相似度可以分解为 \(\operatorname{sim}(q,k)=\phi(q)^\top\phi(k)\),就能利用结合律先计算 \(\sum_j\phi(k_j)v_j^\top\),再由 query 读取。
- 在因果场景中,这个汇总量可以逐 token 更新,于是 Attention 变成了一个具有固定大小状态的递推模型。
最值得记住的图景是:
\[\boxed{\text{显式 token-to-token 注意力图}\quad\longrightarrow\quad\text{可累积的记忆状态}}\]1. 先把标准 attention 写清楚
标准 scaled dot-product attention 是:
\[ \mathrm{Attention}(Q, K, V) = \mathrm{softmax}\left(\frac{QK^\top}{\sqrt{d_k}}\right)V \]其中:
- \(Q \in \mathbb{R}^{n \times d_k}\)
- \(K \in \mathbb{R}^{n \times d_k}\)
- \(V \in \mathbb{R}^{n \times d_v}\)
- \(n\) 是序列长度
对第 \(i\) 个 token 来说,它的输出可以写成:
\[ o_i = \sum_{j=1}^{n}\alpha_{ij} v_j \]其中权重是:
\[ \alpha_{ij} = \frac{\exp(q_i^\top k_j / \sqrt{d_k})}{\sum_{l=1}^{n}\exp(q_i^\top k_l / \sqrt{d_k})} \]这就是 attention 的核心:\(q_i\) 和所有 \(k_j\) 做匹配,然后按匹配结果对 \(v_j\) 加权求和。
问题也在这里。
因为每个 \(q_i\) 都要和所有 \(k_j\) 比一遍,所以你会得到一个 \(n \times n\) 的注意力矩阵:
\[ QK^\top \in \mathbb{R}^{n \times n} \]所以长度维度上的代价是二次的。序列一长,时间和显存就都顶不住。
2. 为什么不能直接先算 \(K^\top V\)
如果没有 softmax,attention 其实就是普通矩阵乘法:
\[ O = QK^\top V \]这时由于矩阵乘法满足结合律,可以改写成:
\[ O = Q(K^\top V) \]这样一来,先算 \(K^\top V\),就不需要显式构造 \(n \times n\) 的中间矩阵了。
但标准 attention 不是这个式子,而是:
\[ O = \mathrm{softmax}(QK^\top)V \]这里的 softmax 是按行做归一化的。它把每一行的打分变成一个概率分布,所以每个 \(o_i\) 都依赖于“这一行所有 token 的相对关系”。
这意味着:
\[ \mathrm{softmax}(QK^\top)V \neq Q(K^\top V) \]原因很简单:softmax 不是线性的,也不能从中间那一步直接拆出去。
所以“先算 \(K^\top V\)”这个想法,只有在没有 softmax 时才成立。
3. linear attention 的真正思路:让相似度可以分解
如果你想把 attention 变成线性复杂度,最自然的思路不是去硬拆矩阵乘法,而是想办法把注意力写成某种可分解形式。
更一般地,可以把归一化 attention 写成:
\[ o_i=\frac{\sum_{j=1}^{n}\operatorname{sim}(q_i,k_j)v_j}{\sum_{j=1}^{n}\operatorname{sim}(q_i,k_j)} \]如果相似度可以写成某个特征映射的内积:
\[ \operatorname{sim}(q,k)=\phi(q)^\top\phi(k) \]这样一来,注意力权重就不再是必须显式计算的两两匹配,而可以变成“先聚合 \(K\) 和 \(V\),再让 \(Q\) 去读这个聚合结果”。
为了看清楚,先看分子:
\[ \sum_{j=1}^{n}\operatorname{sim}(q_i,k_j)v_j \]代入可分解相似度:
\[ \sum_{j=1}^{n}\phi(q_i)^\top \phi(k_j) v_j \]由于 \(\phi(q_i)\) 和求和变量 \(j\) 无关,可以把它提到外面:
\[ \phi(q_i)^\top \sum_{j=1}^{n}\phi(k_j)v_j \]这一步就是 linear attention 的核心。分母也可以用同样的方法拆开,并用另一个累积量完成归一化。
注意,这里不是把 \(K^\top V\) 原封不动提前算掉,而是把“核化后的 key/value 聚合”提前算掉。
这里有一条很重要的概念边界:有些 Linear Attention 直接选择新的可分解核,例如 \(\operatorname{ELU}(x)+1\);另一些方法才是去近似 softmax 的指数点积核。前者重新定义了注意力相似度,后者试图逼近原来的 softmax attention,不能笼统地说成同一件事。
4. 详细推导:从逐 token 公式到可实现形式
我们从单个位置 \(i\) 开始。
标准 softmax attention 的输出是:
\[ o_i = \sum_{j=1}^{n}\frac{\exp(q_i^\top k_j)}{\sum_{l=1}^{n}\exp(q_i^\top k_l)}v_j \]把分子分母分开写:
\[ o_i = \frac{\sum_{j=1}^{n}\exp(q_i^\top k_j)v_j}{\sum_{l=1}^{n}\exp(q_i^\top k_l)} \]现在引入特征映射 \(\phi(\cdot)\),近似:
\[ \exp(q_i^\top k_j)\approx \phi(q_i)^\top\phi(k_j) \]于是分子变成:
\[ \sum_{j=1}^{n}\phi(q_i)^\top\phi(k_j)v_j \]把 \(\phi(q_i)\) 提到外面:
\[ \phi(q_i)^\top\left(\sum_{j=1}^{n}\phi(k_j)v_j^\top\right) \]这里为了维度一致,把 \(v_j\) 写成列向量时,里面是一个外积累积。 定义:
\[ S=\sum_{j=1}^{n}\phi(k_j)v_j^\top \]那么分子就是:
\[ \phi(q_i)^\top S \]分母同理:
\[ \sum_{j=1}^{n}\phi(q_i)^\top\phi(k_j) = \phi(q_i)^\top\left(\sum_{j=1}^{n}\phi(k_j)\right) \]定义:
\[ z=\sum_{j=1}^{n}\phi(k_j) \]于是最终可以写成:
\[ o_i \approx \frac{\phi(q_i)^\top S}{\phi(q_i)^\top z + \varepsilon} \]这里加一个很小的 \(\varepsilon\),是为了避免分母太小导致数值不稳定。
这就是 linear attention 最核心的形状。
它的意义非常明确:
- \(S\) 负责存“历史 key 和 value 的压缩摘要”
- \(z\) 负责存“历史 key 的归一化摘要”
- 当前 query \(q_i\) 只需要和这个摘要交互一次
于是原本每个 token 要和所有历史 token 两两交互,变成了:
- 先把所有历史信息压成一个固定大小状态;
- 再用当前 query 去读这个状态。
5. 矩阵形式更直观
把所有 token 一次写完,会更好看。
令:
\[ \Phi(Q)\in\mathbb{R}^{n\times r},\quad \Phi(K)\in\mathbb{R}^{n\times r} \]其中 \(r\) 是特征映射后的维度。 那么可以写成:
\[ O = \frac{\Phi(Q)\left(\Phi(K)^\top V\right)}{\Phi(Q)\left(\Phi(K)^\top \mathbf{1}\right)} \]这里:
- \(\Phi(K)^\top V \in \mathbb{R}^{r \times d_v}\)
- \(\Phi(K)^\top \mathbf{1} \in \mathbb{R}^{r}\)
\(\mathbf{1}\) 是全 1 向量,表示对所有 key 做求和。
这个式子非常关键,因为它直接告诉你复杂度怎么降下来:
- \(\Phi(K)^\top V\) 只需要扫一遍序列
- \(\Phi(K)^\top \mathbf{1}\) 也只需要扫一遍序列
- 最后 \(\Phi(Q)\) 再扫一遍序列
所以长度 \(n\) 上的复杂度从二次变成线性。
6. 复杂度到底降在哪里
标准 attention 的主要开销是构造 \(n \times n\) 的注意力矩阵。
如果忽略常数,复杂度可以粗略看成:
\[ O(n^2 d_k + n^2 d_v) \]而 linear attention 先算:
\[ \Phi(K)^\top V \]这是 \(r \times d_v\) 的累积,代价约为:
\[ O(n r d_v) \]再算:
\[ \Phi(Q)(\cdot) \]代价约为:
\[ O(n r d_v) \]所以只要 \(r\) 是固定的,长度维度就是线性的:
\[ O(n) \]严格说,上面只计算 attention mixing 的主要项;生成 \(\Phi(Q)\) 和 \(\Phi(K)\) 还会带来特征映射本身的成本。若 \(r\approx d_k\approx d_v\approx d\),常见写法是 \(O(nd^2)\)。所谓“线性”是指它关于序列长度 \(n\) 线性,并不是其他维度都消失了。
7. causal linear attention 为什么还能递推
如果是自回归生成场景,我们通常要求不能看未来 token。
这时 linear attention 还有一个额外好处:它可以递推更新。
定义到时刻 \(t\) 为止的状态:
\[ S_t = \sum_{j=1}^{t}\phi(k_j)v_j^\top \]\[ z_t = \sum_{j=1}^{t}\phi(k_j) \]那么它们的递推式就是:
\[ S_t = S_{t-1} + \phi(k_t)v_t^\top \]\[ z_t = z_{t-1} + \phi(k_t) \]当前输出则是:
\[ o_t = \frac{\phi(q_t)^\top S_t}{\phi(q_t)^\top z_t + \varepsilon} \]这意味着在推理时,你不需要保存完整的 KV cache,只要保存固定大小的 \(S_t\) 和 \(z_t\)。
这就是 causal linear attention 在长上下文生成里特别有吸引力的原因:记忆占用和长度无关,而是和特征维度有关。
更严格地说,这个“固定大小状态”直接对应流式执行和逐 token 解码。如果训练时为了并行而保存每个位置的前缀状态,中间激活仍可能达到 \(O(nrd_v)\);因此不能把推理阶段的常数状态,直接等同于所有训练实现都只占常数内存。
8. 一个最小实现长什么样
下面这个伪代码能把上面的公式对应起来:
import torch
def phi(x):
return torch.nn.functional.elu(x) + 1.0
def linear_attention(q, k, v, eps=1e-6):
# q: [B, H, N, R]
# k: [B, H, N, R]
# v: [B, H, N, D]
q = phi(q)
k = phi(k)
kv = torch.einsum("bhnr,bhnd->bhrd", k, v)
z = k.sum(dim=-2)
numerator = torch.einsum("bhnr,bhrd->bhnd", q, kv)
denominator = torch.einsum("bhnr,bhr->bhn", q, z)
return numerator / (denominator[..., None] + eps)这段代码的结构非常清楚:
kv对应 \(\sum_j \phi(k_j)v_j^\top\)z对应 \(\sum_j \phi(k_j)\)- 分子和分母都只做一次聚合读出
如果换成 causal 版本,就把 kv 和 z 改成逐步累积即可。
9. 两条不同路线:换一个核,还是近似 softmax
linear attention 的成败,很大程度上取决于 \(\phi(\cdot)\) 怎么选,但常见方法其实有两种不同目标。
直接定义可分解的注意力核
Katharopoulos 等人的 Linear Transformer 使用可分解的相似度,常见特征映射是:
\[ \phi(x)=\operatorname{ELU}(x)+1 \]它得到的是一种新的 kernel attention,通常不等于标准 softmax attention。正值映射可以让分母更容易保持稳定,但核的选择也直接限制了模型能表达怎样的相似度。
用随机特征近似 softmax 核
softmax 分子对应指数点积核:
\[ \exp(q^\top k/\sqrt{d_k}) \]Performer 使用 FAVOR+ 正交随机特征近似这个核,使它也能写成 \(\phi(q)^\top\phi(k)\)。它的目标是近似常规 full-rank softmax attention,而不是随意换一种相似度。
所以更准确的总结是:Linear Attention 是一类依靠可分解特征映射实现线性计算的机制;其中有些方法重新定义注意力核,有些方法专门近似 softmax 核。
10. 与 KV cache 的差异
标准 Transformer 做自回归推理时,需要保存每层所有历史 token 的 key 和 value:
\[ K_{\le t}\in\mathbb{R}^{t\times d_k},\qquad V_{\le t}\in\mathbb{R}^{t\times d_v} \]缓存大小随上下文长度 \(t\) 线性增长。Linear Attention 保存的则是:
\[ S_t\in\mathbb{R}^{r\times d_v},\qquad z_t\in\mathbb{R}^{r} \]只要 \(r\) 和 \(d_v\) 固定,这部分状态相对于序列长度就是常数级。
但“历史被压缩”既是优点,也是能力瓶颈。标准 Attention 可以针对当前 query 重新访问某个具体历史 token;Linear Attention 只能从聚合状态中读出历史。一旦不同 token 的信息在有限状态中互相干扰,后续 query 就很难把它们重新分开。
11. 一个三个 token 的直觉例子
假设某个 query \(q\) 对三个历史 token 的核权重分别是 \(w_1,w_2,w_3\)。普通的归一化加权输出为:
\[ o=\frac{w_1v_1+w_2v_2+w_3v_3}{w_1+w_2+w_3} \]如果 \(w_j=\phi(q)^\top\phi(k_j)\),分子就能写成:
\[ w_1v_1+w_2v_2+w_3v_3=\phi(q)^\top\left[\phi(k_1)v_1^\top+\phi(k_2)v_2^\top+\phi(k_3)v_3^\top\right] \]括号里的内容与当前 query 无关,因此历史 token 可以先把信息写入同一个状态:
\[ S=\sum_j\phi(k_j)v_j^\top \]query 到来后只需读取一次 \(S\),不再重新逐个扫描 \(k_1,k_2,k_3,\ldots,k_n\)。这就是“每个 query 与所有 key 交互”变成“query 读取累积状态”的最小例子。
12. 它为什么有用,又为什么不完全等价
linear attention 的优点很直接:
- 不需要显式构造 \(n \times n\) 注意力矩阵
- 长序列时更省显存、更省时间
- causal 场景下可以递推,适合流式生成
但它也有明显局限:
- 历史信息被压缩成固定状态,表达力弱于完整 softmax attention
- 重新定义核的方法不等于 softmax;随机特征方法则只是在近似 softmax
- 如果任务特别依赖“精确地回看某个历史 token”,linear attention 可能不如标准 attention
- 理论复杂度更低不保证短序列上墙钟时间更快,实际表现还取决于特征维度和硬件算子
所以它更像一种取舍:
你用更低的代价,换取更好的长序列可扩展性。
13. 和“先算 \(K^\top V\)”的直觉到底差在哪
这个问题值得单独收一下。
你的直觉其实抓到了“先聚合后读取”的骨架。
但标准 attention 里,不能直接聚合原始 \(K\) 和 \(V\),因为 softmax 会把每个 query 对历史 token 的偏好重新归一化。
linear attention 做的事情是:
- 不保留逐对的相似度矩阵;
- 选择或近似一个能写成 \(\phi(q)^\top\phi(k)\) 的核;
- 再利用结合律,把历史项压成状态 \(S\) 和 \(z\)。
所以它本质上不是“把 KV 提前算掉”,而是“把 attention 改成可累积的核回归”。
14. 一句话总结
如果你只记一句话,那就是:
linear attention 不是简单换一下矩阵乘法顺序,而是选择或近似一个可分解的注意力核,从而把原本显式的 \(n \times n\) 交互,改成固定状态的累积与读取。
它适合长序列、流式生成、低显存推理;
但它也不是标准 attention 的完全替代,因为它牺牲了一部分精确的全局匹配能力。