Qwen3.8-27B 的视觉塔 27 层:patch 16 与那个空的 deepstack 数组

2026-08-16

翻 Qwen3.8-27B 这个仓库时,有一件事挺容易漏掉:model card 的 “Model Overview” 那一节(README.md:32README.md:53)看着挺全,隐藏维度、层数、注意力头数、FFN 中间维度、上下文长度都列了,但这些条目全都挂在 Language Model 这个层级之下。视觉编码器在整节里只出现过一次,就是第 34 行那句 Type: Causal Language Model with Vision Encoder。深度多少、每层多宽、patch 怎么切、有几个注意力头——一个数字都没有。

想知道这些,只能去读仓库根目录的 config.json。这篇就干这一件事:把 vision_config 这一块逐个键抄出来,和随仓的两个 preprocessor 配置对一遍,再把那个空数组照实记下来。

先说清楚边界。这是一个模型权重仓,不含建模源码architectures 里那个 Qwen3_5ForConditionalGeneration 类的实现不在本仓。所以下面所有字段,我们能给的只有名字、值、所在行号,以及它和别的文件对不对得上。字段在推理时怎么被用、值改了会怎样,本仓文件没有写,我们也不推断。我们没有下载权重、没有部署、没有推理过一个 token,本文不涉及生成质量、速度、显存的任何描述。

vision_config 一共十四个键

config.json 整个文件 4,312 字节、140 行,结构只有三层:顶层、text_configvision_configvision_configconfig.json:122config.json:137,用 Python 数出来是 14 个键

字段名行号
deepstack_visual_indexes[](空数组)config.json:123
depth27config.json:124
hidden_act"gelu_pytorch_tanh"config.json:125
hidden_size1152config.json:126
in_channels3config.json:127
initializer_range0.02config.json:128
intermediate_size4304config.json:129
model_type"qwen3_5"config.json:130
num_heads16config.json:131
num_position_embeddings2304config.json:132
out_hidden_size5120config.json:133
patch_size16config.json:134
spatial_merge_size2config.json:135
temporal_patch_size2config.json:136

这十四个数字,在 README.md 里一个都查不到。depth=27hidden_size=1152num_heads=16intermediate_size=4304num_position_embeddings=2304 这五项我们逐个在 model card 里检索过,均无对应表述。

三层的键数放在一起看更直观:顶层 11 个键、text_config 34 个键、vision_config 14 个键。视觉这一块是三层里最短的一块,十四行读完就到底了,中间没有再嵌套的子对象——config.json 里唯一的子对象是 text_config 下的 rope_parameters,视觉侧没有对应的东西。

第一个坑:层数字段不叫 num_hidden_layers

如果你按语言侧的习惯去 vision_config 里找 num_hidden_layers,会找不到——这个键在 vision_config根本不存在。视觉侧的层数字段名是 depth,值是 27config.json:124)。而语言侧用的是 num_hidden_layers: 64config.json:98)。同一份 config.json 里,两块用了两个不同的字段名表示层数。

顺手可以对照的还有几处「视觉侧没有」:text_config 里存在的 dtypeattention_dropoutrms_norm_epsattention_bias 这四个键,在 vision_config 的十四个键里一个都没有。激活函数也不是同一个值:text_config.hidden_act"silu"config.json:17),vision_config.hidden_act"gelu_pytorch_tanh"config.json:125)。initializer_range 倒是两边都有,值都是 0.02config.json:19config.json:128)。

另一处数值上的巧合:vision_config.out_hidden_size5120,与 text_config.hidden_size5120config.json:18)相同;而 vision_config.hidden_size 自己是 1152。我们只陈述这三个数字的字面关系,不解释它们在前向过程里各自承担什么。

patch 16 与合并尺寸 2:三个文件、两套字段名

patch_sizetemporal_patch_sizespatial_merge_size 这一组,是本仓少数能跨文件互相印证的地方。除了 config.json,随仓还有 preprocessor_config.json(图像侧,21 行)和 video_preprocessor_config.json(视频侧,21 行)。三处对照如下:

config.jsonvision_configpreprocessor_config.jsonvideo_preprocessor_config.json
patch 尺寸patch_size: 16:134patch_size: 16:6patch_size: 16:6
时间 patchtemporal_patch_size: 2:136temporal_patch_size: 2:7temporal_patch_size: 2:7
合并尺寸spatial_merge_size: 2:135merge_size: 2:8merge_size: 2:8

数值三处全对得上。但字段名并不一样:在 config.json 里它叫 spatial_merge_size,在两个 preprocessor 里叫 merge_size。如果你要写脚本去比对这两侧配置,或者要给某个推理框架传参,这个名字差异是必须先知道的一件事——按 spatial_merge_size 去 grep 两个 preprocessor 文件,会一无所获。

两个 preprocessor 里还有一组类名值得并列记下来:processor_class 都是 "Qwen3VLProcessor"preprocessor_config.json:19video_preprocessor_config.json:19),而 image_processor_type"Qwen2VLImageProcessorFast"preprocessor_config.json:20),video_processor_type"Qwen3VLVideoProcessor"video_preprocessor_config.json:20)。这三个类名分别带 Qwen3VLQwen2VL 字样,而 config.json:3architectures 写的是 Qwen3_5ForConditionalGenerationconfig.json:7model_type"qwen3_5"。四处并列在这里,我们不推断原因、也不判断哪个是「对的」。

顺带一提 vision_config.model_type 的值是 "qwen3_5",与顶层 model_typeconfig.json:7)完全相同;而 text_config.model_type 带了后缀,是 "qwen3_5_text"config.json:94)。视觉侧没有对应的 _vision 后缀。

那个空的 deepstack_visual_indexes

vision_config 的第一个键是 deepstack_visual_indexes,值是 []config.json:123)。

这里要抠得细一点,因为三种情况在写文章时经常被混为一谈:这个键不是缺失不是 null,而是存在且值为一个长度为 0 的数组。我们用 Python 校验过类型与长度,打印结果是 deepstack [] <class 'list'> 0

然后是第二件事:README.md 全文检索 deepstack(不区分大小写)零命中。也就是说,model card 里没有任何一句话解释这个字段是什么、空数组代表什么、什么情况下该往里填东西。本仓又没有建模源码可读,所以我们没能在仓库里找到与之对应的任何说明或实现。

按「配置里出现 ≠ 功能可用」这条规矩,正确的处理方式是照实标注:键在、值为空数组、本仓无说明。至于它意味着某个能力被关掉了、还是这一版本就没有这一路,我们没有依据,不推断。你要是把它当成一个已经生效的开关去写文档或做二次封装,那是在拿一个仓库里没有依据的假设当前提。

同样的纪律也适用于旁边那几个字段。in_channels: 3num_position_embeddings: 2304num_heads: 16 这些名字看着都很好猜,但「好猜」和「仓库里写了」是两回事。本仓能给的就是字面值。

顺便说个读配置时的通用习惯,和这个仓库无关:判断一个键是「不存在」「值为 null」还是「值为空容器」,不要靠肉眼扫 JSON 文本,用 k in objobj[k] is Nonelen(obj[k]) 三步分别问一遍。这三种状态在下游代码里往往走完全不同的分支,而在文本里看起来差别很小。deepstack_visual_indexes 属于第三种。

视觉相关的四个 token id

视觉侧还有一组数字落在 config.json 顶层,不在 vision_config 里面。把它们拿到 tokenizer_config.jsonadded_tokens_decoder 里逐个查,四个都对得上:

顶层字段idtokenizer 中的 content
vision_start_token_idconfig.json:139248053<|vision_start|>
vision_end_token_idconfig.json:138248054<|vision_end|>
image_token_idconfig.json:5248056<|image_pad|>
video_token_idconfig.json:121248057<|video_pad|>

一个可以顺手记下来的观察:顶层引用的四个 id 是 53、54、56、57,中间的 248055 没有被顶层任何字段引用。它对应什么,我们没有排查本仓 33 个新增 token 的完整清单,不做猜测。

你自己核一遍

上面每个数字都可以在本地复核,不需要下载权重。把仓库里的 config.jsonpreprocessor_config.jsonvideo_preprocessor_config.json 放在同一个目录下,在 <你的项目目录> 里执行:

python -c "
import json,io
d=json.load(io.open('config.json',encoding='utf-8'))
v=d['vision_config']
print('n vision keys', len(v))
for k in v: print(k, '=', v[k])
print('deepstack', v['deepstack_visual_indexes'], type(v['deepstack_visual_indexes']), len(v['deepstack_visual_indexes']))
"

Windows 下 PowerShell 与 cmd 对引号的处理和 bash 不同,把上面这段存成 .py 文件再 python 该文件名 执行更省事;Linux / macOS 侧直接照抄即可。这是我们统计事实时用的口径,不涉及模型加载。

收尾时要留的几条限定

  • model card 自述本模型是 native vision-language modelREADME.md:20),Highlights 第五条写的是 Native support for image and video understanding, from STEM diagrams and documents to hour-scale videos.README.md:29)。这些是 model card 的自述,本仓没有可供核对的实现,我们也没有跑过任何评测。
  • video_preprocessor_config.jsonsize.longest_edge 的发布值是 25165824,而 README.md:561 自称这份 size 是 “conservatively configured”,并在 README.md:563 建议改成 {"longest_edge": 469762048, "shortest_edge": 4096}发布值与官方建议值不是一个数,两处并列在此,不推断影响。
  • model card 在 README.md:407 的注释里写 This feature is currently supported only in vLLM.(指通过 extra_body 配视频帧采样),该段本身是被注释掉的示例代码。属于限定条件,照实标出。
  • 截至 2026-08-16,这个仓库的下载量与点赞数是 267,725 / 10,284,权重按 18 个 .safetensors 分片发布。这两组数字只是当天的元数据,不用来推导质量、成熟度,也不用来推算体积或资源需求

最后回到开头那件事:视觉侧的十四个数字只在 config.json 里,model card 一个字都没写。这不是一个需要解释的现象,只是一个你在读这个仓库时必须知道的事实——找不到,就是没写在那儿,去 config.json:122config.json:137 看。

延伸阅读


本文依据 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?报名体系课或加入会员,照着学、照着用。