这是 Qwen 团队作为「未来 Qwen4 架构预览」放出的首个开源权重模型。它把此前 Qwen3-Next 的「Gated DeltaNet + 门控全注意力」骨干,替换成了「Gated DeltaNet + Qwen Sparse Attention(QSA)」,并配上 Gated Residual、N-gram Embedding、MTP 与 Muon/AdamW 混合优化器。本文按官方模型卡与 config.json 逐字段拆开,重点把注意力那一层——尤其是 QSA 的 indexer 与 micro-block 稀疏机制——讲到每个符号。
config.json,我把它当作权威一手规格来解读;文中凡属我基于公开机制(DeltaNet / Mamba2 / DeepSeek Sparse Attention 等技术线)做的推断与延伸,都会明确标注为「解读」而非原文断言。
先把官方架构图放上来。这张图的信息密度很高,右侧是放大的「一个 Hybrid Block」内部,左侧是整体堆叠。
把 config.json 里的关键数字对齐到这张图,就是下面这张「配置总表」。后面每一节会把其中一块拎出来单独拆。
| 模块 | 关键配置 | 数值(来自 config.json) |
|---|---|---|
| 整体 | 总参 / 激活 / 层数 / hidden | 125B / 6B / 48 层 / hidden_size=2560 |
| 词表 | vocab / n-gram / 输出 | 248320 · n-gram 2000 万(ngram_size=3)· LM 输出 248320 |
| 层布局 | full_attention_interval=4 | 每 4 层出现 1 层 full(=QSA),其余 3 层 linear(=GDN) |
| QSA(全注意力层) | Q/KV 头 · head_dim · RoPE | 24 Q 头 / 2 KV 头(GQA)· head_dim=256 · 旋转维 64(partial_rotary_factor=0.25) |
| QSA · Indexer | 结构 · 预算 | MQA 4 Q 头 / 1 KV 头 · indexer_head_dim=128 · 预算 512 块 / 2048 token(indexer_budget=2048, 压缩比 4) |
| GDN(线性注意力层) | V/QK 头 · head_dim · conv | 48 V 头 / 16 QK 头 · head_dim=128 · 短卷积核 linear_conv_kernel_dim=4 |
| MoE | 专家数 · 激活 · 中间维 | 512 专家,选 10 路由 + 1 共享 · moe_intermediate_size=640 |
| Gated Residual | 分支 · 瓶颈秩 | 4 分支 · hc_lowrank=320(bottleneck rank) |
| MTP | 层数 · 训练 | 1 层,multi-step 训练(mtp_num_hidden_layers=1) |
| 上下文 | 原生 · 可扩 | 262144 原生,YaRN 扩到 1,000,000 |
| 视觉塔 | ViT | depth=27, hidden 1152, patch 16, 输出对齐 2560 |
config.json 里的 layer_types 数组是这个模型最诚实的「设计蓝图」——它逐层列出了每一层是 linear_attention(GDN)还是 full_attention(QSA)。规律非常干净:linear, linear, linear, full 每 4 层一循环,共 12 个循环 = 48 层。这正对应模型卡里写的 12 × (3 × (Gated DeltaNet → MoE) → 1 × (Qwen Sparse Attention → MoE))。
rope_theta=1e7,用于多 token 预测的训练时监督。这是全文的核心,也是这次基于官方 modeling_qwen4_exp.py 源码重写的部分。QSA 是 Qwen3.8-Flash-Next 相对 Qwen3-Next 最大的改动——把那 1/4 的「门控全注意力」换成了「块级稀疏注意力」。它落到代码里是两个类协作:Qwen4ExpTextQSAIndexer(选块、产出稀疏 mask)+ Qwen4ExpTextAttention(拿 mask 做门控注意力)。下面先立靶子,再照着 Qwen4ExpTextQSAIndexer.forward() 一行一行走。
relu(·) 后按 head 求和再 /√d。——初版我猜的是「max / 均值点积」,源码给的是 ReLU + sum-over-heads,这是一个刻意的非负、多头投票式打分。对每个 query 位置 t、每个 head h,标准注意力计算:
逐符号拆开看它到底贵在哪:
head_dim=256。先看 Qwen4ExpTextAttention.forward() 的头两行——它把整个 QSA 的调用关系摊开了:
所以 QSA = 「indexer 决定每个 query 能看见哪些 KV」→「把不该看的位置在 mask 里屏蔽掉」→「主注意力照常算,但只有选中的位置参与 softmax」。它没有 gather、没有搬运 KV——纯靠一张 mask 把稠密注意力掐成稀疏。下面把 indexer 逐段走完。
index_qk_proj 把 hidden 投成 4 个 indexer-query 头 + 1 个 key 头(各 128 维),q 过 RMSNorm + RoPE。relu(q·kᵀ) 按 head 求和 /√d 得块分数,取 Top-512 块。index_head_dim=128 上归一),稳定打分尺度。token_budget // compress_ratio = 2048 // 4 = 512。这行代码就是「预算 2048 token = 512 块」换算的出处——每个 query 最多选 512 个块。indexer_n_heads=4, indexer_kv_heads=1:4 个 query 头共享 1 个 key 头(MQA 极致),打分成本极低。对每个 (batch, query) 位置,取它可见的 key 下标,每 compress_ratio=4 个连续可见 token 组成一个「完整块」;不足 4 个的尾巴单独处理(见 Step 4)。块代表向量这样算:
-1 做占位符,散射时把 -1 全丢到「第 kv_length 列」再切掉,干净地得到布尔可见矩阵;eager 模式再转成 0 / −inf 的加性 mask。eager_attention_forward 完全不用改——它就是标准的 softmax(QKᵀ·scaling + mask)·V,mask 里已经包含了稀疏信息。这样 QSA 能直接复用现成的 attention kernel(含 SDPA),不需要为「选中块」写专门的 gather-attention kernel。代价是:训练/短序列时它逻辑上仍算了全部 QKᵀ(只是 mask 掉),真正的省算要靠推理引擎(vLLM/SGLang)识别 mask 结构做块稀疏 kernel。换句话说:这份 modeling 是「参考实现」,重在语义正确与可复用;生产提速靠 serving 引擎的稀疏 kernel。
indexer 给完 mask,主注意力还有一个初版没细讲的细节——输出门控。看 Qwen4ExpTextAttention:q_proj 的输出宽度是 2×,劈成「真正的 query」和「门 gate」:
o 再乘 sigmoid(gate) ——逐元素、数据相关地缩放每个通道,等价于给注意力输出加了个 SiLU/GLU 式的自门控。head_dim=256 上各过 RMSNorm 再算注意力——稳定长上下文下的注意力分数尺度(QK-Norm,近年大模型标配)。repeat_kv 在算之前把 KV 复制回 24 头)。apply_rotary_pos_emb 里 rotary_dim = cos.shape[-1],只对 q/k 的前 rotary_dim 维施加旋转、后面维度原样拼回:
apply_interleaved_mrope 负责交织。rope_type 改 yarn、factor=4。官方提醒 YaRN 是静态缩放,略伤短文本,只在需要时开。modeling 是推理/前向参考实现:indexer 的 Top-k 是硬选择(不可导),代码里没有出现对齐 indexer 打分的辅助损失——它假定 indexer 已训好。按同技术线(DeepSeek Sparse Attention)的通行做法,通常会用一个 KL / 蒸馏损失让 indexer 的块打分去逼近主分支真实注意力分布(配 stop-gradient)。这部分仍以 Qwen 技术报告为准,本文只如实说明「前向代码里看不到训练 loss」。
QSA 讲透了,再看承担 3/4 层的 GDN。它是 Qwen3-Next 就在用的线性注意力,核心是「用一个固定大小的状态矩阵 S_t 概括全部历史」,从而把复杂度从 O(N²) 降到 O(N)。它的递推式把「自适应遗忘」和「定点改写」合二为一:
残差连接(residual + norm)是深层 LLM 能训起来的基础。Qwen3.8-Flash-Next 在此之上做了 Gated Residual:在一条加宽的(expanded)残差流上,用数据相关的门控来调制信息进出。架构图里的 GR Write / GR Read 就是它。
这是很有意思的一块:51B 参数几乎全砸在一张巨大的 n-gram 查找表上,但它几乎不增加计算量。
机制:把输入里连续的 2~3 个 token 拼成一个 n-gram,用它去索引一张 2000 万行的 embedding 表,取出的向量加进第 2 层的表示。
「512 个瘦专家、每 token 选 10+1」是典型的细粒度 MoE:专家越多越小,组合数越大、专精度越高,是 6B 激活量却有 125B 总参的直接原因。
顶部挂一个 1 层的 MTP(Multi-Token Prediction)模块(约 4B 参数,multi-step 训练)。训练时不止预测「下一个 token」,还预测再往后几个,给模型更密的监督信号、提升样本效率;推理时可用作投机解码的草稿头,加速生成。
模型卡给出的语言能力横评(对比 Qwen3.8-27B 稠密、Qwen3.7-Plus 397B MoE、DeepSeek-V4-Flash、Claude-Opus-4.6)。Qwen3.8-Flash-Next 只激活 6B,却在多数项领先,尤其 agentic 类。
| 能力 / Benchmark | Flash-Next (6B act) | Qwen3.8-27B | 3.7-Plus (397B) | DS-V4-Flash | Opus-4.6 |
|---|---|---|---|---|---|
| Agentic coding · DeepSWE 1.1 | 58.7 | 42.2 | 16.5 | 54.4 | — |
| SWE-bench Pro | 62.5 | 61.7 | 55.8 | 56.0 | 53.4 |
| SWE-bench Multilingual | 81.0 | 73.8 | 75.8 | — | 77.5 |
| Long-horizon office · CoWorkBench | 73.9 | 70.7 | 65.1 | 45.1 | 68.2 |
| JobBench(职业任务) | 55.7 | 33.4 | 27.6 | 41.3 | 36.6 |
| Real-world tool use · Toolathlon | 73.5 | 67.1 | 50.6 | 70.3 | — |
| 指令遵循 · IFBench | 81.3 | 79.5 | 79.1 | 79.2 | 62.5 |
| 科学推理 · GPQA Diamond | 91.7 | 89.2 | 90.3 | 90.8 | 91.3 |
| 竞赛编程 · LiveCodeBench v6 | 91.9 | 90.3 | 89.6 | 90.6 | 88.8 |
| 多学科推理 · HLE | 35.9 | 30.8 | 34.7 | 33.8 | 40.0 |