Transformers 中 ModernVBert 视觉-语言编码器全解析:从 ModernBert + SigLIP 架构到掩码视觉语言推理实践
导读
ModernVBert 是 Hugging Face Transformers(本仓库)中一款面向视觉文档理解与检索场景的视觉-语言(Vision-Language)编码器模型,它将 ModernBert 文本编码器与 SigLIP 视觉编码器组合为统一的双塔结构,并创新性地通过 pixel shuffle 连接器(Connector) 将图像 patch 特征压缩投影到文本嵌入空间,使文本 token 可以在纯 MLM 式目标下直接"看见"图片内容。本文以 官方模型文档 为核心骨架,结合本仓库 modernvbert 源码目录 与 测试套件 进行源码级展开。读完本文,你将掌握:ModernVBert 的整体架构与运行链路、ModernVBertConfig 全部关键配置项的真实含义与默认值、利用 ModernVBertForMaskedLM 做图文融合掩码预测的完整可运行代码,以及如何将该模型接入文本分类、词元分类等下游任务。
一、模型是什么:为视觉文档检索而生的双编码器
依据 官方模型文档 的 Overview,ModernVBert 是一个 Vision-Language encoder:
- 文本侧:复用 ModernBert 编码器,负责对 OCR/文档文本与视觉占位 token 的融合序列建模;
- 视觉侧:复用 SigLIP 视觉编码器,负责从原始像素提取图像 patch 表征;
- 优化目标:视觉文档理解(visual document understanding)与检索(retrieval)任务。
模型出自论文 ModernVBERT: Towards Smaller Visual Document Retrievers。同时,从 源码类注释 可以看到一句关键信息:ModernVBert 是视觉检索器 ColModernVBert 的基础模型——本仓库也确实存在 colmodernvbert 模型模块及其对应的 ColModernVBertForRetrieval 自动映射(见 modeling_auto.py 中相关映射条目)。也就是说,ModernVBert 定位并非生成式多模态大模型,而是可支撑"密集检索 + 后期交互/分块表征"的高效双塔编码底座。
在代码层面,ModernVBert 的实现走的是 Transformers 的 modular 开发管线:唯一可手工编辑的源文件是 modular_modernvbert.py,而 modeling_modernvbert.py 与 configuration_modernvbert.py 均由前者自动生成(文件头部的 CI 提示明确禁止手工编辑生成文件)。从模块头部继承关系可以确认它的实现血统:
ModernVBertConfig继承自PreTrainedConfig,声明model_type = "modernvbert";ModernVBertPreTrainedModel与ModernVBertModel分别继承自 SmolVLM 的SmolVLMPreTrainedModel/SmolVLMModel(见 modular_modernvbert.py),因此它天然继承了 SmolVLM 家族"文本+图像多输入、<image>占位 token 替换、变长多图 batch"的成熟框架,但inputs_merger合并逻辑被完全重写以适配 ModernBert 编码器特性。
二、整体架构与数据流:从像素到融合序列的四步流水线
综合 modeling_modernvbert.py 的 forward、get_image_features、inputs_merger 三处实现,一次典型的前向过程可分为四个阶段:
2.1 阶段一:文本嵌入与视觉特征提取(可并行)
forward 入口先判断是否提供了 inputs_embeds;若没有,则用文本模型的嵌入层对 input_ids 做查表得到文本嵌入(modeling_modernvbert.py)。同时,只要传入 pixel_values,就调用 get_image_features 走视觉通路。
2.2 阶段二:SigLIP 视觉编码与"真实图像"去冗余
视觉输入 pixel_values 的形状为 (batch_size, num_images, num_channels, height, width),即 batch 内允许每张样本携带任意数量的图片。为了高效处理变长图片数,模型在进入视觉编码器之前会:
- 将
(batch_size, num_images, ...)展平为(batch_size * num_images, ...); - 检测并剔除全零的 padding 图像(
real_images_inds,见 modeling_modernvbert.py),保证只把真实图像送进 SigLIP; - 若未提供
pixel_attention_mask,则默认构造全 1 的掩码;否则同步去除 padding 图像对应的掩码行; - 把逐像素注意力掩码按 patch 划分折叠为 patch 级注意力掩码(
patches_subgrid.unfold(...)求和后取大于 0),与 SigLIP 视觉模型的patch_attention_mask参数对接(modeling_modernvbert.py)。
上述 "padding 图像不进视觉骨干" 的细节同样体现在 forward 的 docstring 中(当 num_images_per_sample=[1, 3, 1, 2] 时只有 7 张真实图进入视觉编码器)。
2.3 阶段三:ModernVBertConnector —— pixel shuffle + 线性投影
这是整个模型最有特色的模块。视觉编码器输出的每个 patch 特征先被 ModernVBertConnector 处理。连接器做两件事:
- pixel shuffle 降序列长、升特征维度:假设 SigLIP 把
H×W图像切为n个 patch、每个 patch 特征维度为d。pixel_shuffle先把(batch, seq=n, embed=d)视为(batch, h, w, d),再按pixel_shuffle_factor在宽、高两个方向重排,最终得到(batch, n/f², d·f²)——序列长度缩减为原来的 1/f²,每个位置的特征维度扩大为原来的 f² 倍(modeling_modernvbert.py)。这意味着 16×16 的 patch 网格在pixel_shuffle_factor=4时只会产生 16 个视觉 token,token 预算被大幅压缩; - 无偏置线性投影到文本隐藏维度:
modality_projection为一个nn.Linear(d·f², hidden_size, bias=False),把重排后的视觉特征映射到 ModernBert 的隐藏空间(modeling_modernvbert.py)。
由 image_seq_len 的计算式 ((image_size // patch_size)²) / pixel_shuffle_factor²(modeling_modernvbert.py)可见,每个图像最终产生的视觉 token 数量由图像分辨率、patch 尺寸与 pixel shuffle 系数三者共同决定。测试套件中对 image_size=16, patch_size=4, pixel_shuffle_factor=2 的用例得到 (4)²/4 = 4 个视觉 token,可与此公式相互印证(test_modeling_modernvbert.py)。
2.4 阶段四:inputs_merger 融合文本与图像序列
连接器产出的视觉 token 序列通过重写后的 inputs_merger(modeling_modernvbert.py)嵌入文本序列。整个流程为:
- 文本序列形如
tok_1 tok_2 ... <image> <image> ... <image> ... tok_n,其中每个<image>用配置中的image_token_id(默认 50407)标识; - 每个图像的
image_seq_len个视觉 token 需要替换掉文本中连续的image_seq_len个<image>占位 token,即把一整块占位 token 换成模型真正"看见"的图像特征块; - 实现上通过
torch.where(image_mask.unsqueeze(-1), image_embeds, inputs_embeds)一次性完成占位替换(modeling_modernvbert.py)。源码中对每个样本执行了"该样本<image>token 总数必须能被patch_size(此处指单图视觉 token 数)整除"的合法性校验,若整除失败会直接报错,防止文本中的占位 token 与视觉块错位(modeling_modernvbert.py)。
最后,融合后的完整嵌入序列整体送入 ModernBert 文本编码器做双向编码,输出 ModernVBertBaseModelOutput(其中额外携带 image_hidden_states 字段,见 modeling_modernvbert.py)。因此 ModernBert 的每个 token 都能通过自注意力"看到"整张图像的全部视觉块,这正是它可用于"看图填空/掩码恢复"的能力来源。
三、配置详解:ModernVBertConfig 的全部关键参数
ModernVBertConfig 的权威定义位于 configuration_modernvbert.py,该文档中的 autodoc 指向的正是这个类。它是一个组合式配置(composite config):顶层只暴露少量参数,其余模型规模相关参数被收拢进 text_config 与 vision_config 两个子配置中(sub_configs = {"text_config": AutoConfig, "vision_config": AutoConfig})。
3.1 顶层专属参数
| 参数 | 类型 | 默认值 | 含义与源码依据 |
|---|---|---|---|
text_config |
PreTrainedConfig / dict |
None(自动取 ModernBert 默认配置) |
文本编码器 ModernBert 的配置;传入 dict 时在 __post_init__ 中被 CONFIG_MAPPING["modernbert"] 实例化(configuration_modernvbert.py) |
vision_config |
PreTrainedConfig / dict |
None(自动取 siglip_vision_model 默认配置) |
视觉编码器 SigLIP Vision 子模型的配置;同上通过 CONFIG_MAPPING["siglip_vision_model"] 实例化(configuration_modernvbert.py) |
image_token_id |
int |
50407 |
文本序列中标识"此处应插入图像特征"的占位 token id,inputs_merger 据此定位替换位置 |
pixel_shuffle_factor |
int |
4 |
Connector 中 pixel shuffle 重排系数 f:序列长度 /f²、特征维度 ×f²,直接决定每个图像产生的视觉 token 数 |
initializer_range |
float |
0.02 |
权重初始化使用的标准差基准值,用于计算各头部的缩放标准差 |
initializer_cutoff_factor |
float |
2.0 |
截断正态初始化(truncated normal)的截断范围系数,权重被裁剪在 ±cutoff_factor × std 内(见 modeling_modernvbert.py) |
classifier_pooling |
Literal["cls", "mean"] |
"cls" |
序列分类时的池化策略:取 [CLS]/首 token 位置或对全序列按 attention_mask 做均值池化(modeling_modernvbert.py) |
classifier_dropout |
float |
0.0 |
分类/词元分类头前的 Dropout 比例 |
classifier_bias |
bool |
False |
分类(预测)头是否带偏置项 |
tie_word_embeddings |
bool |
False |
是否将 MLM 输出层与词嵌入层权重绑定 |
3.2 子配置与模块拼接规则
text_config直接驱动 ModernBertConfig 对应的结构字段(如vocab_size、hidden_size、num_hidden_layers、decoder_bias等)。当需要把 ModernBert 替换为更大/更小的主干时,只需改写text_config,上层代码中诸如text_config.hidden_size、text_config.num_hidden_layers的引用会自动生效;vision_config必须是 SigLIP Vision Model 兼容配置,代码中实际使用hidden_size(patch 特征维度)、image_size与patch_size(决定 patch 网格边长)三个字段,缺一不可(见 modeling_modernvbert.py 与 Connector 构造处的vision_config.hidden_size);- 测试替身配置(text 侧
hidden_size=32、vision 侧image_size=16/patch_size=4/hidden_size=64)展示了两个子配置如何分别被实例化为ModernBertConfig与字典后组合进ModernVBertConfig(test_modeling_modernvbert.py)。
3.3 用配置实例化模型
依据 configuration_modernvbert.py 官方 docstring,最小用法如下:
from transformers import ModernVBertConfig, ModernVBertModel
# 直接采用默认的 ModernBert + SigLIP 组合
configuration = ModernVBertConfig()
model = ModernVBertModel(configuration)
# 读取回模型实际生效的配置
cfg = model.config
如需精细化自定义,可先构造文本与视觉子配置再合并:
from transformers import ModernVBertConfig
config = ModernVBertConfig(
text_config={
"vocab_size": 30528,
"hidden_size": 768,
"num_hidden_layers": 12,
},
vision_config={
"image_size": 512,
"patch_size": 16,
"hidden_size": 1152,
},
pixel_shuffle_factor=4,
classifier_pooling="mean",
)
四、能力矩阵:四个预训练模型类及其输出结构
官方模型文档 通过 autodoc 列出了 4 个类。下面按源码逐一说明其职责与 forward 差异。
4.1 ModernVBertModel(基础编码器)
- 职责:完成"图像+文本 → 融合后的双向表征",供下游特征提取、向量化检索使用。
- 独有的两个方法:
get_image_features(pixel_values, pixel_attention_mask=None):单独编码图像并返回 Connector 处理后的视觉特征(被塞进BaseModelOutputWithPooling.pooler_output返回,见 modeling_modernvbert.py);inputs_merger(...):上文所述的融合逻辑,可被子类覆写。
- forward 主要入参:
input_ids、attention_mask、position_ids、inputs_embeds、pixel_values、pixel_attention_mask、image_hidden_states(支持跳过视觉编码直接喂入预计算视觉特征,便于两阶段缓存/加速)。 - 返回:
ModernVBertBaseModelOutput,除常规last_hidden_state、hidden_states、attentions外还带image_hidden_states(形状(batch_size, num_images, seq_len, hidden_size))。
4.2 ModernVBertForMaskedLM(看图填词,官方示例入口)
结构为 base + ModernVBertPredictionHead + lm_head:
ModernVBertPredictionHead:继承 ModernBert 的预测头实现(modular 中class ModernVBertPredictionHead(ModernBertPredictionHead): pass),由 Dense → 激活 → LayerNorm 组成(modeling_modernvbert.py);lm_head:nn.Linear(hidden_size, vocab_size, bias=text_config.decoder_bias),负责把表征映射回词表做词元预测;- 掩码 token 与图像 token 均不参与 loss 计算:docstring 明确
labels中值为image_token_id的位置会被忽略,loss 只在普通文本标签上计算(modeling_modernvbert.py); - 词嵌入可按需与输出层解耦:
_tied_weights_keys记录了lm_head.weight与文本嵌入tok_embeddings.weight之间的绑定关系(modeling_modernvbert.py)。
4.3 ModernVBertForSequenceClassification(图文序列分类)
- 在基础模型之上堆叠预测头 + Dropout +
nn.Linear(hidden_size, num_labels); - 关键差异在池化策略:
classifier_pooling="cls"时取序列首位置;"mean"时用attention_mask做加权平均,同时兼容inputs_embeds与input_ids两种入口并自动补全缺失的掩码(modeling_modernvbert.py); - 自动根据
labels的形态推断problem_type(regression/single_label_classification/multi_label_classification)并选择 MSELoss / CrossEntropyLoss / BCEWithLogitsLoss。
4.4 ModernVBertForTokenClassification(词元级标注)
- 结构同序列分类(
head → Dropout → classifier),但对last_hidden_state的每个位置独立做分类,返回(batch_size, seq_len, num_labels)的 logits,适合文档版 NER、版面元素标注等视觉词元任务(modeling_modernvbert.py)。
4.5 支持的后端与测试覆盖
ModernVBertPreTrainedModel 声明了完整的高级注意力后端支持:_supports_flash_attn、_supports_sdpa、_supports_flex_attn、_supports_attention_backend 均为 True,同时 supports_gradient_checkpointing = True、input_modalities = ("image", "text")(modeling_modernvbert.py),与官方文档顶部 FlashAttention/SDPA 徽章呼应。测试套件还注册了如下 pipeline 映射:feature-extraction、fill-mask、text-classification、image-classification、token-classification、zero-shot(test_modeling_modernvbert.py),意味着可直接通过 transformers.pipeline 零配置调用。四个类的前向输出形状均有单元测试断言覆盖(如 logits 形状 (batch, seq, vocab) / (batch, num_labels)),可作为你自行验证实现的对照。
五、端到端实战:加载模型进行"看图填词"推理
以下是 官方模型文档 中的 Python 示例,已按源码补全必要说明,可直接复制运行。它演示的是模型最核心的用法:给定"图 + 带 [MASK] 文本",让模型根据图像内容预测被遮住单词。
import torch
from huggingface_hub import hf_hub_download
from PIL import Image
from transformers import AutoModelForMaskedLM, AutoProcessor
processor = AutoProcessor.from_pretrained("./mvb")
model = AutoModelForMaskedLM.from_pretrained("./mvb", device_map="auto")
image = Image.open(
hf_hub_download("HuggingFaceTB/SmolVLM", "example_images/rococo.jpg", repo_type="space")
)
text = "This [MASK] is on the wall."
# 用对话模板组织多模态消息({"type": "image"} + {"type": "text"})
messages = [
{
"role": "user",
"content": [
{"type": "image"},
{"type": "text", "text": text},
],
},
]
# 先套用 chat template 得到含 <image> 占位符的提示词,再统一编码
prompt = processor.apply_chat_template(messages)
inputs = processor(text=prompt, images=[image], return_tensors="pt").to(model.device)
# 推理(编码器模型,无需生成循环)
with torch.no_grad():
outputs = model(**inputs)
# 定位 [MASK] 位置并取词表上的 argmax
masked_index = inputs["input_ids"][0].tolist().index(processor.tokenizer.mask_token_id)
predicted_token_id = outputs.logits[0, masked_index].argmax(axis=-1)
predicted_token = processor.tokenizer.decode(predicted_token_id)
print("Predicted token:", predicted_token) # Predicted token: painting
运行要点与源码佐证:
- 路径说明:官方示例用本地目录
./mvb表示已下载好的权重与处理器文件;实际使用也可直接传 Hub 上的模型标识(如"ModernVBERT/modernvbert")。测试套件在 test_modeling_modernvbert.py 中正是用AutoProcessor.from_pretrained、AutoTokenizer.from_pretrained与ModernVBertForMaskedLM.from_pretrained三件套加载该模型的真实 checkpoint 做集成验证; - Auto API 可用性:
AutoModelForMaskedLM(映射到modernvbert→ModernVBertForMaskedLM)、AutoProcessor(modernvbert→Idefics3Processor)等 Auto 映射均已注册,见 modeling_auto.py 与 processing_auto.py,因此无需手工 import 具体类; - chat template 缺省行为:官方推理示例未显式传
add_generation_prompt,而集成测试中传add_generation_prompt=False(test_modeling_modernvbert.py),说明对编码器 MLM 任务应关闭生成提示(不加 assistant 开场); - 交互式核验:上述代码最后用
argmax输出单一最可能词;测试中则用softmax + topk核对了前 5 个候选词的概率分布(test_modeling_modernvbert.py),读者可仿照该写法获取多候选及置信度; - 数据精度:模型权重加载时可指定
torch_dtype(集成测试使用float32),get_image_features内部也会把pixel_values统一到模型 dtype 以保证 fp16 等低精度兼容(modeling_modernvbert.py)。
六、接入下游任务:分类与词元标注示例
在完成预训练/微调后,ModernVBertForSequenceClassification 与 ModernVBertForTokenClassification 可直接用于图文分类与视觉词元标注。二者加载与调用模式相同:
from transformers import AutoModelForSequenceClassification, AutoProcessor
import torch
processor = AutoProcessor.from_pretrained("./mvb")
# 注意分类模型需显式指定标签数(或从模型配置读取 num_labels)
model = AutoModelForSequenceClassification.from_pretrained("./mvb", num_labels=2)
model.eval()
# 组装与前面一致的 messages(image + text)
# ...
inputs = processor(text=prompt, images=[image], return_tensors="pt")
with torch.no_grad():
outputs = model(**inputs) # outputs.logits: (batch, num_labels)
label_id = outputs.logits[0].argmax().item()
源码层面的三类 head 差异已在第四节详述,这里再补充两点与训练/微调相关的实现事实:
- 分类与词元分类头均先经
ModernVBertPredictionHead(Dense → 激活 → LayerNorm)再经Dropout(config.classifier_dropout)后进线性分类层(modeling_modernvbert.py 与 modeling_modernvbert.py); - 各新增头部使用截断正态分布初始化,其标准差按部位缩放:MLM 头与 Connector 投影使用
initializer_range / sqrt(2 * text_config.num_hidden_layers),分类头使用initializer_range / sqrt(text_config.hidden_size)(modeling_modernvbert.py),截断边界统一由initializer_cutoff_factor控制。
七、典型应用场景与延伸
结合论文定位与仓库结构,ModernVBert 面向的典型应用包括:
- 视觉文档检索底座:作为 ColModernVBert 检索模型的基础双塔编码器(源码注释明确说明),适合把"文档页面截图/版面图"与"文本查询"统一编码后做向量匹配;
- 看图填空 / 图文互释:利用
ModernVBertForMaskedLM让 [MASK] 处的文本 token 通过注意力读取图像上下文完成预测(如官方示例的 rococo 画作中预测出painting); - 版面级理解:序列/词元分类头可支撑文档页分类、区域/实体标注等视觉词元级任务。
如需继续深挖,仓库内可供研读的权威材料有:源码主体 modeling_modernvbert.py、可编辑的模块化定义 modular_modernvbert.py、配置定义 configuration_modernvbert.py 及完整测试与真实 checkpoint 集成验证 test_modeling_modernvbert.py;文本与视觉主干分别参考 ModernBert 与 SigLIP 文档。
结语
ModernVBert 提供了一条"紧凑双塔 + 像素重排压缩视觉 token + 纯掩码目标"的视觉文档编码路径:把 SigLIP 的视觉 patch 通过 pixel shuffle 降到最少 token 数,再以 ModernBert 完成图文联合双向编码,最终以轻量 MLM 头/分类头适配多种检索与理解任务。本文从官方文档出发、以源码为证据,完整还原了它的配置体系、四阶段数据流、四类模型结构与端到端用法。实际落地时,建议结合自身文档分辨率换算 image_seq_len 预算、合理选择 pixel_shuffle_factor,并通过 Auto API 统一加载 checkpoint 与处理器,即可快速复现"看图填词"乃至构建专属的视觉文档检索/理解管线。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0627
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00