2D Grounding 架构 v2
内部技术介绍 物体分支 部件分支 2026-10-29

物体走“说→定位→切→验”,
部件走“说→直接切→验”。

同一份 dense_caption 同时产出物体行与部件行。物体分支保留原有定位链; 部件分支跳过 box,用 SAM3 短名词短语直接出 mask,再用两问验区挡住“切到整个物体”。 一句话:框的语义单位是物体,部件不能从框里长出来。

SAM3 已成为默认分割器 2026-10-29 起全面弃用 SAM2 · 100 图 A/B:export +6.1%、耗时 −13.5%、refine 命中 54.9% → 77.6%

0.138 → 0.636
部件 IoU:现状 A → C_union(7 个干净 GT 样本)
part study
17.45label/s
GroundingPI 定位吞吐,600 次定位 34 秒
GroundingPI smoke
56GB
三个服务合计显存(34 + 17 + 5.3)
服务实测 / 官方模型卡
+17%
端到端耗时实测:18.6 s/图(10 图 · 0.4 部件/图);按 3 部件/图外推 +37%
部件分支冒烟

口径:部件指标只统计 7 个有真实 part GT 的样本;吞吐与显存来自 GroundingPI / SAM3 / 27B 服务实测;成本为 10 图实测 + 3 部件/图外推。

01 架构

两条分支,共用一次 caption

差别只有一处:部件不做 box 定位。物体链每一步都以“框”为单位,框的粒度是物体;把部件塞进这条链,SAM 只会忠实地切出整个物体。部件分支把短语直接交给 SAM3 的文本接口,mask 的语义单位才对得上。

VLM · 一次调用dense_caption输出两种行
物体行 [0: mug, white, left]
部件行 [0.1: handle, curved]   # 0.1 = 父物体 0 的部件
物体分支5 步 · 复用现状
locate_boxesGroundingPI
每个物体行出一次框;不拒识,空目标交给下游
SAM3 框 prompt
box → mask,物体级分割
pool refine概念池
按概念池收敛框与实例,多实例在此归并
verify_region
问“是不是这个东西”,挡掉不存在的目标
5 类 concept prompts
ENTITIES SPATIAL AFFORDANCES RELATIONS PHYSICS
部件分支4 步 · 跳过定位
短语归一化object.part → NP
mug.handle → "mug handle";≤2 词,head-final
SAM3 文本 prompt无 box
短 NP 直接出 mask;图像编码每图只做一次
空结果 → 丢弃,不退回物体框
verify_part问两问
Q1 是不是该部件 Q2 part / whole_object
PARTS 类第 6 类
新增 concept family,写 parent_object / part_name

为什么部件不走 locate定位交付的是物体框。框再准,SAM 也只能在里面切出物体;实测整条链路的部件 IoU 是 0.138。

为什么共用 caption部件行不是第二次 VLM 调用。P2 提示词下 11/11 张图产出部件行,平均 1.64 行/图。

为什么出口要统一物体进 5 类 concept family,部件进 PARTS,并写父子字段;导出 schema 不变。

图示对应实现:concept=part 跳过 box 阶段,concept=object/region 维持原链。caption 行数见 part study 的 P0/P1/P2 对照。

02 证据

为什么这么拆:三个证据

三个问题各有独立数据:定位该不该换专用模型、部件能不能走定位、分割器该不该换。

证据一

定位交给专用模型,VLM 只负责“说”

0.82–0.99
GroundingPI 框与 27B accepted 框的 IoU,4 张可比图
单例最大偏差 ≤2 px17.45 label/s600 label / 34 s

读数

  • 小目标更稳:pio 的苹果只有 31×33 px,GroundingPI 框住了;27B 的 mask 反而落到旁边的刷子上。
  • 吞吐够用:600 次定位 34 秒,约 17.45 label/s,定位不再是瓶颈。
  • 代价是不拒识:4/4 个明确不存在的目标都返回了框,所以 verify_region 不能省。

来源:GroundingPI smoke(5 图,含 partafford / roborefit / vabench / pio / hot3d),27B 同图对照。官方模型卡 + 本地 smoke

证据二

部件不能走定位:语义单位错了,框再准也没用

0.138 → 0.636
部件 IoU,现状 A → SAM3 文本(C_union),提升 4.6×
面积比 9.30 → 1.76溢出 0.861 → 0.316

同一批 7 个 part GT 样本,四条路线

A 现状27B 框→SAM20.138
BGPI 框→SAM20.493
C_npSAM3 短 NP0.625
C_union多实例并集0.636
DWeVisOne0.546
00.250.500.75

A 切出的是整个物体:面积是 GT 的 9.3 倍。C 用文本 prompt 直接切部件,面积比降到 1.76×。耗时也从 1.06 s 降到 0.42 s/part(含摊销的图像编码)。part study · 7 样本

证据三

mask 等价,端到端 SAM3 更优 —— 已全面弃用 SAM2

+6.1%
100 图端到端导出,SAM3 716 行 vs SAM2 675 行
mask IoU 0.951:基本等价但产出、接受率、耗时三项都更好

同一批 100 图,同实例、同参数、顺序跑

指标
SAM2
SAM3
导出行数
675
716 +6.1%
题目接受率
55.8%
59.2% +3.4pp
单图耗时
19.3s
16.7s −13.5%
分割调用
143ms
24.4ms −83%
refine 命中
54.9%
77.6%

accepted 282 vs 277(−1.8%)落在噪声内:同一臂独立重跑的波动就有 −4.1%(符号检验 p=0.89)。A/B 100 图 · 修复正方形转置后

03 实测

四个模型的实测对比

表一是整条链路(caption → 定位 → 切 → 验 → 出题)在 100 张图上的结果;表二只切部件,用 7 个有真实 part GT 的样本;表三是显存账。

表一 · 100 图全链路

模型单图accepted接受率 exportcaption 行显存
Embodied-R1.5-8B 12.5s36564.3% 8016.6634 GB
Qwen3.8-27B 19.5s28857.7% 7286.1678 GB
RoboBrain2.5-4B 9.7s18275.1% 5932.5724 GB
MiMo-Embodied-7B 58.2s17460.8% 5646.237 GB
Molmo2-8B 20.4s19663.3% 4086.7736 GB
InternVL3.5-8B 9.6s20241.3% 1146.4635 GB

同参数:max-regions 5 / workers 2 / concurrency-per-worker 6;100/100 完成,0 失败。来源:100 图全链路跑批,2026-10-29。

读表R1.5 是当前主线:12.5 s/图、365 accepted、801 行 export、34 GB;比 27B 快 1.56×、多接受 26.7%,显存只用 44%。
读表快 ≠ 能出数据:InternVL3.5 单图 9.6 s 最快,但接受率 41.3%、export 只有 114 行;MiMo 58.2 s/图,是 R1.5 的 4.7 倍。

表二 · 部件级四条路线(7 个有真实 part GT 的样本)

路线IoU中位召回 溢出 ↓面积比 ↓每次耗时
A 现状(27B 物体框→SAM2) 0.138 0.0870.8380.861 9.301.06s
B GroundingPI part 框→SAM2 0.493 0.4980.8780.453 3.201.15s
C_np SAM3 短名词短语 0.625 0.6670.8990.309 1.720.42s
C_union 多实例并集 0.636 0.7480.9240.316 1.760.42s
D WeVisOne 0.546 0.4470.9040.416 2.081.05s

7 样本:11 个样本中剔除 1 个混杂 GT(口沿+把手根)、1 个物体级 GT(整把剪刀)、2 个 proxy GT。IoU 按 best-component 计。来源:part study,2026-10-29。

读表召回都高,差距全在溢出:五条路线召回 0.838–0.924,A 的溢出 0.861、面积比 9.3;C 的溢出 0.316、面积比 1.76。切得“够全”不难,切得“不多”才是分水岭。
读表B 证明瓶颈在框:换成 part 框就能从 0.138 拉到 0.493;但小部件上 GroundingPI 会退化成物体框(roboafford_94 只有 0.070),不能单独依赖。
读表C_union 的中位 0.748 比均值更能说明稳定:A 的中位只有 0.087;均值被个别高分样本抬高,中位没有。
读表D 不是不能用,是偏胖:召回 0.904,但面积比 2.08、溢出 0.416,倾向把零件连一圈本体一起包进来。

表三 · 显存账

服务角色显存
Embodied-R1.5说话 / 验区 / 出题34 GB
GroundingPI (vLLM)只出框17 GB
SAM3只切 mask5.3 GB
合计56 GB

占 H200 141 GB 的 40%;三个服务可串行起停,峰值还能更低。来源:服务实测显存 + 官方模型卡。

04 可视化

同一张图,四种切法

三组真实样本,同一张图、同一个 part:A 切整个物体,B 框偏,C 切到部件,D 切到部件但偏胖。每张图顶部是出图时烧录的路线、part 与 IoU;GT 面板按同一尺寸叠加。

GT 真值 mask A 现状 27B 物体框→SAM2 B GPI part 框→SAM2 C_np SAM3 短 NP D WeVisOne 点击图片放大
案例 01

partafford_10350 · mug handle

GT 372 px 单实例

A 的 mask 面积是 GT 的 16.9 倍:不是切歪,是语义单位错了。C 的边界贴着把手;D 把把手和一片杯身连在一起。

GT参考
把手真值,372 px
A 现状IoU 0.045
整只杯子,面积 16.9×
B GPI 框IoU 0.498
框偏到杯壁
C_np SAM3IoU 0.530
只切把手
D WeVisOneIoU 0.345
把手 + 杯身一片

← 横向滑动查看五联 →

案例 02

partafford_15614 · spoon handle

GT 1,100 px 细长目标

同一张图:C 的 mask 贴着把手边缘,IoU 0.842;D 多带了一截勺碗(0.760);A 把整个勺子连同勺碗一起切了。

GT参考
勺柄真值
A 现状IoU 0.302
整个勺子
B GPI 框IoU 0.560
框尾越出把手
C_np SAM3IoU 0.842
贴住把手
D WeVisOneIoU 0.760
多带一截勺碗

← 横向滑动查看五联 →

案例 03

roboafford_94 · two mug handles

GT 两实例 多实例

GT 是两个杯子把手。A 选了没有把手的那只杯(0.012);C_np 只覆盖一个把手(0.667);换成 C_union 取并集后 0.748——多实例必须 merge。

GT2 实例
白杯 + 粉杯的把手
A 现状IoU 0.012
选了没把手的杯子
B GPI 框IoU 0.070
退化成整只粉杯
C_np SAM3IoU 0.667
只切到一个把手
D WeVisOneIoU 0.447
把手 + 杯沿

← 横向滑动查看五联 →

图注:mask 叠加色由各脚本出图时固定(A 橙 / B 绿 / C 青 / D 粉),GT 面板用紫色 + 白边重新叠加。文件:assets/overlays/{image}__{route}__{part}.png,原始 overlay 与 mask 保留在 part study 的 runs_part/。注意:本组图只用于看形态,均值以表二为准。

05 踩过的坑

六个会让指标“看起来对”的坑

前四个是模型行为,后两个是实现与提示词细节。共同点:不报错,只悄悄地给出错的结果。

P1

SAM3 只吃短名词短语

短语一长就 0 命中:11 个样本里 2 个直接空结果。归一化目标是最多两个词、head-final 的 NP。

✓ brush head
✗ toothbrush brush head → 0 instances

处理:object.part → "<part-head> <object-head>";空结果丢弃,或走 GPI 出框 → SAM3 框 prompt 兜底,并标记 part_mask_source。

P2

SAM3 不拒答

给一个图里根本没有的概念 lizard,它照样返回 mask,score 0.867。文本 prompt 只回答“哪里最像”,不回答“有没有”。

prompt: "lizard" → mask ✓, score 0.867 # 图中无蜥蜴

处理:不能只看 score 阈值;必须过 verify_part,并保留 Q2 的粒度标签。

P3

GroundingPI 不拒答

4/4 个明确不存在的目标都出了框。the red sports car 给了几乎全图的框——把“指代失败”表达成了“目标很大”。

"the red sports car" → box ≈ 整张图 # 图中无此车

处理:定位只做候选生成,verify_region 必须保留;全图级框直接判退化。

P4

label 里的逗号会被拆成多个 phrase

GroundingPI 把逗号当分隔符:mug, white, left 会变成三个 phrase 分别定位,返回的框数量与语义都对不上。

"mug, white, left" → ["mug", "white", "left"] # 3 次定位

处理:进模型前清洗,只保留 head 名词与必要修饰;属性拆到独立字段。

P5

WeVisOne 的拒答不稳

直接问“这块是不是该部件”,接受/拒绝随措辞波动;单段式 prompt 不能作为唯一闸门。

单段:detect + segment + judge → accept 不稳

处理:两段式——先“检测过闸”,再“box 驱动 matte”;把判断和分割解耦。

P6

正方形图的 mask 转置 bug

用 shape 判断要不要转置,在正方形图上恒成立,mask 被静默转置。100 张 hot3d 里影响 3 张。

# 错:H==W 时恒成立
if a.shape == (W, H): a = a.T
# 对:只有非正方形才可能靠 shape 判断
if a.shape == (W, H) and W != H: a = a.T

处理:正方形图无法靠 shape 判断,必须在读取时显式记录 transposed 标记;修完后重跑受影响的 3 张。

06 成本

加部件分支:估算 +37%,实测 +17%

增量集中在三处:SAM3 文本切部件、part 验区、part 出题。caption 与 locate 一次都不多调——部件行搭同一趟车。

环节现状调用加部件后增量
dense_caption1001000
locate_boxes4764760
SAM3 文本切部件0300+300
verify_region475775+300
concept_prompts435735+300
verify_prompt_text12401420+180
合计2892~3970+37%

口径:现状合计取 100 图跑批日志的实际调用数(2,892);分行只统计主要阶段,与合计差 166 次属未单列的零散调用。增量按 3 部件/图 × 100 图估算,分行相加 1,080、合计取 1,078(取整)。来源:100 图跑批 + 外推。

每 100 图调用量

现状 2,892+1,078
加部件后~3,970 +37%

按 3 个 part/图估算:3 × 100 次文本切 + 300 次 part 验区 + 300 次 part 出题 + 180 次 prompt 校验。
若按 2 个 part/图,增量降到约 +25%。

07 下一步

三条待验证,都有明确的证伪条件

现在的主线结论只在 27B 上闭环;R1.5 的部件能力、三方出框、验题松紧都还没有同口径数据。