Qwen3.8-27B 的混合注意力:由 config 里哪几个字段承载

2026-08-16

看 model card 的时候,“混合注意力”往往只是一行公式或者一句话。可真要落到配置文件上,问题就变成很具体的一个:这套结构到底是由哪几个字段承载的? 是一个开关,还是一张表,还是两组各自独立的维度参数?

我们把 Hugging Face 仓库 Qwen/Qwen3.8-27B 在 2026-08-16 的快照 1d4bf0f 拉下来,只读其中的文本配置与 model card,逐个字段核了一遍。先说结论:承载这套结构的不是某一个字段,而是一张 64 项的数组 + 一个间隔数 + 两组名字完全不同的头维度字段。下面按 config.json 里的实际位置逐个来。

先看文件本身的形状

config.json 在仓库根目录,我们统计到 4,312 字节、140 行。它只有三层:顶层、text_configvision_config,没有第四层嵌套的配置块(rope_parameterstext_config 下的一个子对象)。用 Python 数键数得到的结果是顶层 11 个键、text_config 34 个键、vision_config 14 个键。

和注意力结构相关的字段全部在 text_configvision_config 那 14 个键里没有任何一个和层类型排布有关,它的层数字段甚至叫 depth(值 27,位于 config.json:124),连 num_hidden_layers 都没有。所以下文说的字段,如无特别说明都在 text_config 下。

第一根承重柱:layer_types

layer_typestext_config 下的一个字符串数组,占据 config.json:21-86——[ 在第 21 行,] 在第 86 行,中间 64 个元素各占一行,即 config.json:22config.json:85

我们把它整个打印出来数过:

  • 数组长度是 64,与同文件 num_hidden_layersconfig.json:98)的 64 相同。
  • 取值只有两种:"linear_attention""full_attention"
  • "full_attention"16 项,"linear_attention"48 项,16 + 48 = 64。
  • 按 0 基下标,full_attention 出现在 3, 7, 11, 15, 19, 23, 27, 31, 35, 39, 43, 47, 51, 55, 59, 63。这 16 个下标对 4 取余全是 3(Python 断言 all(i % 4 == 3) 返回 True),相邻下标之差的集合是 {4},即等间距 4。
  • 换成”第几层”来说(1 基),第 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64 层是 full_attention,其余 48 层是 linear_attention
  • 首层(下标 0,config.json:22)是 linear_attention,末层(下标 63,config.json:85)是 full_attention——数组以 full_attention 结尾

把 64 项按 4 个一组切开正好 16 组,我们打印了前两组做核对,都是 ['linear_attention', 'linear_attention', 'linear_attention', 'full_attention']

这就是第一个要点:这套结构在配置里是被”一层一层写死”的,不是靠某个规则字符串描述的,而是 64 行明明白白摆在那儿。你想知道第 37 层是什么类型,直接去数第 37 项就行,不需要推。

第二根承重柱:full_attention_interval

full_attention_intervalconfig.json:15,值是 4

它和上面那张表在数值上是自洽的:num_hidden_layers ÷ full_attention_interval = 64 ÷ 4 = 16,恰好等于 full_attention 在数组里出现的次数;而我们实际数出来的相邻间距也恒为 4。

这里必须停一下。这两处只是数值一致,仓库文件里并没有写明谁推导谁。这是个模型权重仓,architectures 里那个 Qwen3_5ForConditionalGenerationconfig.json:3)的实现不在本仓,我们没有推理代码可查。所以「加载时到底是读 layer_types 还是按 full_attention_interval 现算」「二者冲突时以哪个为准」,本仓文件没有说明,我们不推断。你只能记住一件事:改其中一个而不改另一个,这两处就会对不上,至于对不上会发生什么,我们没有依据说。

第三根承重柱:两组各自独立的头维度字段

很多人默认”注意力头”就那么一组参数。但在这份 config.json 里,头维度字段按前缀分成完全分开的两套命名,一个字都不共用:

分组字段名行号
不带 linear_ 前缀的一组num_attention_heads24config.json:97
不带 linear_ 前缀的一组num_key_value_heads4config.json:99
不带 linear_ 前缀的一组head_dim256config.json:16
linear_ 前缀的一组linear_num_key_heads16config.json:89
linear_ 前缀的一组linear_num_value_heads48config.json:90
linear_ 前缀的一组linear_key_head_dim128config.json:88
linear_ 前缀的一组linear_value_head_dim128config.json:91

这里只按字段名的前缀分组。两组字段分别作用在 layer_types 的哪一类层上,config.json 里并没有写明,我们不推断;后面对 model card 那一节会说明这层对应关系是怎么被”对上”的、边界又在哪。

两组的写法并不对称:不带前缀的那组只有一个 head_dim256),config 里没有再分开写 Q 与 KV 的维度字段;带 linear_ 前缀的那组则把 key 与 value 的维度拆成两个字段各写一遍,虽然两个字段的值都是 128

同一区块(config.json:87-92)还有另外两个字段:linear_conv_kernel_dim = 4config.json:87)与 mamba_ssm_dtype = "float32"config.json:92)。后者和 text_config 顶上的 dtype"bfloat16"config.json:13)不是同一个值,两个 dtype 字段并存。这几个字段各自作用于什么、linear_conv_kernel_dim 的确切含义是什么,我们未能从本仓任何文件中确认——本仓只有权重与配置,没有建模源码。照录数值,不解释。

另外两个带 gate 字样的字段也在 text_config 里:attn_output_gate = trueconfig.json:11)、output_gate_type = "swish"config.json:100)。它们同样没有本仓文档可对照。

顺带记一处对照:text_config 里还有 attention_bias = falseconfig.json:9)与 attention_dropout = 0.0config.json:10),而 vision_config 那 14 个键里这两个字段都不存在rms_norm_epsdtype 同样只在 text_config 里有)。也就是说,两边并不是同一套字段表的两份拷贝,看视觉侧时别拿语言侧的字段名去找。

顺手记一组容易看错的乘积

既然两侧的头维度是分开写的,很容易有人拿它们去乘一乘再和 hidden_size 对。我们确实乘过,结果照录如下——这些乘积 config.json 里一个都没有直接写出来,是我们自己算的

  • num_attention_heads × head_dim = 24 × 256 = 6144,而 hidden_size = 5120config.json:18),两者不相等
  • num_key_value_heads × head_dim = 4 × 256 = 1024
  • linear_num_value_heads × linear_value_head_dim = 48 × 128 = 6144
  • linear_num_key_heads × linear_key_head_dim = 16 × 128 = 2048

值得留意的只有一点:上面第一条与第三条算出来都是 6144,数值相同。至于这个相同是不是刻意的、61445120 不等又意味着什么,本仓文件没有任何说明,我们不推断,也不拿这些数去推算参数量、显存或任何别的东西。列在这里只是想让你在自己算的时候不至于以为算错了。

把 model card 的公式和数组对一遍

model card 的 “Model Overview” 节在 README.md:32README.md:53。其中 README.md:41 那一行原文是:

Hidden Layout: 16 × (3 × (Gated DeltaNet → FFN) → 1 × (Gated Attention → FFN))

我们的核对步骤是这样走的:

  1. 读出 layer_types,长度 64,与 README.md:40Number of Layers: 64 一致;
  2. 数两种取值的个数:full_attention 16 个、linear_attention 48 个。公式里外层重复 16 次,每次 3 个 DeltaNet 单元 + 1 个 Attention 单元,即 16×3 = 48、16×1 = 16——数量对上;
  3. 校验顺序:full_attention 下标全部满足 i % 4 == 3,说明每 4 层一组、组内前 3 层是 linear、第 4 层是 full,与公式里”3 个之后接 1 个”的顺序对上;
  4. 切片核对 layer_types[0:4]layer_types[4:8],两组完全相同。

结论:在”块数 = 16""块内比例 3:1""块内顺序先 linear 后 full”这三点上,README.md:41 的公式与 config.json:21-86 的数组吻合,我们没有发现矛盾。

同一节里其余几行也和 config 对得上:Number of Linear Attention Heads: 48 for V and 16 for QKREADME.md:43)对应 linear_num_value_heads = 48linear_num_key_heads = 16;Gated DeltaNet 的 Head Dimension: 128README.md:44)对应 config 里分开写的那两个 128Number of Attention Heads: 24 for Q and 4 for KVREADME.md:46)对应 244;Gated Attention 的 Head Dimension: 256README.md:47)对应 head_dim = 256

但有两处必须说清的边界

第一,公式里的 FFN 在 layer_types 里没有任何对应元素。数组只有两种注意力类型的取值,不含 FFN 项。model card 说每个单元后面跟一个 FFN,这一点无法从 layer_types 核对,我们也没有权重结构可读来核实。

第二,“Gated DeltaNet” 和 “Gated Attention” 这两个名词在 config.json 里一次都没出现。config 对应位置的字符串是 "linear_attention""full_attention"。我们是按”数量 48/16 + 顺序 3:1”把两组名词对上的,这是名称层面的对应关系,不是 config 里写明的映射。至于 config 里那两个 gate 字段和 model card 的 “Gated” 字样是否指同一件事,本仓文件没有说明,我们不推断。

你自己怎么核一遍

上面关于排布的那些结论,都出自在仓库根目录读取 config.json 的下面这段(只读文本配置,不加载权重):

python -c "
import json
d=json.load(open('config.json',encoding='utf-8'))
lt=d['text_config']['layer_types']
full=[i for i,v in enumerate(lt) if v=='full_attention']
lin=[i for i,v in enumerate(lt) if v=='linear_attention']
print('full count',len(full)); print('full idx (0-based)',full)
print('full idx (1-based)',[i+1 for i in full]); print('linear count',len(lin))
print('all full idx %4==3 (0based)?', all(i%4==3 for i in full))
print('interval diffs', sorted(set(full[k+1]-full[k] for k in range(len(full)-1))))
print('groups of 4:', [lt[k*4:(k+1)*4] for k in range(2)])
"

我们在快照 1d4bf0f 上得到的输出是:full count 16full idx (0-based) [3, 7, 11, 15, 19, 23, 27, 31, 35, 39, 43, 47, 51, 55, 59, 63]linear count 48all full idx %4==3 (0based)? Trueinterval diffs [4],以及前两组切片都等于 ['linear_attention','linear_attention','linear_attention','full_attention']。上游仓库内容随时可能更新,请以你手上那份快照跑出来的结果为准。

最后提醒两句和这篇直接相关的事。一是模型名与 config 里的类名字样不同:README.md:7 的标题是 # Qwen3.8-27B,而 config.json:3architectures["Qwen3_5ForConditionalGeneration"]config.json:7model_type"qwen3_5"config.json:94text_config.model_type"qwen3_5_text"README.md:20 另有一句原文 Built on the architectural foundation of Qwen3.5。四处并列,我们不做因果解释,但你按类名去查资料时会用得上。二是这些字段的取值属于架构选择,它带来什么效果、适不适合你的场景,我们没有任何依据评价,也不打算据此推算任何东西。

延伸阅读


本文依据 Hugging Face 仓库 Qwen/Qwen3.8-27B 的 model card 与随仓配置文件 (config.jsongeneration_config.jsonpreprocessor_config.jsonchat_template.jinja 等)整理, 核对日 2026-08-16,对应仓库快照 1d4bf0f。 本文内容为 model card 与配置文件口径,我们没有下载权重、没有部署、也没有推理过这个模型, 因此不涉及生成质量、推理速度与显存占用的任何描述;文中所有评测数字均为 model card 自述,我们没有复现。 模型仓库内容随上游更新而变动,请以官方最新说明为准。

想系统学会用 AI?报名体系课或加入会员,照着学、照着用。