3 层线性注意力配 1 层全注意力,在同样的训练配方(1.4T token)下,短上下文、长上下文和 RL 三种设定都胜过了全注意力的基线;同时 KV cache 最多减少 75%,1M 上下文下 decode 吞吐最多提高约 6 倍。这是 Moonshot AI 2025 年 10 月发布的混合注意力架构 Kimi Linear。它的核心是一个新的线性注意力模块 KDA(Kimi Delta Attention):在 Gated DeltaNet 的基础上,把“每个头一个标量”的遗忘门换成“每个通道一个”的细粒度门,并为这个结构设计了专门的分块并行算法。
KDA 处在线性注意力一条清晰的演化线上:加性记忆 → 遗忘门 → delta 规则 → Gated DeltaNet → 通道级门。这套架构后来成了 Kimi K3 的骨架,见K3 那篇。
1. 为什么要换掉 softmax 注意力
标准的 softmax 注意力在第 \(t\) 个位置计算
$$o_t = \sum_{j\le t}\frac{\exp(q_t^\top k_j)}{\sum_{l\le t}\exp(q_t^\top k_l)}\,v_j .$$它有两个随长度增长的代价:
- prefill 的计算量是二次的:prefill 指一次性处理整段输入提示。长度 \(T\) 的序列,每个头的打分矩阵是 \(T\times T\),FLOPs 约 \(2T^2 d\)(\(d\) 是头维)。
- decode 时要保留全部历史的 K/V:decode 指逐个生成新 token。每一步都要和之前所有 token 的 key、value 做注意力,所以它们被缓存下来(KV cache),大小随长度线性增长;每生成一个 token 都要把整个 cache 从显存读一遍,decode 因此受限于显存带宽。
Agent 和 RL 的趋势让这两点更痛:一条轨迹里有大量工具调用和观察结果,上下文动辄几十万 token;RL 的 rollout 本身就是长时间的 decode。所以目标很明确:要一个质量不输全注意力、但长序列下又快又省显存的注意力。
2. 线性注意力:三种等价形式
2.1 去掉 softmax
线性注意力(Katharopoulos 等,2020)把 \(\exp(q^\top k)\) 换成普通内积(或一个特征映射后的内积),并暂时忽略归一化:
$$o_t = \sum_{j\le t}(q_t^\top k_j)\,v_j = \Big(\sum_{j\le t} v_j k_j^\top\Big) q_t .$$关键在第二个等号:把求和与 \(q_t\) 交换顺序后,括号里的东西与 \(q_t\) 无关,可以随着 \(t\) 递推维护。下面向量都是列向量,状态 \(S\in\mathbb R^{d_k\times d_v}\):
$$S_t = S_{t-1} + k_t v_t^\top,\qquad o_t = S_t^\top q_t .$$这就是递推形式:每步 \(O(d_kd_v)\),状态大小固定,与长度无关。decode 时不再需要 KV cache,只需要一个 \(d_k\times d_v\) 的矩阵。代价是:所有历史都被压进了这个固定大小的矩阵里,后面几节的改进都围绕“怎么更好地利用这块有限的记忆”展开。
2.2 并行形式与分块形式
训练时我们一次拿到整条序列,递推是串行的,不适合 GPU。等价的并行形式是
$$O = \big(QK^\top \odot M\big)V,$$\(M\) 是下三角因果掩码(\(M_{tj}=1\) 当且仅当 \(j\le t\))。这又回到了 \(T\times T\) 的矩阵,二次复杂度。实践中用的是两者之间的分块形式(chunkwise):把序列切成长度 \(C\)(常取 64)的块,块内用并行形式(矩阵乘,适合 Tensor Core),块间用递推传递状态:
$$O_{[t]} = Q_{[t]}S_{[t]} + \big(Q_{[t]}K_{[t]}^\top\odot M\big)V_{[t]},\qquad S_{[t+1]} = S_{[t]} + K_{[t]}^\top V_{[t]} .$$第一项是“之前所有块的贡献”(inter-chunk),第二项是“块内的贡献”(intra-chunk)。总计算量约 \(O(TCd + Td^2)\),对 \(T\) 线性。后面 KDA 的算法就是这个框架加上衰减和 delta 规则之后的推广。
2.3 在线学习的视角
比较各种线性注意力变体,有一个很好用的统一视角:把状态 \(S\) 看成一个“快权重”(fast weight),即一个把 key 映射到 value 的联想记忆(用 \(S^\top k\) 读出 key \(k\) 对应的值);每来一个 token,就对某个损失做一步梯度下降。不同的线性注意力,区别只在损失函数。普通线性注意力对应的损失是
$$\mathcal L_t(S) = -\langle S^\top k_t,\ v_t\rangle,\qquad \nabla_S\mathcal L_t = -k_tv_t^\top \ \Rightarrow\ S_t = S_{t-1} + k_tv_t^\top .$$这是一个无界的相关性目标:只会不断强化最近的 key–value 对,没有任何“该忘掉什么”的准则,状态无限累积,长序列下不同记忆相互干扰。状态只有 \(d_k\times d_v\) 这么大(KDA 里是 128×128),能互不干扰地存下的 key 最多 \(d_k\) 个(彼此正交的 key),这是线性注意力的根本容量限制。既然存不下全部,就必须有办法决定忘掉什么、覆盖什么,这正是接下来两节的内容。
3. 加上遗忘:衰减与门控
最直接的改进是在递推里乘一个衰减:\(S_t = A_t S_{t-1} + k_tv_t^\top\)。不同方法的差别只在 \(A_t\) 的形式:
| 方法 | 状态更新 | 衰减粒度 |
|---|---|---|
| 线性注意力 | \(S_t = S_{t-1} + k_tv_t^\top\) | 无 |
| RetNet | \(S_t = \alpha S_{t-1} + \beta_t k_tv_t^\top\) | 常数标量 |
| Mamba2 | \(S_t = \alpha_t S_{t-1} + \beta_t k_tv_t^\top\) | 数据相关标量(每头) |
| GLA | \(S_t = \operatorname{Diag}(\alpha_t) S_{t-1} + k_tv_t^\top\) | 数据相关、逐通道 |
| DeltaNet | \(S_t = (I-\beta_tk_tk_t^\top)S_{t-1} + \beta_tk_tv_t^\top\) | 无(但有 delta 修正) |
| Gated DeltaNet | \(S_t = \alpha_t(I-\beta_tk_tk_t^\top)S_{t-1} + \beta_tk_tv_t^\top\) | 数据相关标量 |
| KDA | \(S_t = (I-\beta_tk_tk_t^\top)\operatorname{Diag}(\alpha_t)S_{t-1} + \beta_tk_tv_t^\top\) | 数据相关、逐通道 |
表里的 \(\alpha_t, \beta_t\) 都在 \([0,1]\) 里,“数据相关”指它们由当前输入 \(x_t\) 经过一个小投影算出来。在在线学习视角里,衰减对应在损失上加一个 Frobenius 范数正则(例如 \(\tfrac12\|\sqrt{1-\alpha_t}\,S\|_F^2\)),也就是快权重上的权重衰减。逐通道的 \(\operatorname{Diag}(\alpha_t)\) 意味着状态的每一行(对应 key 的一个维度)有自己的遗忘速度。GLA 最早系统地用了这种对角门,并给出了能分块并行的实现。
4. DeltaNet:把状态当成在线回归
4.1 从重构损失推出 delta 规则
DeltaNet 把损失换成重构误差:希望用 key 读出来的东西 \(S^\top k_t\) 等于 \(v_t\):
$$\mathcal L_t(S) = \tfrac12\big\|S^\top k_t - v_t\big\|^2,\qquad \nabla_S \mathcal L_t = k_t\big(S^\top k_t - v_t\big)^\top .$$以学习率 \(\beta_t\) 走一步梯度下降:
$$S_t = S_{t-1} - \beta_t k_t\big(S_{t-1}^\top k_t - v_t\big)^\top = \big(I-\beta_tk_tk_t^\top\big)S_{t-1} + \beta_t k_tv_t^\top .$$这就是经典的 delta 规则。直观上:先读出这个 key 当前对应的旧值 \(S^\top k_t\),把它擦掉一部分,再写入新值。如果同一个 key 第二次出现、对应的值变了,普通线性注意力会把两个值叠加,delta 规则则会用新值替换旧值。
4.2 为什么要对 key 做 L2 归一化
转移矩阵 \(I-\beta kk^\top\) 是一个(广义)Householder 变换。若 \(\|k\|=1\),它的特征值是:在与 \(k\) 正交的 \(d_k-1\) 维子空间上为 1,沿 \(k\) 方向为 \(1-\beta\)。只要 \(\beta\in[0,1]\),所有特征值都在 \([0,1]\) 里,反复相乘不会发散。如果 \(\|k\|\) 不受控,\(1-\beta\|k\|^2\) 可能小于 \(-1\),状态就会爆炸。所以 KDA 对 \(q,k\) 都做 L2Norm,\(\beta\) 用 sigmoid 输出,保证转移矩阵的特征值始终落在 \([0,1]\) 里。
4.3 能并行吗
delta 规则让转移矩阵依赖于数据(而且依赖于 \(k_t\) 本身),不再是简单的累加,看起来比线性注意力难并行得多。关键是秩 1 更新的乘积有紧凑表示:若干个 \(I-\beta_ik_ik_i^\top\) 的乘积可以写成 \(I - \sum_i k_i w_i^\top\) 的形式(经典的 WY 表示),而 \(w_i\) 可以通过解一个下三角线性方程组一次性求出。这使得 DeltaNet 也能按块并行(Yang 等,2024)。第 7 节会对 KDA 完整推导这一点。
5. Gated DeltaNet,以及“门控即位置编码”
DeltaNet 只会“覆盖”,不会主动“遗忘”:与当前 key 正交的旧记忆永远保留。Gated DeltaNet(GDN)加一个标量遗忘门 \(\alpha_t\in[0,1]\):
$$S_t = \alpha_t\big(I-\beta_tk_tk_t^\top\big)S_{t-1} + \beta_tk_tv_t^\top .$$在优化视角下,这是先对快权重做权重衰减 \(\tilde S = \alpha_t S_{t-1}\),再在 \(\tilde S\) 上做一步重构损失的 SGD。两种机制互补:门控负责整体清空过时的记忆,delta 规则负责精确地改写某个 key 对应的值。Qwen3-Next 等模型用的就是 GDN。
5.1 门控与 RoPE 的类比
门控还有另一种理解方式:它在起位置编码的作用。为了看清这一点,把注意力分数写成统一的形式
$$s_{t,i} = q_t^\top\Big(\prod_{j=i+1}^{t} R_j\Big)k_i .$$RoPE 里 \(R_j\) 是块对角的二维旋转,旋转矩阵的乘积只依赖于相对位置 \(t-i\),所以可以把绝对位置分别作用到 \(q\) 和 \(k\) 上,再在内积里变成相对位置。把 GDN 的递推展开:
$$o_t = \sum_{i\le t}\Big(q_t^\top\prod_{j=i+1}^{t}\alpha_j\big(I-\beta_jk_jk_j^\top\big)\,k_i\Big)\,v_i ,$$形式完全一样,只是“位置变换”\(\alpha_j(I-\beta_jk_jk_j^\top)\) 是数据相关、可学习的,而且不必是正交矩阵。所以 GDN 可以看作一种乘性的、可学习的位置编码,放松了 RoPE 的正交性约束。
这个类比也解释了为什么需要通道级门控。RoPE 的一个关键优点是每对维度有不同的旋转频率,相当于在特征维上做非均匀傅里叶变换:有的维度编码近距离,有的编码远距离。GDN 每个头只有一个标量衰减,所有维度以同样速度遗忘,缺少这种逐维度的多样性。KDA 就是来补这一点的。
6. KDA:通道级的遗忘门
6.1 定义
KDA 把 GDN 的标量 \(\alpha_t\) 换成对角矩阵 \(\operatorname{Diag}(\alpha_t)\),\(\alpha_t\in[0,1]^{d_k}\):
$$S_t = \big(I-\beta_tk_tk_t^\top\big)\operatorname{Diag}(\alpha_t)\,S_{t-1} + \beta_tk_tv_t^\top \in\mathbb R^{d_k\times d_v},\qquad o_t = S_t^\top q_t .$$注意顺序:先逐通道衰减,再做 delta 修正。状态的第 \(c\) 行对应 key 的第 \(c\) 个维度,它有自己的保留率 \(\alpha_{t,c}\)。于是模型可以学会把需要长期保存的信息写进“慢”通道(\(\alpha\approx1\)),把短期信息写进“快”通道(\(\alpha\) 小),快通道很快被清空,不会干扰慢通道里的长期记忆。
6.2 参数化(每个头)
$$\begin{aligned} q_t, k_t &= \operatorname{L2Norm}\big(\operatorname{Swish}(\operatorname{ShortConv}(W_{q/k}x_t))\big)\in\mathbb R^{d_k},\\ v_t &= \operatorname{Swish}\big(\operatorname{ShortConv}(W_vx_t)\big)\in\mathbb R^{d_v},\\ \alpha_t &= f\big(W_\alpha^{\uparrow}W_\alpha^{\downarrow}x_t\big)\in[0,1]^{d_k},\qquad \beta_t = \operatorname{Sigmoid}(W_\beta x_t)\in[0,1]. \end{aligned}$$- \(d_k=d_v=128\),所有实验都是这个值。
- ShortConv:核大小为 4 的逐通道因果卷积,让每个位置先混合前几个 token 的信息,捕捉局部依赖。消融里去掉它会变差(第 10 节)。
- 逐通道衰减 \(\alpha_t\) 先过一个低秩投影(\(2304\to128\to d_k\)),再过衰减函数 \(f\)。\(f\) 的形式和 GDN、Mamba2 一样在对数域里定义:\(\log\alpha_t = -e^{A}\operatorname{Softplus}(z_t + b)\),\(z_t\) 是投影的输出,\(A\) 是每个头一个可学习标量,\(b\) 是偏置。Softplus 非负,所以 \(\log\alpha_t\le0\),\(\alpha_t\) 自然落在 \((0,1]\) 里。
- \(\beta_t\) 是每个头一个标量,决定这一步写入多强。
输出端:先做逐头 RMSNorm,再乘一个数据相关的输出门,最后过输出投影:
$$o_t = W_o\Big(\operatorname{Sigmoid}\big(W_g^{\uparrow}W_g^{\downarrow}x_t\big)\odot\operatorname{RMSNorm}\big(\operatorname{KDA}(q_t,k_t,v_t,\alpha_t,\beta_t)\big)\Big).$$输出门让每个通道可以按当前输入决定输出多少,也能缓解 attention sink(模型把大量注意力堆在少数几个 token 上的现象)。它和 \(\alpha\) 一样用低秩投影,这样和基线比较时参数量对得上,效果与全秩相当。门的激活用 sigmoid 而不是 GDN 用的 swish,消融显示 swish 门明显更差。
6.3 演示:标量门与通道门
演示在一个 16×16 的小状态上真实地跑 KDA 递推。序列里每隔 10 个 token 有一个“事实”token,它的 key 落在前 8 个通道(“慢通道”);其余是“噪声”token,key 落在后 8 个通道。通道门模式下慢通道保留率为 \(\alpha_{\text{slow}}\)、快通道为 \(\alpha_{\text{fast}}\);标量门模式下所有通道用同一个 \(\alpha\),取两者的几何平均(总的遗忘量相同,只是分配方式不同)。最后用每个事实的 key 去查询状态,看读出的值和原值的余弦相似度。
这里人为地把事实和噪声分到不同通道,是为了模拟训练好的模型会做的事(把需要长期保存的信息写进慢通道)。真实模型里这种分工是学出来的。可以切换“delta 规则”和“纯加法(无 delta)”看两者的差别。
标量门:S(行 = key 通道,上 8 行为慢通道)
通道门:S(同上)
序列结束时,用每个事实的 key 查询:读出值与原值的余弦相似度(横轴 = 事实距离结尾的步数)
维度 dk=dv=16,序列长 160,key 为随机单位向量,value 为随机高斯向量(固定种子)。热图颜色:紫色为正、橙色为负,深浅为绝对值。(示意)
可以观察到:标量门要在“记得久”和“清噪声”之间二选一——\(\alpha\) 大则噪声堆积干扰事实,\(\alpha\) 小则事实很快被遗忘;通道门可以两者兼得。关掉 delta 规则后,同一通道子空间里多个事实相互叠加,召回明显变差,这就是 DeltaNet 相对普通线性注意力的优势。
7. KDA 的分块并行算法
递推形式适合 decode,但训练时逐 token 串行太慢。KDA 同样可以像第 2.2 节那样分块并行:块内用矩阵乘,块间传状态。难点在于转移矩阵 \(A_t\) 不再是单位阵,块内的状态变换要连乘一串矩阵。记一个块内的位置 \(r=1,\dots,C\),块的初始状态为 \(S^0\)。定义
$$A_r = \big(I-\beta_rk_rk_r^\top\big)D_r,\quad D_r=\operatorname{Diag}(\alpha_r),\qquad \gamma^r = \prod_{j=1}^{r}\alpha_j\ (\text{逐元素}),\qquad \Gamma^{i\to r} = \operatorname{Diag}\!\big(\gamma^r/\gamma^i\big)=D_r\cdots D_{i+1}.$$\(\gamma^r\) 是从块开头到位置 \(r\) 的累积衰减,\(\Gamma^{i\to r}\) 是从位置 \(i\) 之后到 \(r\) 的累积衰减,\(\Gamma^{r\to r}=I\)。
7.1 展开递推
块内第 \(r\) 步的状态可以拆成“初始状态被变换后的部分”和“块内写入累积的部分”:
$$S^r = \underbrace{A_r\cdots A_1}_{P^r}\,S^0 + \underbrace{\sum_{i=1}^{r}A_r\cdots A_{i+1}\,\beta_ik_iv_i^\top}_{H^r}.$$(第二项可以这样理解:第 \(i\) 步写入的 \(\beta_ik_iv_i^\top\) 之后还要经过 \(A_{i+1},\dots,A_r\) 的变换。)直接算 \(P^r\) 要做 \(r\) 次 \(d_k\times d_k\) 的矩阵乘,太贵。目标是把它们写成“若干向量外积之和”的紧凑形式,这样就能用矩阵乘批量计算。
7.2 WY 表示
断言:存在向量 \(w_1,\dots,w_r\in\mathbb R^{d_k}\),使得
$$P^r = \Gamma^{0\to r} - \sum_{i=1}^{r}\Gamma^{i\to r}k_iw_i^\top,\qquad w_r = \beta_r\Big(\Gamma^{0\to r}k_r - \sum_{i\lt r} w_i\,\big(k_i^\top\Gamma^{i\to r}k_r\big)\Big).$$归纳:设对 \(r-1\) 成立。注意 \(D_r\Gamma^{i\to r-1} = \Gamma^{i\to r}\),所以
$$\begin{aligned} P^r &= (I-\beta_rk_rk_r^\top)\,D_rP^{r-1} = (I-\beta_rk_rk_r^\top)\Big(\Gamma^{0\to r}-\sum_{i\lt r}\Gamma^{i\to r}k_iw_i^\top\Big)\\ &= \Gamma^{0\to r}-\sum_{i\lt r}\Gamma^{i\to r}k_iw_i^\top - k_r\,\underbrace{\beta_r\Big(k_r^\top\Gamma^{0\to r} - \sum_{i\lt r}\big(k_r^\top\Gamma^{i\to r}k_i\big)w_i^\top\Big)}_{w_r^\top}. \end{aligned}$$因为 \(\Gamma^{r\to r}=I\),最后一项正是 \(\Gamma^{r\to r}k_rw_r^\top\),断言对 \(r\) 成立。对 \(H^r\) 做完全相同的归纳,可得
$$H^r = \sum_{i=1}^{r}\Gamma^{i\to r}k_iu_i^\top,\qquad u_r = \beta_r\Big(v_r - \sum_{i\lt r}u_i\,\big(k_i^\top\Gamma^{i\to r}k_r\big)\Big).$$7.3 UT 变换:把递推变成一次三角求逆
上面 \(w_r, u_r\) 的递推是串行的,但它们其实是一个下三角线性方程组。记块内矩阵 \(K,V\in\mathbb R^{C\times d}\),\(\Gamma\in\mathbb R^{C\times d_k}\) 的第 \(r\) 行是 \(\gamma^r\)。系数 \(k_r^\top\Gamma^{i\to r}k_i = \sum_c k_{r,c}k_{i,c}\,\gamma^r_c/\gamma^i_c\) 正好是矩阵 \((\Gamma\odot K)(K/\Gamma)^\top\) 的第 \((r,i)\) 元。把 \(u\) 的递推移项:
$$\Big(I + \operatorname{StrictTril}\big(\operatorname{Diag}(\beta)(\Gamma\odot K)(K/\Gamma)^\top\big)\Big)U = \operatorname{Diag}(\beta)V .$$于是
$$\mathcal M = \Big(I + \operatorname{StrictTril}\big(\operatorname{Diag}(\beta)(\Gamma\odot K)(K/\Gamma)^\top\big)\Big)^{-1}\operatorname{Diag}(\beta),\qquad W = \mathcal M(\Gamma\odot K),\quad U = \mathcal M V .$$(\(W\) 的方程完全一样,只是右端的 \(V\) 换成 \(\Gamma\odot K\)。)\(C\times C\) 下三角矩阵(\(C=64\))的逆用前代法逐行求,代价小;其余全是矩阵乘。这一步叫 UT 变换,目的是把串行的、非矩阵乘的计算压到最少,让大部分 FLOPs 都落在 Tensor Core 上。
7.4 块间状态更新与输出
代回 \(S^C = P^CS^0 + H^C\):
$$S_{[t+1]} = \operatorname{Diag}(\gamma^C)\,S_{[t]} + \big(\Gamma^{\cdot\to C}\odot K\big)^\top\big(U - WS_{[t]}\big).$$块内第 \(r\) 个输出 \(o_r^\top = q_r^\top S^r\) 同样展开后,堆叠成矩阵:
$$O_{[t]} = \underbrace{(\Gamma\odot Q)\,S_{[t]}}_{\text{块间}} + \underbrace{\operatorname{Tril}\big((\Gamma\odot Q)(K/\Gamma)^\top\big)}_{\text{块内}}\ \underbrace{\big(U - WS_{[t]}\big)}_{\text{“伪 value”}} .$$这个结构和第 2.2 节普通线性注意力的分块形式几乎一样:块间项用初始状态读,块内项是一个下三角的 \(C\times C\) 注意力矩阵乘以 value。区别是 value 被换成了“伪 value” \(U-WS\)——delta 规则的效果全部被吸收进了 \(U\) 和 \(W\)。注意 Tril 包含对角线:每个输出读的是当前 token 写入之后的状态。
7.5 伪代码
把上面的公式写成 PyTorch 风格的伪代码(\(g\) 是对数衰减 \(\log\alpha\),块内做 cumsum 得到 \(\log\gamma\)):
def chunk_kda(q, k, v, g, beta, C=64): # q,k: [T,dk] v: [T,dv] g: [T,dk] (log α)
S = zeros(dk, dv); out = []
for blk in split(range(T), C):
Q, K, V, b = q[blk]*dk**-0.5, k[blk], v[blk], beta[blk]
G = g[blk].cumsum(0) # log γ^r,逐通道
# A[r,i] = β_r Σ_c k_rc k_ic exp(G_rc − G_ic),严格下三角
A = strict_tril(b[:,None] * ((K*exp(G)) @ (K*exp(-G)).T))
M = inv(I + A) * b[None,:] # 前代法求逆,再右乘 Diag(β)
W, U = M @ (exp(G)*K), M @ V
Vt = U - W @ S # 伪 value
Aqk = tril((Q*exp(G)) @ (K*exp(-G)).T) # 含对角
out.append((Q*exp(G)) @ S + Aqk @ Vt)
decay = exp(G[-1:] - G) # γ^C/γ^r
S = exp(G[-1])[:,None] * S + (K*decay).T @ Vt
return cat(out)
这里有一个数值问题:\(K/\Gamma\) 里的 \(1/\gamma\) 是累积衰减的倒数,块内越往后越大,在半精度下会溢出。解决办法沿用 GLA:在对数域里算相对衰减 \(\exp(G_r-G_i)\)(\(r\ge i\) 时它不超过 1),并把块再切成 16 个 token 的二级小块(secondary chunking)。非对角的小块之间可以先减去一个公共的参考点再相乘,直接用 Tensor Core 做稠密矩阵乘;对角的小块要逐个位置对计算。上面伪代码为了易读直接写了 exp(-G),实际 kernel 里不会这样做。(K3 后来改用有下界的衰减,让对角小块也能走 Tensor Core。)
7.6 FLOPs
每个头、长度 \(T\)、头维 \(d_h\)、块长 \(C=64\) 时,两者的理论 FLOPs 是:
$$\mathrm{FLOPs}_{\text{KDA}} = 6Td_h^2 + 3TCd_h + TC^2,\qquad \mathrm{FLOPs}_{\text{Attn}} = 2T^2d_h .$$令两者相等,\(d_h=128\) 时交点约在 \(T\approx 3d_h+1.5C+C^2/(2d_h)\approx 500\)。也就是说几百 token 以上 KDA 每头的计算就更省,到 1M 时差三个数量级。推理时 prefill 用分块 kernel,decode 切换到递推 kernel(每步只读写 128×128 的状态)。
8. 为什么比一般 DPLR 快
更一般的“对角加低秩”(DPLR,Diagonal-Plus-Low-Rank)转移矩阵写作
$$S_t = \big(D - a_tb_t^\top\big)S_{t-1} + k_tv_t^\top .$$S4 用的是静态 DPLR,RWKV-7 用的是数据相关的 DPLR。KDA 也是 DPLR 的一种,展开就是
$$S_t = \big(\operatorname{Diag}(\alpha_t) - \beta_tk_tk_t^\top\operatorname{Diag}(\alpha_t)\big)S_{t-1} + \beta_tk_tv_t^\top,\qquad D=\operatorname{Diag}(\alpha_t),\ a_t = \beta_tk_t,\ b_t = k_t\odot\alpha_t .$$表达能力上二者都有细粒度衰减,但 KDA 把 \(a\)、\(b\) 都绑定到 \(k\) 上,并且共享 \(\alpha_t\),从而可以把 \(\operatorname{Diag}(\alpha_t)\) 提出来,写成“先 GLA 式逐通道衰减、再 DeltaNet 式 Householder 更新”。这个约束带来的计算上的好处:
- 一般 DPLR 在块内需要四个 \(C\times C\) 的交互矩阵(\(A_{qk}, A_{qb}, A_{ab}, A_{ak}\)),每个都涉及 \(1/\Gamma\),都需要二级分块来保证数值稳定;KDA 因为 \(a=b=k\)(差一个标量和衰减),只需要 \(A_{qk}\) 和 \(A_{kk}\) 两个,二级分块从四次降到两次。
- 块间与输出计算里,KDA 又省掉了大约三次矩阵乘。
在 batch 1、16 头的 kernel 测试中,长度直到 64K 的范围内 KDA 的速度都接近一般 DPLR 的 2 倍。
9. Kimi Linear 的架构:3:1 混合与 NoPE
9.1 为什么还要混合全注意力
KDA 再好,状态也是固定大小的。精确检索和逐字复制这类任务需要从压缩的记忆里取回整段历史,对纯线性注意力在原理上就很难。所以 Kimi Linear 把 KDA 和少量全注意力层(MLA)混合。混合方式选的是按层交替,而不是在一层里混合不同的头,理由是基础设施简单、训练稳定。经验上 3 层 KDA 接 1 层 MLA 的均匀 3:1 比例在质量与吞吐之间最好。
9.2 MLA 层用 NoPE
Kimi Linear 的所有 MLA 层都不加位置编码(NoPE),位置信息和近因偏置完全交给 KDA 层。理由来自第 5.1 节:KDA 本身就是一种可学习的、逐通道多频率的乘性位置编码,作用类似甚至强于短卷积或滑动窗口注意力这类辅助组件。NoPE 对 MLA 还有两个实际好处:
- 推理时 MLA 可以转成高效的纯 MQA。MLA 本来就把 K/V 压成一个所有头共享的隐向量,推理时把上投影矩阵吸收进 query 和输出投影,就相当于所有头共用一组 key/value 的 MQA。用 RoPE 时,位置旋转夹在 query 和 key 之间,吸收不掉,只能另开一个单独旋转的小分支;没有 RoPE 就没有这个麻烦。
- 长上下文训练更简单,不需要调 RoPE 的频率底数,也不需要 YaRN 一类方法。
实验(第 10.5 节)显示,用 RoPE 的版本在短上下文上差不多,但长上下文明显更差。一个解释是位置偏置在深度上的分布:带 RoPE 时,全局注意力层承担了强而显式的相对位置信号,KDA 只提供较弱的隐式位置偏置,模型过分依赖短程顺序,训练中途扩展到长上下文时适应性差;NoPE 让位置偏置在各层分布更均衡,外推更稳。
9.3 模型配置
主干沿用 Moonlight(Moonshot 之前的 16B MoE 模型)的结构,区别是 MoE 稀疏度(expert 总数 / 每 token 选中的 expert 数)提高到 256/8 = 32:
| 项目 | 值 |
|---|---|
| 总参数 / 激活参数 | 48B / 3B |
| 层数 | 27(20 KDA + 7 MLA) |
| 隐藏维度 | 2304 |
| KDA 头数 × 头维 | 32 × 128(\(d_k=d_v=128\)) |
| ShortConv 核大小 | 4 |
| MLA 头数、KV 压缩维度 | 32、512(另有 64 维所有头共享的 key 分量),NoPE |
| MoE | 256 个路由 expert,router 每 token 选 8 个;另有 1 个共享 expert 始终激活;expert 中间维 1024 |
| 第一层 | dense FFN(为了训练稳定) |
| 最大上下文 | 1,048,576 |
10. 实验
10.1 合成任务
合成任务用来单独考察记忆机制。模型是 2 层、2 头、头维 128 的小模型,最多训练 20000 步,学习率在 {5e-5, 1e-4, 5e-4, 1e-3} 里网格搜索。三个任务:
- Palindrome:把一串随机 token 倒序输出。需要从固定大小的状态里精确取回全部历史,对线性注意力很难。
- MQAR(多查询联想召回):上下文里有若干 key–value 对,最后给出多个 key,要回答对应的 value。已知它和语言建模能力高度相关。
- Stack:64 个独立的栈,序列里是 PUSH/POP 操作,POP 时要预测对应栈最近压入的元素,考察状态追踪。
结果:长度从 256 增加到 2048,三个任务上 KDA 的准确率都最高;在 Palindrome 和 MQAR 上 KDA 比 GDN 收敛快得多。只有乘性衰减、没有 delta 规则的 Mamba2 在这个设定下三个任务都失败。
10.2 消融
消融以缩放律实验中最小的配置(16 头 16 层)为基准,同 FLOPs、同超参:
| 变体 | 训练 PPL | 验证 PPL |
|---|---|---|
| 3:1(KDA:MLA,最终选择) | 9.23 | 5.65 |
| 0:1(纯 MLA) | 9.45 | 5.77 |
| 1:1 | 9.29 | 5.66 |
| 7:1 | 9.23 | 5.70 |
| 15:1 | 9.34 | 5.82 |
| 去掉输出门 | 9.25 | 5.67 |
| swish 输出门 | 9.43 | 5.81 |
| 去掉卷积层 | 9.29 | 5.70 |
验证集的分布与预训练语料差别很大,强调分布偏移下的泛化,所以训练与验证 PPL 的数值差距大。几点:7:1 训练 PPL 与 3:1 相同但验证更差;1:1 验证接近但推理开销更大;纯全注意力反而最差。
10.3 缩放律
按 Moonlight 结构训练一组 MoE(激活 653M 到 1.7B,64 选 8 的 expert,Muon),MLA 基线按 Chinchilla 方法逐个网格搜索超参,Kimi Linear 保持 3:1、其余完全照搬 MLA 的配置。拟合结果:MLA \(2.3092\times C^{-0.0536}\),Kimi Linear \(2.2879\times C^{-0.0527}\),在算力最优训练下 Kimi Linear 约有 1.16 倍的计算效率,也就是达到同样损失少用约 14% 的算力。KDA 的超参没有专门调过,这个优势可能还偏保守。
10.4 主实验设置
三个模型——Kimi Linear、全 MLA 基线、混合 GDN 基线(GDN-H)——架构、参数量和训练配置完全相同(另有一个用 RoPE 的 Kimi Linear 作为 NoPE 的消融)。都用 4096 上下文、MuonClip、WSD,从 K2 的预训练语料里采样 1.4T token;学习率 1.1e-3,全局 batch 3200 万 token,退火和长上下文激活沿用 K2。SFT 在 K2 的 SFT 数据上加了推理数据,分多阶段;RL 用数学、代码、STEM 提示,沿用 K1.5 的算法并加上截断重要性采样(缓解训练与推理引擎精度不一致带来的策略偏差)、动态调整 KL 惩罚和 mini-batch 数,防止熵坍缩;同时像 K2 一样加 PTX 损失。
10.5 结果(1.4T token,同配方)
| 基准 | MLA | GDN-H | Kimi Linear |
|---|---|---|---|
| 预训练(基座) | |||
| MMLU | 71.6 | 72.2 | 73.8 |
| MMLU-Pro | 47.2 | 47.9 | 51.0 |
| BBH | 71.6 | 70.6 | 72.9 |
| GSM8K | 83.7 | 81.7 | 83.9 |
| EvalPlus | 59.5 | 63.1 | 60.2 |
| SFT 后 | |||
| MMLU-Pro | 65.7 | 64.8 | 67.4 |
| GPQA-Diamond (Avg@8) | 57.1 | 58.6 | 62.1 |
| AIME 2025 (Avg@64) | 20.6 | 21.1 | 21.3 |
| LiveCodeBench v6 | 25.1 | 25.4 | 26.0 |
| MATH500 | 80.8 | 83.0 | 81.2 |
| 长上下文(128K) | |||
| RULER | 81.3 | 80.5 | 84.3 |
| MRCR | 22.6 | 23.9 | 29.6 |
| RepoQA | 63.0 | 63.0 | 68.5 |
| LongBench v2 | 36.1 | 32.6 | 35.0 |
| 7 项长上下文平均 | 52.2 | 51.2 | 54.5 |
Kimi Linear (RoPE) 的长上下文平均是 51.8,比 NoPE 版低 2.7。整体的层次关系是:预训练和 SFT 阶段 Kimi Linear > GDN-H > MLA;长上下文上 Kimi Linear 仍第一,但 GDN-H 掉到 MLA 后面;数学 RL 中 Kimi Linear 的训练准确率增长明显快于 MLA,差距逐渐拉大,MATH500 和 AIME 2025 测试曲线也是如此。也有例外:EvalPlus 和 MATH500 上 GDN-H 更高,LongBench v2、Frames 上 MLA 更高。
10.6 5.7T 的发布版本
发布的 checkpoint 按同样流程训练到 5.7T token(与 Moonlight 相同),支持 1M 上下文。和 Moonlight(同样 3B 激活,但 16B 总参)比,基座 MMLU-Pro 54.8 vs 42.4、MATH 58.5 vs 45.3;指令版 RULER@128K 95.4、RULER@1M 94.8,AIME 2025 58.6,LiveCodeBench v6 45.7(Moonlight-Instruct 11.9)。这个比较里总参数和稀疏度也变了(MoE 稀疏度是 Moonlight 的 3 倍左右),所以它不是纯粹的注意力对照,同配方的对照还是看上面 1.4T 的结果。
11. 效率:KV cache、prefill 与 decode
实测数据(三个模型都是 48B 配置、相同层数与头数):
- KV cache:只有 1/4 的层(MLA)需要随长度增长的 cache,最多减少 75%。
- prefill:4K–16K 与 MLA 相当;128K 起明显更快;512K 时 2.3 倍,1M 时 2.9 倍。细粒度衰减相对 GDN-H 几乎没有额外延迟。
- decode:要分两种情况看。batch 固定为 1 时,1M 上下文下每输出 token 时间(TPOT)约快 2.2 倍(512K 约 1.8 倍)。这时时间主要花在读 KV cache 上,而混合模型只有 7/27 的层有 cache,加速比的上限就是这个 cache 压缩比(约 3.9 倍),读权重等固定开销让实际值更低。如果把省下的显存用来放更大的 batch,1M 上下文下平均 TPOT 为 1.84 ms,MLA 为 11.48 ms,约 6.3 倍。
为什么放大 batch 能把 2 倍多变成 6 倍?计算器按 Kimi-Linear-48B 的结构估算每条序列的缓存大小,并用一个简单的带宽模型估算 decode:每一步要从显存读一遍被激活的权重和所有序列的缓存,时间 ≈ 字节数 / HBM 带宽;在给定的缓存显存预算内 batch 取最大。
MLA 每 token 每层缓存 512 + 64 = 576 个 BF16 数(512 维压缩 KV 加 64 维共享 key;用 NoPE 时这 64 维只是不做旋转,仍然要缓存);KDA 每层每序列是 32 个 128×128 状态加短卷积缓存。权重读取量 = 非 expert 参数约 1.45B(含输出头)+ 每层的共享 expert 和被 batch 中任一 token 选中的路由 expert(BF16)。这个模型忽略了计算、通信和 kernel 效率,只用于看趋势。
把上下文设为 1M、预算 120 GB 左右,就能看出 batch 的作用:全 MLA 每条 1M 序列的缓存约 33 GB,混合模型约 8.5 GB,同样的显存能多放约 4 倍的序列;而每一步读权重的开销是被整个 batch 分摊的,batch 越大,每个 token 分到的权重读取越少,所以吞吐的提升可以超过缓存本身的压缩比。
12. 小结
- KDA = Gated DeltaNet 的 delta 规则 + GLA 的逐通道衰减。delta 规则解决“覆盖”,逐通道门解决“按维度决定记多久”,后者也让 KDA 成为一种可学习的多频率位置编码,从而全注意力层可以用 NoPE。
- 算法上关键是把 DPLR 的 \(a,b\) 都绑定到 \(k\):WY 表示 + UT 变换让 delta 规则可分块并行,只需要两个块内交互矩阵,比一般 DPLR 快约一倍。
- 架构上 3:1 按层混合,在同配方 1.4T token 下短、长上下文和 RL 都胜过全 MLA;长序列下省 75% 的 KV cache,大 batch decode 在 1M 时快约 6 倍。
这些设计在 Kimi K3 里几乎原样保留,K3 又在 KDA 上改了衰减的参数化(加下界,消掉对角小块的逐位置计算)和输出门(改成全秩),见K3 那篇。
参考与延伸阅读
想看分块算法的完整推导和 kernel 伪代码,推荐读报告的 §3 与附录 B、C;KDA 的 Triton 实现在 flash-linear-attention 里。
- Kimi Team. Kimi Linear: An Expressive, Efficient Attention Architecture. arXiv:2510.26692:§2 预备知识、§3 KDA、§4 架构、§5 实验、§6 讨论、附录 B、附录 C、附录 D。
- Kimi-Linear-48B-A3B-Instruct 的 config.json。
- KDA kernel:fla-org/flash-linear-attention;代码与模型:MoonshotAI/Kimi-Linear。
- 线性注意力与它的演化:A. Katharopoulos et al. Transformers are RNNs(2020);S. Yang et al. Gated Linear Attention Transformers with Hardware-Efficient Training(2023,逐通道门与分块算法、二级分块);S. Yang et al. Parallelizing Linear Transformers with the Delta Rule over Sequence Length(2024,DeltaNet 的 WY 表示与分块并行);S. Yang, J. Kautz, A. Hatamizadeh. Gated Delta Networks(2024)。
- Kimi Team. Kimi K3: Open Frontier Intelligence. arXiv:2607.24653,§2.1.1 讲了 K3 对 KDA 衰减参数化的修改。
- 想先补 MLA 的背景,推荐读 DeepSeek-V2 的报告:arXiv:2405.04434。