Skip to content

约 12 分钟阅读

12. 线性注意力、状态空间模型与混合架构:用固定大小的状态代替 KV Cache ​

上一篇的各种办法,都在“少看一点”或“少存一点”上做文章:滑动窗口让大部分层只看近处,稀疏注意力只挑一部分位置计算。但只要还有一层完整注意力,KV Cache 就随上下文线性增长,资料助手把整本员工手册放进去,Llama-3.1-8B 单个请求就要 16 GiB。

这一篇看一条更彻底的路线:不再逐个 token 保存 K、V,而是把全部历史压进一个大小固定的状态,每来一个 token 更新一次。线性注意力、Mamba 这类状态空间模型、门控 DeltaNet 都属于这条路线。它们的代价同样明确:状态装不下所有细节,纯线性模型在“从上下文里原样找回某个信息”这件事上明显变差。所以 2024 年以来走这条路线的大模型几乎都采用了混合架构:大部分层用固定状态,少数层保留完整注意力。读完你应该能看懂 Qwen3.5、Kimi Linear、Jamba、Nemotron-H 的层排布,算出它们的缓存占用,并说清楚为什么主流大模型很少只用线性层。

把历史压成一个矩阵 ​

先回到 softmax 注意力(第 03 篇)。当前 token 的查询 q 和每个历史 key 打分、softmax,再对 value 加权求和。softmax 要求先看到所有分数才能归一化,所以每个历史 token 的 K、V 都得留着。

如果去掉 softmax,直接用点积当权重,输出就变成:

text
o = Σₛ (q · kₛ) vₛ = (Σₛ vₛ kₛᵀ) q = S q

S = Σₛ vₛ kₛᵀ      一个 d_v × d_k 的矩阵,每来一个 token 加一项:S ← S + v kᵀ

括号换了个位置,所有历史就被“预先加”成了一个矩阵 S。这就是线性注意力(linear attention):每个新 token 只做一次 S ← S + v kᵀ 和一次 o = S q,计算和存储都与历史长度无关。名字里的“线性”指总计算随长度线性增长,而不是平方。实际模型通常会先对 q、k 做一个特征变换或归一化,这里省略不影响理解。

用 2 维的玩具数字看它到底存下了什么。资料助手依次读到三个词,它们的 key、value 如下:

text
“年假” k₁ = [1, 0]     v₁ = [5, 1]
“申请” k₂ = [0, 1]     v₂ = [2, 4]
“报销” k₃ = [0.6, 0.8] v₃ = [0, 6]

写入前两个后:S = v₁k₁ᵀ + v₂k₂ᵀ = [[5, 2], [1, 4]]
  用 k₁ 读:S·[1, 0] = [5, 1]  ✓   用 k₂ 读:S·[0, 1] = [2, 4]  ✓

左边 KV Cache 把三个 token 的 K、V 共 12 个数都存下来;右边线性注意力只存一个 2×2 矩阵,前两个正交的键能准确读回,第三个键写入后三个读数都被污染

前两个 key 互相垂直(正交),写进 S 后互不干扰,用哪个 key 读就精确得到哪个 value。KV Cache 存了 8 个数,S 只存 4 个,效果一样。这就是线性注意力的吸引力:Decode 每一步的工作量固定,不会因为前面读过 12 万个 token 而变慢;缓存大小也固定,不会因为上下文变长而撑爆显存。

容量有限:第三个键值对来了 ​

问题出在第三个 token。2 维空间里最多只有 2 个互相垂直的方向,“报销”的 key [0.6, 0.8] 必然和前两个重叠:

text
再写入“报销”:S = [[5, 2], [4.6, 8.8]]
  用 k₁ 读:[5, 4.6],应为 [5, 1]
  用 k₂ 读:[2, 8.8],应为 [2, 4]
  用 k₃ 读:[4.6, 9.8],应为 [0, 6]

三个读数全错了。这不是玩具例子特有的问题:每个头的状态是 d_k × d_v 个数,最多只能无干扰地存 d_k 对键值。真实模型每头是 128 × 128,Qwen3.5-397B 的一层有 64 个这样的头,容量比玩具大得多,但它仍是一个固定的数,而上下文可以无限长。softmax 注意力就没有这个问题:KV Cache 里每个原始 V 都在,只要 q 和 k₁ 的打分足够突出,就能取回接近 [5, 1] 的值。

所以线性化之后,核心问题变成了“怎样管理一份有限的记忆”:什么时候该忘掉旧内容,写入新内容时怎样少破坏已有内容。下面两种机制分别回答这两件事。

门控:让模型决定忘掉多少 ​

最朴素的线性注意力只加不减,越往后 S 里的东西越多、越混乱。加一个衰减门控就能主动遗忘:

text
S ← αₜ S + vₜ kₜᵀ      αₜ ∈ (0, 1),由当前 token 算出

αₜ 接近 1 时保留历史,接近 0 时清掉历史重新开始。关键是 αₜ 随输入变化:读到一个新章节标题,模型可以选择忘掉上一章的细节;读到正文,就保留。

状态空间模型(state space model,SSM)从另一个方向得到了几乎相同的结构。它来自控制理论,用一个隐藏状态 h 概括历史:hₜ = A hₜ₋₁ + B xₜ,输出 yₜ = C hₜ。早期的 SSM 里 A、B、C 是固定的,不随输入变化,在语言这种离散数据上效果不好。Mamba(Gu 和 Dao,2023 年 12 月)的关键改动是让这些参数随输入变化,论文称之为“选择性”:每个 token 自己决定状态里保留什么、丢掉什么。它报告的推理吞吐约为同等 Transformer 的 5 倍,3B 规模时与两倍大小的 Transformer 相当。Mamba-2(2024 年 5 月)进一步把 A 简化成每个头一个标量衰减,并证明这类 SSM 和带衰减门控的线性注意力可以写成同一类矩阵运算(论文称为 SSD,结构化状态空间对偶),由此能用矩阵乘法高效训练,核心层快 2 到 8 倍。

从“状态”的角度看,Mamba-2 和门控线性注意力是一回事:每个头存一个固定大小的矩阵,每个 token 按输入决定的比例衰减旧状态、写入新内容。Nemotron-H-8B 的 Mamba2 层有 128 个头,每头的状态是 64 × 128。

delta 规则:先擦掉旧值,再写新值 ​

门控只能整体衰减,没法“精确修改某一条”。delta 规则换了写入方式:写入前先用新 key 读一下当前状态,看它已经记着什么,只把差值写进去:

text
S ← S + β (vₜ − S kₜ) kₜᵀ      β ∈ (0, 1] 是写入强度

S kₜ 是状态目前对这个 key 的“记忆”,vₜ − S kₜ 是需要修正的部分。用同样三个 token、β = 1 重算:

text
三步后:用 k₃ 读:[0, 6]  ✓(刚写入的这条精确)
        用 k₁ 读:[2.24, 2.32],用 k₂ 读:[−1.68, 5.76]

最新的那条被精确写入,代价是和它重叠的旧内容被改写了一部分。容量仍是 2 维,delta 规则改变的是“谁让位”:普通线性注意力让所有条目一起变模糊,delta 规则优先保证新写入的准确。

门控 DeltaNet(Gated DeltaNet,Yang、Kautz、Hatamizadeh,ICLR 2025)把两者合在一起:先按门控衰减整个状态,再用 delta 规则写入。论文的说法是,门控负责快速清空,delta 规则负责精确更新;它在语言建模、上下文检索和长度外推上都优于 Mamba2 和 DeltaNet。Transformers 里 Qwen3_5MoeGatedDeltaNet 调用的 torch_recurrent_gated_delta_rule,逐 token 的循环简化后是:

python
# 一个头:q, k: [T, 128](已做 L2 归一化),v: [T, 128];g: [T] 衰减(≤0),beta: [T]
S = zeros(128, 128)                       # 状态:每个头 128×128,与 T 无关
for t in range(T):
    S = S * exp(g[t])                     # 门控:整体衰减
    pred = k[t] @ S                       # 状态对 k[t] 目前的记忆 [128]
    S = S + outer(k[t], beta[t] * (v[t] - pred))   # delta 规则:只写差值
    o[t] = q[t] @ S                       # 读出

其中 β 是 in_proj_b 的输出过 sigmoid,g 由 in_proj_a、A_log、dt_bias 算出,这几个参数名和 Mamba 一脉相承。训练时不会真的逐 token 循环,而是用分块算法(源码里的 torch_chunk_gated_delta_rule)把序列切成块并行计算。Kimi Linear 的 KDA(Kimi Delta Attention)在此基础上把衰减从“每头一个数”细化到“每个维度一个数”,源码注释写的就是“与 GDN 基本相同,但衰减按通道”,每一维可以有自己的遗忘速度。

纯线性模型为什么召回差 ​

上面的玩具例子已经给出了直觉:固定大小的状态装不下任意多的细节。几项研究从不同角度给出了证据,强度和边界各不相同。

Zoology(Arora 等,2023 年 12 月)预训练了 17 个注意力模型和门控卷积模型(与 SSM 同属固定状态的一类),发现两者在 Pile 上最多相差 2.1 的困惑度,其中 82% 可以由关联召回(associative recall)解释,也就是“前文出现过 A 对应 B,后文看到 A 时说出 B”的能力。在专门的召回任务上,70M 参数的注意力模型胜过 1.4B 参数的门控卷积模型。这是迄今最直接的定量证据,不过它测的是门控卷积,不是后来的 Mamba-2 或门控 DeltaNet。

Jelassi 等(2024 年 2 月)从理论上证明,两层 Transformer 就能复制指数长度的字符串,而广义 SSM 受固定状态限制做不到;实验中,预训练的 Transformer 在复制和从上下文检索信息上远强于同规模的 SSM。Jamba 论文(2024 年 3 月)观察到一个更贴近使用的现象:纯 Mamba 模型在少样本分类时经常不按示例给出的格式回答,在 IMDB 上要求回答“Positive”或“Negative”,它却输出“Very Good”“Funny”,准确率 48.8,纯注意力 84.1,混合模型 90.9。作者推测这与注意力层里的归纳头(induction head)有关,并说明这只是个案观察。

对资料助手来说,这类弱点会表现为:手册里明确写着“申请需提前 5 个工作日”,模型却答成“提前几天”;要求原样引用条款编号时编号对不上;按示例格式输出时格式漂移。判断一个模型是否有这个问题,最直接的办法是做“电话簿”式测试:给一长串“姓名—号码”对,再随机问其中几个,看准确率随列表长度的变化。纯注意力模型在上下文窗口内大体平稳,纯线性模型往往在超过状态容量后迅速下降。

混合架构:少数层保留完整注意力 ​

既然固定状态擅长高效地概括历史,注意力擅长精确取回,那就各用一部分层。Zoology 已经发现,加入少量依赖输入的注意力就能补上 97.4% 的差距。后来的混合模型基本都按这个思路,只是比例和组件不同。

四个混合模型的层排布:Qwen3.5 每 4 层 1 层注意力,Kimi Linear 27 层中 7 层 MLA,Jamba 每 8 层 1 层注意力,Nemotron-H-8B 的 52 个块里只有 4 个注意力块

模型发布线性层 / SSM完整注意力比例FFN上下文
Jamba v0.12024-0328 层 Mamba4 层 GQA7:1隔层 MoE(16 选 2)256K
Nemotron-H-8B2025-0424 个 Mamba2 块4 个 GQA 块6:124 个稠密 MLP 块8K
Qwen3-Next-80B-A3B2025-0936 层 Gated DeltaNet12 层门控注意力3:1MoE 512 选 10 + 1 共享256K
Kimi Linear 48B-A3B2025-1020 层 KDA7 层 MLA(不用 RoPE)约 3:1MoE 256 选 8 + 1 共享1M
Qwen3.5-397B-A17B2026-0245 层 Gated DeltaNet15 层门控注意力3:1MoE 512 选 10 + 1 共享256K,可扩至约 1M

表里的层数都来自各模型的 config.json:Qwen 系列看 layer_types(每 4 层的最后一层是 full_attention),Kimi Linear 看 linear_attn_config 里的 full_attn_layers [4, 8, 12, 16, 20, 24, 27] 和 kda_layers,Jamba 看 attn_layer_period 8 和 attn_layer_offset 4,Nemotron-H 看 hybrid_override_pattern。最后这个字段要小心读:Nemotron-H 把混合层和 FFN 拆成了独立的块,M 是 Mamba2、* 是注意力、- 是 MLP、E 是 MoE,52 个字符是 52 个块,不是 52 层“注意力 + FFN”。NVIDIA 后来的 Nemotron-3-Nano-30B-A3B 用同样的格式,52 个块是 23 个 Mamba2、6 个注意力和 23 个 MoE。

可以看出两个阵营。2024 年到 2025 年初的 Jamba、Nemotron-H 用 Mamba 系列,注意力占比很低(1/8 到 1/7);2025 年下半年以后的 Qwen3-Next、Kimi Linear、Qwen3.5 换成 delta 规则的线性注意力,注意力占比提高到 1/4。Qwen 的注意力层还带一个输出门(源码里 q_proj 输出维度是 2 倍,一半用作 sigmoid(gate) 乘到注意力输出上,对应 config 里的 attn_output_gate)。Kimi Linear 的 MLA 层干脆不用位置编码,位置信息交给 KDA 层;它的论文报告在相同训练配方下全面超过全 MLA 的基线,KV Cache 最多减少 75%,1M 上下文时解码吞吐最多 6 倍。这些都是各团队在自己的评测上得出的结论,独立复现还不多。

混合也有失效的地方。全文检索能力集中在少数几层注意力上,注意力层越少,这几层越容易成为瓶颈;Nemotron-H-8B 只训练到 8K 上下文,层比例在更长上下文上是否够用要看后续版本的验证。判断方法和上一节一样:用电话簿式测试和自己的长文档问答,比较同一模型在不同长度上的准确率曲线。

推理显存:缓存从随长度增长变成大部分固定 ​

混合架构对推理最直接的影响在缓存上。每个请求要存两样东西:注意力层的 KV Cache,随长度增长;线性层的固定状态(加上短卷积的几个 token 缓存),与长度无关。以 Qwen3.5-35B-A3B 为例(40 层:30 层 Gated DeltaNet、10 层注意力,注意力 2 个 KV 头 × 256 维):

text
注意力 KV:2 × 10 层 × 2 头 × 256 × 2 字节 = 20 KiB / token
  128K:20 KiB × 131072 = 2.5 GiB
线性层状态:每层 32 个 V 头 × 128 × 128 × 4 字节(FP32)= 2 MiB
  30 层 × (2 MiB + 卷积缓存 64 KiB) ≈ 62 MiB,不管上下文多长
合计 128K ≈ 2.56 GiB;对比 Llama-3.1-8B 的 16 GiB

线性层状态按 FP32 计,是因为 Qwen3.5 的 config 里 mamba_ssm_dtype 为 float32,累加很多步的状态对精度更敏感;用 BF16 存时减半,各推理引擎的默认设置可能不同。

128K 上下文、单个请求:Llama-3.1-8B 的 KV Cache 16 GiB,几个混合模型降到 1 到 3 GiB,固定状态只占几十到一百多 MiB

模型(单请求)KV / token固定状态8K128K256K
Llama-3.1-8B128 KiB01.00 GiB16.00 GiB32.00 GiB
Qwen3.5-35B-A3B20 KiB61.9 MiB0.22 GiB2.56 GiB5.06 GiB
Qwen3.5-397B-A17B30 KiB184.2 MiB0.41 GiB3.93 GiB7.68 GiB
Qwen3-Next-80B-A3B24 KiB74.2 MiB0.26 GiB3.07 GiB6.07 GiB
Kimi Linear 48B-A3B7.88 KiB41.9 MiB0.10 GiB1.03 GiB2.01 GiB
Jamba v0.116 KiB15.8 MiB0.14 GiB2.02 GiB4.02 GiB
Nemotron-Nano-9B-v216 KiB137.5 MiB0.26 GiB2.13 GiB4.13 GiB

都是按 config 推出的估算(注意力 KV 按 BF16,Kimi Linear 的 MLA 每层每 token 存 512 + 64 维潜向量)。Jamba 一行在 256K 时是 4 GiB,和 Jamba 论文给出的 4GB 一致,论文同表里 Mixtral 是 32GB、Llama-2-7B(每 token 512 KiB 的 MHA)是 128GB。Nemotron-H-8B 本身只支持 8K,这里换成支持 128K 的 Nemotron-Nano-9B-v2,同样 4 层注意力。

有三点要放在一起看。第一,这只是缓存,权重另算:Qwen3.5-35B-A3B 的权重按 BF16 约 70 GB,比 Llama-3.1-8B 大得多,显存总账见推理系列的 显存账本。第二,短上下文时优势不明显,8K 时几种模型的缓存都在 1 GiB 以内,固定状态甚至可能比少量 token 的 KV 还大;混合架构的收益主要在长上下文和高并发上。第三,固定状态给推理引擎带来了新麻烦。KV Cache 可以按 token 截断、按块共享,前缀缓存 和 PagedAttention 都依赖这一点;而线性层的状态是“读到第 N 个 token 为止的全部历史”揉在一起的结果,没法从中间切开。要复用一段公共前缀,就得在前缀末尾把状态整个保存下来;投机解码猜错要回退时,也得保留回退点的状态快照。引擎要为这两种缓存分别管理,这是混合模型在部署上的额外复杂度。

线性注意力把 softmax 去掉后,历史就能压成一个固定大小的矩阵,Decode 每一步的计算和存储都不再随上下文增长;代价是容量有限,新内容会干扰旧内容。门控让模型主动遗忘,delta 规则让写入只改差值,Mamba-2、门控 DeltaNet、KDA 都是在管理这份有限的记忆。纯线性模型在关联召回和复制上明显不如注意力(格式跟随上也有个案观察),所以实际模型都保留了 1/8 到 1/4 的完整注意力层,单个 128K 请求的缓存从 16 GiB 降到 1 到 4 GiB。到这里,第二部分讲完了主流架构的几条演进线:MoE 改 FFN,MLA 和稀疏注意力改注意力,线性层和混合架构改“怎样记住历史”。第三部分开始逐个拆解主流模型,先从 Llama 家族 开始,看这些设计在一个具体家族里是怎样一代代加进去的。

别急,先让缓存热一下。