Skip to content

7.6 Qwen3.5:线性注意力混合体

前面几节已经分别展示了纯全局注意力架构(Llama、Qwen3)和滑动窗口混合架构(Gemma 3)。它们的共同点是:不论局部还是全局,注意力矩阵的计算始终遵循 Softmax 范式,复杂度对序列长度保持 O(n2)(或受窗口大小限制的 O(nW))。2025 年中发布的 Qwen3.5 则走出了一条截然不同的路线——在同一个模型中混合使用线性注意力(DeltaNet)和全局 Softmax 注意力,以 3:1 的比例交替堆叠。这一设计使得仅 0.8B 参数的模型便能在推理效率与生成质量之间取得令人瞩目的平衡,也标志着"线性+全局"混合注意力正式从研究论文走向量产模型。

本节将以 Qwen3.5-0.8B 为对象,剖析其混合架构的设计哲学,逐一拆解线性注意力层与全局注意力层的实现差异,最后讨论这一架构趋势的更广泛意义。

Qwen3.5 混合注意力架构

图 7-21:Qwen3.5-0.8B 的混合注意力架构。24 层中 18 层使用 DeltaNet 线性注意力、6 层使用全局 Softmax 注意力,按 3:1 比例交替排列。

7.6.1 架构总览:0.8B 参数的混合布局

Qwen3.5-0.8B 的完整配置如下:

超参数说明
vocab_size248,320词表大小
context_length262,144最大上下文长度(256K)
emb_dim1,024嵌入维度
n_layers24Transformer 层数
n_heads8全局注意力层的查询头数
n_kv_groups2全局注意力层的 KV 组数
head_dim256全局注意力层的每头维度
hidden_dim3,584FFN 中间维度
rope_base10,000,000RoPE 基频(107
partial_rotary_factor0.25RoPE 部分旋转因子
linear_num_value_heads16线性注意力层的 Value 头数
linear_num_key_heads16线性注意力层的 Key 头数
linear_key_head_dim128线性注意力层的 Key 头维度
linear_value_head_dim128线性注意力层的 Value 头维度
linear_conv_kernel_dim4线性注意力层的因果卷积核大小

24 层 Transformer 按以下固定模式排列:

层  0: linear_attention          层 12: linear_attention
层  1: linear_attention          层 13: linear_attention
层  2: linear_attention          层 14: linear_attention
层  3: full_attention    ←       层 15: full_attention    ←
层  4: linear_attention          层 16: linear_attention
层  5: linear_attention          层 17: linear_attention
层  6: linear_attention          层 18: linear_attention
层  7: full_attention    ←       层 19: full_attention    ←
层  8: linear_attention          层 20: linear_attention
层  9: linear_attention          层 21: linear_attention
层 10: linear_attention          层 22: linear_attention
层 11: full_attention    ←       层 23: full_attention    ←

24 层中有 18 层线性注意力、6 层全局注意力,比例为 3:1——每 4 层为一个周期,前 3 层使用 DeltaNet 线性注意力,第 4 层使用标准 Softmax 全局注意力。

几个关键设计选择值得注意:

独立的 head_dim 与部分旋转。 全局注意力层的 head_dim=256 远大于 emb_dim / n_heads = 128,但 RoPE 仅作用于其中 25%(partial_rotary_factor=0.25),即 64 个维度参与旋转,其余 192 个维度直接通过。这种"部分旋转"策略与 Gemma 3 的做法异曲同工:大 head_dim 赋予每个头更强的表达能力,而部分旋转避免了对所有维度施加位置编码的约束。

线性注意力层使用不同的头配置。 线性注意力层有 16 个 Key/Value 头、每头维度 128,与全局注意力层的 8 个查询头、head_dim=256 完全不同。这种异构设计是因为两类注意力机制对参数的使用方式截然不同:全局注意力依赖大维度 Q/K 内积来精确匹配远程 token,线性注意力则通过状态矩阵的递推更新来压缩历史信息——更多但更小的头有利于状态矩阵维护多条独立的"记忆通道"。

Weight Tying。 输入嵌入层与输出投影层共享权重。模型总参数约 10.1 亿,其中嵌入矩阵占 248,320×1,0242.54 亿,使用 Weight Tying 后唯一参数量降至约 7.5 亿。

7.6.2 两种注意力层的实现

Qwen3.5 的核心创新在于让两种计算范式——Softmax 注意力和线性注意力——共存于同一个模型中。两者共享相同的 RMSNorm、SwiGLU FFN 和残差连接结构,仅在"token mixing"模块上有本质区别。

全局注意力层:门控查询投影。 Qwen3.5 的全局注意力层在标准 GQA 的基础上增加了一个门控机制——Query 投影的输出维度是标准值的 2 倍,一半作为 Query,另一半作为门控信号:

python
class GroupedQueryAttention(nn.Module):
    def __init__(self, d_in, num_heads, num_kv_groups, head_dim):
        super().__init__()
        self.d_out = num_heads * head_dim
        # Query 投影输出 2 倍维度:一半 Query,一半 Gate
        self.W_query = nn.Linear(d_in, self.d_out * 2, bias=False)
        self.W_key = nn.Linear(d_in, num_kv_groups * head_dim, bias=False)
        self.W_value = nn.Linear(d_in, num_kv_groups * head_dim, bias=False)
        self.out_proj = nn.Linear(self.d_out, d_in, bias=False)

    def forward(self, x, mask, cos, sin):
        b, num_tokens, _ = x.shape
        # 分离 Query 和 Gate
        q_and_gate = self.W_query(x)
        q_and_gate = q_and_gate.view(b, num_tokens, self.num_heads, self.head_dim * 2)
        queries, gate = torch.chunk(q_and_gate, 2, dim=-1)
        gate = gate.reshape(b, num_tokens, self.d_out)

        # 标准 GQA 流程:QKNorm → RoPE → 注意力计算
        keys = self.W_key(x)
        values = self.W_value(x)
        # ... (QKNorm, RoPE, 注意力矩阵计算) ...

        context = (attn_weights @ values).transpose(1, 2).reshape(b, num_tokens, self.d_out)
        # 门控:Sigmoid(gate) 逐元素缩放注意力输出
        context = context * torch.sigmoid(gate)
        return self.out_proj(context)

门控查询投影的作用是让模型能够逐元素地调节注意力输出的强度。直观理解:Query 的一半负责"从哪里读取信息",另一半负责"读到的信息保留多少"。这种设计在 Mamba-2 和 Griffin 等混合架构中已有先例,核心动机是当全局注意力层数量较少时,每一层需要承担更精细的信息筛选任务——门控机制赋予了这一能力。

线性注意力层:Gated DeltaNet。 线性注意力层采用 Gated DeltaNet(详见 §6.6),其核心递推公式为:

St=αtSt1+kt[βt(vtSt1Tkt)]T,yt=Stqt

其中 StRd×d 是状态矩阵,αt 为衰减门,βt 为更新门。与全局注意力层相比,线性注意力层有三个关键实现差异:

  1. 因果卷积前置。 QKV 投影后、进入递推之前,先通过一个核大小为 4 的深度可分离因果卷积(depthwise causal Conv1d),对局部相邻 token 进行短程混合。这一步的作用类似于 Mamba 中的因果卷积——弥补线性注意力在极短距离依赖上的不足:
python
self.conv1d = nn.Conv1d(
    in_channels=conv_dim,     # key_dim * 2 + value_dim
    out_channels=conv_dim,
    kernel_size=4,            # 仅看前 4 个 token
    groups=conv_dim,          # 深度可分离:每个通道独立卷积
    padding=3,                # 因果填充
    bias=False,
)
  1. L2 归一化替代 QKNorm。 线性注意力层在递推计算前对 Query 和 Key 做 L2 归一化(而非全局注意力层的 RMSNorm)。L2 归一化将向量缩放到单位球面,确保状态矩阵 St 中的外积更新不会因为 Q/K 范数爆炸而导致数值不稳定。

  2. 门控 RMSNorm 输出。 线性注意力层的输出先经过一个门控 RMSNorm:o=RMSNorm(y)SiLU(z),其中 z 是输入 x 经过独立线性投影得到的门控信号。这与全局注意力层的 Sigmoid 门控不同——SiLU 允许负值通过(虽然幅度很小),有助于梯度流动。

TransformerBlock:按层类型分发。 与 Gemma 3 的混合注意力类似,Qwen3.5 通过一个 layer_type 标志在初始化时决定每层使用哪种 token mixing 模块:

python
class TransformerBlock(nn.Module):
    def __init__(self, cfg, layer_type, layer_idx):
        super().__init__()
        self.layer_type = layer_type

        if layer_type == "full_attention":
            self.token_mixer = GroupedQueryAttention(...)
        elif layer_type == "linear_attention":
            self.token_mixer = Qwen3_5GatedDeltaNet(cfg, layer_idx)

        self.ff = FeedForward(cfg)  # SwiGLU,所有层共享
        self.norm1 = RMSNorm(cfg["emb_dim"])
        self.norm2 = RMSNorm(cfg["emb_dim"])

    def forward(self, x, mask, cos, sin):
        shortcut = x
        x = self.norm1(x)
        if self.layer_type == "full_attention":
            x = self.token_mixer(x, mask, cos, sin)
        else:
            x = self.token_mixer(x)  # 线性注意力不需要掩码和 RoPE
        x = x + shortcut
        shortcut = x
        x = self.norm2(x)
        x = self.ff(x)
        x = x + shortcut
        return x

一个重要的实现细节:线性注意力层不接收掩码和 RoPE 参数。这是因为 DeltaNet 的递推天然是因果的——每步只依赖之前的状态,无需显式因果掩码;同时,递推状态的更新方式已隐含了位置信息的编码,不依赖 RoPE。

7.6.3 零偏心 RMSNorm

Qwen3.5 延续了 Gemma 3 引入的零中心参数化 RMSNorm——权重初始化为零向量,前向传播时使用 (1+w) 作为缩放因子:

python
class RMSNorm(nn.Module):
    def __init__(self, emb_dim, eps=1e-6):
        super().__init__()
        self.eps = eps
        self.weight = nn.Parameter(torch.zeros(emb_dim))  # 初始化为 0

    def forward(self, x):
        x_norm = x.float() * torch.rsqrt(
            x.float().pow(2).mean(dim=-1, keepdim=True) + self.eps
        )
        return (x_norm * (1.0 + self.weight.float())).to(x.dtype)

这与 Qwen3 使用的标准 RMSNorm(权重初始化为 1,直接乘以 w)在功能上完全等价(1+0=1),但将训练初期权重锚定在零附近,使得梯度更新的幅度更容易控制。这种参数化在混合架构中尤为重要:线性注意力层和全局注意力层的输出分布可能存在显著差异,零中心 RMSNorm 使两类层在训练初期的行为更加一致,有利于稳定训练。

7.6.4 为什么是线性+全局混合?

线性注意力的状态矩阵递推

图 7-22:线性注意力的状态矩阵递推过程。固定大小的状态矩阵通过门控遗忘和增量更新压缩全部历史信息,实现对序列长度线性的推理复杂度。

Gemma 3 的 5:1 滑动窗口+全局混合已经证明了"不是所有层都需要全局注意力"这一直觉。Qwen3.5 将这一思路推进了一步:不是所有层都需要 Softmax 注意力。两种混合策略的对比如下:

维度Gemma 3(SWA + Full)Qwen3.5(DeltaNet + Full)
局部层机制滑动窗口 SoftmaxDeltaNet 线性递推
局部层复杂度O(nW)O(nd2)(对 n 线性)
局部层 KV 缓存保留最近 W 个 token固定 d×d 状态矩阵
全局层作用跨窗口信息整合精确远程检索
混合比例5:13:1
位置编码双 RoPE 基频全局层使用 RoPE,线性层不使用

两种策略背后有一个共同的认知:大部分 Transformer 层在处理文本时,注意力权重高度集中在局部区域。既然如此,为这些层配备完整的 O(n2) Softmax 注意力是一种浪费。区别在于替代方案的选择:

  • 滑动窗口方案(Gemma 3)保留了 Softmax 的精确匹配能力,但将视野限制在固定窗口内。优势是实现简单(只需修改掩码),劣势是窗口外的信息完全不可见——即使是窗口边界附近的强依赖也会被截断。

  • 线性注意力方案(Qwen3.5)用状态矩阵取代显式的 token-to-token 注意力矩阵。优势是理论上能通过递推将任意远的信息压缩进状态中,没有硬性的窗口截断;劣势是状态矩阵容量有限(d×d),对远程精确检索的能力弱于 Softmax——当需要精确回忆某个特定 token 的内容时,DeltaNet 的表现不如全局注意力。

这正是混合架构的设计逻辑:线性注意力层负责高效处理局部模式和渐进式的上下文压缩,全局注意力层负责需要精确匹配的远程信息检索。两类层各司其职、优势互补。

7.6.5 效率分析

计算复杂度。 在 Qwen3.5-0.8B 的 24 层中,18 层线性注意力的复杂度为 O(nd2)d=128,状态矩阵更新的代价),6 层全局注意力的复杂度为 O(n2dh)dh=256)。当 n=262,144(256K)时,线性层的计算量远低于全局层。混合架构的总计算量约为:

C混合=18×O(nd2)+6×O(n2dh)

相比 24 层全部使用全局注意力的 24×O(n2dh),全局注意力的计算量降低至 6/24=25%。在超长序列场景下,O(n2) 部分占总计算量的比重随 n 增长而增大,但由于仅有 6 层承担这一开销,瓶颈被大幅缓解。

KV 缓存。 全局注意力层的 KV 缓存随序列长度线性增长,但仅有 6 层需要存储完整的 KV 历史。线性注意力层不需要 KV 缓存——它们通过固定大小的状态矩阵 SR128×128 压缩全部历史信息,外加一个因果卷积的短状态(核大小为 4)。以 BF16 精度、序列长度 32K 为例:

  • 6 层全局注意力的 KV 缓存:6×32,768×2×256×2×2384 MB(2 个 KV 组、head_dim 256、KV 各一份、BF16 每元素 2 字节)
  • 18 层线性注意力的状态:18×16×128×128×29.4 MB(16 个头、128×128 状态矩阵、BF16)

KV 缓存总量约 393 MB,远低于 24 层全局注意力所需的约 1.5 GB。更重要的是,线性注意力层的状态大小与序列长度完全无关——无论输入 4K 还是 256K token,18 层线性层的内存占用恒定为 9.4 MB。

推理性能。 在 Nvidia A100 GPU 上,Qwen3.5-0.8B 以 BF16 精度运行时显存占用约 2.54 GB(含模型权重和 KV 缓存),生成速度约 8-9 tokens/sec(无 KV 缓存优化的基础模式)。模型的 float32 理论内存为 7.63 GB,BF16 为 3.81 GB。

7.6.6 混合注意力的趋势

Qwen3.5 并非孤例。2025 年以来,多个主流模型相继采用了线性注意力与全局注意力的混合架构:

模型线性注意力机制全局注意力比例总参数量
Qwen3.5-0.8BGated DeltaNet25%(6/24 层)0.8B
Kimi LinearGated DeltaNet约 20%未公开
Zamba-2Mamba-2约 17%7B
Falcon-H1Mamba-2约 25%1.5B–34B

这些模型的共同模式是:线性注意力层处理大部分局部、渐进式的上下文压缩任务,少量全局注意力层定期"刷新"模型对完整上下文的精确记忆。线性层与全局层的比例通常在 3:1 到 5:1 之间,过多全局层会削弱效率优势,过少则会导致远程信息丢失。

这一趋势的技术驱动力是明确的:随着上下文窗口从 4K 扩展到 128K 乃至 1M,纯 Softmax 注意力的 O(n2) 开销变得不可承受。但完全放弃 Softmax 转向纯线性注意力也不可行——线性注意力在精确检索任务(如"在 10 万字文档中找到某个特定事实")上的表现仍然弱于 Softmax。混合架构是当前工程上的最优折中:用大量线性层承担"日常"的局部处理,用少量全局层保底精确检索能力。

Qwen3.5 DeltaNet 线性注意力

图 7-23:Gated DeltaNet 线性注意力的递推机制。通过固定大小的状态矩阵压缩历史信息,实现对序列长度线性的计算复杂度。

本节小结

本节以 Qwen3.5-0.8B 为案例,剖析了线性注意力与全局注意力混合架构的设计与实现:

  • 混合架构布局:24 层中 18 层使用 Gated DeltaNet 线性注意力、6 层使用标准 Softmax 全局注意力,按 3:1 比例交替排列(每 4 层一个周期)。两类层共享 SwiGLU FFN 和零中心 RMSNorm,仅在 token mixing 模块上有本质区别。
  • 全局注意力层的创新:引入门控查询投影(Query 投影输出 2 倍维度,一半作 Query、一半作 Sigmoid 门控),使少量全局层具备更精细的信息筛选能力。使用 GQA(8 头 / 2 KV 组)、QKNorm、部分 RoPE(仅 25% 维度旋转)。
  • 线性注意力层的实现:采用 Gated DeltaNet 递推机制,前置因果卷积(核大小 4)处理极短距离依赖,L2 归一化 Q/K,门控 RMSNorm + SiLU 输出。不需要因果掩码和 RoPE。
  • 效率优势:线性层的状态矩阵大小固定(128×128,与序列长度无关),18 层线性注意力的状态仅占约 9.4 MB(BF16),全局注意力的 KV 缓存降至 6 层。在 256K 上下文下,全局注意力计算量降至纯 Softmax 架构的 25%。
  • 设计哲学:线性注意力层负责高效的局部模式处理和渐进式上下文压缩,全局注意力层负责精确的远程信息检索。两类层各司其职,是当前超长上下文模型在 O(n2) 瓶颈与精确检索需求之间的工程最优折中。