想象一下,你拿着老照片看一张全家福:你一眼就能说出“牵着小男孩的是外婆”“后排戴眼镜的是二叔”。注意到没有——你不只是“看见”了这些人,你还“读懂”了他们之间的关系。而现在的 AI 呢?让它看这张照片,它多半只能说“这里有人、有椅子、有桌子”,像第一次登门拜访的陌生人,只数得出人头,却说不清“谁是谁的谁”。 场景图(Scene Graph)要解决的,正是这个问题:它让 AI 不只“看见”画面里的物体,还要“看懂”物体之间的关系——人坐在椅子上、杯子放在桌子上、车停在房子旁边。这些关系被组织成一张“关系图”:每个物体是一个节点,每条关系是一条带标签的线,整张图就像一本家族关系谱系图。 从机器臂抓起杯子、到无人车判断“路口的人会不会走向车道”,再到 AR 眼镜把虚拟信息贴到正确的墙上——场景图都是背后的“关系大脑”。这篇文章会用“全家福与家族关系谱”这个比喻,带你从零认识场景图:它长什么样、怎么从一张图片里“牵出”关系线、靠什么算法让关系越传越准、怎么评价画得好不好,最后看看机器人们是怎么靠它上岗工作的。
场景图是 3D 感知与场景理解的“关系层”能力。掌握它,意味着你能从“会检测物体”升级为“能理解场景”,这正是机器人导航、自动驾驶、AR 等方向高级感知工程师的核心竞争力。
目录
可视化演示
展示3D场景图构建、物体关系预测与图查询遍历,节点为物体边为空间关系。
本节配有交互动效(进入视口后自动加载,约 3KB)。
模式1:场景图构建 节点表示场景中检测到的物体 边表示物体间空间关系 G = (V, E), V=objects, E=relations 场景图结构化描述3D场景语义信息。
场景图基础——关系谱系图的“点”与“线”
过年看全家福,外婆会指着照片讲:“这是你妈,她旁边是你爸;这是你表哥,他站在你舅舅前面。”你注意到没有——外婆讲的从来不是“这里有五个人”,而是“谁和谁是什么关系”。对 AI 来说,只说出“这里有人、有杯子、有桌子”,就像陌生人看全家福,只数得出人头,说不清亲情线在哪里。
场景图(Scene Graph)要做的,就是把这种“关系理解”变成一种正式的数据结构。它把场景中的每个物体看作一个“节点”(node),把物体与物体之间的关系看作一条“带标签的边”(edge),从而把整幅画面组织成一张图。这张图,就是 AI 心里的“家族关系谱”——检测框只回答“有什么”,场景图回答“谁和谁是什么关系”。
一张图被定义为两个集合的配对:顶点集合 \(\mathcal{V}\) 和边集合 \(\mathcal{E}\)。每个顶点 \(v_i\) 携带类别属性(人/桌/杯),每条边是一个三元组 \((v_i, r_{ij}, v_j)\),其中 \(r_{ij}\) 是关系标签,如“坐在、挂在、在……旁边”。关系大致分三类:空间关系(左/右/上/下)、动作关系(坐/拿/推)、归属与容纳关系(属于/包含)。这个概念在 2017 年前后的 Visual Genome 数据集和相关工作中被系统化,此后成为视觉与语言、机器人感知的“公共语言”。
就像家族谱的每条线都不能乱画,场景图中的每条边也必须承载明确的语义。有了这张“谱”,后面的推理、导航、问答才有依据——这正是它比“一摞检测框”高明的地方。
- 图的整体定义\(G\) 代表一张完整的场景图,它由两部分组成——点集与边集,就像家族谱由“家族成员”和“成员间的连线”组成。
- 节点集合的含义每个 \(v_i\) 是场景中的一个物体,比如“人”“杯子”“桌子”;在家族谱里,每个 \(v_i\) 就是一个家族成员。
- 边集合的含义每条边是一个三元组,\(r_{ij}\) 表示 \(v_i\) 与 \(v_j\) 之间的关系标签,如“坐在上面”“站在旁边”——对应谱系图上“父—子”“夫—妻”那根连线。
感知构建流程——先从全家福里“认人”,再“牵线”
家族关系谱不是天生就有的,得靠长辈们“一边看照片一边认亲”:先认出“这是二舅”,再确认“二舅站在姥爷后面”,最后七嘴八舌合成一张完整的谱系图。机器构建场景图,也是这条流水线,只是把“长辈”换成了神经网络。
流水线第一站是目标检测:在图像中找出“哪里有物体、是什么类别、框在哪”,相当于先点清楚照片里有几个人、几张桌子。第二站是关系推理:对每一对候选物体,判断它们之间有没有关系、是什么关系,相当于“认亲”。第三站是图组装:把物体变成节点、关系变成边,并处理同一个物体被多个框反复检测到的“数据关联”问题,合并成一张干净的图。
学术上,场景图生成常被建模为概率问题:给定图像 \(I\),生成场景图 \(G\) 的概率被分解为“每个节点被正确检出的概率 × 每条关系边被判对的概率”。这种分解让模型可以分阶段训练、分阶段排查错误,也解释了为什么工程上常说“检测错了,关系一定跟着错”——关系预测完全建立在节点之上。
长辈认亲偶尔也会认错——把表哥认成堂哥。关系推理也一样:两个物体挨得近,不等于真的有语义关系(比如人碰巧站在墙边)。所以现代方法会在关系推理中加入“物体类别先验”和全局上下文,让“牵线”更谨慎。
- 图像作为条件\(P(G \mid I)\) 表示“给定图像 \(I\) 时生成场景图 \(G\) 的概率”,图像是整张全家福,图是我们要写出的关系谱。
- 节点概率\(P(v_i \mid I)\) 是第 \(i\) 个物体被正确检测出来的概率,相当于“长辈有没有认错人”。
- 边概率给定两个物体和整张图像,它们之间关系标签为 \(r_{ij}\) 的概率,相当于“这层亲戚关系确认得对不对”。
节点与边的特征表示——每个人的“数字档案卡”
家族谱上每个人名下都要有档案:照片、身高、在合影里的站位、和谁是亲戚。场景图给每个节点准备的“档案卡”,就是特征向量——一串固定长度的数字,浓缩了这个物体的外观、位置和类别。
节点特征通常由三部分拼成:外观特征(用 CNN 从检测框区域提取的颜色、纹理、形状)、空间特征(归一化框坐标、面积、中心点)、语义特征(类别标签的向量表示)。边的特征则编码两个物体之间的相对位置、距离、尺度差,以及关系标签的嵌入——就像谱系图上每条线都标注了“父子”“夫妻”等不同的关系类型。
光有档案还不够,节点之间要实现“信息交换”,这正是图神经网络(GNN)登场的理由。GNN 通过“消息传递”让每个节点聚合邻居的特征、更新自己的档案。下面是一个经典的图卷积聚合公式:新特征等于对邻居特征做度数归一化求和后,再过一层非线性变换。
一轮聚会后,每个人档案里都多了一栏“从亲戚那听来的消息”:杯子知道自己在桌子上,桌子知道自己旁边有椅子。这种“越聚越全”的过程,让单个物体的特征带上了整个场景的上下文。
- 邻居集合的定义\(\mathcal{N}(i)\) 是与节点 \(i\) 直接有边相连的节点集合,也就是“档案卡上写了亲戚关系”的那些物体。
- 归一化聚合操作用两个节点的度数平方根做归一化,防止“朋友特别多”的节点话语权过大——相当于家族里人脉最广的亲戚也不能独占话筒。
- 非线性变换聚合得到的消息 \(\mathbf{m}_i\) 经过可学习权重矩阵 \(\mathbf{W}^{(l)}\) 和激活函数 \(\sigma\),得到下一层特征。
关键算法——消息在关系线上如何传播
家族情报的传播有个特点:人们更愿意相信和自己关系近的人的话。你妈跟你说“邻居家换车了”,比一个八竿子打不着的远房亲戚说同样的话,更容易被你记住。图注意力网络(GAT)就是给这条直觉装上了“权重旋钮”。
普通图卷积对所有邻居一视同仁地按度数加权;GAT 则给每条边学习一个注意力系数 \(\alpha_{ij}\),表示“节点 \(j\) 对节点 \(i\) 有多重要”。计算方式如下:把两个节点的变换特征拼接起来,过一个可学习的打分向量 \(\mathbf{a}\),再用 softmax 把同一节点的所有邻居权重归一化为和为 1 的分布。
消息传一轮,节点能“看见”直接邻居;传两轮,能看见“朋友的邻居”。但 GNN 有个著名的坑——过平滑:层数多了以后,所有节点特征越来越像,最后变成“全家福里所有人都长着一张脸”。工程上常用残差连接、限制层数、结合原始特征来缓解。好的家族情报网,既要信息流通,又不能流到“所有人都说同样的话”。
- 特征拼接把节点 \(i\) 和节点 \(j\) 各自变换后的特征拼成一个长向量,作为“这一对关系”的原始描述。
- 注意力打分可学习的向量 \(\mathbf{a}\) 对拼接结果做点积打分,得到一个标量 \(z_{ij}\),表示“\(j\) 对 \(i\) 的重要程度”。
- softmax 归一化对节点 \(i\) 的所有邻居分数做指数归一,使所有 \(\alpha_{ij}\) 加起来等于 1,相当于“票数归一”。
性能评估与优化——这份关系谱到底准不准
关系谱画好之后,怎么知道画得准不准?家族里的做法是让最有威望的长辈逐条核对:“这条线画对了,那条把表姐标成堂姐了,还有一条漏了。”场景图领域的“长辈核对”,就是召回率与平均召回率。
场景图预测的常见评测是:模型对每对物体给出关系打分,取 Top-K 条与真实标注比对。Recall@K 表示“真实关系里有多少比率进了 Top-K”;mR@K 更进一步——先按关系类别分别算召回,再取平均。为什么非要按类平均?因为场景图关系高度“长尾”:“在……旁边”出现几千次,“骑着”只出现几十次。总召回会被高频类拉高,掩盖低频类全面失败——就像只看“总的认亲正确率”,会忽略“远房亲戚全认错”的问题。
工程优化主要有三方向:一是稀疏化——不要把物体两两全连,只保留空间邻近且置信度高的边;二是类别平衡——对低频关系过采样或重加权;三是鲁棒性——用多帧/多视角融合应对遮挡和模糊。一份“看起来很大”的谱系图不值得骄傲,值得骄傲的是“每条关系线都经得起核对”。
- 分子的含义模型对所有候选关系打分后,取分数最高的 \(K\) 条,统计其中与真实标注一致的三元组数量。
- 每类召回先按关系类别 \(r\) 分别算出各自的 Recall@K,再对所有类别取平均,避免“在……旁边”这类高频关系主导总分。
- 类别总数\(|\mathcal{R}|\) 是全部关系类别的数量,作为平均时的分母,代表“有多少种关系线需要被照顾到”。
3D场景图应用——懂规矩的机器管家上岗
家族关系谱的终极价值是“办事”:办家宴按辈分排座、送礼按亲疏备礼。3D 场景图之于机器人,就是这份“办事用的谱系图”——它让机器人在三维空间里不只“看到”物体,还“知道”物体之间的层次与关系,从而执行复杂的语义任务。
3D 场景图把层次化结构做成图的骨架:场景节点下挂着房间节点,房间节点下挂着家具,家具上又支撑着物体。边用“包含”“支撑”“挂在”等关系连接不同粒度。数据来源通常是 RGB-D 相机或激光雷达:深度图与点云提供几何,RGB 提供语义,多视角融合减少遮挡造成的断裂。
有了这张图,语义导航变成“图上的检索 + 决策”:用户说“去厨房把桌上的杯子拿过来”,系统先在图中找到“杯子”节点,顺着“厨房→桌子→杯子”的关系链确定目标位置,再结合 SLAM 位姿规划路径。目标检索的形式化表达如下:在所有候选节点中,选出与自然语言查询匹配分数最高的那个物体。
管家不需要记住每件东西的三维坐标,它只需要一本不断更新的“关系谱”:东西放哪了、哪件在哪件的上面。这就是场景图让机器人从“会动”走向“懂事”的关键一跃。
- 候选节点集合\(\mathcal{V}\) 是场景图中所有可被选为目标的物体节点,相当于管家手里那份“可调用物品清单”。
- 相似度打分函数\(s(\text{query}, o)\) 把自然语言查询(如“桌上的杯子”)与节点 \(o\) 的特征做匹配打分,分数越高越匹配。
- 取最大值操作在全部节点中选出得分最高的 \(o^{*}\) 作为目标,之后沿关系边规划“走到哪、先做什么”。
AI 应用场景
服务机器人语义导航
阶段:感知与定位 → 语义导航
解决的问题:传统机器人只会“按坐标走”,用户说“去厨房拿桌上的杯子”它完全听不懂。3D 场景图把自然语言指令映射到“节点 + 关系”上,让机器人理解“杯子在桌子上、桌子在厨房里”这条关系链,再结合 SLAM 位姿规划路径。
具体案例:家庭服务机器人先构建分层 3D 场景图(房间层→家具层→物体层),收到语音指令后,在图里检索“杯子”节点并沿“厨房→桌子→杯子”的关系边导航,到达后结合抓取位姿估计完成取物。
自动驾驶路侧感知与轨迹预测
阶段:环境感知 → 行为预测
解决的问题:路口场景里“车、人、车道、信号灯”互为上下文,单独检测每个目标无法判断“行人会不会横穿”。场景图把目标之间的空间与语义关系显式建模,为预测模型提供结构化输入。
具体案例:路侧感知系统在路口构建场景图:车辆节点与行人节点连边,边标签为“正在接近”“在人行道旁”;预测模块结合这些关系边输出行人横穿概率,提前触发车辆减速。
AR 内容锚定与场景检索
阶段:3D 感知 → 语义理解 → 内容叠加
解决的问题:AR 眼镜需要把虚拟信息“贴”在真实物体及其关系上,比如“画框右侧显示作者简介”。没有场景图,系统不知道“画框的右侧”是哪里;有了场景图,虚拟内容可以锚定到关系边上。
具体案例:AR 导览应用实时构建展馆场景图,把“名画—挂在—墙上”的关系连同位姿一起存储。用户转头时,虚拟标签跟随“画框右侧”的空间关系平滑移动,不会漂移或穿墙。
Python 演示
"""场景图Scene Graph演示:从检测框构建关系图,两轮消息传递增强特征,输出三元组"""import numpy as np REL_NAMES = ["左", "右", "上", "下"] class SceneGraphBuilder: """输入: 物体名、归一化检测框、初始特征; 输出: 关系边与增强特征""" def __init__(self, feat_dim=8, w_scale=0.4): self.feat_dim = feat_dim self.gate_w = np.random.randn(feat_dim, feat_dim) * w_scale def build(self, names, boxes, feats): boxes = np.asarray(boxes, dtype=float) feats = np.asarray(feats, dtype=float) centers = (boxes[:, :2] + boxes[:, 2:]) / 2 edges = [] n = len(names) for i in range(n): for j in range(i + 1, n): dx, dy = centers[j] - centers[i] if np.hypot(dx, dy) > 0.5: continue if abs(dx) > abs(dy): rel = 1 if dx > 0 else 0 else: rel = 3 if dy > 0 else 2 edges.append((i, j, rel)) h = feats.copy() for _ in range(2): # 两轮消息传递 new_h = h.copy() for u, v, _r in edges: msg = np.tanh(h[u] @ self.gate_w) # 邻居u发来消息 new_h[v] += 0.3 * msg msg = np.tanh(h[v] @ self.gate_w) new_h[u] += 0.3 * msg h = new_h / (np.linalg.norm(new_h, axis=1, keepdims=True) + 1e-9) return edges, h def main(): builder = SceneGraphBuilder() names = ["人", "桌子", "杯子", "椅子", "台灯"] boxes = [[0.05, 0.30, 0.35, 0.75], [0.30, 0.35, 0.70, 0.60], [0.55, 0.45, 0.68, 0.58], [0.72, 0.25, 0.95, 0.70], [0.10, 0.45, 0.25, 0.62]] rng = np.random.default_rng(42) feats = rng.normal(size=(len(names), builder.feat_dim)) edges, h = builder.build(names, boxes, feats) print("检测到 %d 个物体, %d 条关系边" % (len(names), len(edges))) for u, v, rel in edges: print(" %s 的%s方有 %s" % (names[u], REL_NAMES[rel], names[v])) print("消息传递后特征形状:", h.shape, " 范数接近1 -> 已归一化") if __name__ == "__main__": main()
centers = (boxes[:, :2] + boxes[:, 2:]) / 2把每个检测框的左上角与右下角相加取平均,得到框中心点,作为判断“谁在谁旁边”的坐标依据。if np.hypot(dx, dy) > 0.5: continue只给相距足够近的物体对牵线:场景图遵循“空间邻近才可能有语义关系”的假设,顺带做了稀疏化剪枝。rel = 1 if dx > 0 else 0依据中心点差值的方向,把几何位置粗分类成左/右/上/下关系标签,对应文中“空间关系”。msg = np.tanh(h[u] @ self.gate_w)邻居特征经过线性变换加 tanh 激活,生成一条“消息”,模拟 GNN 的消息传递。new_h[v] += 0.3 * msg把消息按 0.3 的折扣累加到目标节点上,折扣越小信息传播越保守,防止特征被邻居“带跑”。h = new_h / (np.linalg.norm(new_h, axis=1, keepdims=True) + 1e-9)对特征做 L2 归一化,防止多轮迭代后数值爆炸,对应文中“过平滑控制”思想。if __name__ == "__main__":可执行入口,保证模块被 import 时不会误跑演示。
常见误区
误区我以为把图片里的物体都用框标出来,再写上类别标签,就是一张场景图了。检测框画得越准,场景图就越完整。
正解检测只回答“有什么”,回答的是节点问题;场景图的核心是“边”,是“谁和谁什么关系”。一张只有节点没有边的图,相当于只有成员名单没有关系线的家族谱——它根本没有完成“场景理解”。
为何常见:因为目标检测是很多人接触视觉的第一站,框和标签的直观输出让人误以为“再进一步就是场景图”,忽略了关系推理这一层独立的难点。
误区既然要表达关系,那把所有物体两两之间都连上边,关系信息不就最全了吗?总比漏掉关系要好。
正解全连接会让图变得极其稠密,绝大多数“边”是噪声(比如“人和墙”之间没有语义关系),既拖慢推理,又干扰注意力机制。工程实践恰恰要做稀疏化:只保留空间邻近、类别先验支持的高置信度边。
为何常见:初学者容易把“信息全”等同于“效果好”,但场景图的价值在于“结构化的语义精炼”,而不是“像素级的关系枚举”。
误区消息传递听起来很强大,那我把 GNN 叠到几十层,每个节点不就能“看见”全图了吗?效果一定更好。
正解GNN 存在过平滑问题:层数过多时,所有节点特征趋于一致,节点彻底丧失区分度,就像全家福里所有人最后都长成同一张脸。实践中通常只用 2~4 层,并配合残差连接、原始特征拼接来缓解。
为何常见:深度学习的直觉是“越深越强”,但图结构上的信息传播是“涟漪式”的,过度传播会抹平差异,这一点反直觉。
误区模型在测试集上 Recall@K 达到 80%,说明关系预测已经很好了,不需要再看别的指标。
正解场景图关系高度长尾,“在……旁边”这类关系出现极多,总召回率会被高频类轻松拉高,掩盖“骑着”“举着”等低频关系全面失败。必须用 mR@K 按类别平均召回,让每种关系线都接受“长辈核对”。
为何常见:总指标直观好算,人们习惯用单一数字判断模型好坏;但长尾分布下,平均数会掩盖结构性短板。
面试题
Q1. 场景图中的“节点”通常表示什么?
- A.一张图像的像素点
- B.场景中的一个物体← 正确答案
- C.相机的内外参数
- D.光照强度分布
答案:B。节点对应场景中的物体(人、桌子、杯子),边对应物体间的关系。像素属于底层图像表示,相机参数和光照属于传感器状态,都不是场景图语义层的组成。
Q2. 场景图中“(人,坐,椅子)”这种表示方式叫什么?
- A.目标检测框
- B.关系三元组← 正确答案
- C.特征向量
- D.语义分割掩码
答案:B。这是标准的关系三元组(主语,关系,宾语)。检测框只给位置,掩码只给区域,特征向量是一串数字,只有三元组显式表达了“谁和谁什么关系”——场景图最核心的信息。
Q3. 从一张图片构建场景图,合理的流程是?
- A.先关系推理,再目标检测,最后图组装
- B.先目标检测,再关系推理,最后图组装← 正确答案
- C.直接对整图做场景图预测,不需要检测
- D.先做图像压缩,再提取关系
答案:B。经典流水线是“检测物体(节点)→ 对物体对预测关系(边)→ 组装成图”。关系推理依赖检测结果,所以检测必须在前;图像压缩与场景图构建没有直接关系。
Q4. 图卷积更新节点特征时,邻居集合 N(i) 指什么?
- A.图像中空间相邻的像素
- B.与节点 i 有边相连的节点← 正确答案
- C.场景图中的所有节点
- D.与节点 i 相似度最高的三个节点
答案:B。邻居是“图上有边相连”的节点,不是像素相邻,也不是全图节点。这正是场景图相比全连接的优势:只聚合有语义关系的上下文,避免无关信息干扰。
Q5. 场景图中的边可以编码哪些信息?
- A.空间方位(左、右、上)← 正确答案
- B.语义关系(坐在、挂在)← 正确答案
- C.像素颜色直方图
- D.相对距离与尺度← 正确答案
答案:ABD。边描述两个物体之间的关系,空间方位、语义关系、相对距离与尺度都是关系属性。像素颜色直方图属于单个物体的外观特征,应放在节点特征中,而非边上。
Q6. 图注意力机制中,计算出的 α_ij 通常需要做什么处理?
- A.对每个节点的所有邻居做 softmax 归一化← 正确答案
- B.直接与邻接矩阵相乘
- C.取绝对值后求平均
- D.做傅里叶变换
答案:A。α_ij 表示节点 j 对节点 i 的重要性权重,所有邻居的权重必须归一化和为 1,因此用 softmax。直接相乘无法保证权重可比,取平均和傅里叶变换都不是注意力机制的标准操作。
Q7. 场景图评测中,mR@K 比 R@K 更受关注,主要原因是什么?
- A.mR@K 对每个关系类别算召回后取平均,缓解高频关系主导← 正确答案
- B.mR@K 计算速度更快
- C.mR@K 不需要真实标注
- D.mR@K 只评估节点不评估边
答案:A。场景图关系存在严重长尾,“旁边/在”这类关系出现极多,R@K 会被高频类拉高。mR@K 先按类别算召回再取平均,低频关系(如“骑着”)也能获得同等话语权。
Q8. 深度 GNN 用于场景图时,缓解“过平滑”的常见策略有哪些?
- A.残差连接← 正确答案
- B.控制消息传递层数← 正确答案
- C.把层数增加到几十层
- D.结合原始节点特征← 正确答案
答案:ABD。过平滑指多层消息传递后节点特征趋同。残差连接、限制层数、与原始特征拼接都能保留节点个性;盲目加深层数会加剧过平滑,使所有节点变成“同一张脸”。
Q9. 场景图最像生活中的哪种表达方式?
- A.一张灰色像素图
- B.一张标注了“谁站在谁旁边”的合影关系图← 正确答案
- C.一段音频波形图
- D.一份随机数列表
答案:B。场景图 = 物体(节点)+ 关系(边),与“合影上标注关系线”结构完全一致,这也是本文一直使用的比喻。像素图、波形图、随机列表都不含结构化语义关系。
Q10. 3D 场景图相比 2D 场景图的挑战包括哪些?
- A.深度信息有噪声← 正确答案
- B.物体互相遮挡常见← 正确答案
- C.3D 候选空间大、计算量高← 正确答案
- D.颜色通道更多所以更好处理
答案:ABC。3D 场景图要融合深度与点云,深度噪声大、遮挡频繁、候选空间从 2D 框升级为 3D 提案,计算量明显增大。多一个颜色通道并不会自动变简单,反而引入更多标定与融合问题。