资讯动态

视觉关系检测与语言先验:让模型理解物体之间的关系

发布时间:2026/10/6 3:32:31 来源:尧图企业网站定制
先问一个很常见的问题给定一张照片你觉得一个目标检测模型能告诉你多少信息框住一辆车、一个行人再各自给个类别标签然后呢如果我想知道“车是不是在人行横道前停了”或者“这个行人是不是在骑自行车”普通检测器直接抓瞎。这正是Visual Relationship DetectionVRD视觉关系检测要补上的一环它不只告诉你画面里有什么还告诉你这些物体之间发生了什么。今天想聊的这篇论文《Visual Relationship Detection with Language Priors》是斯坦福团队在2016年发表的工作也是这个方向绕不开的早期经典之一。核心思路一句话就能概括在视觉模型的基础上把语言里关于关系的“常识”作为先验并进去让模型能处理训练时没见过甚至没标注过的关系组合。无论你是想做场景图生成、视觉问答还是搞图文检索这篇论文都值得花时间读透。1. 先搞清楚Visual Relationship Detection到底在解决什么问题1.1 从目标检测到关系理解差的那一步是什么目标检测的输出是一组“bounding box 类别标签”本质上就是对图片里的每一块区域做分类。这种做法在单物体场景下很够用可一到真实世界就露怯了。真实场景里的物体很少孤立存在一辆车停在路边一个人牵着狗杯子放在桌上。人眼扫一眼就能自动组织出这些语义关系但检测模型完全无感知。VRD的任务就是把这种感知变成显式输出一般表示成一个三元组subject, predicate, object比如人, 骑, 自行车、狗, 在...旁边, 人、书, 在...上面, 桌子。它要求模型同时做三件事找到主体物体、找到客体物体、判断二者之间的语义关系。差的那一步说白了就是“上下文”。检测模型学会了“有什么”却没学会“在干什么”。而“在干什么”恰恰是视觉问答、图文检索、机器人交互这些上层任务真正需要的东西。比如做图文检索用户不会搜“图片里有一辆车”而是会搜“一辆车停在树下的路边”这里的关键不是车而是“停在路边”这个关系。没有关系理解这类需求根本接不住。1.2 为什么关系检测这么难组合爆炸和长尾分布如果你以为VRD只是“在检测器后面加一个分类头”那就太小看它了。这个任务真正难的地方在于输出空间太大了。VRD常用数据集里有100类物体、70种谓词把所有可能的subject, predicate, object组合枚举一遍数量是100 × 70 × 99将近70万种。而一个数据集里能标注出来的关系样本通常只有几万条。这就产生了两个非常棘手的问题。第一是组合爆炸。70万种可能组合绝大多数在训练集里压根没有对应样本模型没见过“人骑骆驼”你让它怎么预测传统的监督学习范式在封闭集合里很舒服一旦遇到开放组合就彻底露怯。第二是长尾分布。不要以为有了几万条标注就够用了这些标注集中在一小部分高频关系上比如“人有头”“人穿衣服”“站在旁边”这类关系占了很大比例剩下的大部分稀有组合可能只有个位数的样本。用交叉熵硬学模型很快会被高频样本带偏宁可猜一个常见的“有”也不愿意预测真正的动作。再加上关系标注本身非常贵。物体检测只需要框个框写个类别关系标注还要求标注员判断“骑”和“推”、“靠近”和“贴着”之间的语义差异标注成本比普通检测高一个量级。这也是VRD领域一直面临的数据天花板有关系的标注样本永远不够。1.3 语言先验用“常识”补足没见过的视觉样本面对这些没见过、没标注过的关系组合这篇论文给了一个很聪明的思路不硬让视觉模型学习所有组合而是去问语言模型。人类在理解图片时有一个巨大的优势——常识。即使你从没见过“人骑骆驼”的照片只要有人告诉你“骆驼是类似马的大型坐骑”你马上就能脑补出“人骑骆驼”大概是个什么姿态。这个常识从哪来从语言里来。语言是高度结构化的符号系统不同物体、不同谓词之间天然存在着关联而这些关联很多时候用不着视觉统计一下语料就能得到。论文的核心想法就是把这种“语言常识”做成一个先验项直接参与打分排序。具体怎么做下一节展开。先把结论放在这里加了语言先验之后模型在训练时从未见过的关系组合上仍然能给出合理的预测这正好补上了视觉样本不足的坑。2. 论文核心方案拆解三个概率相乘的打分函数2.1 整体框架检测、分类和先验如何分工论文把这套方案的形式化做得非常干净。整篇论文的决策函数可以理解为三个概率项相乘Score(subject, predicate, object | image) P(o1, o2 | image) × P(predicate | o1, o2, image) × P(predicate | o1, o2)第一项P(o1, o2 | image)是前景检测概率它回答的问题是“这张图里同时出现这两个物体的可能性有多大”。实际实现里一般用Faster R-CNN的输出近似先检测出一批候选框然后对物体对做一次联合筛选。第二项P(predicate | o1, o2, image)是视觉关系分类概率它由两个框对应的RoI特征拼接或外积后过一个分类头得到。这一项完全依赖视觉证据负责判断从图像内容来看这两个物体之间最像什么关系。第三项P(predicate | o1, o2)就是整篇论文的精华——语言先验。它的输入只有两个物体类别没有图像信息输出的是“在语言世界里这两种物体之间出现某个关系词的合理性”。这三项各自承担不同的角色最后用乘法组合成对三元组的最终打分。为什么要拆开而不是直接做一个端到端的大分类器因为三个模块能用的训练数据是不一样的。检测分支可以用大量弱标注图片训练语言先验完全不需要图片只有视觉关系分支才依赖昂贵的关系标注。拆开以后三个模块可以各自利用不同来源的数据这才是缓解标注稀缺的关键。2.2 语言先验里藏了什么频率、词向量和谓词迁移语言先验这一项乍看起来简单真正读进去会发现论文在这里面塞了很多细节。我理解它其实并了三类信息进去。第一类是标准频率先验。很简单直接统计语料或训练集里每个subject, predicate, object组合出现的频次归一化成一个条件概率表。这个先验对高频关系很有用但对稀有的组合基本是零。第二类是语义先验用的是word2vec。把物体类别和谓词都映射到向量空间里然后计算两个物体和某个关系词在语义空间中的契合度。比如“马”和“骆驼”的向量距离很近那么“人骑马”里学到的关系语义就能迁移到“人骑骆驼”上。这种相似度计算不依赖特定组合的训练样本是应对零样本关系的关键。第三类可以理解成基于相似关系的迁移先验。有些谓词之间存在天然的语义关联比如“骑”和“乘坐”、“放置”和“放在”都有重叠含义。论文利用这种关系层面的相似性把已经学到的视觉模式迁移到从未出现过的组合上有点像用已知词去预测生僻词的语义。这三类信息最后会加权组合成一个统一的先验矩阵。训练时可以和视觉分支一起参与排序推理时直接查表就行计算成本几乎可以忽略。这里我个人的体会是频率先验负责兜底语义先验负责迁移相似关系转移负责应对语义边界模糊的情况三者在不同数据条件下各有各的价值。2.3 损失函数与训练细节负样本比正样本更重要训练目标上论文没有选择传统的softmax分类而是用了一种排序损失。原因也很直白输出空间太大而且一张图里通常只有少数几个关系是真实存在的我们真正关心的是“给定一张图前K个预测里能命中多少个真值”。排序损失的核心逻辑是让正样本三元组的得分高于负样本三元组的得分并且至少要高出一定间隔。实现起来类似对比学习里的做法对每个正样本构造若干负样本然后让模型学会区分。这里最大的坑就是负样本怎么选。一开始我跑基础版本时负样本用随机替换谓词的方式生成模型很快就收敛到了一个无聊的解高频关系永远高置信稀有关系几乎不输出。后来才发现论文里专门提到要用类似hard negative mining的策略也就是在训练过程中动态挑那些模型当前最容易搞错、得分最高的错误组合来当负样本。这个动作对最终指标的影响非常明显比调模型结构还大。训练流程上常见做法是先预训练好Faster R-CNN让它输出高质量的proposal然后在冻结检测器的前提下训练关系分支。关系分支的输入是两个RoI的特征融合输出是谓词分类分数最后再和语言先验相乘得到三元组分数。如果一开始就联合训练检测器和关系分支关系任务的梯度很容易干扰检测器收敛效果并不好。3. 数据集与评估搞懂VRD benchmark 才能做对比3.1 VRD数据集长什么样100类物体、70种谓词论文发布了一个配套数据集后来简称为VRD数据集这也是后续很多VRD工作必跑的基准之一。数据集包含约5000张图片官方划分是4000张训练、1000张测试。物体类别一共100类涵盖人、动物、汽车、电子设备、家具、食物等常见日常物体谓词一共70类既有“骑、吃、拿”这类动作也有“在...上、在...里、靠近”这类空间关系还有“比...大、比...高”这类比较关系。数据集的标注格式是三元组配上两个bounding box也就是subject, predicate, object加subject框和object框。整个数据集的关系标注数量在数万量级具体能查到官方文档。这个规模在今天动辄百万级的视觉数据集面前不算大但也正是因为“小而难”才逼出了语言先验这种非视觉的方案。预处理阶段有一个容易被忽略的点不同复现仓库对谓词的处理可能不一样。有的仓库会做字符串归一化比如把空格、时态、单复数统一有的直接保留原始表述。这些细节会直接影响vocabulary的构成最终影响评估结果。我自己在跑复现项目时经常遇到同一个模型在两个仓库里指标差一截查下来往往不是模型问题而是vocabulary对不上。3.2 评估指标为什么用Recall50/100而不是mAPVRD最常用的评估协议是SGDET全称Scene Graph Detection要求模型直接输出一组三元组预测然后和真值做匹配。匹配条件很严格subject框和object框都要和真值框的IoU大于0.5且subject类别、predicate、object类别三样全对才算命中。围绕这个匹配规则主流指标是RecallK一般取K50或者K100。做法是把模型预测的所有三元组按置信度从高到低排序取前K条数一数里面有多少比例的真值三元组被召回。这个指标很直观给定一个上限K模型能捞回多少真实关系。为什么不直接用mAP因为三元组空间实在太大了按类别逐类算AP在工程上很繁琐而且正负样本极度不均逐类指标会被高频类别带跑偏。更重要的是实际应用里大家关心的是“我拿前K条结果给用户看里面有没有对的”而不是“所有类别平均排名有多准”。RK更贴近真实使用诉求。需要注意R50/100并不是一个绝对公平的指标它对候选框生成策略非常敏感。如果两个模型用的proposal数量不同、置信度阈值不同即使关系分支一模一样RK也会差不少。所以横向比较时先把检测部分对齐再谈关系模块谁强谁弱这是做实验的基本素养。3.3 零样本关系检测在测什么unseen组合才是真难点论文最有价值的一个实验设置是零样本关系检测。具体做法是不光看测试集整体RK还把测试集里的三元组按“subject-object配对在训练集里是否出现过”分成两类。如果训练集有“人-自行车”的配对样本那测试时遇到“人-自行车”就算seen如果训练集从未出现过“人-骆驼”这种配对测试时遇到就算unseen。在seen组合上模型可以依赖视觉记忆语言先验的贡献有限。但在unseen组合上视觉分支完全使不上劲因为压根没有对应的训练样本这时候模型的唯一希望就是语言先验或者某种跨组合的泛化能力。论文的实验结果里去掉语言先验后unseen组合的RK掉得非常厉害加上先验之后提升非常明显。这个消融结果就是整篇论文立论的关键证据。这也解释了为什么这篇论文在后续工作里被反复引用。它第一次明确地把“视觉证据不足时靠语言知识补位”这个思路形式化并验证有效后来场景图生成、开放词汇检测甚至多模态大模型里的很多做法都能看到这个思想的影子。4. 实验结果与我的复现心得先验到底带来了什么4.1 论文报告的结果怎么读消融实验是重点读论文实验章节我的建议是别先盯着绝对数字看先看消融对比。论文里最核心的对比就是带语言先验和不带语言先验两套设置尤其要看unseen组合上的差距。如果只看整体RK语言先验的贡献容易被高频关系的表现掩盖一旦把unseen组合单独拉出来差距就非常刺眼。这也符合直觉先验的增益主要集中在数据稀疏的场景在高频任务上它基本是陪跑。具体数字我不在这里抄了因为不同实现、不同预训练模型、不同评估协议跑出来会有差异直接以原文表格为准。我更想强调一个阅读方法把“表格里的指标”和“方法里的模块”对应起来看。比如去掉检测模块会掉多少、去掉语言先验会掉多少、两者都保留会怎样这样你才能得到“哪个模块在什么条件下起作用”的准确认知。4.2 我踩过的几个坑负样本、proposal质量与后处理复现这篇论文的时候我遇到过几个非常典型的坑逐个分享一下。第一个坑是负样本太容易模型退化成高频预测器。早期版本我用随机负样本训练跑了十几个epoch之后发现R100卡在低位上不去。排查下来模型学会的是“只要我没把握我就输出一个高频关系”。后来改成困难负样本挖掘每次迭代动态挑高分的错误组合来更新指标才有了明显的台阶式提升。第二个坑是检测框质量对关系分支的影响远超预期。很多预测错误根本不是关系分类错而是框就没框对。比如一辆车被两个proposal重复框住或者行人框半截在画面外关系分支拿到这种烂特征再好的分类头也没用。建议先把NMS的IoU阈值调宽松一点或者提高proposal数量上限确保关系分支有足够多的高质量候选框可用。第三个坑是后处理不能粗暴做全局NMS。关系检测有一个特点同一个物体可能身兼多个关系比如“人有头”和“人在门口”它们共用同一个subject框如果按检测任务习惯对整个三元组预测做全局NMS很多正确关系会被挤掉。建议先按三元组置信度排序再按subject框做轻量的局部去重而不是一股脑全部抑制。第四个坑是词向量不一致会引发连锁问题。用word2vec、GloVe还是fastText得到的语义相似度矩阵差别很大。换一套词向量语言先验的标定就变了需要重新调整先验项的融合权重。做复现实验时先固定词向量版本再跟别人比指标否则结果没有可比性。4.3 从这篇论文到场景图生成它对后续工作的影响这篇论文在VRD领域的地位相当于“奠基性工作”。后续几个重要方向都能看到它的影子。比如VTransE把视觉关系映射到向量空间做翻译式推理Neural Motifs把统计先验和全局上下文结合起来做场景图解析还有后来专门解决长尾偏置的Unbiased SGG系列底层思路都在回答同一个问题视觉样本不够时如何用结构化的先验知识来补。如果要做场景图生成这篇论文基本是必读的前传。场景图可以简单理解成整张图的关系图节点是object边是predicate而VRD做的其实就是“场景图检测”的子集。理解了这篇论文的语言先验思想再去看场景图生成里各种利用统计统计先验、语言embedding的方法会顺畅很多。我自己读这篇论文时有一个很强烈的感受真正有价值的工作往往不是把模型堆得很复杂而是把问题拆清楚然后给一个漂亮的补位方案。放到今天语言先验这个概念已经被多模态预训练模型吸收了但它的逻辑内核——用语言知识补足视觉样本的稀疏性——依然值得反复咀嚼。5. 想复现这篇论文这份实操清单请收好5.1 环境与代码选型Caffe老实现和PyTorch复现怎么选论文原版代码是基于Caffe的老实现距今比较久远直接在现代Linux环境下跑会遇到一堆兼容性问题比如CUDA版本、旧依赖库、protobuf冲突等我并不建议硬啃原版环境。更稳妥的做法是找社区里的PyTorch复现版本成熟仓库已经帮你处理好了数据加载、训练流程和评估脚本。选复现仓库有几个筛选标准。第一看数据预处理逻辑是否对vocabulary做了统一处理第二看评估代码是否实现了SGDET标准协议第三看issue活跃度一个有人维护、有人踩坑后修复过的仓库会省下大量调试时间。如果只是学习原理也可以直接加载预训练权重跑一遍推理不必从头训练。如果决定自己造轮子核心模块可以拆成三块检测器用Faster R-CNN关系头是两个RoI特征的融合加分类语言先验是词向量加统计矩阵的查表操作。硬件方面训练Faster R-CNN建议至少有8GB以上显存的显卡如果只是做推理或微调关系分支普通消费级卡也够用。5.2 数据处理与训练流程先训检测器再训关系分支数据准备阶段首先下载VRD数据集并确认标注文件格式解析出每个三元组对应的subject框、object框和谓词标签。然后统一物体类别和谓词的字符串到id的映射这里强烈建议直接沿用官方vocabulary不要自己发明一套预处理规则。训练流程我推荐分两步走。第一步用一个预训练的Faster R-CNN在VRD的物体框上做微调目标是产出尽量准的proposal第二步冻结检测器只训练关系分支。关系分支的输入是两个RoI的feature经过融合层后输出70维的谓词分类分数。等关系分支收敛后再在推理阶段加上语言先验项进行联合打分。语言先验模块的构建不依赖图形训练可以预先算好。第一步统计训练集里每个谓词在不同物体对上的频次做平滑后得到频率先验矩阵第二步把物体类别和谓词分别映射成词向量计算语义相似度第三步构思相似关系迁移矩阵把相近谓词之间的统计互相借用。最后把这三个矩阵做加权融合得到最终的P(predicate | o1, o2)查表项。推理阶段就比较简单了检测器取Top-N候选框枚举物体对提取RoI特征得到视觉分数乘上语言先验查表项按最终分数排序取Top-K条三元组输出。5.3 评估流程与常见报错排查指标不对先查协议评估流程本身的代码量不大核心就是实现IoU匹配和RK计算。但有几个容易踩的坑。常见报错第一类是数据格式问题物体框的坐标是x1, y1, x2, y2还是x, y, w, h不同仓库之间经常不一致解析完一定要可视化几张图确认框是对的。第二类是词汇表映射错误训练和评估用了不同的谓词id映射导致标签错位模型指标看起来很高或者很低实际是数据泄漏或者负样本污染。排查指标异常的技巧我总结了一个顺序。先看负样本构造确认GT关系没有被错误当负样本再看评估匹配重点检查IoU阈值是0.5还是更低是否subject和object都要求IoU然后用一个小训练子集做sanity check看看模型能不能过拟合到这一小批样本上能过拟合才说明管线通顺。最后一定要可视化预测结果画出检测框和关系标签肉眼扫一眼就知道错误是框的问题还是关系理解的问题。还有一个深坑是RK的计算协议细节。K是指每张图取Top-K再汇总还是先对全图所有三元组排序再取Top-K不同实现会有差异跑出来的指标可能差好几个点。复现之前先确认好评估脚本里的定义否则对比没有任何意义。最后分享一个小技巧正式跑大规模训练之前先写一个极简版本的调试脚本只保留最核心的检测和关系分支用几十张图片快速过一遍训练和评估确认每个环节都通了再上全量数据。这个习惯救了我很多次能省去大量排查时间。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑