ZSVG论文精读
3D视觉定位(3DVG)旨在根据文本描述来定位三维(3D)对象。传统的监督式3DVG方法通常需要大量的标注数据和预定义的词汇表,这可能带来一定的局限性。为解决此问题,我们利用大语言模型(LLM)的强大能力,提出了一种用于实现零样本、开放词汇3DVG的新颖视觉编程方法。我们的方法始于一个独特的基于对话的模式,通过与LLM互动,建立对零样本3DVG的基础理解。在此之上,我们设计了一个包含三种类型模块的
Basic Information
- Title:Visual Programming for Zero-shot Open-Vocabulary 3D Visual Grounding
- Author:Zhihao Yuan, Jinke Ren, Chun-Mei Feng, Hengshuang Zhao, Shuguang Cui, Zhen Li
- Institution:FNii, CUHKSZ; SSE, CUHKSZ; IHPC, A*STAR, Singapore; HKU
- Conference:CVPR 2024
- Homepage:https://curryyuan.github.io/ZSVG3D
Abstract
3D视觉定位(3DVG)旨在根据文本描述来定位三维(3D)对象。传统的监督式3DVG方法通常需要大量的标注数据和预定义的词汇表,这可能带来一定的局限性。为解决此问题,我们利用大语言模型(LLM)的强大能力,提出了一种用于实现零样本、开放词汇3DVG的新颖视觉编程方法。我们的方法始于一个独特的基于对话的模式,通过与LLM互动,建立对零样本3DVG的基础理解。在此之上,我们设计了一个包含三种类型模块的视觉程序:视角无关模块、视角依赖模块和功能模块。这些专门为3D场景定制的模块协同工作,以执行复杂的推理和定位任务。此外,我们开发了一种创新的“语言-对象关联模块”,将现有3D对象检测器的应用范围扩展到开放词汇场景。大量的实验证明,我们的零样本方法能够超越一些监督式基线方法,标志着向实现高效3DVG迈出了重要一步。代码已在 https://curryyuan.github.io/ZSVG3D 上提供。
Current Issues, Challenges, Author’s Motivation, and Proposed Solution
3D视觉定位(3DVG)旨在通过文本描述在3D场景中定位特定对象。这项技术已成为自主机器人、虚拟现实和元宇宙等众多新兴应用中的关键组成部分。举例来说,如图1(a)所示的3D扫描及其描述——“它是离门最近的键盘”,3DVG的目标是精确定位绿色盒子中的键盘,同时消除桌子等潜在的干扰物。尽管这个任务对人类来说看似简单,但由于机器固有的感知能力有限,这对它们构成了巨大的挑战。

传统的监督式3DVG方法通过利用ScanRefer和Referit3D等公共数据集中的丰富标注来实现这一目标。这些方法通常将3DVG定义为一个匹配问题:首先通过3D检测器生成可能的候选对象,然后通过融合视觉和文本特征来识别最佳匹配。虽然这些方法能够产生精确的结果,但对于现实世界的应用而言,获取足够标注数据的资源消耗巨大,几乎不具备可行性。此外,这些方法在训练过程中常常受到预定义词汇表的限制,这使得它们在开放词汇的场景中表现欠佳。
为了解决这些问题,我们提出了一种用于3DVG的新颖视觉编程方法,该方法整合了零样本学习和大语言模型(LLM)。
零样本学习方法 可以通过利用 CLIP 在3D领域的预训练能力来泛化到新的类别。而大语言模型(LLMs)因其强大的规划和推理能力,可以促进3DVG的实现。考虑到这一点,我们首先提出一个与LLM进行对话的基础版本。它描述场景中所有对象的位置和大小,并指示LLM通过交互式对话来定位目标物体。尽管该基础方法设计简洁,但LLM固有的随机性和控制限制使其难以捕捉视角依赖的查询并解析三维空间中的空间关系,而这正是3DVG的主要挑战。
为了克服这一局限,我们进一步开发了一种新的视觉编程方法,如图1(b)所示。该方法主要包括三个步骤:(1)利用LLM生成一个3D视觉程序,(2)将该程序解释为Python代码,以及(3)通过执行代码来确定目标边界框。为了提升定位精度,我们引入了一个新颖的语言-对象关联(LOC)模块,该模块旨在将3D点云的精细几何辨别能力与2D图像的细粒度外观信息相结合。
总而言之,我们的贡献可以概括如下:
- 我们提出了一种创新的3D视觉编程方法,该方法无需在监督式学习中使用大量的“对象-文本”配对标注。
- 我们通过设计关系模块(relation modules) 和 语言-对象关联模块(LoC modules) 这两种类型的模块,将视觉程序转换为Python代码。前者明确定义了3D空间中的视角依赖和视角无关关系,而后者则为开放词汇定位任务捕捉几何与外观信息。
- 我们在两个流行的数据集,即ScanRefer和Nr3d上进行了广泛的实验。我们首次对整个验证集进行了评估,而不仅仅是评估少量样本。结果表明,我们的方法性能优越,甚至可以与现有的监督式方法相媲美。
监督式3DVG
3DVG在从自主机器人到元宇宙等许多新兴应用中已备受关注。一方面,像ScanRefer和Referit3D这类经过密集标注的数据集,可以为ScanNet提供良好对齐的对象-文本配对。另一方面,大多数现有方法将3DVG视为一个匹配问题,即利用对象标识符来生成候选对象,并通过融合视觉与文本特征来找到最佳匹配项。在此基础上,一些工作尝试探索不同候选提案之间的对象属性和关系。此外,部分研究也利用了掩码建模和对成对数据进行对比学习等先进技术,对3D语言预训练进行了探索,随后在下游任务上进行微调。另外,NS3D利用CodeX来生成分层程序,但它仍然需要标注数据来训练其神经符号网络,因此缺乏开放词汇和零样本能力。
室内3D场景理解
对室内环境的理解研究已非常广泛。特别是,RGB-D扫描数据集的出现,极大地推动了包括3D对象分类、3D对象检测、3D实例分割等多个研究领域的边界。然而,这些方法通常受限于一个封闭的语义类别标签集,这限制了它们在真实世界场景中的适用性。近期在开放词汇图像理解方面的进展,启发了在开放词汇设置下进行3D场景理解的研究。例如,LERF通过在训练过程中渲染CLIP学习一个语言场,从而能够为任意语言查询生成3D相关性图。OpenScene从2D开放词汇分割模型中提取图像特征,然后训练一个3D网络以生成与多视图融合像素特征对齐的特征。OpenMask3D利用闭集网络生成实例掩码,同时丢弃分类头。尽管取得了这些进步,但这些方法仍然缺乏空间推理和常识推理能力。
用于视觉语言任务的大语言模型(LLM)
大语言模型(LLM)的最新进展展现了令人印象深刻的零样本规划和推理能力。学术界提出了如“从少到多”(Least-to-Most)、“循序渐进思考”(Think-Step-by-Step)和“思维链”(Chain-of-Thought)等提示技术来激发LLM的潜力。这些模型能够理解人类指令,将复杂目标分解为子目标,并控制机器人智能体在无需额外训练的情况下执行任务。此外,当与专门的视觉模型结合时,LLM能够显著提升视觉语言任务的性能。例如,Visual ChatGPT利用ChatGPT作为核心协调器,连接多种视觉基础模型来解决更具挑战性的问题。VISPROG利用上下文学习能力,为解决复杂的视觉语言推理和图像编辑任务生成高级模块化程序。ViperGPT直接调用可用模块的API,并为图像定位生成可执行的Python代码。然而,将这些能力应用于零样本3D语言定位领域,至今仍是一个未被探索的领域。
Method
我们介绍一种基础方法,即“与LLM对话”,用以解决3DVG中的标注问题。然后,我们将分别阐述用以处理视角依赖关系的视觉编程方法,以及语言-对象关联(LOC)模块的设计。

与LLM对话
为实现3DVG的目标,我们提议与大语言模型(LLM)发起一场对话。对话的输入包含一个真实世界的RGB-D扫描数据和一个自由格式的文本描述 T T T 。该文本描述提供了关于点云表示 P ∈ R N × 6 P \in \mathbb{R}^{N \times 6} P∈RN×6 中目标对象的具体信息,其中 P P P 是一个包含了颜色信息的三维点的集合, N N N 是此类点的总数。LLM在被扫描的房间中扮演一个代理(agent)的角色,旨在根据给定的文本描述识别出指定的对象。为了弥合模型在理解文本方面的熟练度与3DVG任务的空间特性之间的鸿沟,我们首先将场景转换成一种文本叙述。这种叙述能够全面地介绍场景中呈现的对象 O O O,包括它们的位置和维度,其表达形式如下:
对象 <id> 是一个 <类别>,位于 (x, y, z),尺寸为 (宽度, 长度, 高度)。
基于这样的文本布局,我们通过向LLM提供场景描述和用户查询来与其进行对话。我们的目标是引导LLM识别查询中提到的对象,同时也能理解并解释其在识别过程中的推理逻辑。特别地,LLM能够模仿人类进行的推理步骤。如图2(a)所示,如果LLM获取了对象信息,它可以提取出与查询语句相关的对象,即目标“键盘”和锚点“门”,并通过计算它与“门”之间的距离,成功地识别出正确的目标“键盘”。
尽管LLM展现出类似人类的强大推理能力,它们仍然存在一些局限性。首先,它无法处理像“右边的窗户”这样的视角依赖问题。这是因为3D场景可以自由地旋转到不同的视角,而LLM通常是依据2D图像进行决策的,即便在对话中给出了提示,它们也往往通过比较3D坐标的x-y值来做出判断。其次,数学计算是LLM的一个普遍弱点,但这对于3D视觉定位又是必不可少的。例如,在图2(a)中,距离计算对于解决“最近”这类关系至关重要,然而LLM却无法总是提供准确的结果。这两个问题源于LLM自身的训练局限性,从而影响了“与LLM对话”这种方法的可靠性。
3D视觉编程
为解决上一节提到的两个问题(即视角依赖和数学计算的局限性),我们引入一种通过大语言模型(LLM)生成视觉程序的新方法。如图2(b)所示,我们首先构建一组示例程序,用以封装在3D视觉定位(3DVG)任务中类似人类的解题策略。每个程序都包含一系列操作,其中每个操作都定义了模块名称、输入参数和一个指定的输出变量。每一步的输出都可以作为后续步骤的输入,从而创建一个能反映视觉内容中逻辑推理的、相互关联的序列。
我们将3DVG的推理过程转化为一个脚本化的视觉程序。具体来说,我们收集了一组上下文示例及其对应的定位描述,然后使用LLM来推断出为该任务量身定制的新视觉程序。例如,对于描述:“位于房间角落,靠近蓝色和黄色海报的圆形鸡尾酒桌”,我们认为该任务由以下描述提示:
在这种情况下,目标是识别出圆形的鸡尾酒桌,这可以转化为一个操作:BOX0 = LOC('圆形鸡酒桌’)。在这里,LOC算子(operator)处理文本查询,并输出目标对象的边界框。我们将在后面详细阐述LOC模块。然而,由于3D场景中可能存在多个相似的对象,仅凭此步骤识别出的结果可能不是唯一的。为了解决这个问题,我们将“蓝黄色海报”作为一个辅助参考点,通过操作 BOX1 = LOC('蓝黄色海报') 进行定位。然后,CLOSEST模块会计算BOX0(候选桌子)和BOX1(海报)之间的邻近度,并选择离海报最近的桌子作为最终结果。
表1总结了3DVG中常见的关系。基于此,我们通过开发三类为3D情境量身定制的详细模块,来呈现我们的视觉程序:
- 视角无关模块 (View-independent modules): 它们处理对象之间的3D空间关系。例如,
CLOSEST模块可以识别邻近度,而无需考虑观察者的位置。 - 视角依赖模块 (View-dependent modules): 它们依赖于观察者的视点。例如,当观察所有窗户(
BOX0)时,RIGHT模块可以确定出作为目标(TARGET)的窗户(BOX1)中哪一个是右边的窗户。 - 功能模块 (Functional modules): 它们包含多个操作,例如
MIN和MAX,可以根据极端标准来选择对象。
这三种类型的模块允许一个操作的输出被送入另一个操作,从而提供了灵活的组合性。它们不仅促进了结构化且准确的推理序列的形成,还整合了3D和2D数据,为3DVG任务产出稳健且可解释的结果。
处理视角依赖关系
在本节中,我们探讨视角依赖关系的复杂性,这对于解释空间关系至关重要。其主要挑战在于这些关系的动态性,因为它们会随着观察者视点的变化而改变。尽管传统的监督方法可以隐式地学习这些关系,但它们无法提供一个明确的解决方案。
在2D平面上,空间关系,特别是“左”和“右”,有着明确的定义。具体来说,“右”对应于x轴的正方向,而“左”则对应负方向。受此启发,我们采用一种2D自我中心视角的方法,以确保空间关系拥有一个一致的参考框架。
我们的视角依赖模块接受一个 target(目标)参数和一个可选的 anchors(锚点)参数。它们会输出那些满足与锚点之间特定空间关系的目标对象。当定位查询未指定锚点时,我们会将其他目标对象视为锚点。这种方法符合我们的直觉,例如,在识别“左边的窗户”时,可以将所有其他的窗户本身都视作锚点。

如图3所示,我们假设在房间中心有一个虚拟相机,即 P center P_{\text{center}} Pcenter,它可以旋转以对齐锚点对象的位置,即 P oa P_{\text{oa}} Poa。然后,3D对象从这个视点被投影到一个2D平面上。
假设该正交相机有一个内参矩阵 I I I,那么2D投影可以通过以下公式获得:
R , T = Lookat ( P center , P oa , up ) ( 1 ) R, T = \text{Lookat}(P_{\text{center}}, P_{\text{oa}}, \text{up}) \quad (1) R,T=Lookat(Pcenter,Poa,up)(1)
( u , v , w ) T = I ⋅ ( R ∣ t ) ⋅ P ( 2 ) (u, v, w)^T = I \cdot (R|t) \cdot P \quad (2) (u,v,w)T=I⋅(R∣t)⋅P(2)
其中Lookat(·)是一个视图变换函数,用于计算旋转矩阵 R R R 和平移矩阵 T T T。 P = ( x , y , z , 1 ) T P = (x, y, z, 1)^T P=(x,y,z,1)T 表示3D坐标向量, u u u 和 v v v 分别表示2D平面上的x轴和y轴坐标,而 w w w 是深度值。根据一个对象中心的 u u u 值,我们可以确定其“左”或“右”的位置——较小的 u u u 值表示“左”。类似地, w w w 值使我们能够区分“前”和“后”。通过综合这些概念,我们便可以定义“之间”的关系。
从3D到2D自我中心视角的转换为解释3D空间中的视角依赖关系提供了一个清晰且一致的解决方案,从而增强了我们模型的空间推理能力。
语言-对象关联模块
尽管我们的零样本3D视觉定位(3DVG)方法不需要大量的定位标注(grounding annotations),但它仍然需要一个基础的视觉模型来进行对象定位。为解决此问题,以往的研究工作通常使用预训练的3D检测器来生成候选对象及其在预定义词汇表内的相应标签(类别)。然而,这种方法受限于一个预定义的类别集合,从而限制了类别预测的范围。为了实现开放词汇的分割,我们开发了一个语言-对象关联(LOC)模块,该模块结合了3D和2D网络的优势,将打标签的能力扩展到闭集(closed set)之外。
例如,在图4中,当我们考虑操作 BOX0 = LOC('圆形鸡尾酒桌') 时,我们首先使用一个3D实例分割网络,筛选出那些预测标签为“桌子”的对象子集。接下来,我们只需要从这个子集中,利用其对应的2D图像来识别出哪一个是“圆形鸡尾酒桌”。通过将每个3D候选对象映射到其2D图像,我们可以提取出与我们查询相关的颜色和纹理细节。为了进一步精确定位到那张圆形的鸡尾酒桌,如图4所示,我们考虑采用三类2D多模态模型:
-
图像分类模型: 我们构建一个动态词汇表,其中既包括具体的查询词“圆形鸡尾酒桌”,也包括其基类“桌子”。然后,我们使用像CLIP这样的流行工具来评估这些词条与图像之间的余弦相似度,以找到与我们查询的最佳关联。
-
视觉问答模型: 我们向模型(例如ViLT)提出问题:“这里有一个[查询]吗?”。然后模型会从其词典中进行筛选,以给出最可能的答案,即“是”或“否”。
-
通用大模型: 我们提交相同的查询,并预期模型会基于生成的文本给出一个响应。这个过程对于验证检测到的桌子与用户查询之间的一致性至关重要。
我们应该指出,我们的方法不局限于特定的3D或2D模型,这使得我们可以灵活地整合各种不同的模型。在实验部分,我们将通过与纯3D和纯2D的对应方案进行比较,来展示LOC模块的优势。我们的设计标志着3D开放词汇实例分割领域的一次飞跃,并且能够提升3DVG中的对象识别准确率。
Experiments
Settings
数据集。 我们使用两个流行的数据集进行实验,即ScanRefer和Nr3D。ScanRefer是为3D视觉定位(3DVG)量身定制的,包含为800个ScanNet场景准备的51,500条句子描述。Nr3D是一个由人类书写的自由格式数据集,通过双人参照游戏在3D场景中收集。这些句子被分为“简单(easy)”和“困难(hard)”两个子集,其中“简单”子集的目标对象只包含一个同类别的干扰项,而“困难”子集则包含多个。根据定位参照对象是否需要特定视点,数据集还可以被划分为“视角依赖(view dependent)”和“视角无关(view independent)”子集。对于这两个数据集,我们都在验证集上评估我们的零样本方法。
评估指标。 我们考虑两种性能评估设置。第一种设置要求生成候选对象,这与真实世界的应用场景紧密对齐。评估指标是Acc@0.25和Acc@0.5,分别代表预测的边界框与真值(ground-truth)之间的交并比(IoU)超过0.25或0.5的正确预测百分比。这是ScanRefer数据集的默认设置。第二种设置则提供真值的对象掩码(mask),因此只需要进行分类,其目标是消除定位误差并实现高精度的定位。这是Nr3D数据集的默认设置。
基线方法。 我们使用六种监督式方法和两种开放词汇的3D场景理解方法进行性能比较。
对于监督式方法,ScanRefer和ReferIt3DNet分别对3D点云和语言进行编码,然后将它们融合以通过预测分数对对象进行排序。TGNN和InstanceRefer则更进一步,通过学习实例级别的特征。3DVG-Transformer和BUTD-DETR分别利用Transformer和DETR架构,代表了当前最优(SotA)的方法。对于开放词汇方法,OpenScene和LERF旨在学习一个与2D CLIP特征对齐的3D表示,从而支持自由格式的语言定位。查询语句 T T T 由CLIP文本编码器处理,其相似度会与提取出的点特征进行计算。最后,它们对得分最高的点进行聚类以确定目标对象。
Main Results
ScanRefer数据集。 表2提供了我们提出的方法在ScanRefer数据集上的定量评估。我们可以看到,我们的零样本方法优于所有基线方法。具体来说,我们的方法取得了32.7的Acc@0.5分数,超越了包括ScanRefer和TGNN在内的监督式方法。另一方面,开放词汇方法LERF和OpenScene的整体准确率分别只有4.8和13.2,即便是在0.25的IoU阈值下也是如此。这是由于它们在推理和定位精度方面存在局限性。

此外,我们的零样本方法也优于在LOC模块中仅利用3D或2D信息的方法。这证明了我们整合视觉编程和感知模块的有效性,凸显了我们的零样本方法在3DVG领域中的导航能力。

Nr3D数据集。 表3展示了不同方法在Nr3D数据集上的性能,其中也提供了实例掩码的真值。我们可以看到,我们的零样本方法再次超越了InstanceRefer等监督式方法。具体而言,我们的零样本方法在“视角依赖”分割上,相比3DVG-Transformer取得了2%的准确率提升。这一性能增益来自于我们的关系模块,从而加强了我们的零样本方法在3DVG任务中的潜力。
Ablation Studies

与LLM对话 vs. 视觉编程。 我们在包含700个样本的ScanRefer验证集上,比较了我们提出的两种零样本3D视觉定位(3DVG)方法的性能。对于这两种方法,我们都使用了两个GPT版本,即GPT-3.5-turbo-0613和GPT-4-0613。每个GPT版本的成本取决于输入和输出的令牌(token)数量。实验结果如表4所示。我们可以观察到,对于这两种零样本方法,基于GPT-4的方法虽然带来了更高的经济成本,但能实现比基于GPT-3.5的方法更高的准确率。另一方面,在准确率和成本方面,视觉编程方法总是优于与LLM对话的方法,这证明了我们所提出的视觉编程方法的有效性。为了节约成本,在其他实验中我们使用了GPT-3.5。
关系模块。 我们现在对不同的关系模块进行消融分析,以探究它们对系统性能的影响。最重要的视角依赖和视角无关模块的结果分别呈现在表5和表6中。我们可以看到,“LEFT”(左)和“RIGHT”(右)是最重要的视角依赖关系,而“CLOSEST”(最近)是最重要的视角无关关系。这一结果与我们的初衷和设计是一致的。
LOC模块。 我们通过分别移除3D组件和2D组件的方式,来对我们的方法进行并列比较。两种模型都利用了Mask3D的实例掩码预测。特别地,纯2D模型仅使用成对的2D图像进行分类,而纯3D模型仅使用3D结果。从表2和表3中可以看出,当室内场景的图像很复杂或与训练样本存在较大差异时,纯2D模型的表现更差。纯3D模型的表现更好,因为它能利用几何信息并且是在闭集标签上训练的。我们的完整模型总能达到最佳性能,因为它既整合了点云的几何独特性,又具备了图像模型的开放词汇能力。
泛化性。 我们的框架对于一系列3D和2D感知模型具有很强的适应性。为了验证这一说法,我们使用几个有代表性的模型进行了实验。对于3D感知,我们使用了三个主干网络,即PointNet++、PointBERT和PointNeXt。对于2D感知,我们使用了在[40]中提出的图像分类模型、一个视觉问答模型,以及一个通用的大型模型BLIP-2进行测试。结果如表7和表8所示。我们可以观察到,我们的框架与其他模型兼容。同时,它还能利用2D和3D基础模型的进展来提升性能。这种跨模型的有效性证明了我们的方法在不断发展的视觉感知模型领域中的稳健性和面向未来的特性。

提示(Prompt)大小的影响。 我们在程序生成过程中使用了不同数量的上下文示例。结果显示在图6中。可以看到,随着示例数量的增加,在ScanRefer和Nr3d上的性能都得到了提升。这是因为更多的示例可以引导LLM在视觉程序生成过程中处理更多的情况。与此同时,这也遵循边际效用递减法则。此外,我们测试了投票技术来聚合多次运行的结果,这也带来了一些性能增益。
错误分析。 为了更好地理解我们框架的局限性,我们进行了如下的错误分析。在每个数据集中,我们选择了一个包含约100个样本的代表性子集,并手动检查了视觉程序提供的基本原理。这种内省的方法帮助我们识别了主要的错误来源,并为改进我们的框架提供了指导。结果如图7所示,它揭示了生成准确的视觉程序是主要的错误来源。通过使用更多的上下文示例和更强大的LLM,性能可以得到提升。第二个错误来源是对象的定位和分类,这表明3D空间中的对象检测和分类仍然是一个关键组成部分。此外,结果还指出需要开发额外的模块来处理更广泛的空间关系,如“opposite”(对面)。这些问题在当前的框架中尚未得到很好的解决。
定性结果

图5展示了从ScanRefer验证集中选取样本的可视化结果。图中的四列分别展示了真值结果、监督方法BUTD-DETR的结果、与LLM对话方法的结果,以及我们的视觉编程方法的结果。从图5(a)和图5(b)中,我们可以观察到,“与LLM对话”和我们的“视觉编程”方法都能在视角无关关系(例如,上方、下方)上取得准确的预测结果。
相反,如图5©和图5(d)所示,BUTD-DETR和“与LLM对话”这两种方法无法很好地处理视角依赖关系(例如,左侧、前方)。这些现有方法固有的不确定性反映了它们的局限性。而我们的视觉编程方法能够利用2D自我中心视角,从而在3D场景中实现准确的预测。
图5(e)展示了一个失败案例,其中“与LLM对话”的方法因为缺乏开放词汇检测能力而无法识别“带轮子的椅子”。此外,我们的视觉编程方法最初也做出了错误的预测,因为LLM未能正确识别“被推”这个关系。幸运的是,当我们使用CLOSEST模块修正程序后,视觉编程方法便能做出正确的预测。
Conclusion
在本文中,我们为3D视觉定位(3DVG)提出了一种新颖的零样本方法,以消除对大量标注和预定义词汇表的需求。我们首先提出了一种与大语言模型(LLM)进行交互式对话的基础方法。在此之上,我们进一步开发了一种视觉编程方法,该方法利用三类模块来驾驭复杂的3D关系。为了适应开放词汇的场景,我们还开发了一个语言-对象关联(LOC)模块,以无缝整合3D和2D的特征。实验结果证明了我们所提出方法的优越性,并凸显了其推动3DVG领域发展的潜力。
Limitations
要找到局限性,我们需要思考模型做出了哪些“理想化假设”,以及在哪些更复杂的真实场景下可能会失效。
-
LLM到程序解析器的脆弱性 (Fragility of the Parser)
- 论文最大的创新点是将语言翻译为视觉程序,但其核心瓶颈也恰恰在此。LLM虽然强大,但它生成的程序逻辑并非100%可靠。论文自身的错误分析也表明,程序生成错误(Prog)是主要的错误来源 。这意味着,如果LLM对自然语言的理解出现一丝偏差,生成的程序在逻辑上就是错的,后续步骤再精确也无法挽回。系统缺乏对生成程序的验证和纠错机制。
-
视觉程序“语法”的局限性 (Limited Grammar of the Visual Program)
- 系统依赖一组预先定义好的功能模块(
LOC,CLOSEST,RIGHT等) 。这套“语法”是封闭的。虽然论文声称是“开放词汇”,但这主要体现在LOC模块对物体本身的识别上,而非对空间关系的理解上。论文的错误分析自己也承认,无法处理像“opposite”(对面)这样的新关系。如果用户提出更复杂、更抽象的描述,如“看起来最舒服的椅子”、“像是刚刚被移动过的物体”,现有模块库将无能为力。
- 系统依赖一组预先定义好的功能模块(
-
静态、孤立的场景理解 (Static and Isolated Scene Understanding)
- 该方法处理的是静态的3D扫描数据 。真实世界是动态的,充满了交互和变化。该框架无法理解涉及时间、动作或因果关系的指令,例如:“找到我刚刚放在桌子上的杯子”或“哪个物体挡住了窗户的光线?”。
-
非交互式的一次性执行 (Non-Interactive “Fire-and-Forget” Execution)
- 整个流程是“一次性”的:输入一句话,输出一个结果。如果模型产生歧义或不确定性(例如,找到两把都离门很近的椅子),它无法像人一样主动提问以澄清(“您是指左边那把还是右边那把?”)。虽然论文一开始提到了对话方法 ,但最终的视觉编程方案却牺牲了这种交互性。
-
对上游模型的严重依赖 (Heavy Reliance on Upstream Models)
- 系统的性能上限被两个核心组件锁死:3D实例分割模型(如Mask3D)的准确率和大语言模型(LLM)的质量。如果底层的Mask3D未能正确分割出物体(即
Loc和Cls错误),那么整个上层逻辑再完美也无济于事,这是一个典型的“错误级联”问题。
- 系统的性能上限被两个核心组件锁死:3D实例分割模型(如Mask3D)的准确率和大语言模型(LLM)的质量。如果底层的Mask3D未能正确分割出物体(即
-
推理成本与延迟 (Inference Cost and Latency)
- 依赖大型LLM(特别是GPT-4)进行程序生成,其推理成本高昂且速度较慢 。这对于需要实时响应的应用(如机器人交互、AR/VR)来说是一个巨大的实际障碍。
Direction For Improvment
-
引入程序验证与反馈循环 (Program Verification & Feedback Loop)
- 在LLM生成程序后,增加一个“验证”步骤。例如,可以再用一个LLM将生成的程序“翻译”回自然语言,然后计算其与原始查询的语义相似度。如果相似度低,则认为程序生成错误,并触发带有错误提示的重新生成。
-
扩充与动态生成关系模块 (Augmenting and Dynamically Generating Modules)
- 短期方案:手动扩充模块库,增加如
OPPOSITE,ABOVE,BIGGEST等更多功能模块。 - 长期方案:研究让LLM动态生成新的模块代码。当遇到未知关系时,通过特定的“元编程”提示(Meta-Programming Prompt),让LLM学习现有模块的实现方式,从而为新关系生成可执行的Python函数代码。这将使系统真正走向“开放关系”理解。
- 短期方案:手动扩充模块库,增加如
-
融合交互式对话 (Integrating Interactive Dialogue)
- 将视觉编程嵌入到一个交互式框架中。当系统检测到不确定性时(例如,多个候选对象得分相近),可以暂停执行并向用户提问。用户的回答(如“左边那个”)将被编译成程序的新一行(
TARGET = LEFT(...)),然后继续执行。这样,对话就成了程序构建的一部分,极大地提升了鲁棒性。
- 将视觉编程嵌入到一个交互式框架中。当系统检测到不确定性时(例如,多个候选对象得分相近),可以暂停执行并向用户提问。用户的回答(如“左边那个”)将被编译成程序的新一行(
-
探索端到端或联合优化 (Exploring End-to-End or Joint Optimization)
- 虽然零样本是本文的亮点,但可以探索少样本微调 (few-shot fine-tuning) 的可能性。通过少量数据对整个管线(特别是分割模块和定位模块)进行联合微调,可能会让各模块之间配合得更默契,缓解错误级联问题。
-
模型蒸馏与轻量化 (Model Distillation and Lightweighting)
- 为了解决成本和延迟问题,可以研究是否能将大型LLM的程序生成能力蒸馏 (distill) 到一个更小的、专门微调过的模型(如T5、Llama的较小版本)上,以满足实际应用的需求。
Appendix
Appendix1:ScanRefer 和 Nr3D 评估设置
这两种评估设置的核心区别在于,它们旨在 解耦(decouple) 并独立评估一个3DVG(3D视觉定位)系统的两种核心能力:
- 视觉感知与定位能力 (Visual Perception & Localization):在复杂的3D场景中准确地“找到”物体的能力。
- 指代关系理解能力 (Referential Comprehension):理解语言描述中复杂的空间、属性关系(如“最左边的”、“…后面的”、“红色的”)并进行正确推理的能力。
第一种设置:端到端(End-to-End)综合评估 (ScanRefer默认设置)
目标:评估模型在真实应用场景下的端到端综合性能。这要求模型从原始的3D场景数据出发,自己完成物体发现和指代识别的全过程。
Pipeline 详细拆解:
Step 1: 输入数据 (Input)
- 3D场景数据 (3D Scene Data):
- 数据结构: 通常是一个点云 (Point Cloud)。
- 数据格式/维度 (Shape): 一个
[N, D]的浮点数矩阵。N: 场景中点的总数量,通常是几十万到上百万。D: 每个点的特征维度。最基础的是6维[X, Y, Z, R, G, B],分别代表三维坐标和颜色。有时也会包含法线等其他特征。
- 文本查询 (Text Query):
- 数据结构: 一个字符串 (String)。
- 示例:
"the chair closest to the window"。
Step 2: 候选对象生成 (Candidate Proposal Generation)
这是该设置的关键步骤,也是模型视觉感知能力的体现。
- 输入:
[N, D]的点云数据。 - 执行模块: 一个独立的、预训练的3D实例分割模型 (3D Instance Segmentation Model),例如论文中可能提到的
Mask3D。 - 处理过程: 该模型扫描整个点云,尝试将属于同一个物体实例的点聚合在一起。它不理解文本查询,只负责找出场景中所有的“物体”。
- 输出: 一组
K个候选对象提案。这组提案通常有两种表示形式:- 实例掩码 (Instance Masks): 一个
[N, 1]的整数向量,其中每个点被分配一个从1到K的实例ID(0通常代表背景)。这精确定义了每个候选对象的形状。 - 3D边界框 (3D Bounding Boxes): 一个
[K, 7+]的矩阵,每行代表一个候选对象。[center_x, center_y, center_z, size_l, size_w, size_h, class_id, ...]。
- 重要提示: 这一步是不完美的。模型可能会漏掉某些物体,或者把一个物体分割成两个,或者把两个物体合并成一个。这引入了定位误差 (Localization Error)。
- 实例掩码 (Instance Masks): 一个
Step 3: 指代关系定位 (Referential Grounding)
现在,模型需要将文本查询与这 K 个不完美的候选对象进行匹配。
- 输入:
K个候选对象(及其特征)。- 文本查询字符串。
- 执行模块: 3DVG模型的核心推理模块。
- 处理过程:
- 模型为文本查询生成一个文本特征向量 (Text Embedding)。
- 模型为
K个候选对象中的每一个都提取一个视觉特征向量 (Visual Embedding)。 - 计算文本特征向量与每一个视觉特征向量之间的相似度分数 (Similarity Score)(例如,余弦相似度)。
- 输出: 相似度分数最高的那个候选对象的索引 (index),记为
i_pred。这个索引指向K个候选对象中的一个。
Step 4: 评估 (Evaluation)
- 输入:
- 模型预测的候选对象
Proposal_pred(即第i_pred个候选对象)。 - 数据集中预先标注的真值对象 (Ground-Truth Object)
Object_gt。
- 模型预测的候选对象
- 执行模块: 评估脚本。
- 处理过程: 计算
Proposal_pred和Object_gt的 3D交并比 (3D Intersection over Union, IoU)。IoU = (Intersection_Volume) / (Union_Volume)
- 输出 (最终指标):
- Acc@0.5: 如果
IoU > 0.5,则认为本次预测正确。最终统计所有样本的正确率。 - Acc@0.25: 如果
IoU > 0.25,则认为本次预测正确。
- Acc@0.5: 如果
此设置的本质:这是一个对整个系统能力的全面大考。模型得分低,可能是因为它“眼睛不行”(Step 2没找到物体),也可能是因为它“脑子不行”(Step 3没理解对关系),无法区分具体是哪个环节出了问题。
第二种设置:逻辑推理专项评估 (Nr3D默认设置)
目标:剥离视觉感知和定位的难度,专门且精确地评估模型对语言和空间关系的理解与推理能力。
Pipeline 详细拆解:
Step 1: 输入数据 (Input)
- 3D场景数据: 同上,
[N, D]的点云。 - 文本查询: 同上,字符串。
- 真值的对象掩码 (Ground-Truth Object Masks): 这是与第一种设置的核心区别。 数据结构: 一个
[N, 1]的整数向量,其中每个点都已经被完美地分配到了一个真值物体的ID。例如,所有属于“门”的点都被标记为1,所有属于“椅子A”的点都被标记为2,所有属于“椅子B”的点都被标记为3,等等。总共有M个已知的、完美的物体分割。
Step 2: 指代关系分类 (Referential Classification)
由于所有物体的位置和形状都已是“开卷”信息,任务从“寻找”变成了“选择”。
- 输入:
M个完美的、已知的物体实例(及其特征)。- 文本查询字符串。
- 执行模块: 3DVG模型的核心推理模块。
- 处理过程:
- 模型为文本查询生成文本特征向量。
- 模型为每一个已知的真值物体(共
M个)提取视觉特征向量。 - 计算文本特征向量与这
M个真值物体的视觉特征向量的相似度分数。
- 输出: 模型认为最匹配的那个真值物体的ID或索引,记为
id_pred。这本质上是一个多选一的分类问题。
Step 3: 评估 (Evaluation)
- 输入:
- 模型预测的物体ID
id_pred。 - 数据集中标注的真值ID
id_gt。
- 模型预测的物体ID
- 执行模块: 评估脚本。
- 处理过程: 直接比较两个ID是否相等。
- 输出 (最终指标): 分类准确率 (Classification Accuracy)。
- 如果
id_pred == id_gt,则预测正确。最终计算总的正确率。
- 如果
此设置的本质:这是一场“闭卷”的逻辑考试。我们确保了模型“看”的能力是100%完美的,因为它拿到了所有物体的标准答案。如果此时模型还犯错,就只能说明它没能理解“离…最近的”、“…后面的”这类复杂的语言和空间关系。这能精准地衡量模型的“大脑”——即推理核心的性能。
| 特性 | ScanRefer 设置 (综合评估) | ** Nr3D设置 (专项评估)** |
|---|---|---|
| 核心目标 | 评估端到端真实场景性能 | 评估纯粹的语言/空间关系推理能力 |
| 是否提供GT物体 | 否 | 是 (核心区别) |
| AI主要任务 | 定位 + 分类 (先找,再认) | 纯分类 (从已知列表中选一个) |
| 引入的误差源 | 定位误差 + 推理误差 | 仅推理误差 |
| 评估指标 | IoU (重合度),如 Acc@0.5 |
Classification Accuracy (分类准确率) |
Appendix2:LOC模块消融
这段文字描述的是一个典型的消融研究 (Ablation Study)。其唯一目的就是通过科学的控制变量法,来验证并量化其“完整模型”中每个关键组件的必要性和贡献。
在这里,研究者提出的LOC模块是一个3D与2D特征融合的方案。为了证明这种融合的优越性,他们设计了两个“被削弱”的对照组版本:一个只用3D信息,一个只用2D信息。通过对比这三者的性能,就能雄辩地证明“3D+2D”为何是最佳选择。
所有这三个模型都共享同一个前提:它们都接收由底层3D实例分割模型(如Mask3D)预测出的实例掩码 (instance mask) 作为输入。这意味着,在比较开始之前,“场景中哪些点云构成一个物体”这个问题已经被初步解答了。它们的区别在于如何利用这些分割好的物体实例来与文本查询进行匹配。
Pipeline 1: 完整LOC模型 (3D + 2D 协同工作)
这是作者提出的最终方案,也是实验中的“完全体”。
目标: 结合3D的几何鲁棒性和2D的开放词汇理解力,实现精准、细粒度的对象定位。
管线拆解:
-
输入 (Input):
- 文本查询 (Text Query): 字符串,例如
"一个红色的皮质扶手椅"。 - 实例掩码 (Instance Masks): 一个
[N, 1]的整数向量,其中N是场景点云总数。该向量将每个点分配给K个检测到的物体实例之一。同时,每个实例还附带一个由3D模型预测的闭集类别(如“椅子”)。
- 文本查询 (Text Query): 字符串,例如
-
Step 1: 3D几何与闭集类别过滤 (Coarse-grained Filtering)
- 执行模块: 3D处理组件。
- 处理过程: 模型首先解析文本查询,提取出核心的、可能存在于闭集词汇表中的基本类别 (base category),比如从“红色的皮质扶手椅”中提取出“椅子”。然后,它会从
K个候选实例中,筛选出所有被3D模型初步判断为“椅子”的实例。 - 输出: 一个数量为
K'(K' <= K) 的候选实例子集。这个子集里的所有物体在几何结构上都与“椅子”类似。这一步极大地缩小了搜索范围。
-
Step 2: 2D外观与开放词汇重排序 (Fine-grained Re-ranking)
- 执行模块: 2D处理组件(例如,基于CLIP的视觉语言模型)。
- 输入:
K'个候选实例子集和完整的文本查询"一个红色的皮质扶手椅"。 - 处理过程:
a. 对于K'个候选实例中的每一个,将其对应的点云投影或渲染成一个或多个2D图像。
b. 将这些2D图像输入到视觉语言模型中,与完整的文本查询进行匹配,计算出一个相似度分数。这个模型能够理解“红色”、“皮质”、“扶手椅”这类细粒度和开放词汇的描述。 - 输出: 在
K'个候选者中,获得最高相似度分数的那个实例,作为最终的预测结果。
Pipeline 2: 纯3D模型 (3D-only Ablation)
这是“消融”掉2D组件后的版本,代表了传统的、依赖几何和固定词汇表的方法。
目标: 验证仅靠3D几何信息和闭集分类的性能上限。
管线拆解:
- 输入: 与完整模型相同。
- 处理过程:
- 模型同样从文本查询中提取基本类别,如“椅子”。
- 它直接在
K个初始候选实例中,选择由3D模型给出的“椅子”类别置信度最高 (highest confidence score) 的那一个。它完全没有能力处理“红色”或“皮质”等任何在2D图像中才能体现的、或超出其闭集词汇表的属性。
- 输出: 3D模型认为最像“椅子”的那个实例。
分析:
- 优势:
因为它能利用几何信息...这意味着它的判断基于稳定的3D结构,不受2D图像视角变化、光照、遮挡的影响,因此结果相对稳健 (robust)。 - 劣势:
...并且是在闭集标签上训练的。这是它的“阿喀琉斯之踵”。它的词汇量被严格限制在训练时见过的几十个类别里,无法泛化到新物体,也无法理解颜色、材质、风格等细粒度描述。
Pipeline 3: 纯2D模型 (2D-only Ablation)
这是“消融”掉3D组件后的版本,代表了完全依赖强大的2D视觉语言模型的方法。
目标: 验证仅靠2D图像和开放词汇模型的性能上限。
管线拆解:
- 输入: 与完整模型相同。
- 处理过程:
- 该模型跳过了3D过滤步骤。它直接将
Mask3D检测出的全部K个实例逐一投影成2D图像。 - 然后,它让2D视觉语言模型将这
K组图像分别与完整的文本查询进行比较,计算相似度分数。
- 该模型跳过了3D过滤步骤。它直接将
- 输出: 在全部
K个候选者中,获得最高相似度分数的那个实例。
分析:
- 优势: 理论上它拥有最强的语言理解能力,能够处理任意复杂的开放词汇描述。
- 劣势:
当室内场景的图像很复杂...: 3D物体投影到2D时会产生巨大的歧义性。例如,从正上方看,椅子、桌子和凳子可能都是一个相似的方形或圆形,导致模型混淆。...或与训练样本存在较大差异时...(Domain Gap): 2D视觉语言模型(如CLIP)是在海量的、高质量的互联网图片上预训练的。而3D扫描数据投影成的2D图像往往充满噪点、几何畸变、纹理缺失和不自然的光照。这种数据分布的巨大差异导致模型性能显著下降。
通过这三个Pipeline的对比,实验结果(表2和表3)揭示了以下事实:
- 纯2D模型表现最差: 尽管它有开放词汇能力,但它无法克服2D视图的歧义性和3D到2D的数据域差异问题,导致在复杂真实场景中频繁出错。
- 纯3D模型表现居中: 它虽然“词汇量小、不懂细节”,但胜在基础扎实,对几何结构的判断稳定可靠,因此下限更高。
- 完整LOC模型表现最佳: 它完美地结合了二者之长。用3D模型的几何稳定性进行高效、可靠的初步筛选,再用2D模型的开放词汇能力进行精准、细致的最终决策。这种“先粗后精”的协同工作流程,使其既稳健又精准,性能远超任何一个单一组件。
Appendix3:错误分析

为什么要进行错误分析?
错误分析就是这样一个过程:研究者们不再关注做对的案例,而是专门挑出错的案例,像侦探一样逐一排查,弄清楚“案发”的第一现场,即导致最终结果错误的最根本原因是什么。这能为后续的改进提供最直接的指导。
“手动检查”的过程
原文提到他们“手动检查了视觉程序提供的基本原理”。这是什么意思呢?
在之前的解析中我们知道,这个框架的核心是让LLM生成一个“视觉程序”,例如:
# 描述:“离门最近的椅子”
Program:
BOX0 = LOC('chair')
BOX1 = LOC('door')
TARGET = CLOSEST(targets=BOX0, anchors=BOX1)
当最终结果出错时,研究人员会回过头来,一步步地检查这个流程:
- 程序本身对吗?(Prog):LLM生成的这个程序,其逻辑是否符合用户的意图?有没有可能它错误地生成了
RIGHT(...)而不是CLOSEST(...)? - 模块执行对吗?(Exec/Rel):如果程序逻辑是对的,那么在执行
CLOSEST这个关系模块时,它有没有算错距离? - 物体定位/分类对吗?(Loc/Cls):在最开始执行
LOC('chair')时,模型到底有没有找到场景中所有的椅子?有没有把一个凳子错误地识别成了椅子?
通过这样的人工排查,他们就能把每一个错误案例归因到具体的步骤上。
图7:错误来源饼图解析
这张图用两个饼图(分别对应ScanRefer和Nr3D两个数据集)直观地展示了错误原因的分布。我们来逐一解释每个扇区代表的含义:
-
Correct (绿色): 正确。这部分代表模型完全做对的案例比例。这是我们的基准,我们希望这个绿色区域越大越好。在Nr3D数据集上,正确率(41.4%)明显高于ScanRefer(31.3%)。
-
Prog (红色) - 程序生成错误 (Program Generation Error):
- 含义: 这是最主要的错误来源。它指的是LLM本身“理解错了”,生成了一个逻辑上就有问题的程序。
- 例子: 用户想找“离门最远的椅子”,但LLM生成的程序却是
CLOSEST(...)。程序本身就是错的,后面即使执行得再完美,结果也必然是错的。 - 解决方案: 如文中所说,通过给LLM提供更多、更高质量的“上下文示例”(就像教学生做题时多给几个例题),或者直接换一个更聪明的LLM(如从GPT-3.5升级到GPT-4),可以改善这个问题。
-
Cls (紫色) - 分类错误 (Classification Error):
- 含义: 这是第二大错误来源。它指的是底层的视觉模型“认错了”物体。
LOC模块成功找到了一个物体,但给它贴错了基本类别的标签。 - 例子: 场景里有一个矮凳和一个茶几,用户想找“茶几”,但模型把那个矮凳识别成了“茶几”。
- 根本原因: 这表明底层的3D物体识别能力仍是瓶颈。
- 含义: 这是第二大错误来源。它指的是底层的视觉模型“认错了”物体。
-
Rel (浅绿色) - 关系模块错误 (Relation Module Error):
- 含义: 程序是对的,物体也找对了,但是在执行关系判断(如
CLOSEST,RIGHT)时出错了。 - 例子: 程序正确地生成了
CLOSEST(...),并且也找到了场景中所有的椅子和门,但在计算距离时出现了偏差,选错了椅子。 - 引申问题: 如文中所说,这也暴露了现有关系模块的局限性。比如用户想找“门对面的椅子”,但系统里根本没有
OPPOSITE(...)这个模块,自然无法处理。
- 含义: 程序是对的,物体也找对了,但是在执行关系判断(如
-
Loc (橙色) - 定位错误 (Localization Error):
- 含义: 这指的是底层视觉模型根本就没找到或者没找全目标物体。
- 例子: 场景里有三把椅子,但
LOC('chair')这一步只检测出了两把,而用户想找的恰好是那把被漏掉的椅子。
-
Exec (蓝色) - 执行错误 (Execution Error):
- 这是一个更宽泛的类别,可以理解为除了上述原因之外的其他执行层面的错误,通常占比较小。
通过这份“体检报告”,研究者得出了几个关键结论:
- 最大的瓶颈在于“大脑规划”:
Prog错误占比最高,说明当前模型最大的挑战是如何让LLM准确地将人类的模糊语言转换成机器可以理解的、逻辑正确的程序步骤。提升LLM的规划能力是未来的首要任务。 - “视力”仍然是基础且关键:
Cls和Loc错误加起来是第二大错误来源,这提醒我们,无论上层逻辑多完美,如果底层的物体检测和分类能力跟不上,整个系统依然会失败。基础视觉模型的性能至关重要。 - “工具箱”需要扩充:
Rel错误和文中提到的opposite例子表明,要让系统更通用,就需要不断开发和完善更多的功能模块(关系模块),让它能处理更丰富的空间关系描述。
Appendix4:方法的全流程
让我们使用论文图 2(b) 和图 3 中的一个复杂例子,因为它涉及了关键的视角依赖 (view-dependent) 关系,这是该方法着力解决的难点之一 。
初始输入:
- 3D 场景扫描 (Input 3D Scan):一个经过处理的室内场景点云。
- 数据结构: 一个大型的点集合
P。 - 数据格式/维度: 一个 PyTorch Tensor 或 NumPy 数组,形状为
[N, 6]。N是场景中点的总数量(例如 N=500,000)。6代表每个点的 6 个特征维度:(x, y, z, R, G, B),即三维坐标和颜色信息 。
- 数据结构: 一个大型的点集合
- 文本描述 (Grounding description):一句描述目标物体的自然语言。
- 数据结构: 字符串 (String)。
- 具体例子:
"Staring at the cabinets you want the window on the right side"(盯着橱柜,你想要右侧的那个窗户) 。
步骤 1: 生成 3D 视觉程序 (Visual Program Generation)
这一步的核心是将自然语言指令转化为一个机器可执行的、结构化的程序。
-
输入:
- 查询文本:
"Staring at the cabinets you want the window on the right side"。 - 上下文示例 (In-context examples): 提供给大语言模型 (LLM) 的几个“问题-程序”对,让它学习如何转换。例如,提供一个例子 :
- 输入描述:
"The round cocktail table in the corner of the room with the blue and yellow poster" - 输出程序:
BOX0=LOC('round cocktail table') BOX1=LOC('blue and yellow poster') TARGET=CLOSEST(targets=BOX0, anchors=BOX1)
- 输入描述:
- 查询文本:
-
处理过程:
- 我们将用户的查询文本和这些上下文示例一起打包成一个 Prompt。
- 将这个 Prompt 发送给一个大型语言模型 (LLM),如 GPT-3.5 或 GPT-4 。
- LLM 利用其在上下文中学习 (in-context learning) 的能力,解析新的查询语句,并模仿示例的格式,生成一个新的、针对当前查询的视觉程序 。
-
输出:
-
数据结构: 一个多行字符串,即“视觉程序”。
-
具体输出:
BOX0=LOC('window') BOX1=LOC('cabinet') TARGET=RIGHT(targets=BOX0, anchors=BOX1) -
含义解析:
BOX0=LOC('window'): 首先,使用LOC(Language-Object Correlation) 模块,在场景中定位所有类别为“窗户”的物体,将结果存入变量BOX0。BOX1=LOC('cabinet'): 同样,使用LOC模块定位所有“橱柜”,结果存入BOX1。TARGET=RIGHT(targets=BOX0, anchors=BOX1): 最后,调用RIGHT模块,以BOX1(橱柜) 为锚点 (anchors),判断BOX0(所有窗户) 中哪一个位于其右侧,并将最终结果存入TARGET。
-
步骤 2: 解释并执行视觉程序 (Program Interpretation and Execution)
现在,系统需要逐行解释并执行上面生成的程序。
执行第 1 行: BOX0 = LOC('window')
-
输入:
- 整个场景的点云数据 (
P, shape[N, 6])。 - 查询词:
'window'。
- 整个场景的点云数据 (
-
处理过程 (Language-Object Correlation 模块):
- 3D 实例分割 (Closed-vocabulary Instance Segmentation): 首先,使用一个预训练好的、基于封闭词汇表的 3D 实例分割网络(如论文中使用的 Mask3D )来处理整个场景的点云。
- 输出: 一个物体提案列表 (list of object proposals)。假设场景中有 1 个桌子、2 把椅子、2 个窗户和 1 个橱柜。模型会输出这 6 个物体的实例信息。每个实例信息可以是一个字典:
{ 'instance_id': 0, 'label_name': 'table', # 预测的类别 'points_mask': <boolean_tensor of shape [N]>, # 标记哪些点属于这个实例 'bbox_3d': [center_x, y, z, size_w, l, h] # 3D包围盒 }
- 输出: 一个物体提案列表 (list of object proposals)。假设场景中有 1 个桌子、2 把椅子、2 个窗户和 1 个橱柜。模型会输出这 6 个物体的实例信息。每个实例信息可以是一个字典:
- 类别过滤 (Filter): 根据
LOC函数的参数'window',从上述列表中筛选出所有label_name是'window'的物体。- 输出: 一个列表,包含所有候选窗户的实例信息。假设我们找到了 2 个窗户。
BOX0_candidates=[window_instance_1, window_instance_2]。
- 输出: 一个列表,包含所有候选窗户的实例信息。假设我们找到了 2 个窗户。
- 2D 多模态模型验证 (2D Multi-modal Models Verification): 论文提到,为了处理更复杂的描述(如“圆的鸡尾酒桌”),
LOC模块还会将每个 3D 物体提案投影到对应的 2D 图像上,并使用 2D 多模态模型(如 CLIP, VQA 模型)进行更精细的匹配 。对于简单的'window',这一步可能直接通过,因为 3D 分割的类别已经足够。- 输入: 每个 3D 窗户实例对应的 2D 图像切片。
- 过程: 使用 CLIP 计算图像和文本
'window'的相似度,或用 VQA 模型提问“这是一个窗户吗?” 。 - 输出: 确认这两个实例都是窗户。
- 3D 实例分割 (Closed-vocabulary Instance Segmentation): 首先,使用一个预训练好的、基于封闭词汇表的 3D 实例分割网络(如论文中使用的 Mask3D )来处理整个场景的点云。
-
本行最终输出 (
BOX0):- 数据结构: 一个包含两个物体实例信息的列表:
[window_instance_1, window_instance_2]。
- 数据结构: 一个包含两个物体实例信息的列表:
执行第 2 行: BOX1 = LOC('cabinet')
- 输入: 场景点云
P和查询词'cabinet'。 - 处理过程: 与上一步完全相同,只是查询词换成了
'cabinet'。 - 本行最终输出 (
BOX1):- 数据结构: 一个只包含一个橱柜实例信息的列表:
[cabinet_instance_1]。
- 数据结构: 一个只包含一个橱柜实例信息的列表:
执行第 3 行: TARGET = RIGHT(targets=BOX0, anchors=BOX1)
这是最关键的一步,用于解决视角依赖关系。
-
输入:
targets:BOX0,即[window_instance_1, window_instance_2]。anchors:BOX1,即[cabinet_instance_1]。
-
处理过程 (View-dependent Module):
- 确定参考系: 论文提出,为了定义“左/右/前/后”,需要建立一个以观察者为中心的自我视角 (egocentric view) 。
- 计算锚点中心 (
P_anchor): 获取cabinet_instance_1的 3D 包围盒中心坐标。 - 设定观察者位置 (
P_center): 简单起见,可以设为整个房间的几何中心 。
- 计算锚点中心 (
- 建立视角: 使用一个
LookAt视图变换函数,计算一个旋转矩阵R和一个平移矩阵T。这个变换的作用是,将整个场景进行虚拟的旋转和平移,使得位于P_center的虚拟相机正好“看向”P_anchor。 - 3D 到 2D 投影: 将目标物体 (targets) 的中心点坐标(即
window_instance_1和window_instance_2的中心点P_w1,P_w2)应用上一步得到的(R, T)变换,并将它们投影到一个 2D 平面上 。- 公式:
(u, v, w)^T = Camera_Intrinsic * (R | T) * P_world。 P_world是窗户在原始世界坐标系下的中心点。(u, v)是投影到 2D 平面后的坐标,w是深度。
- 公式:
- 2D 空间关系判断: 在这个投影后的 2D 平面上,关系就变得非常明确了 。
- “右 (right)” 对应于
u值更大的那个点 。 - “左 (left)” 对应于
u值更小的那个点 。 - “前 (front)” 和 “后 (behind)” 可以通过比较深度值
w来判断 。
- “右 (right)” 对应于
- 筛选: 比较
window_instance_1和window_instance_2投影后的u值。假设window_instance_2的u值更大,那么它就是“右侧的窗户”。
- 确定参考系: 论文提出,为了定义“左/右/前/后”,需要建立一个以观察者为中心的自我视角 (egocentric view) 。
-
本行最终输出 (
TARGET):- 数据结构: 一个只包含最终目标物体实例信息的列表:
[window_instance_2]。
- 数据结构: 一个只包含最终目标物体实例信息的列表:
最终产出 (Final Output)
- 程序执行完毕,
TARGET变量中存储的就是最终定位到的物体。系统返回该物体的 3D 包围盒信息window_instance_2['bbox_3d']。
import torch
# 假设这些是预先加载或定义的外部库/模型
from llm_api import LargeLanguageModel
from perception_models import Mask3D, CLIPModel, VQAModel
# --- 数据结构定义 (为了清晰) ---
class ObjectInstance:
def __init__(self, instance_id, label_name, points_mask, bbox_3d):
self.id = instance_id
self.label = label_name # str, e.g., 'chair'
self.mask = points_mask # Tensor [N], bool
self.bbox = bbox_3d # Tensor [6], (center_xyz, size_wlh)
def get_center(self):
return self.bbox[:3]
class SceneData:
def __init__(self, point_cloud):
# point_cloud: Tensor [N, 6] -> (x, y, z, r, g, b)
self.point_cloud = point_cloud
self.num_points = point_cloud.shape[0]
# 预先计算场景中心,用于视角依赖模块
self.scene_center = torch.mean(point_cloud[:, :3], dim=0)
# --- 核心模块实现 ---
def generate_visual_program(query_text: str, llm: LargeLanguageModel) -> str:
"""
步骤 1: 使用 LLM 将自然语言查询转换为视觉程序。
"""
# 构建 few-shot prompt,包含上下文示例
prompt = f"""
Here are some examples of converting natural language to a visual program:
Description: The round cocktail table in the corner of the room with the blue and yellow poster.
Program:
BOX0=LOC('round cocktail table')
BOX1=LOC('blue and yellow poster')
TARGET=CLOSEST(targets=BOX0, anchors=BOX1)
---
Description: {query_text}
Program:
"""
# 调用 LLM API 生成程序
program_string = llm.generate(prompt)
return program_string
def execute_loc(scene_data: SceneData, object_description: str,
detector_3d: Mask3D, clip_model: CLIPModel) -> list[ObjectInstance]:
"""
执行 LOC 模块: 定位场景中的物体。
"""
# 1. 使用 3D 实例分割模型获取所有物体提案
# all_proposals 是一个 ObjectInstance 对象的列表
all_proposals = detector_3d.predict(scene_data.point_cloud)
# 2. 粗略过滤:基于描述中的名词(这里简化处理,实际可能需要NLP解析)
# 例如,对于 "round cocktail table", 核心名词是 "table"
main_category = object_description.split(' ')[-1] # 简单提取最后一个词为类别
candidate_proposals = [p for p in all_proposals if p.label == main_category]
if not candidate_proposals:
return []
# 3. 精细匹配:使用 2D 多模态模型进行验证
# (为简化,此处仅示意,实际需要投影3D点到2D图像)
verified_proposals = []
text_features = clip_model.encode_text(object_description)
for proposal in candidate_proposals:
# 假设有函数可以从3D实例中提取2D图像
image_2d = extract_2d_image_for_instance(proposal, scene_data)
image_features = clip_model.encode_image(image_2d)
# 计算相似度并根据阈值筛选
similarity = torch.cosine_similarity(text_features, image_features)
if similarity > 0.8: # 假设阈值为 0.8
verified_proposals.append(proposal)
return verified_proposals
def execute_right(targets: list[ObjectInstance], anchors: list[ObjectInstance], scene_data: SceneData) -> list[ObjectInstance]:
"""
执行 RIGHT 模块 (视角依赖)。
"""
if not targets or not anchors:
return []
# 1. 确定锚点中心和观察者位置
anchor_center = torch.stack([anc.get_center() for anc in anchors]).mean(dim=0)
observer_pos = scene_data.scene_center
# 2. 计算 LookAt 视图变换矩阵
# look_at 返回 4x4 的视图矩阵 (包含了 R 和 T)
view_matrix = look_at(observer_pos, anchor_center, up_vector=torch.tensor([0, 0, 1]))
# 3. 投影目标到 2D 平面并比较 u 坐标
projected_coords = []
for target_obj in targets:
target_center_homogeneous = torch.cat([target_obj.get_center(), torch.tensor([1.0])])
# 应用视图变换,忽略相机内参和透视除法以简化,只关心相对位置
camera_coords = torch.mv(view_matrix, target_center_homogeneous)
u = camera_coords[0] # x-axis in camera space
projected_coords.append(u)
# 找到 u 值最大的那个物体的索引
rightmost_idx = torch.argmax(torch.tensor(projected_coords))
return [targets[rightmost_idx]]
def execute_closest(targets: list[ObjectInstance], anchors: list[ObjectInstance]) -> list[ObjectInstance]:
"""
执行 CLOSEST 模块 (视角无关)。
"""
if not targets or not anchors:
return []
anchor_center = torch.stack([anc.get_center() for anc in anchors]).mean(dim=0)
min_dist = float('inf')
closest_target = None
for target_obj in targets:
dist = torch.norm(target_obj.get_center() - anchor_center)
if dist < min_dist:
min_dist = dist
closest_target = target_obj
return [closest_target]
# --- 主流程 ---
def ZSVG3D_pipeline(scene_point_cloud: torch.Tensor, query_text: str):
"""
论文提出的 Zero-shot 3D Visual Grounding 完整流程。
"""
# 0. 初始化
llm = LargeLanguageModel()
detector_3d = Mask3D()
clip_model = CLIPModel()
scene_data = SceneData(scene_point_cloud)
# 1. 生成视觉程序
program_str = generate_visual_program(query_text, llm)
print(f"Generated Program:\n{program_str}")
# 2. 解释并执行程序
# 将模块名映射到执行函数
module_executors = {
'LOC': lambda args: execute_loc(scene_data, args[0], detector_3d, clip_model),
'RIGHT': lambda args: execute_right(args[0], args[1], scene_data),
'CLOSEST': lambda args: execute_closest(args[0], args[1]),
# ... 可以添加 'LEFT', 'FRONT', 'BEHIND' 等其他模块
}
# 存储中间变量,如 BOX0, BOX1
variables = {}
# 逐行解析并执行
for line in program_str.strip().split('\n'):
# 解析如 "VAR=FUNC(arg1,arg2,...)" 的行
var_name, expression = line.split('=')
func_name = expression[:expression.find('(')]
args_str = expression[expression.find('(')+1:-1]
# 解析参数 (简化版,实际需要更鲁棒的解析)
raw_args = []
if 'targets' in args_str: # 假设参数格式为 "targets=VAR1, anchors=VAR2"
parts = args_str.split(',')
target_var = parts[0].split('=')[1]
anchor_var = parts[1].split('=')[1]
raw_args = [variables[target_var], variables[anchor_var]]
else: # 假设参数为 "('description')"
raw_args = [args_str.strip("'")]
# 查找并执行函数
result = module_executors[func_name](raw_args)
# 存储结果到变量
variables[var_name] = result
print(f"Executed: {line} -> Found {len(result)} object(s).")
# 3. 返回最终结果
final_target = variables.get('TARGET', None)
if final_target and len(final_target) > 0:
print(f"\nFinal Target Found: {final_target[0].label} (ID: {final_target[0].id})")
return final_target[0].bbox
else:
print("\nCould not find the target object.")
return None
# --- 辅助函数 (需要实际实现) ---
def look_at(eye, center, up):
# 实现标准的LookAt视图矩阵计算
# 返回一个 4x4 的 torch.Tensor
pass
def extract_2d_image_for_instance(instance, scene_data):
# 实现从3D实例点云和场景数据中渲染或提取2D图像切片的功能
pass
# --- 示例运行 ---
if __name__ == '__main__':
# 伪造一些输入数据
dummy_point_cloud = torch.rand(100000, 6) # N=100k, (x,y,z,r,g,b)
my_query = "Staring at the cabinets you want the window on the right side"
# ZSVG3D_pipeline(dummy_point_cloud, my_query)
print("\nAbove is the pseudo-code for the ZSVG3D pipeline.")
print("To run it, all helper functions and models need to be implemented.")
Appendix5:3D如何投影到2D
论文没有用大段的数学公式来赘述这个投影过程,因为它在计算机图形学和 3D 视觉中是一个相对标准的操作,尤其是对于像 ScanNet 这样的数据集。下面我将结合论文内容和该领域的标准实践,为您详细解析这个过程。
具体实现方法解析
这个过程的核心依赖于数据集的构成。像 ScanNet 这样的数据集,不仅仅提供一个最终的、合并好的 3D 点云,它还保留了生成这个 3D 场景所使用的原始 RGB-D 视频序列以及每一帧图像对应的相机姿态(位置和朝向)。这就是实现 3D 到 2D 映射的关键。
具体流程如下:
-
获取 3D 物体提案 (3D Proposal):
- 如我们之前讨论的,系统首先通过一个 3D 实例分割网络(如 Mask3D)在整个场景的点云中识别出一个个的物体实例 。
- 输入: 一个物体的 3D 点集(例如,属于
instance_id=2的所有点)。
-
寻找最佳 2D 视角 (Find the Best 2D View):
- 一个 3D 物体可能在原始的多个 2D 图像中都出现过。系统需要找到一个或多个“最好”的视角来代表这个物体。
- 过程:
- 系统会遍历原始数据集中的所有 2D 图像帧。
- 对于每一帧,利用其已知的相机姿态(相机内参矩阵
K和外参矩阵[R|t]),将 3D 物体的点集投影到该 2D 图像平面上。 - “最佳”视角的评判标准可以是:
- 可见点数最多:在该视角下,物体的大部分点没有被其他物体遮挡。
- 投影面积最大:物体在该 2D 图像中看起来最大,细节最清晰。
- 最靠近图像中心:避免物体在图像边缘被切割。
-
提取 2D 图像切片 (Extract 2D Image Patch):
- 一旦确定了最佳的 2D 图像帧,系统就会在那个 2D 图像上,根据 3D 点的投影位置计算出一个紧密的 2D 包围盒 (bounding box)。
- 然后,从该图像中将这个包围盒内的区域裁剪出来,形成一个独立的、只包含该物体的 2D 图像切片。
-
输入 2D 多模态模型 (Feed to 2D Models):
- 最后,这个提取出的 2D 图像切片被送入各种 2D 多模态模型中进行精细的语义理解 。例如,在图 4 的例子中,几个不同的“桌子”的 2D 图像被提取出来,然后由 CLIP 或 VQA 模型来判断哪一个才是“圆的鸡尾酒桌” (round cocktail table) 。
论文通过以下几句话清晰地阐述了这个工作流程:
- 指明目的和方法: “通过将每个 3D 提案映射到其对应的 2D 图像,我们可以提取与我们查询相关的颜色和纹理细节。” (By mapping each 3D proposal to its 2D image, we can extract the color and texture details pertinent to our query.)
- 举例说明: “然后我们只需要使用对应的 2D 图像从这个子集中识别出一个‘圆的鸡尾酒桌’。” (Then we only need to identify a round cocktail table from this subset using the corresponding 2D imagery.)
- 图示: 图 4 直观地展示了这一流程:左侧是 3D 场景和分割结果,中间的 “Filter: Table” 步骤后,右侧 “2D Multi-modal Models” 框中展示的就是从不同 3D 桌子实例中提取出的对应 2D 图像切片 。
- 消融实验的佐证: 在 4.4 节的消融研究中,论文提到了 “2D-only model” (纯 2D 模型),并说明它“仅仅使用配对的 2D 图像进行分类” (“solely employs the paired 2D images for classification”) ,这再次证实了数据集中存在这种 3D 物体与 2D 图像的配对关系。
论文描述了 “做什么” (将 3D 提案映射到 2D 图像以进行精细分类)和 “为什么做”(利用 2D 图像丰富的颜色和纹理细节,并借助强大的 2D 多模态模型来解决开放词汇问题),但它省略了 “如何做” 的底层数学细节,因为这是基于数据集已有信息(RGB-D 帧+相机姿态)的一个标准计算机视觉任务。
火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。
更多推荐

所有评论(0)