做室内场景理解的人应该都有过类似的体验:模型能给出房间里每个点的语义标签,椅子、桌子、窗帘分得清清楚楚,但下游模块真正想问的问题却很难回答——“这把椅子在支撑桌子吗?”“门左边最近的是什么?”“这个房间里人可能坐在哪里?”传统的3D语义分割输出的是逐点类别,本质上是一堆无结构的标签云,缺了物体之间的关联信息。CVPR 2021的这篇《Learning 3D Semantic Scene Graphs From 3D Indoor Reconstructions》就是冲着这个缺口去的:它从3D室内重建的网格中同时预测语义分割和3D语义场景图,把“有什么物体”和“物体之间是什么关系”放进同一个可端到端训练的框架里。
这篇笔记我会从问题背景、数据定义、方法结构、实验结论和复现心得五个角度展开,把我读论文时的思考过程和后来跑实验时踩过的坑一起写进去。适合正在做室内三维场景理解、机器人交互或者AR导航相关工作的人参考,对刚接触场景图这个方向的同学来说,也可以当一篇带注释的入门导读。
1. 为什么3D场景理解需要“图”而不是“框”:从下游需求的视角打开这篇论文
1.1 从语义分割到场景图:下游任务缺的到底是什么
先明确一个概念:3D语义场景图(3D Semantic Scene Graph)是一种用图结构描述室内场景的表示方式。图的节点是场景中的物体对象,图的边是对象之间的关系。和常见的3D物体检测相比,场景图多出来的正是“关系”这一维度。
当我们把视角切到下游应用时,区别就很明显了。一个扫地机器人要完成“把沙发底下的垃圾扫出来”这样的指令,它需要的不只是一个标注了“沙发”的检测框,还需要知道沙发底下是否存在通往下方的空隙、沙发和地面的相对高度、周围是否有遮挡物。这些信息用检测框表达很别扭,但用图结构表达非常自然。关系背后隐含的是可供推理的语义,而这种语义正是当前大部分3D感知模型所欠缺的。
作者在论文里把这个问题定义为“从3D室内重建生成3D语义场景图”,关键词在于“生成”而不是“重建”。也就是说,输入是已经扫描并重建好的室内场景网格或点云,输出则是一张结构化的场景图。这是把感知和认知连接起来的一步,也是这篇论文的定位所在。
1.2 为什么“重建 + 识别”的老路线在3D场景图上走不通
很多人第一次看到这个题目时的直觉反应是:既然要做场景图,那先做一个三维物体检测器,检测出所有物体,再用一个关系分类器去预测两两之间的关系,不就可以了吗?这确实是2D图像场景图生成里主流的“检测后分类”流水线思路。
问题是,这套思路搬到3D室内重建场景下会遇到几个非常现实的问题。
第一,3D重建网格的质量参差不齐。ScanNet这类数据集中,物体表面存在大量空洞、残缺和扫描噪声,直接在上面做物体检测,候选框的质量比2D检测差不少。检测框一旦不准,后面的关系分类就成了“残渣上做雕刻”。
第二,关系分类高度依赖上下文。支撑关系这种物理语义,单看局部的两个物体往往不够。比如“桌子支撑着杯子”这种关系,你需要知道桌子的上表面是水平平面,杯子底面几乎贴在桌面上,这两条信息单独看任何一个物体都得不到,必须放到一个更大的感受野里联合推理。
第三,也是更本质的问题,流水线方法把语义分割、物体检测、关系分类三个阶段完全分开,误差逐级累积。前一个阶段出错,后一个阶段没有能力修正。作者在论文中明确提到,这种累积误差是推动他们做联合学习的主要动机。
1.3 和2D视觉场景图相比,3D场景图难在哪里
2D场景图生成(比如从Visual Genome图像中生成场景图)在几年前已经有不少工作,但直接迁移到3D室内重建场景是不行的。对比下来,3D版本主要有三个额外的难点。
第一个难点是几何噪声。3D重建中的网格不像自然图像那样像素规整,表面破损、法向估计不准确、物体间相互穿插都是常态。模型必须对这些噪声有一定鲁棒性,否则提取出来的几何特征本身就是脏的。
第二个难点是视角和空间关系。2D图像中的“左边”“右边”依赖相机朝向,而3D场景中“支撑”“邻近”这类关系是真三维的物理接触和空间拓扑,表达方式更复杂。
第三个难点是标注成本。图像场景图的标注可以在一张2D图上画出物体的框并连线,3D场景图需要在完整的室内重建中标注物体边界和物体间关系,工作量高一个量级。这也是为什么当时专门做3D场景图的数据集非常稀缺,直到3RScan出现才让这个方向有了可以训练和评测的基准。
理解了这三个难点,再看作者提出的方法就会容易得多:他们用一个联合学习框架把语义分割和场景图生成结合起来,本质上是用“语境的全局信息”去弥补“几何局部的不可靠”。
2. 数据与问题定义:3D场景图在ScanNet和3RScan里长什么样
2.1 节点是什么、边是什么:场景图的图结构定义
先看论文对场景图的形式化定义。一张3D语义场景图记为G = (O, E)。其中O是节点集合,每个节点对应场景中的一个物体对象,节点本身带有语义类别标签,比如椅子、桌子、门、窗帘。E是边集合,每条边连接一对节点,并带有一个关系类别标签。
在3RScan数据集中,关系类别被设计为两种主要类型:supporting(支撑)和proximate(邻近)。支撑关系表示一个物体物理上承载着另一个物体,比如桌子支撑着杯子;邻近关系表示两个物体在空间上靠得很近,但没有物理接触或支撑关系,比如床的旁边放着床头柜。
这里有个细节值得注意:场景图并不是把分割出来的所有超点都当作节点。论文的做法是,先对所有超点做语义类别判断,其中那些被判定为真实物体对象(比如椅子、桌子这类类别,而不是墙、地板这类建筑结构)的超点,才被进一步当作图中的候选节点。建筑结构类别的超点承担的是提供上下文信息的角色,它们不进入最终场景图的节点集合。
2.2 3RScan与ScanNet的标注差异及其对训练的影响
论文的实验主要在两个数据集上进行:3RScan和ScanNet,这两个数据集侧重点很不一样。
3RScan是当时少有的带3D场景图标注的数据集。它提供了完整的三维网格重建、语义分割标注,以及物体级别的标注框和物体之间的关系边。训练时可以直接用场景图监督信号。ScanNet虽然规模更大、语义分割标注更完善,但没有完整的场景图GT,作者的处理方式是先从语义分割结果中用规则派生出一部分关系标注,或者在ScanNet上只评测语义分割部分。
这种数据集差异直接影响训练策略。在3RScan上可以用完整的场景图损失来训练,在ScanNet上则主要以语义分割损失为主,场景图能力更多依赖模型的泛化。因此读论文结果时需要留意实验是在哪个数据集上报告的,3RScan的指标更能代表场景图生成的真实水平。
2.3 从网格重建到超点:如何生成可学习的图节点
场景图最终要落到可学习的特征上,而3D重建的输入是一堆无结构的网格和点云,不能直接当作图的节点来用。论文采用的中间表示是“超点”,也就是通过几何过分割算法把重建网格分成一个个空间紧凑、几何一致的区域。
类比一下2D图像的SLIC超像素,就很容易理解超点是什么。超点内部往往对应物体的一个连续表面片,比如一个椅子的坐面、一条桌腿,或者一面墙的大块区域。把超点作为基本处理单元,既能保留局部几何细节,又能把PointNet++这类点云特征提取器的作用范围框定在局部有意义的区域内。
超点的粒度对后续图构建影响很大。粒度太粗,一个超点可能同时覆盖两个物体,语义不纯;粒度太细,节点数量暴增,图规模变大,显存和计算量都会承压。实际使用中需要根据场景规模调整过分割的参数,这是后面复现部分我会重点展开的细节。
2.4 评价指标:edge recall、语义分割mIoU和关系分类得分怎么理解
论文评价分两条线:一条是语义分割质量,用的是标准的mIoU;另一条是场景图生成质量,用的是图结构相关的指标,包括节点分类的recall、边预测的recall,以及关系分类的准确率。
mIoU不用多解释。值得多说的是edge recall这类指标:它的计算方式是,模型预测的图中存在的边,有多少比例能匹配上GT图中的边。只看这个指标不够,因为模型如果无脑把所有节点两两连边,recall会很高但毫无意义,所以通常需要配合precision或者使用类似R@50的召回设定,限制只取置信度最高的前K条边来计算。
读论文结果时要注意:这类指标对候选边的采样方式极其敏感。如果候选边只在高置信度节点之间生成,edge recall自然会更高,但这不意味着模型真的学到了关系推理能力。这也是复现时很多人被指标差异困惑的原因。
3. 方法拆解:SGGNN如何用注意力消息传递同时优化分割与场景图
3.1 全景:从原始输入到联合输出的完整流程
这篇论文的核心模型叫SGGNN,全称Semantic Scene Graph Neural Network。整体流程可以划分为四个阶段:
首先是输入预处理阶段。从3D重建网格中采样点云,然后做几何过分割生成超点,每个超点内部包含一组点坐标和颜色信息。接着用PointNet++这类点级backbone对每个超点内的点做特征提取,通过池化得到每个超点的初始特征向量。
第二个阶段是图构建。所有超点作为图节点,节点间的特征向量作为边特征。边并不需要在所有节点对上生成,可以通过空间邻近关系、几何距离等策略采样候选边,控制图的密度。
第三个阶段是消息传递。SGGNN在图上执行多轮迭代,每轮迭代中节点特征和边特征交替更新。节点更新时通过注意力机制聚合邻居节点和相连边的信息,边更新时则利用两端节点的特征刷新自身表达。这个阶段是方法的核心创新点。
第四个阶段是联合预测。经过多轮消息传递后,每个节点接一个分类头做语义标签预测,同时接一个二分类头判断它是不是物体对象;候选边接一个关系分类头做关系类别预测。所有分类头的损失在训练时相加,统一回传。
3.2 超点特征提取:PointNet++这类backbone为什么够用
超点特征提取是整个框架的地基。论文选择在超点内部使用PointNet++做点级特征提取,提取出的逐点特征经过池化后形成超点级特征。
为什么选PointNet++而不是当时更新的一些体素方法?一个很实际的原因是超点本来就是稀疏的,体素化会在空区域浪费大量计算量,而PointNet++直接处理点云,通过多层级采样和分组聚合,天然适合这种输入。另一个原因是室内场景重建的点云规模通常在几十万到上百万点,PointNet++的分层结构可以逐步降采样,让后续图结构的规模可控。
特征空间决定了后续消息传递的信息天花板。如果超点特征只包含局部几何信息,没有任何全局语境,那么无论消息传递层做得多复杂,都无法凭空获得场景级别的信息。这也是论文强调联合训练的原因:语义分割本身就是上下文相关的任务,一个超点是椅子的坐面还是桌面,很大程度上要看它周围的物体是什么。
3.3 注意力消息传递:节点和边缘怎么互相“传话”
SGGNN的消息传递机制是论文最核心的设计。整个过程用伪代码表示大概是这样的:
# 初始化:超点特征为 h_node,边特征为 h_edge for t in range(T): # 1. 用注意力机制更新节点特征 for node_i in nodes: context = 0 for neighbor_j in neighbors(node_i): # 综合邻居节点、当前节点和边的特征计算注意力权重 attn_weight = attention(h_node[i], h_node[j], h_edge[i, j]) context += attn_weight * message(h_node[j], h_edge[i, j]) h_node_new[i] = update(h_node[i], context) # 2. 用更新后的节点特征更新边特征 for edge_ij in edges: h_edge_new[i, j] = edge_update(h_edge[i, j], h_node_new[i], h_node_new[j])消息传递的有效性来自两个关键设计。第一是节点更新时同时消耗“节点自身特征”“邻居节点特征”“边特征”三路输入,而不仅仅靠邻居节点的平均;第二是边特征和节点特征交替更新、互相强化,经过多轮迭代后,一条“桌子-杯子”的边能逐渐编码出“桌面上表面与杯子底面的支撑接触”这种复杂信息。
这里用到的注意力机制本质上是让模型自己学习该关注哪些邻居。一个杯子超点在更新自身特征时,应该更多地关注桌面超点而不是天花板超点,这种关系学习的柔性程度远超固定权重的GCN。
3.4 目标函数设计:分类损失和场景图损失怎么组合
在训练时,SGGNN同时输出三种预测:每个超点的语义类别、每个超点是否为物体对象、每条候选边的场景图关系标签。对应的损失函数有三项:语义分割用的交叉熵损失、物体对象二分类用的损失、场景图关系分类用的损失。三者在最终的loss中线性加权。
这个设计体现了作者“用语义分割服务场景图、用场景图服务语义分割”的思路。物体对象二分类可以看作是语义分割的辅助任务,它与语义分割的区别在于:语义分割需要区分所有细粒度类别,而物体对象二分类只要判断是不是物体;但正是这个看似更简单的任务,决定了场景图节点的质量,所以它对场景图loss的贡献非常大。
多任务联合训练带来的一个实际好处是共享特征表示。同一个特征既用于细粒度语义分割,又用于节点对象判定,又用于边关系分类,模型被迫在多个层级上抽象场景信息,这种约束通常比单任务训练泛化性更好。
4. 实验结论再解读:哪些提升是真的、哪些模块才是关键
4.1 两个数据集上的核心结果说明了什么
论文在3RScan上同时报告了语义分割和场景图生成的结果,在ScanNet上主要验证泛化能力。语义分割方面,SGGNN相比不加图消息传递的baseline有明显提升,这说明图结构推理确实能为逐点分类带来正面收益。场景图生成方面,无论节点分类还是边分类的ot指标都领先于没有联合学习的对照方法。
我的理解是,这个提升本质上来自两处:一是图消息传递路径让每个超点的特征都能从整个场景中获得上下文,相当于把语义分割的感受野扩充到了整个场景;二是联合学习让物体对象分类、语义分割、关系分类三个任务互相监督,有效缓解了单一任务的标注噪声和歧义。
一个比较有说服力的细节是,论文的可视化结果显示,经过SGGNN之后,原本被分割成两块的同一物体(比如一张被桌腿遮挡的桌面)在特征空间里趋于一致,这正是消息传递使“同一物体的不同部分”互相交换信息的结果。
4.2 消融实验:迭代轮数、注意力机制、边更新到底有没有用
论文做了多组消融实验,最值得关注的有三个。
第一个是迭代轮数T的影响。通常T从1增大到3时指标持续上升,继续增大则收益变小甚至会有轻微下降。这和消息传递的收敛特性有关,T太小,信息还没有充分传输;T太大,一方面容易出现特征过度平滑,另一方面显存占用和训练时间成倍增加。
第二个是注意力机制的消融。如果把注意力换成简单的平均聚合,场景图关系分类的指标明显下降。这说明“应该关注谁”这件事是需要学习的,平均聚合把所有邻居一视同仁,等于主动放弃了关系推理中最重要的“选择性”能力。
第三个是边特征更新的消融。固定边特征不参与更新,只让节点更新,场景图的edge指标退化明显。这个现象很好地验证了作者的设计:边不仅是传递节点信息的管道,它本身就应该在学习过程中被不断修正,因为它承载的是物体间的关系这一核心监督信号。
4.3 定性结果中的有价值发现
论文可视化中有一个规律非常有助于理解方法:经过SGGNN处理后的结果,物体之间的边界往往比baseline更干净。这看起来像是语义分割的进步,但本质上是场景图约束带来的结构化正则效果——一个物体不能既是杯子又是桌子,两个物体之间不能同时存在支撑和邻近两种互相矛盾的关系。
这种结构化正则很难通过堆数据或调参获得,是图结构本身带来的归纳偏置。它给我的启发是:在很多3D感知任务里,模型输出的结构化程度往往被忽视,而结构化约束往往比单纯增加网络容量更有效。
另一个值得注意的点是,SGGNN在ScanNet上的泛化效果并没有在3RScan上那么惊艳。ScanNet和3RScan的重建质量、房间类型、物体分布都有差异,跨数据集的泛化本身就是当前3D场景理解的难点。这也提醒我们,场景图方法对训练数据的依赖比想象中更强。
5. 复现笔记:超点分割、训练细节与容易踩的坑
下面这部分来自我自己复现和跑实验时的一些具体操作和实际心得。论文公开的代码和官方数据是主要参考,但我补充了一些常见实践中会遇到的问题,供准备动手复现的同学参考。
5.1 数据处理:超点分割的粒度控制与显存平衡
第一个实际工程量是超点分割。论文使用的过分割算法需要你输入目标区域大小等参数,这个参数对结果影响很大。分割粒度过粗,超点会跨物体导致语义标签不纯;粒度过细,节点数量能到几千甚至上万,全连接图基本别想训练。
实际操作时可以先对场景里的点云规模和房间大小做个统计,再设定目标超点数在500到2000之间比较合适。超点太少丢失几何细节,超点太多显存和训练时间都吃不消。此外,各场景的点云密度差异很大,同一个过分割参数在不同房间上效果可能天差地别,建议按场景做归一化处理。
3RScan下载和预处理需要稍微花点时间。注册就可以拿到数据,但数据集的网格文件在预处理阶段尽量把水密性检查做一下。侧面、地面缺失很常见,缺失表面会导致点云密度不均匀,最终干扰超点分割质量。
5.2 训练策略:BatchSize、迭代轮数与损失权重
训练SGGNN时显存消耗的主要来源不是PointNet++,而是全图的消息传递。点云场景大、边数量多时,注意力权重矩阵大小会快速膨胀。我在复现时把每条边的输入先做特征降维,再进入注意力计算,显存占用下降非常明显,指标几乎没有损伤。
迭代轮数T不要盲目调大。如果直接设成5轮以上,训练时间翻倍不说,指标提升极其有限。我用的是论文接近的3轮设定,收敛速度和最终指标都比较均衡。另外一个容易被忽视的点是:T轮迭代之间共享权重还是独立权重会显著影响参数量和训练稳定性,论文中的循环共享结构相比每层独立权重更稳。
损失权重方面,语义分割损失通常是最大的,物体对象二分类损失次之,场景图关系损失虽然重要,但建议初始时给一个较小的权重,否则训练前期会出现关系分支的学习噪声干扰节点特征收敛的问题。等语义分割先趋于稳定,再上调关系损失权重,整体训练会更平顺。
5.3 常见复现问题和调试对策
复现过程中最容易遇到的问题有三个。
第一个是指标对不上。这类场景图任务用的评估脚本和通用mIoU脚本细节不同,有的脚本只统计特定类别,有的对边做去重,直接用通用脚本会得到偏差很大的数字。强烈建议只用官方评估代码,自己写的评估函数很容易在“看似正确”的细节上埋雷。
第二个是训练不收敛或loss爆炸。这通常和边采样策略有关。全连接边会引入大量无意义的长距离边,关系分类任务被大量“无关系”的负样本淹没。推荐做法是用空间球查询产生候选边,半径要足够覆盖同类物体正常摆放的间距,又不能大到让所有物体都互相连接。
第三个问题是预测图中物体的重复节点。一个物体被分割成多个超点时,可能被当作多个节点重复输出。这个问题的根源在超点分割粒度,调试时可以先看可视化确认分割是否过细,再调整过分割参数。
5.4 后续可行的扩展方向
从这篇论文出来之后,3D场景图这个方向的热度一直在上升。顺着这条线往下走,有几个扩展方向我觉得非常值得尝试。
第一个是引入多视角RGB信息。论文本身基本是几何驱动,但室内物体表面纹理和颜色对类别判断和关系推理也有很强帮助,特别是几何特征相似但语义不同的物体。颜色信息在超点特征里简单拼接就有效果,值得一试。
第二个是结合新的点云Transformer结构。现在可以更灵活地对超点序列做全局注意力建模,替代部分手工构建的图结构,有可能会在长距离关系和全局场景理解上带来提升。
第三个方向是把场景图用于下游规划。比如在机器人操作任务中,用场景图提供的支撑关系判断抓取顺序;在AR导航任务中,用物体之间的邻近关系做空间语义指示。3D场景图的价值不只体现在感知指标上,应用场景的落地效果才更能说明问题。
对于刚接触这个方向的人,我最后再补一句实操心得:不要急着在ScanNet上刷场景图指标,先在3RScan上把语义分割和场景图的小规模实验完整跑通一遍,吃透数据格式、评估脚本、超点分割这三个基础环节,再接大场景和大模型都不迟。场景图任务的数据处理复杂度和坑的数量,远不是丢进一个模型就能解决的。把基础打牢,后面不管是复现论文还是做自己的改进,都会顺畅很多。