从 Full Attention 到 Gated DeltaNet:Qwen3.5 线性注意力

从 Full Attention 到 Gated DeltaNet:Qwen3.5 线性注意力

TL;DR

Qwen3.5 最值得关注的架构变化之一,是使用 Gated DeltaNet(GDN)替代大部分传统 Softmax Attention,并采用 Gated DeltaNet 与 Full Attention 的混合结构。其核心思想是 Attention 解释成一种 key-value associative memory,再通过 recurrent state 对历史信息进行压缩;在此基础上,Delta Rule 负责对 memory 进行有针对性的纠错,而 gating 则负责控制旧信息的遗忘速度。

本文从标准 Full Attention 出发,逐步推导 Linear Attention、recurrent state、Delta Rule 和 Gated DeltaNet,并进一步讨论 Qwen3.5 中的实际计算过程、memory capacity、interference,以及这种架构相对于传统 Attention 的优势与局限。

1. Full Attention 的痛点:二次增长

我们先从最熟悉的 Transformer Self-Attention 开始,对于输入序列:

X=(x1,x2,,xT)X=(x_1,x_2,\ldots,x_T)

在计算注意力时,我们首先要让 X 通过三个 projection 计算得到 qt,kt,vtq_t, k_t, v_t

qt=Wqxt,kt=Wkxt,vt=Wvxtq_t=W_qx_t,\qquad k_t=W_kx_t,\qquad v_t=W_vx_t

根据 causal self-attention,第 tt 个 token 的输出为:

yt=i=1tat,iviy_t = \sum_{i=1}^{t} a_{t,i}v_i

其中:

at,i=exp(qtki/dk)j=1texp(qtkj/dk)a_{t,i} = \frac{ \exp(q_t^\top k_i/\sqrt{d_k}) }{ \sum_{j=1}^{t} \exp(q_t^\top k_j/\sqrt{d_k}) }

即:

yt=softmax(qtKtdk)Vt\boxed{ y_t = \operatorname{softmax} \left( \frac{q_tK_{\le t}^{\top}}{\sqrt{d_k}} \right) V_{\le t} }

这里最关键也是最耗费算力的是:QKQK^\top 需要计算一个:T×TT\times T 的 matrix。这就意味着,随着序列长度 TT 增长,Attention 的核心计算和存储都会二次复杂度地增长。

另外值得一提的是,在自回归 decoding 时,模型为了让未来 token 能访问过去信息,需要保存历史:$ K_1,\ldots,K_t $ 和:$ V_1,\ldots,V_t $,这便是 KV Cache。

2. Linear Attention:改变计算顺序降低复杂度

为了更好地改进 Attention 的计算,我们需要从另一个侧面来理解 attention:我们可以将 Attention 看作一种 key-value associative memory。其实,这也是 attention 最开始被用于语言翻译时的观察。

假设一个翻译家需要要将一段文字从中文翻译为英文,那么他/她在翻译不同词语时必定会先提取出上下文中对文本意义有决定性作用的某些词,再根据这些关键词的内容来思考如何写下下一个词,从而确保给出的翻译内容准确。

attention 计算中的三个张量计算正是在模拟人类翻译时的工作方式:对于每次计算, keys 来保存上下文中的“地址”信息,values 保存上下文中“内容”, 那么 queries 则需要根据上下文内容中“地址信息” key ,计算出加权的语义相关度,然后获取 values 中的内容,与之做运算,得到下一个词。而 softmax 激活函数则提供了对 associative memory 的可学习非线性映射手段。

所以,Attention 中 QKTQK^T 计算实际上是为了获得语义相关度的一种手段,那么,是否可以更省算力地获得这个语义相关度呢?

回到之前的例子,请特别注意到这个观察:KV Cache 中的 keys 保存了上下文中的“地址”信息,values 保存了上下文中“内容”,这些其实都是静态的已经固定下来的信息,我们可以大胆地提前“处理”这些固定信息,得到一个 KV 相关的压缩 memory,然后在 query 到来时,直接用 memory 与 query 计算即可。

这个思路并非空穴来风,事实上它获得了数学上的支持,假设

QRT×D,KRT×D,VRT×D,Q\in \mathbb{R}^{T \times D}, K\in \mathbb{R}^{T \times D}, V\in \mathbb{R}^{T \times D},

  • Full Attention 下先计算 QKTQK^T,再计算 (QKT)V(QK^T)V,那么计算量为:O(T2D)O(T^2D)
  • 先计算 KTVK^TV,再计算 Q(KTV)Q(K^TV),二者在数学上等价(不考虑softmax),但计算量却为:O(D2T)O(D^2T)

考虑到长文本场景中,T>>D,因此改变计算顺序可以非常有效地降低计算量,从二次复杂度变为一次。而这里的 KTVK^TV 可以理解成提前计算出来的固定信息, Q(KTV)Q(K^TV) 表示到来的 query 直接处理这些提前计算好的 memory ,从而降低计算量。

3. 引出 Recurrent State

所以,我们得到了 Linear Attention 的优化出发点:

能不能把 query 和 key 的 计算分解开,通过改变矩阵乘法的顺序的方法降低计算复杂度?

简单起见,我们先暂时忽略 Softmax,只看:

yt=i=1t(qtki)viy_t = \sum_{i=1}^{t} (q_t^\top k_i)v_i

注意:qtkiq_t^\top k_i 是一个标量,因此:

(qtki)vi=qt(kivi)(q_t^\top k_i)v_i = q_t^\top(k_iv_i^\top)

于是:

yt=i=1tqt(kivi)y_t = \sum_{i=1}^{t} q_t^\top(k_iv_i^\top)

由于 qtq_t 与历史索引 ii 无关,可以把它提到求和外:

yt=qti=1tkiviy_t = q_t^\top \sum_{i=1}^{t} k_iv_i^\top

定义:

St=i=1tkivi\boxed{ S_t= \sum_{i=1}^{t} k_iv_i^\top }

那么:

yt=qtSt\boxed{ y_t=q_t^\top S_t }

这就是 Linear Attention 最核心的一步。

实际上,上面公式中的 StS_t 就是我们之前说明的 KTVK^TV ,即提前计算出来的固定 memory,我们这里给它一个正式的名称:Recurrent State(循环状态)。

为什么叫 Recurrent State 呢?

因为

St=i=1tkiviS_t = \sum_{i=1}^{t}k_iv_i^\top

可以把最后一个 token 计算单独拿出来:

St=i=1t1kivi+ktvt=St=St1+ktvtS_t = \sum_{i=1}^{t-1}k_iv_i^\top + k_tv_t^\top = \boxed{ S_t=S_{t-1}+k_tv_t^\top }

于是我们发现,这个 StS_t 是一个步骤由前一步决定的马尔科夫链状态,故而称为 Recurrent State。这个公式还意味着,它无需每次都重新遍历整个 KV 上下文历史,只需要将前一个状态结果缓存下来,就可以很容易获得下一步的 Recurrent State


4. 如何处理 softmax?换个可线性运算的激活函数

上面的推到我们故意忽略了 softmax,直接默认计算 qkq^\top k,但标准 Attention 使用的是 softmax=exp(qk)jexp(qk)softmax=\frac{\exp(q^\top k)}{\sum_j{\exp(q^\top k)}}。一旦加上 softmax 后,计算顺序就不满足结合律,我们之前所有的努力都会前功尽弃!

因此,我们需要考虑一个更好的激活函数 KK,即可以满足结合律,又能实现 QK 分解的运算,它满足:

K(q,k)=ϕ(q)ϕ(k)K(q, k) = \phi(q)^\top\phi(k)

其中 ϕ\phi 表示激活函数分解后的算子,于是:

yt=i=1tϕ(qt)ϕ(ki)viy_t = \sum_{i=1}^{t} \phi(q_t)^\top \phi(k_i)v_i

同样地,我们可以改变计算顺序:

yt=ϕ(qt)(i=1tϕ(ki)vi)y_t = \phi(q_t)^\top \left( \sum_{i=1}^{t} \phi(k_i)v_i^\top \right)

于是,我们需要重新定义 Recurrent State:

St=i=1tϕ(ki)vi=St1+ϕ(kt)vt\boxed{ S_t= \sum_{i=1}^{t} \phi(k_i)v_i^\top = S_{t-1} +\phi(k_t)v_t^\top }

5. 线性 Attention 的本质理解

目前看起来一切顺利,我们改造了 Full Attention 的计算顺序,使用 Recurrent State + 线性激活函数来替换之前 Full Attention,并在每个新 token 时通过下面手段更新 memory:

St=St1+ϕ(kt)vtyt=ϕ(qt)StS_t=S_{t-1}+\phi(k_t)v_t^\top \\ y_t = \phi(q_t)^\top S_t

上面的公式可以“通俗易懂”地解释为:

线性 Attention 通过维护一个 KV-associative memory,压缩了 Full Attention 中复杂庞大的 KV 张量,从而加速 Attention 机制的计算,方法是:每新来一个 token,就把它的 kv 信息固定到 Recurrent State 的 memory 中,然后执行 Recurrent State 与 query 的计算,得到下一个 token

现在我们重新审视一下 Recurrent State 的计算公式:

St=i=1tϕ(ki)viS_t= \sum_{i=1}^{t} \phi(k_i)v_i^\top

注意到,这个公式与线性联想记忆(LAM)模型非常像:

线性联想记忆(LAM)模型

LAM 是一种单层前馈神经网络,权重矩阵来存储输入向量与输出向量之间的线性关联。其核心思想最早由 James A. Anderson 和 Teuvo Kohonen 在 1972 年提出
其工作原理可以概括为“外积存储,矩阵检索”:

  1. 存储(写入):对于每个键值对 (ki,vi)(k_i, v_i),计算它们的外积 vikiv_i k_i^\top,并将所有外积累加,形成记忆矩阵 MM

M:=ivikiM := \sum_i v_i k_i^\top

这种更新方式源于 Hebbian 学习规则,即“一起激发的神经元,连接在一起”。每个外积 vikiv_i k_i^\top 都是一个秩为 1 的矩阵,累加后矩阵的等于存储的键值对数量。

  1. 检索(读取):当需要根据一个查询键 kjk_j 提取对应的值时,只需计算 MMkjk_j 的乘积:

Mkj=(iviki)kj=ivi(kikj)M k_j = \left(\sum_i v_i k_i^\top\right) k_j = \sum_i v_i (k_i^\top k_j)

如果所有的键 kik_i 都是正交归一化的(即 kikj=0k_i^\top k_j = 0iji \neq j,且 kiki=1k_i^\top k_i = 1),那么上式将精确地返回 vjv_j,实现完美检索

对于非正交的键,检索会产生误差,此时可以通过最小二乘法来寻找最优的存储矩阵 WW,即最小化误差 iviWki2\sum_i \|v_i - W k_i\|^2

Recurrent State 的计算公式为:

St=i=1tϕ(ki)viS_t = \sum_{i=1}^{t}\phi(k_i)v_i^\top

这个公式与 LAM 的存储公式 M:=ivikiM := \sum_i v_i k_i^\top 完全一致。状态矩阵 StS_t 就是不断累加外积 vtktv_t k_t^\top 得到的记忆矩阵(为简单起见,我们之后的书写会略掉ϕ()\phi()函数,但实际计算时还是需要考虑的)。

在推理时,模型用查询 qtq_t 与状态 StS_t 相乘得到输出:

yt=qtSty_t =q_t S_t

这又与 LAM 的检索过程 MkjM k_j 完全一致。

那么我们换一个角度,将 SS 看成一个 associative memory,其中存储了若干
S:kv \boxed{ S:k\rightarrow v }
的键值对,给定一个 key:kk,memory 应该输出:SkSk

因此,如果当前希望 memory 记住:

kvk\rightarrow v

理想状态自然应该满足:

Sk=v\boxed{ Sk=v }

这就是把矩阵 SS 当作一个线性 key-value memory 后,对“正确记忆”的数学表达。

6. Recurrent State 更新与优化

从上一小节中,我们注意到线性 Attention 中的 Recurrent State 更新方式与 LAM 模型一致。我们不妨就把它当作是一个模型,若当前 memory 为 St1S_{t-1},则它对 ktk_t 的预测是:

v^=St1kt\hat v=S_{t-1}k_t

但 memory 的优化目标是:vtv_t,因此 memory 的误差为:

e=vtSt1kt\boxed{ e=v_t-S_{t-1}k_t }

我们可以通过最小二乘法的方式来定义损失函数:

L(S)=12St1ktvt2L(S) = \frac12 ||S_{t-1}k_t-v_t||^2

那么我们真正的问题变成:如何修改 SS,使 SkSk 更接近 vv?这就是一个普通的优化问题。

对 Memory 做一次梯度下降

L(S)=12St1ktvt2L(S) = \frac12 ||S_{t-1}k_t-v_t||^2

关于 SS 的梯度:

SL=(St1ktvt)kt\nabla_SL= (S_{t-1}k_t-v_t)k_t^\top

做一步梯度下降,步长 βt\beta_t

St=St1βtSLS_t= S_{t-1} -\beta_t\nabla_SL

代入得到:

St=St1+βt(vtSt1kt)kt\boxed{ S_t= S_{t-1} + \beta_t (v_t-S_{t-1}k_t) k_t^\top }

这就是 Delta Rule。

因此 Delta Rule 的“Delta”非常字面:

ΔSt=StSt1\boxed{ \Delta S_t= S_t-S_{t-1} }

而:

ΔSt=βt(vtSt1kt)kt\boxed{ \Delta S_t= \beta_t (v_t-S_{t-1}k_t)k_t^\top }

即根据当前预测误差,需要计算 memory 应该改变多少。

7. 为什么突然这么复杂?

我们原先的 Recurrent State 更新公式非常通俗易懂,

St=St1+ktvtS_t=S_{t-1}+k_tv_t^\top

但引入了 LAM 和梯度下降更新之后,一切变得复杂起来了:

St=St1+βt(vtSt1kt)kt S_t= S_{t-1} + \beta_t (v_t-S_{t-1}k_t) k_t^\top

或许各位读者希望知道原因。

从感性上认知看,St=St1+ktvt S_t=S_{t-1}+k_tv_t^\top 意味着每次新来的 token 信息会被保存到 memory 中,但它没解决记忆的修正写入问题,而这其实是必须的:因为在自然语言中,上文的语义记忆并非一成不变,会因不同的下文的词到来发生改变。

举例而言:

  • “我妈妈给我买了一个苹果,我很喜欢它,因为它很好吃。”
  • “我妈妈给我买了一个苹果,我很喜欢它,因为它拍照很出片。”

显然,“苹果”一词的词义在这句话的最后发生了转变,一个指向了水果,一个指向了苹果手机。如果解决不了记忆的修正写入,仅仅新加入 token 信息是不足的。

那为何这个公式可以起作用呢?回到复杂的数学公式上来:

St=St1+βt(vtSt1kt)ktS_t= S_{t-1} + \beta_t (v_t-S_{t-1}k_t)k_t^\top

令:

et=vtSt1kte_t=v_t-S_{t-1}k_t

则:

St=St1+βtetktS_t=S_{t-1}+\beta_te_tk_t^\top

现在重新用同一个 key 查询:

StktS_tk_t

得到:

Stkt=St1kt+βtetktktS_tk_t= S_{t-1}k_t + \beta_te_tk_t^\top k_t

所以:

Stkt=St1kt+βtkt2etS_tk_t = S_{t-1}k_t + \beta_t|k_t|^2e_t

又因为:

et=vtSt1kte_t=v_t-S_{t-1}k_t

所以:

Stkt=(1βtkt2)St1kt+βtkt2vt\boxed{ S_tk_t= (1-\beta_t|k_t|^2)S_{t-1}k_t + \beta_t|k_t|^2v_t }

也就是说:更新后的 memory output,是旧 prediction St1ktS_{t-1}k_t 与新 target vtv_t 之间的插值。如果 βtkt2=1\beta_t|k_t|^2=1,那么 $ S_tk_t=v_t $ 一次 update 就把这个 key 的 memory 修正到目标值。

于是 Delta Rule 至此拥有了真正更新与修正的能力。

这里的 Delta update 公式:

ΔS=β(vSk)errorkaddress\Delta S= \beta \underbrace{(v-Sk)}_{\text{error}} \underbrace{k^\top}_{\text{address}}

可以这样理解:

kT=修改 memory 的方向\boxed{k^T=\text{修改 memory 的方向}}

而:

β(vSk)=应该修改多少、往哪里修改\boxed{\beta(v-Sk)=\text{应该修改多少、往哪里修改}}

因此:

  • kk:告诉 memory 在哪里改;
  • vSkv-Sk:告诉 memory 改成什么样;
  • β\beta:告诉 memory 改多少。

这比简单的 kvkv^\top 更聪明。因为普通 Linear Attention 是“新知识来了,直接写进去”。而 Delta Rule 是“先读取 memory,看看我已经知道多少;然后只写入缺少的部分。”这也是理解 GDN 的核心。

8. Linear Attention 新挑战与遗忘机制

但可纠正与更新的 state 并不是终点。从感性上看,一旦我们选择用一个有限且固定大小的 Recurrent state ($ S_t\in\mathbb R^{d_v\times d_k} $)表示记录上下文的 memory 时,我们就必须想办法主动丢弃些不重要的上下文信息,因为我们无法用有限的状态张量记录几乎无限的上下文信息。

从数学上看,目前有:

St=St1+βt(vtSt1kt)ktS_t= S_{t-1} + \beta_t (v_t-S_{t-1}k_t)k_t^\top

虽然它可以修改特定方向,但是如果过去的信息对应不同的 key 方向,那么过去的信息可能长期残留。

考虑:

k1k20k_1^\top k_2\approx0

那么针对 k2k_2 的更新:

ΔS2e2k2=(v1S0k1)k2\Delta S_2 \propto e_2k_2^\top=(v_1-S_{0}k_1)k_2^\top

主要修改 k2k_2 对应的方向。但它不会自动清除:

k1v1k_1\rightarrow v_1

因此随着:$ T\rightarrow\infty $,历史信息不断写入固定大小的 SS。这就产生了一个基本悖论,无限历史可以被写入有限的空间中。

而自然语言中的信息天然存在不同时间尺度:

  • 某个局部变量名可能只需要几十个 token;
  • 当前讨论主题可能需要几千个 token;
  • 一个关键事实可能希望长期保留。

对此,我们可以使用一个遗忘系数来主动地过去久远且不重要的知识遗忘掉,记住最关键的和最近不久读过的信息。

αt(0,1)\alpha_t\in(0,1),有:

St=αtSt1+βt(vtSt1kt)ktS_t= \alpha_tS_{t-1} + \beta_t (v_t-S_{t-1}k_t)k_t^\top

于是 αtSt1\alpha_tS_{t-1} 会衰减旧 memory 而 $ \beta_t(v_t-S_{t-1}k_t)k_t^\top $ 负责针对当前 key 做纠正

9. α\alpha 的含义

如果暂时没有新信息:

St=αSt1S_t=\alpha S_{t-1}

那么:

St=αnStnS_t= \alpha^nS_{t-n}

所以历史信息的会按照 α\alpha 的数值指数衰减,越往前信息就越不重要,被逐渐遗忘。

那么这个 α\alpha 值如何被选定?在实际 Qwen3.5 GDN 中,αt\alpha_t 不是简单的一个固定标量参数。它由模型根据当前 hidden state 动态产生。

模型 Qwen3.5 的实现中有独立的 WaW_a projection 和参数化的 decay:

at=Waxta_t=W_ax_t

然后通过公式计算的得到原始门控值 gtg_t

gt=exp(Alog)softplus(at+dt_bias)g_t = -\exp(A_{\log}) \odot \text{softplus}(a_t + \text{dt\_bias})

其中:

  • AlogA_{\log}:一个可学习的参数向量(通常初始化为对数均匀分布),控制每个通道的基础衰减速率,决定了每个通道的“基础遗忘速度
  • dt_bias\text{dt\_bias}:一个可学习的偏置项,通常按 key 通道存储。两者共同作用,使模型能够对不同通道、不同时间步的衰减速率进行细粒度控制
  • \odot:逐元素乘法
  • softplus()\text{softplus}(\cdot):激活函数,softplus(x)=log(1+ex)\text{softplus}(x) = \log(1 + e^x),确保输出为正。它的作用是确保输入到指数函数中的值 at+dt_biasa_t + \text{dt\_bias} 经过缩放后,最终能让 gtg_t 保持在一个合理的数值范围内,避免梯度消失或爆炸
  • ata_t 的动态性:ata_t 是当前输入 xtx_t 的函数,这意味着 αt\alpha_t 是数据依赖的。模型可以根据当前 token 的内容,决定是快速清除旧记忆(αt0\alpha_t \to 0)还是保留更多历史信息(αt1\alpha_t \to 1

10. Qwen3.5 GDN 的实际计算流程

到此为止,我们已经讲完了整个 Recurrent State 循环更新的过程,

St=αtSt1+βt(vtSt1kt)kt\boxed{ S_t= \alpha_tS_{t-1} + \beta_t (v_t-S_{t-1}k_t)k_t^\top }

现在我们跳出细节,看一下整体模型在线性 Attention 环节要做哪些计算,我们先用数学把实际模型对应起来。对于输入:xtx_t,Qwen3.5 的 GDN 首先通过 projection 得到 Q/K/V 相关表示,可以概括为:

xtLinearCausalConv1DSiLU(qt,kt,vt)x_t \rightarrow \operatorname{Linear} \rightarrow \operatorname{CausalConv1D} \rightarrow \operatorname{SiLU} \rightarrow (q_t,k_t,v_t)

同时产生:

βt=σ(bt)\beta_t=\sigma(b_t)

以及 decay 相关的:

gtg_t

然后进入 gated delta recurrence。Qwen3.5 的实际实现继承自 Qwen3-Next 风格的 Gated DeltaNet,并使用 causal convolution、recurrent/chunkwise GDN kernel 等组件。

把不影响核心思想的工程细节暂时省略,可以写成:

qt,kt,vt=fqkv(xt)q_t,k_t,v_t= f_{\text{qkv}}(x_t)

βt=σ(Wbxt)\beta_t= \sigma(W_bx_t)

gt=exp(Alog)softplus(Waxt+ba)g_t= -\exp(A_{\log})\odot \operatorname{softplus}(W_ax_t+b_a)

然后:

αt=egt\alpha_t=e^{g_t}

Recurrent State 更新:

St=αtSt1+βt(vtSt1kt)ktS_t= \alpha_tS_{t-1} + \beta_t (v_t-S_{t-1}k_t)k_t^\top

输出:

yt=Stqty_t=S_t^\top q_t

随后经过 gated RMSNorm 和 output projection。

11. Qwen3.5 为什么还需要 Full Attention?

这是理解 Qwen3.5 架构和 GDN 自身的关键一步。如果 GDN 已经这么高效,为什么不全部使用 GDN?因为 GDN 毕竟依靠的是一个固定大小的 memory 记录信息,内部还有遗忘衰减机制,而 Full Attention 保留:(k1,v1),,(kT,vT)(k_1,v_1),\ldots,(k_T,v_T) 的所有信息,因此若全部使用 GDN,对模型的训练收敛和知识遗忘就难以控制,选择 3:1 的线性 Attention 和 Full Attention 架构应该是一个模型性能、能力与训练成本之间的折中之选。

12. GDN 优缺点

优点:

  • 长序列计算复杂度更低 GDN:O(T)O(T),关于 sequence length 呈线性增长
  • Decode 时 recurrent state 大小固定,StO(dkdv)S_t\sim O(d_kd_v),因此长上下文 decode 时,GDN 不需要随着历史长度无限增长的 KV cache
  • 马尔科夫状态天然适合流式推理。因为:St=f(St1,xt) S_t=f(S_{t-1},x_t) 所以理论上只需要:St1S_{t-1} 和当前 token,这非常适合 streaming。

缺点:

  • 信息瓶颈与遗忘:固定大小的状态是一个信息瓶颈。对于需要精确回忆大量细节的任务,线性压缩可能导致信息丢失,出现“遗忘”。
  • 稳定性约束:Delta更新规则的稳定性依赖于步长,与键向量范数的乘积保持在一个范围内,这可能对训练超参数敏感。

13.小结

GDN 可以看成一个固定容量、可遗忘、可纠错的在线 Key-Value Memory:每个 token 先用 key 从 memory 中读取已有答案,再根据 target 与 prediction 的差值修改 memory,同时通过动态 decay 决定旧信息还能保留多久。

数学上:

Stmemory=αtSt1forget+βt(vtSt1kt)ktdelta correction\boxed{ \underbrace{S_t}_{\text{memory}}= \underbrace{\alpha_tS_{t-1}}_{\text{forget}} + \underbrace{ \beta_t (v_t-S_{t-1}k_t)k_t^\top }_{\text{delta correction}} }

查询:

yt=Stqt\boxed{ y_t=S_t^\top q_t }

这两个公式基本就是理解 GDN 的核心。

参考资料

  1. Yang, S., Kautz, J., Hatamizadeh, A. Gated Delta Networks: Improving Mamba2 with Delta Rule, ICLR 2025。
  2. Qwen3.5 Hugging Face Transformers model documentation:3:1 Gated DeltaNet / Gated Attention hybrid architecture。
  3. Hugging Face Qwen3.5 implementation:“Qwen3_5GatedDeltaNet” 及 recurrent/chunk GDN kernel 接口。
  4. NVIDIA Gated DeltaNet official implementation。

从 Full Attention 到 Gated DeltaNet:Qwen3.5 线性注意力
https://dingfen.github.io/2026/09/19/2026-9-19-gdn/
作者
Bill Ding
发布于
2026年9月19日
更新于
2026年9月20日
许可协议