See What I Mean: Aligning Vision and Language Representations for Video Fine-grained Object Understanding

Paper: arXiv:2605.18018 Code: HumanMLLM/SWIM Code reference: main @ 1b97d22f (2026-05-20)

1. Motivation(研究动机)

现有 Video MLLM 在“整段视频发生了什么”这一类全局理解任务上已经很强,但在“请描述视频里那个穿棕色衣服的男人 / 某个被语言指代的对象”这种细粒度对象理解上仍然有两个断层。第一,很多强细粒度方法依赖显式 visual prompts,例如 point、box、mask 或额外 region encoder;这能告诉模型目标在哪里,但推理时用户必须额外提供视觉提示,不符合真实交互里“只用自然语言指代对象”的常见方式。第二,通用 MLLM 即使能读懂属性词,也未必能把 object noun 稳定绑定到正确 visual tokens:论文对 Qwen2.5-VL 的 cross-attention 可视化显示,颜色、纹理等 attribute words 往往在视觉区域上更尖锐,而 object nouns 的激活更分散。

Figure 1 解读:传统 fine-grained model 把 mask/point/box 当作推理时的硬提示,模型从视觉提示定位对象;SWIM 则希望训练后让模型从纯文本里的 referring expression 自己找对象。因此本文不是再加一个 detector 或 region encoder,而是把 mask supervision 留在训练阶段,用它纠正语言 token 与视觉区域的绑定。

本文要解决的具体问题是:在不改变基础 MLLM 架构、推理时不输入 mask/point/box 的前提下,让模型能够从自然语言 reference 中锁定视频内指定对象,并围绕该对象回答外观、动作、时序变化和关系问题。这个问题值得做,因为细粒度对象理解是视频助手从“场景描述器”变成“可交互视觉助手”的关键:用户真正关心的往往不是整段视频,而是其中某个对象是否在移动、穿什么、与谁互动、下一步会怎样。

Figure 2 解读:图中比较 Qwen2.5-VL 与 SWIM 对 object nouns 和 attribute words 的 cross-attention。基线模型对 brownbeardbaseball cap 等属性词能产生较局部的热点,但对 man 这类高层名词容易扩散到背景或多个实体;SWIM 训练后 noun attention 更集中,说明方法针对的不是普通答案质量,而是“文本里哪个词对应视频里哪个区域”的 alignment gap。

2. Idea(核心思想)

核心洞察:如果 object noun 在 MLLM 的 cross-attention 中没有自然形成局部峰值,那么可以在 supervised fine-tuning 时直接把该 noun token 的 attention map 当成可监督对象,用实例 mask 约束它聚焦到正确区域;推理时删掉 mask,只保留已经被训练出来的语言到视觉区域的内隐绑定能力。

SWIM 的创新可以压缩成两件事:一是构造 NL-Refer,把原 VideoRefer 中 <region> / visual-prompt 风格的对象指代改写成自然语言 referring expression,并用 <ins>...</ins> 标出最关键的 object noun;二是在 Qwen2.5-VL 的训练中抽取这些 noun token 到 visual tokens 的多层 attention map,用 ground-truth mask 加 BCE-style attention loss。与 VideoRefer、PixelRefer、DAM 等依赖推理时 visual prompt 的方法不同,SWIM 的 mask 只在训练中作为 alignment regularizer 出现,推理输入仍是普通 video + text。

3. Method(方法)

3.1 Overall framework:从 NL-Refer 到 attention supervision

Figure 3 解读:SWIM pipeline 分成三段:先把带 <region> 的 VideoRefer 数据改写成自然语言指代,并标出 <ins>object noun</ins>;再把 video/text 输入 MLLM,定位被标记 noun 在 token 序列中的位置;最后从指定 decoder layers 取 noun-to-vision cross-attention,和目标 mask 对齐。直觉上,这相当于告诉模型:“你生成关于这个对象的回答时,负责指代对象的那个词应该真的看向该对象。”

整体数据可写成: 其中 是视频, 是改写后的用户问题, 是目标对象的回答, 是目标对象在相关帧上的 binary instance mask。论文正文强调 NL-Refer 来自 VideoRefer-700K 的 detailed-caption subset,共约 125K videos;released README / data config 还包含 refined-format-videorefer-qa-0-10k.json 与 LLaVA-Video supplementary data。

3.2 NL-Refer:把 visual prompt 改成可监督的语言指代

原 VideoRefer 样本里常见的问题形式是“marked area / <region>”,这对 visual-prompt 方法友好,但没有显式告诉模型“这个区域对应文本里的哪个 noun”。SWIM 用 GPT-4o 根据配对的 assistant response 把 placeholder 改写成简洁、无歧义的 referring expression ,并在其中选出单个最能代表目标实例的 noun ,用 <ins> delimiter 包起来。这样一个样本同时具有:自然语言 reference、可定位 token span、目标 mask 三者的确定对应关系。

这个设计避免了两个常见失败:如果只保留 mask,模型无法学习“man / dog / cup”等词在语言空间里的指代规律;如果只做普通 SFT,模型可能答对大意,但 attention 仍然分散,遇到相似对象时容易把属性或动作归到错误实例上。

3.3 Cross-attention alignment loss

训练时把 tokenize 成长度 的文本序列,设被 <ins> 标出的 noun token 位置为 。在第 个 cross-attention module 中,令 noun token 的 query 为 ,视觉 token keys 为 ,则 noun-to-visual attention 为: 随后把 reshape / interpolate 到与 mask 对齐的空间网格 。论文公式写作从 layer set 做简单平均: 最后用 pixel-wise BCE 让 attention map 接近 mask: **论文公式与 released code 实现差异:**论文 method 写的是对多层 attention 做 mean aggregation,Table 4 也显示 Mean fusion 的 Avg. 为 3.78;但 main@1b97d22fmodeling_qwen2_5_vl.pyextract_and_fuse_attentions 中对 layers [2, 7, 12, 17, 22, 27] 先跨 head 平均,再对 layer stack 做 torch.prod(stacked, dim=0),最后按行归一化。released code 的训练总 loss 也不是论文里单独写出的 BCE,而是 loss = text_loss * 0.05 + loss_mask;其中 loss_mask 调用的是 BCE 函数,代码注释仍写“mIoU Loss”。

3.4 Released code 路径下的实际训练数据流

LazySupervisedDataset 从 YAML 读取多个 JSON shards;VideoRefer 样本会被转成 Qwen conversation:system prompt 强调 grounding,user content 包含 video/image 与 text prompt,assistant content 使用原回答。collate_fn 再做四件关键事情:

  • 从 chat template 文本中解析 <ins>...</ins>,记录同一词在全局文本中第几次出现,然后删除 <ins> 标签,避免标签本身进入普通语言建模目标。
  • <|vision_end|> 分隔视觉 token 与后续文本,把 attn_labels 中视觉前缀置为 -100,pad/image token 置为 -101
  • 对每个 <ins> 内容重新 tokenize,在 input ids 中找到对应 occurrence,把 ins_contents_labels 标成实例 id。
  • 若样本携带 object_masksprocess_vision_info 会把 mask frame indices 强制包含在视频采样帧里;vision_process.py 内部返回 sample_index_inputs(来自 fetch_videomask list),在 collate_fn 中被赋值为 mask_index,再把 ins_masksmask_indexins_contents_labels 一起传入 Qwen2.5-VL forward。

3.5 PyTorch-style pseudocode(基于 released code)

def parse_ins_tags_and_build_labels(text, tokenizer, input_ids):
    spans = re.finditer(r"<ins>(.*?)</ins>", text)
    ins_contents, occurrence = [], defaultdict(int)
    for m in spans:
        word = m.group(1)
        if m.start() > 0 and text[m.start() - 1] == " ":
            word = " " + word
        occurrence[word] += 1
        ins_contents.append((word, occurrence[word]))
 
    clean_text = re.sub(r"</?ins>", "", text)
    ins_labels = torch.full_like(input_ids, -101)
    for instance_id, (word, target_occ) in enumerate(ins_contents):
        word_ids = tokenizer(word)["input_ids"]
        seen = 0
        for pos in range(input_ids.numel() - len(word_ids) + 1):
            if torch.equal(input_ids[pos:pos + len(word_ids)], torch.tensor(word_ids)):
                seen += 1
                if seen == target_occ:
                    ins_labels[pos:pos + len(word_ids)] = instance_id
                    break
    return clean_text, ins_labels
def fuse_multilayer_attention(attentions, target_layers=(2, 7, 12, 17, 22, 27)):
    selected = []
    for layer_idx in target_layers:
        # released code shape comment: (batch, k_len, n_heads, q_len)
        layer_attn = torch.stack(attentions[layer_idx])
        layer_attn = layer_attn.mean(dim=2)      # mean over heads
        layer_attn = layer_attn.transpose(1, 2)  # (batch, q_len, k_len)
        layer_attn = layer_attn[:, :-1]          # drop last query token
        selected.append(layer_attn)
    fused = torch.prod(torch.stack(selected, dim=0), dim=0)
    return fused / (fused.sum(dim=-1, keepdim=True) + 1e-6)
def collect_attention_mask_pairs(fused_attn, ins_label_indices, ins_labels,
                                 mask_index, ins_masks, video_grid_thw,
                                 merge_size=2):
    pairs = []
    for b in range(fused_attn.size(0)):
        T = int(video_grid_thw[b, 0])
        H = int(video_grid_thw[b, 1]) // merge_size
        W = int(video_grid_thw[b, 2]) // merge_size
        attn_per_word = fused_attn[b].view(-1, T, H * W)
        for word_pos in ins_label_indices[b].view(-1).tolist():
            instance_id = int(ins_labels[b][word_pos])
            for frame_idx, mask_dict in ins_masks[b][instance_id].items():
                frame_positions = [p for p, val in enumerate(mask_index[b]) if str(val) == str(frame_idx)]
                for frame_pos in frame_positions:
                    pred = attn_per_word[word_pos, frame_pos].view(H, W)
                    pred = (pred - pred.min()) / (pred.max() - pred.min() + 1e-6)
                    gt = torch.as_tensor(mask_dict["mask"], dtype=pred.dtype, device=pred.device)
                    pred = F.interpolate(pred[None, None], size=gt.shape, mode="bilinear", align_corners=False)[0, 0]
                    pairs.append((pred, gt))
    return pairs
def swim_training_loss(logits, labels, pairs):
    text_loss = F.cross_entropy(logits[:, :-1].reshape(-1, logits.size(-1)),
                                labels[:, 1:].reshape(-1), ignore_index=-100)
    if not pairs:
        return 0.05 * text_loss
    mask_loss = torch.stack([F.binary_cross_entropy(pred, gt.to(pred)) for pred, gt in pairs]).mean()
    return 0.05 * text_loss + mask_loss

Code reference: main @ 1b97d22f (2026-05-20) — pseudocode and mapping based on this commit

Paper ConceptSource FileKey Class/Function
NL-Refer / VideoRefer JSON 转 conversationQ-R1/src/open-r1-multimodal/src/open_r1/sft_videorefer_qwen25vl.pyLazySupervisedDataset, _maybe_apply_format_convert_videorefer
<ins> token 定位与 attention supervision labelsQ-R1/src/open-r1-multimodal/src/open_r1/sft_videorefer_qwen25vl.pyextract_ins_with_global_occurrence, collate_fn
视频帧采样并强制包含 mask 帧Q-R1/src/open-r1-multimodal/src/open_r1/data_process/vision_process.pyprocess_vision_info, fetch_video
多层 attention 融合与 pred/GT mask 配对transformers/src/transformers/models/qwen2_5_vl/modeling_qwen2_5_vl.pyextract_and_fuse_attentions, collect_pred_gt_pairs_from_fused_attn
BCE mask loss + language losstransformers/src/transformers/models/qwen2_5_vl/modeling_qwen2_5_vl.pycompute_bce_loss_from_pairs, forward

4. Experimental Setup(实验设置)

Datasets

  • NL-Refer training data:由 VideoRefer-700K detailed-caption subset 改写而来,正文写约 125K videos;released data config 包含四个 detailed-caption shards(0–12K、12–50K、50–100K filtered、100–125K)和 refined-format-videorefer-qa-0-10k.json
  • Supplementary SFT data:released data_config/videorefer.yaml 还加入 filtered_valid_llava_video_178k_1.3M_abspath_tts_a100_200k_new.json,README 称为 LLaVA-Video supplementary data。
  • VideoRefer-Bench-D:400 curated entries from Panda-70M,按 SC / AD / TD / HD 四个维度由 0–5 打分。
  • VideoRefer-Bench-Q:198 videos from DAVIS-2017 and MeViS,1,000 region-linked multiple-choice questions,含 Basic、Sequential、Relationship、Reasoning、Future 五类。
  • General benchmarks:MVBench、VideoMME、ActivityNet-QA,用来检查 SWIM 是否牺牲通用视频理解能力。

Baselines and metrics

Fine-grained 表中同时比较 generalist models 与 specialist models。generalist 包括 LongVU-7B、LongVA-7B、LLaVA-OV-7B、Qwen2-VL-7B、Qwen2.5-Omni-7B、InternVL2-26B、Qwen2.5-VL-7B、GPT-4o-mini、GPT-4o;specialist 包括 Elysium、Artemis、Osprey、Ferret、PAM、DAM、VideoRefer。VideoRefer-Q 用五类 multiple-choice accuracy 和 Avg.;VideoRefer-D 用 SC、AD、TD、HD 及 Avg.。Alignment analysis 还使用 GamePoint@P / GamePoint@K、AP、AUC、NSS、Precision:GamePoint 衡量高 attention 区域落在目标 mask 内的比例,AP/AUC/NSS/Precision 衡量 attention map 与 mask 的像素级一致性。

Training config(以 released config/launch script 为准)

  • Base model:README 与代码均指向 Qwen2.5-VL-7B-Instruct;inference model 发布在 BBBBCHAN/SWIM-7B
  • Actual launch scriptQ-R1/src/open-r1-multimodal/run_scripts/run_sft_videorefer_qwen25vl.sh 使用 torchrun --nproc_per_node=8--deepspeed local_scripts/zero3_offload.json--per_device_train_batch_size 1--gradient_accumulation_steps 4--bf16 true--torch_dtype bfloat16--gradient_checkpointing true--attn_implementation flash_attention_2--num_train_epochs 1--save_steps 300WANDB_MODE=offline
  • Vision / video preprocessing env:脚本设置 VIDEO_MAXRES=448VIDEO_MINRES=288MAXRES=1536PAD2STRIDE=1FORCE_NO_DOWNSAMPLE=1LOAD_VISION_EARLY=1
  • Learning rate caveat:README “Key Training Parameters” 写 learning rate 为 2e-5 with cosine schedule,但 actual launch script at main@1b97d22f 没有显式传入 --learning_rate;因此笔记只把它作为 README-reported value,不把它当作 launch-script-verified override。

5. Experimental Results(实验结果)

5.1 Fine-grained VideoRefer-Bench 主结果

MethodPromptVideoRefer-Q Avg.BasicSeq.Rel.Rea.Fut.VideoRefer-D Avg.SCADTDHD
Qwen2.5-VL-7BText71.878.069.758.279.973.23.244.333.192.882.58
GPT-4oText71.362.374.566.088.073.73.254.153.313.112.43
VideoRefer-7BMask71.975.468.659.389.478.13.464.443.273.103.04
DAM-8BPoint/Box/Mask3.684.693.613.343.03
SWIMText78.383.875.066.793.780.73.784.923.853.432.96

结论很直接:在只用 text prompt 的情况下,SWIM 在 VideoRefer-Q 平均 78.3%,比 Qwen2.5-VL-7B 的 71.8% 高 6.5 points,也超过需要 mask prompt 的 VideoRefer-7B;在 VideoRefer-D 上平均 3.78,超过 DAM-8B 的 3.68。HD 维度不是最高(VideoRefer-7B 3.04、DAM-8B 3.03,SWIM 2.96),说明 SWIM 的主要收益来自对象定位、外观和时序描述,而 hallucination 抑制并非所有维度都压倒 visual-prompt specialist。

5.2 General video benchmarks

MethodMVBenchVideoMMEActivityNet
VideoLLaMA254.647.950.2
VideoChat2-HD51.154.649.1
VideoLLaMA2.157.354.9-
LLaVA-Next-Video-46.553.5
LLaVA-Octopus51.755.753.4
INST-IT-54.055.2
VideoRefer59.655.9-
SWIM62.155.955.6

SWIM 在 MVBench 62.1、VideoMME 55.9、ActivityNet 55.6,说明 attention regularization 没有把模型过拟合到只会局部对象描述;至少在这三组 general benchmark 上,它保留了通用视频理解能力。

5.3 Ablations:层选择、融合方式、loss 函数

  • Layer selection:单层 supervision 从 layer 1/13/27 分别得到 3.43/3.48/3.52;三层 [1,13,27] 达 3.72;六层 [1,6,11,16,21,26][2,7,12,17,22,27] 都是 3.78;十四层为 3.77。结论是跨深度分散选层比只用单层更稳定,但层数继续增加收益很小。
  • Fusion method:Add 3.57,Pool 3.49,Prod. 3.55,Mean 3.78。论文结果支持 mean fusion,但 released code 当前采用 product fusion,这是上面标出的 paper-code gap。
  • Attention loss:mIoU 3.71,Focal 3.69,Dice 3.74,BCE 3.78;BCE 对稀疏 attention map 更直接,因为它逐像素惩罚背景误激活和目标区域低响应。

Figure 4 解读:数据量从 30K 到 125K mask-annotated samples 增加时,VideoRefer-D score 整体上升;图中标注的关键点包括 30K 为 3.23、50K 为 3.39、80K 为 3.69、100K 为 3.68、125K 为 3.78。100K 附近有小平台,但 125K 继续提升,说明这个训练信号还没有明显饱和。

5.4 Attention localization and alignment metrics

GamePoint@P 衡量 top attention pixels 是否落在 mask 内: Table 6 中 Qwen2.5-VL-7B 在 G.P.@P-1/5/10 上为 0.329/0.293/0.270,SWIM 为 0.392/0.348/0.317;最高 attention 点和 top-region 更常落在正确目标里。Appendix 的 GamePoint@K 也一致:Qwen2.5-VL-7B 在 K=1/5/10/50/100 为 0.330/0.328/0.331/0.330/0.329,SWIM 为 0.373/0.375/0.374/0.373/0.374。

Figure 6 解读:SWIM 在 AP、AUC、NSS、Precision 四个 text-visual alignment metrics 上都高于 Qwen2.5-VL:AP 0.26→0.30,AUC 0.62→0.67,NSS 0.39→0.50,Precision 0.28→0.39。这说明提升不是只体现在答案分数,而是 attention map 与目标 mask 的空间一致性也更强。

5.5 Qualitative comparison and robustness

Figure 5 解读:定性例子展示同一个 video/text reference 下,Qwen2.5-VL 的 attention 热点更容易覆盖多个对象或落在背景区域,而 SWIM 更集中在被语言指代的目标实例上。结合 Figure 2,这说明 SWIM 的收益不是简单 prompt engineering,而是训练时 noun-level grounding 被显式强化。

Appendix 还做了 synonym perturbation:把 VideoRefer-Bench-D prompt 中 <ins> 标注词替换成同义表达。Qwen2.5-VL-7B 从 2.97 提到 3.43(可能因为 prompt 更明确),SWIM 从 3.78 轻微降到 3.74;SWIM* 的 SC/AD/TD/HD 为 4.86/3.78/3.36/2.96,说明模型对同义自然语言指代有一定鲁棒性,但 TD、AD 有小幅下降。

5.6 Limitations and takeaways

论文没有单独的 Limitations section。可以从实验边界读出几个 caveat:第一,SWIM 的 attention supervision 依赖 mask-annotated training data,NL-Refer 的质量与 GPT-4o 改写/标注 noun 的准确性会影响监督信号;第二,released code 与论文在 layer fusion 上存在 mean vs product 的差异,复现时必须固定 commit 并核对实现;第三,HD 指标不是最强,说明对象定位变好不等价于完全解决 hallucination;第四,方法主要在 VideoRefer-Bench 与三个 general video benchmarks 上验证,跨领域长视频、多人多物体高歧义 reference 的泛化仍需要更多证据。

总体结论:SWIM 把“mask 只作为训练时 alignment teacher”这件事做得很干净。它没有要求推理时输入 visual prompt,却能在 text-only reference 下超过一批需要 point/box/mask 的 specialist baselines;最有价值的部分不是某个新网络结构,而是把 cross-attention map 从解释工具变成了训练信号。