首页
/ Transformers 中的 GroupViT 模型指南:基于文本监督的分组视觉 Transformer 与零样本语义分割

Transformers 中的 GroupViT 模型指南:基于文本监督的分组视觉 Transformer 与零样本语义分割

2026-09-07 15:35:18作者:伍霜盼Ellen

GroupViT(Grouping Vision Transformer)是 🤗 Transformers 中一类核心用于零样本语义分割的视觉-语言模型,通过图像文本对比学习自动习得分组能力。本文以仓库 docs/source/en/model_doc/groupvit.md 文档为骨架,结合 configuration_groupvit.pymodeling_groupvit.py 源码展开,帮助读者掌握 GroupViT 的架构原理、三类配置对象、五类公开 API 的用法,并给出可直接复制的零样本语义分割推理示例。

GroupViT 模型概述

GroupViT 于论文 GroupViT: Semantic Segmentation Emerges from Text Supervision 中提出,作者为 Jiarui Xu、Shalini De Mello、Sifei Liu、Wonmin Byeon、Thomas Breuel、Jan Kautz、Xiaolong Wang。该模型由 NVIDIA 研究团队提出,由社区贡献者 xvjiarui 贡献到 Hugging Face Transformers,模型页于 2022-02-22 发布在 HF papers 上,2022-06-28 正式合入 Transformers。

CLIP 启发,GroupViT 属于视觉-语言(vision-language)模型,能在任意给定类别词汇上执行零样本语义分割,即无需针对分割任务微调、也不需要任何像素级标注。

论文核心思想

论文摘要指出:分组(grouping)与识别(recognition)是视觉场景理解的重要组成部分,例如目标检测和语义分割。在端到端深度学习中,图像区域的分组通常通过像素级识别标签的自上而下监督隐式发生。而 GroupViT 的做法是将分组机制重新引入深度网络,使得语义片段仅通过文本监督即可自动涌现。

具体而言,作者提出层级化的分组视觉 Transformer(hierarchical Grouping Vision Transformer),它超越了常规的规则网格(regular grid)表征,学习将图像区域逐步分组为越来越大的任意形状片段。模型在大型图像-文本数据集上使用对比损失与文本编码器联合训练,在没有任何像素级标注的条件下,学会了将语义区域分组到一起,并以零样本方式成功迁移到语义分割任务。论文报告的数据为:在 PASCAL VOC 2012 上取得 52.3% mIoU、在 PASCAL Context 上取得 22.4% mIoU,性能可与需要更高监督程度的 SOTA 迁移学习方法相当。注意上述分割精度是论文原文的实验数据,仅在论文语境下成立,具体复现请以实际权重与评测脚本为准。

架构组件与源码位置

GroupViT 在仓库中的代码分为三个文件:

  • 配置:src/transformers/models/groupvit/configuration_groupvit.py
  • 建模:src/transformers/models/groupvit/modeling_groupvit.py
  • 权重转换脚本:src/transformers/models/groupvit/convert_groupvit_nvlab_to_hf.py(用于将 NVlabs 官方仓库的权重转换为 HF 格式)
  • 测试:tests/models/groupvit/test_modeling_groupvit.py

modeling_groupvit.py 顶部可以清晰看到 GroupViT 的三个核心思想组件:

1. 文本侧(GroupViTTextTransformer):结构与 CLIP 文本编码器基本一致,代码注释明确标注 # Copied from transformers.models.clip.modeling_clip.CLIPTextEmbeddings with CLIP->GroupViT,词表大小默认 49408(对应 CLIP BPE 词表),max_position_embeddings 默认 77。文本侧以 EOS token 位置处的 hidden state 作为池化输出(见 GroupViTTextTransformer.forward 中基于 eos_token_id 的 argmax 取特征逻辑)。

2. 视觉侧(GroupViTVisionTransformer):这是与普通 ViT 最大的不同点。它在 GroupViTVisionEncoder 内按 depths 划分成多个 GroupViTStage(对应论文中的 Grouping Layer),每个 stage 内部由若干 GroupViTEncoderLayer(Transformer 层)+ 一个 GroupViTTokenAssign 分组下采样模块构成。

3. 投影与对比损失(GroupViTModel):视觉与文本侧各自经过 visual_projection / text_projection 两层 MLP(中间含 BatchNorm1d 与 ReLU),得到共同嵌入空间的特征,随后做归一化与余弦相似度计算;return_loss=True 时通过 image_text_contrastive_loss 计算对称的对比损失(该函数 Copied from transformers.models.clip.modeling_clip)。

关键的分组机制实现

  • GroupViTGroupRepresentation:负责将视觉特征分组为语义段。
  • GroupViTAssignAttentionmodeling_groupvit.py L160 附近):分组注意力。其 get_attn 在训练阶段使用 gumbel_softmax(..., dim=-2, hard=hard)(gumbel-softmax 松弛 + 直通估计),推理阶段退化为 hard_softmax 或普通 softmax;同时用 assign_eps 做数值稳定(attn / (attn.sum(...) + assign_eps))。
  • GroupViTTokenAssign:stage 末尾的"下采样"模块,将 num_group_tokens 个 group token 通过 project_group_token(Mixer MLP)投影为 num_output_groups 个,再以 assign attention 将图像 token 聚合到这些组上。
  • hard_softmax / gumbel_softmax:硬分配 + 直通梯度(straight-through),保证"每个图像区域只能属于一个语义组"的离散分组可反向传播。
  • get_grouping_from_attentions:将各 stage 的注意力图逐级矩阵相乘,得到从最高分辨率 patch 到最终语义组的分组图(grouping map),其形状为 [batch_size, num_groups, height, width],这是零样本分割 logits 的关键。

与 CLIP 的关键差异

GroupViT 视觉编码器不采用 [CLS] token,测试代码中有明确注释 # no [CLS] token for GroupViT(见 test_modeling_groupvit.py)。视觉特征经过最后一级 stage 后,把剩余 token 的均值作为池化输出(pooled_output = last_hidden_state.mean(dim=1))。正因为保留了"分组后 token 与原始 patch 的对应关系",模型才能输出空间上的分组图,从而支撑分割任务。

配置类详解

GroupViT 使用组合式配置结构:GroupViTConfig 是顶层配置,内部以 sub_configs = {"text_config": GroupViTTextConfig, "vision_config": GroupViTVisionConfig} 组合两个子配置。三者都继承自 PreTrainedConfig,可序列化为 JSON 并随权重保存。

GroupViTTextConfig(文本子配置)

对应默认检查点为 nvidia/groupvit-gcc-yfcc。其主要参数及源码默认值(configuration_groupvit.py):

参数 默认值 说明
vocab_size 49408 词表大小,与 CLIP BPE 词表一致
hidden_size 256 文本 Transformer 隐层维度
intermediate_size 1024 FFN 中间层维度
num_hidden_layers 12 Transformer 层数
num_attention_heads 4 注意力头数
max_position_embeddings 77 最大序列长度(CLIP 风格,与 padding 到 77 的 tokenizer 配套)
hidden_act "quick_gelu" 激活函数,文本侧用 quick GELU
layer_norm_eps 1e-5 LayerNorm epsilon
dropout / attention_dropout 0.0 dropout 概率
initializer_range / initializer_factor 0.02 / 1.0 权重初始化参数
pad_token_id 1 padding token id
bos_token_id 49406 BOS token id
eos_token_id 49407 EOS token id(池化取特征的位置)

model_type = "groupvit_text_model",且设置了 base_config_key = "text_config"

GroupViTVisionConfig(视觉子配置)

视觉侧的关键在于描述分组层级结构的四个参数(源码默认值):

参数 默认值 说明
depths [6, 3, 3] 每个 stage 的编码层数
num_group_tokens [64, 8, 0] 每个 stage 的 group token 数量
num_output_groups [64, 8, 8] 每个 stage 的输出组数量,0 表示无分组
assign_eps 1.0 assign attention 中归一化使用的 epsilon
assign_mlp_ratio [0.5, 4] 用于推断分组 MLP 隐层维度的比例

视觉侧其余参数:

参数 默认值 说明
hidden_size 384 视觉 Transformer 隐层维度
intermediate_size 1536 FFN 中间层维度
num_hidden_layers 12 总层数,必须等于 sum(depths),配置类在 validate_architecture 中校验并在不一致时告警
num_attention_heads 6 注意力头数
image_size 224 输入图像尺寸
patch_size 16 patch 尺寸(每 patch 16×16,224 图像得到 14×14=196 个 patch)
num_channels 3 输入通道数
hidden_act "gelu" 视觉侧激活函数
layer_norm_epsdropout 与文本侧类似 常规超参

model_type = "groupvit_vision_model"base_config_key = "vision_config"

理解 depths=[6,3,3]num_group_tokens=[64,8,0]num_output_groups=[64,8,8] 的含义,只需对照 GroupViTVisionEncoder 的构建循环:第 1 个 stage(depth 6)持 64 个 group token 并从 196 个 patch 聚合出 64 个输出组;第 2 个 stage(depth 3)接收上一 stage 的 64 组 token,投影为 8 个 group token 并输出 8 个更粗的语义组;第 3 个 stage(depth 3)无 group token(num_output_groups=8 时 downsample 分支依条件关闭)。token 数量沿层级逐级减少而语义粒度逐级变粗,最终 8 个输出组对应图像中若干主要语义区域。

GroupViTConfig(顶层组合配置)

参数 默认值 说明
projection_dim 256 文本/图像投影后的共同嵌入维度
projection_intermediate_dim 4096 投影层(两层 MLP)的中间层维度
logit_scale_init_value 2.6592 可学习 logit 缩放参数的初始值(对应 self.logit_scale.exp() 的初始化)
output_segmentation False 前向时是否返回分割 logits
text_config / vision_config None 两个子配置;为 None 时自动初始化为默认子配置

model_type = "groupvit"。在 __post_init__ 中,顶层配置会处理三种传入方式并兼容旧版 text_config_dict / vision_config_dict 关键字(存在键冲突时以 dict 中的值为准并记录日志),最终统一构造出 GroupViTTextConfigGroupViTVisionConfig 实例。

模型类与前向用法

GroupViT 共暴露 5 个模型类(顶层入口在 src/transformers/models/groupvit/__init__.py):

  • GroupViTModel:完整双塔模型,用于对比学习、图像文本检索与零样本分割;
  • GroupViTTextModel:仅文本塔;
  • GroupViTVisionModel:仅视觉塔。

三者均继承 GroupViTPreTrainedModel(基于 PreTrainedModel),支持 from_pretrainedsave_pretrained、梯度检查点(supports_gradient_checkpointing = True)等标准能力。

GroupViTModel

这是最常用的入口,核心方法:

  • forward:接收 input_idspixel_valuesattention_maskposition_ids,可选 return_lossoutput_attentionsoutput_hidden_statesoutput_segmentation。返回 GroupViTModelOutput,其中:
    • lossreturn_loss=True 时的对比损失;
    • logits_per_image / logits_per_text:图像与文本之间的相似度分数(由 L2 归一化嵌入做矩阵乘再乘以 logit_scale.exp() 得到);
    • image_embeds / text_embeds:投影并归一化后的嵌入;
    • segmentation_logitsoutput_segmentation=True 时的逐像素分类分数;
    • text_model_output / vision_model_output:两个子塔的完整输出。
  • get_text_features:只提取文本侧投影后的特征(应用于下游检索或最近邻分类);
  • get_image_features:只提取图像侧投影后的特征。

最常用的零样本图像分类示例(与 CLIP 完全一致的范式,复制自 modeling_groupvit.py docstring):

from transformers import AutoProcessor, GroupViTModel
from transformers.image_utils import load_image

model = GroupViTModel.from_pretrained("nvidia/groupvit-gcc-yfcc")
processor = AutoProcessor.from_pretrained("nvidia/groupvit-gcc-yfcc")

image = load_image("http://images.cocodataset.org/val2017/000000039769.jpg")
inputs = processor(
    text=["a photo of a cat", "a photo of a dog"], images=image, return_tensors="pt", padding=True
)

outputs = model(**inputs)
logits_per_image = outputs.logits_per_image  # image-text similarity
probs = logits_per_image.softmax(dim=1)  # label probabilities

输出分割 logits:output_segmentation=True

这是文档"Usage tips"中特别强调的用法:在 GroupViTModel 的 forward 中传入 output_segmentation=True,即可得到输入文本类别对应的分割 logits。源码中该选项会自动打开 output_attentionsif output_segmentation: output_attentions = True),随后经过一条完整流水线(modeling_groupvit.py L1285 附近):

  1. vision_outputs.last_hidden_state 取出分组后的组级特征 image_group_embeds(形状 [B, num_group, hidden])并投影;
  2. get_grouping_from_attentions 把各 stage 的注意力图链式相乘并上采样,得到与原始图像分辨率一致的分组图[B, num_group, H, W]);
  3. 组级特征与每条文本嵌入求相似度得 logits_per_image_group,再与分组图做矩阵乘并 reshape 为 [B, text_batch, H, W],即 segmentation_logits

需要注意GroupViTModelOutput 的 docstring 给出重要警告——分割 logits 的尺寸不一定与传入的 pixel_values 相同(避免在特征图上做两次插值损失质量),读者应在后处理时检查 logits 形状并按需上采样到原图尺寸。分组图的实际空间尺寸由输入图像与 patch 数共同决定。

GroupViTTextModel

仅文本编码器,返回 BaseModelOutputWithPoolinglast_hidden_state + pooler_output)。其分词器使用 CLIPTokenizer(该模型无自有 tokenizer,沿用 CLIP 的 BPE tokenizer,参见源码 docstring):

from transformers import CLIPTokenizer, GroupViTTextModel

tokenizer = CLIPTokenizer.from_pretrained("nvidia/groupvit-gcc-yfcc")
model = GroupViTTextModel.from_pretrained("nvidia/groupvit-gcc-yfcc")

inputs = tokenizer(["a photo of a cat", "a photo of a dog"], padding=True, return_tensors="pt")
outputs = model(**inputs)
last_hidden_state = outputs.last_hidden_state
pooled_output = outputs.pooler_output  # pooled (EOS token) states

GroupViTVisionModel

仅视觉编码器,同样返回 BaseModelOutputWithPooling(视觉侧 pooled output 为分组后 token 的均值)。预处理使用 AutoProcessor(对应 CLIPProcessor,图像侧按 CLIP 归一化统计量处理):

from PIL import Image
from io import BytesIO
import httpx
from transformers import AutoProcessor, GroupViTVisionModel

processor = AutoProcessor.from_pretrained("nvidia/groupvit-gcc-yfcc")
model = GroupViTVisionModel.from_pretrained("nvidia/groupvit-gcc-yfcc")

url = "http://images.cocodataset.org/val2017/000000039769.jpg"
with httpx.stream("GET", url) as response:
    image = Image.open(BytesIO(response.read()))

inputs = processor(images=image, return_tensors="pt")
outputs = model(**inputs)
last_hidden_state = outputs.last_hidden_state
pooled_output = outputs.pooler_output

零样本语义分割的完整推理

将以上能力组合起来,即得到与文档导向一致的核心用法——用任意类别词汇做分割:

from transformers import AutoProcessor, GroupViTModel
import torch

model = GroupViTModel.from_pretrained("nvidia/groupvit-gcc-yfcc")
processor = AutoProcessor.from_pretrained("nvidia/groupvit-gcc-yfcc")

image = load_image("path/to/image.jpg")  # 任意输入图像
texts = ["cat", "dog", "background"]     # 任意给定的类别词汇

inputs = processor(text=texts, images=image, return_tensors="pt", padding=True)
with torch.inference_mode():
    outputs = model(**inputs, output_segmentation=True)

seg_logits = outputs.segmentation_logits            # [1, num_texts, H, W]
seg_pred = seg_logits.argmax(dim=1)                 # [1, H, W] 逐像素类别

这里 seg_logits 的第 0 维对应当前 batch 内单张图像,第 1 维与文本类别一一对应;argmax(dim=1) 即得到逐像素的类别图。类别词汇完全由使用者在推理时给出,体现了"零样本"的特性——模型训练阶段从未见过这些类别名对应的像素标注。

预训练检查点与权重转换

源码与文档中使用的官方检查点为 nvidia/groupvit-gcc-yfcc(在 GCC+YFCC 大规模图文数据集上训练)。从转换脚本 convert_groupvit_nvlab_to_hf.py 可见其支持两种权重名称:groupvit-gcc-yfccgroupvit-gcc-redcaps。该脚本供权重复现使用:将 NVlabs 官方格式的 state_dictrename_key / convert_state_dict 映射为 HF 命名后,调用 convert_groupvit_checkpoint 导出(可选 push_to_hub 上传 Hub),普通用户直接 from_pretrained 即可。

测试文件 test_modeling_groupvit.py 覆盖了视觉塔、文本塔与整模型的前向、注意力、池化、配置一致性等标准检查项,可作为理解各子模块输入输出形状与 API 契约的参考。

零样本迁移的关键机制总结

最后将"从文本监督到像素级分割"的实现链条归纳如下(全部可在 modeling_groupvit.py 中逐行对应):

  1. 图像经 patch embedding(Conv2d,kernel=stride=patch_size)切分为 patch 序列,加上可学习位置编码;不使用 [CLS] token
  2. 每个 GroupViTStage 由若干 Transformer 层 + GroupViTTokenAssign 组成。Assign 模块先做 cross attention(GroupViTCrossAttentionLayer)让 group token 读取图像全局信息,再用 GroupViTAssignAttention 依据 group token 对图像 patch 做硬分配(训练用 gumbel-softmax、推理用 hard-softmax),把图像 token 聚合为更少、更粗的分组;
  3. 多级分组使 token 从 196 → 64 → 8 逐级变少,语义从 patch 级聚合到片段级,这是"分组机制"在架构层面的落地;
  4. 文本侧编码类别描述,两塔通过投影层进入同一 256 维嵌入空间,训练时用对称对比损失约束图像整体与文本语义对齐(image_text_contrastive_loss,实现与 CLIP 相同);
  5. 推理零样本分割时,把各级注意力图相乘得到每个原始 patch 到 8 个语义组的软分组(grouping map),将每个组的图像嵌入与文本嵌入的相似度分数"分配回"各像素,即得逐类别分割 logits。

正因上述设计与任意文本类别的对齐,GroupViT 才能做到不需要任何像素级标注、也不需要下游微调,直接在推理阶段对任意类别词汇输出语义分割结果。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
898
5.82 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
921
1.84 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.8 K
1.02 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
531
596
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.02 K
519
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.36 K
1.46 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
391