
1. 从抓取任务倒推点云实例分割到底在解决什么问题机器人抓取这条链路真正卡住人的往往不是夹爪本身而是眼前这堆东西到底是什么、各自在哪。我做过的几个抓取项目里机械臂本体、手眼标定、路径规划这些环节都有成熟方案可以照搬唯独感知这一环一旦场景从单个孤零零的物体变成桌面上堆着七八个互相遮挡的零件整套流程立刻崩掉。基于改进DGCNN的点云实例分割这类工作之所以值得花时间啃原因就在这儿——它解决的正是把一坨分不清你我的点云切成一个个属于同一个物体的点集这件事。点云实例分割说白了就是给三维空间里的每个点打两个标签它属于哪一类语义以及它属于这一类里的第几个个体实例编号。前者让机器人知道那是杯子、那是螺丝刀后者让机器人知道桌上这三个都是杯子我要抓左边那个别把另外两个碰倒。适合看这篇内容的人应该是对三维视觉有基本概念、手里有深度相机或激光雷达、正在做桌面分拣或料箱抓取这类任务的朋友如果你只是想跑通一个二维检测模型这里的内容对你帮助不大。我先把结论放在前面这套方法的上限很大程度上不由网络结构决定而是由实例定义与抓取任务的匹配度决定。举个具体的例子一把剪刀摊在桌上两个刀柄算一个实例还是两个从语义上讲是一个物体但从抓取上讲你抓起一个刀柄整个剪刀就跟着走了。如果你的实例分割模型把两个刀柄切成两个实例抓取规划器会分别给每个刀柄生成位姿结果就是重复抓取和碰撞判断失效。这类问题在原论文里通常一笔带过但落到工程上非常要命。所以我在看任何一篇这类论文时第一件事是去看它的实例标注规范和评价指标怎么定的第二件事才是看它的网络改了什么。另外要说清楚一个前提这类方案基本都建立在单帧、有组织或无组织的局部视角点云上传感器大多是结构光或ToF的深度相机工作距离在0.3到1.5米之间。这个约束很重要因为它决定了点云密度、噪声特性和遮挡模式。远距离激光雷达那种稀疏点云几万个点铺满几十米和近距离深度相机几十万个点集中在1平方米内遇到的坑完全是两回事前者的问题是不够点后者的问题是对称性和透明材质。2. DGCNN的骨架拆解与它的三个短板2.1 EdgeConv到底在算什么要把改进讲明白得先把原版说透。DGCNNDynamic Graph CNN在点云上的核心是EdgeConv这一层。常规卷积在图像上作用在规则的像素网格上点云没有网格邻居关系是算出来的不是排好的。EdgeConv的做法是对每个点找它的k个最近邻然后对每一条有向边(i, j)构造一个边特征通常形式是 h(x_i, x_j - x_i)也就是既看中心点自身的坐标又看邻居相对于中心点的偏移方向。这一步很关键——如果只用x_j网络学到的就是绝对位置对平移极其敏感加上差值项之后学到的更多是局部几何形状泛化会好很多。之后在每条边的特征上做一次共享MLP再对每个点的k条边做最大池化得到该点的新特征。我习惯用一个比喻跟组里新人解释把每个点想象成一个人EdgeConv的第一步是让每个人去问自己最近的k个朋友你相对我在哪个方位、多远然后用一个统一的模板共享MLP把这些回答翻译成一句话再从k句回答里挑最响亮的那一句最大池化作为这个人的新自我介绍。所有人同时更新一遍这个自我介绍就不再只是自己的坐标而是带有周边形状信息的描述。堆叠几层每个点的描述里就混进了越来越大范围的形状信息。但这里有个常被忽略的细节最大池化沿k维做得到的特征对邻居的排列顺序不敏感这正好解决了点云无序性问题。代价是信息有损——k个邻居只保留最强响应一些柔和的、弥散的几何线索会被丢掉。这是原版DGCNN在实例分割任务上第一个不适应的地方后面会展开。2.2 原始DGCNN用在实例分割上的三处不适应我把实际遇到的问题归成三类这三类基本覆盖了绝大多数改进DGCNN论文的动机。第一类是边界糊。EdgeConv的kNN图是纯几何距离驱动的两个紧贴在一起的物体比如叠在一起的积木在接触面附近的点它们的k近邻里会混进另一个物体的点。因为距离近网络没有理由区分它们。结果就是两个实例在接触处粘连分割掩码连成一片。这在抓取场景里是致命错误——你会在两个物体中间生成一个抓取位姿夹下去两边都夹不稳。第二类是局部几何特征欠表达。原始EdgeConv的输入只有坐标xyz法向量、曲率这些已经能算出来的局部几何量完全没用上。对于平面、圆柱、球面这些形状差异明显的抓取目标法向量其实是极强的判别信号。虽然理论上MLP能通过邻域坐标隐式学出法向但那要消耗网络容量和数据而法向量用PCA几行代码就能算出来。我在自己的复现里验证过显式加三个法向分量之后小物体边长3至5厘米的实例IoU能涨好几个点。第三类是感受野单一且偏小。DGCNN只用一个k值k20的话单层感受野只覆盖周围一圈邻居堆三四层理论感受野是指数扩张但邻居集合重叠严重实际有效范围远小于指数。结果是小物体分割还行大物体比如一个大纸箱的中部区域因为周围几何太平坦网络拿不到足够上下文容易出现空心或者碎片。多尺度kNN是很自然的补丁。2.3 改与不改的边界判断这里我想强调一个工程上的判断不是所有改进都值得上。我见过不少复现工作把能想到的模块全堆上去注意力、多尺度、特征融合、位置编码全加参数量翻三倍推理从30毫秒涨到110毫秒精度只涨1.2个点。放在抓取流水线上这1.2个点换不来任何实际收益因为抓取成功率瓶颈往往在后处理和执行端。我的判断标准很简单看三个数实例级AP涨了多少、边缘区域的误分割率降了多少、单帧推理时间涨了多少。前两个是收益第三个是成本。如果成本翻倍而收益不到2个点我会砍掉。这个原则在后面每一处改进我都会提一句它值不值。3. 改进方案的逐层设计3.1 局部几何描述子的显式注入最划算的一步也是最容易被低估的一步。输入不再只是xyz我一般构造一个8维向量三个坐标、三个法向、一个曲率近似值、一个局部点密度。法向量用k邻域协方差矩阵的最小特征值对应的特征向量用PCA算k取30左右曲率用最小特征值除以特征值之和这个比值近似反映局部表面的弯曲程度平面接近0边缘和尖角处较大点密度用k邻域平均距离的倒数它其实是个很有用的隐式信号——传感器在斜面上点会稀疏在正对面上点会密集密度异常往往意味着边界或者遮挡。这一步的成本几乎为零因为法向量估计本来在很多流程里就要做用于抓取位姿生成可以复用。注意一个坑法向量有正负号歧义。PCA算出来的法向朝里朝外是随机的如果直接喂给网络等于给了一个随机翻转的特征会拖慢收敛甚至引入噪声。解决办法是统一朝向把法向量和视点方向做点积如果为负就翻转。视点方向可以用点云质心到点的向量近似因为单视角点云基本都是从一侧看过去的。这个技巧在很多点云库里有实现但自己写也就三行。还有一点输入特征要做归一化。坐标我一般是先减去质心再除以一个尺度因子比如点云包围盒最长边的长度或者固定值让坐标落在-1到1之间。法向量本来就在-1到1。曲率和密度要做标准化密度这个量动态范围很大直接取对数再标准化会更稳。不做归一化的直接后果是训练初期loss剧烈震荡因为不同维度的量纲差了两三个数量级共享MLP的第一层权重会被大数值维度主导。3.2 多尺度kNN与注意力加权的边特征这是改动最大的部分也是这类论文的创新点所在。我拆成两个可独立取舍的子改动。多尺度kNN不只用k16而是并行用k8、k16、k32三个分支每个分支各自做EdgeConv然后拼接融合。直觉是k8关注最精细的局部能分辨边缘、尖角k32覆盖更大的邻域能感知物体整体走向中间的k16做折中。三个分支的参数不共享因为不同尺度的几何统计特性确实不同。实现上k32的邻居集合包含了k16的可以直接复用距离矩阵的前若干列省一次kNN计算。我在一块消费级显卡上实测三尺度相比单尺度kNNEdgeConv部分耗时从约11毫秒涨到约19毫秒这个代价我认为可以接受。注意力加权原始EdgeConv对k条边一视同仁先算特征再池化但实际上边缘附近的邻居里属于同一物体的点和属于另一物体的点可信度完全不同。做法是在边特征上加一个权重权重由一个小的打分函数产生输入是边特征本身或者中心点与邻居的特征差异。最终池化变成加权最大池化或者加权求和。这里有个陷阱加权求和会削弱无序性保证吗不会因为权重是对称的但会让平坦区域的特征被大量相似邻居平均掉反而模糊。我的经验是加权最大池化更稳权重只用来抑制坍缩邻居的响应。还有一种更轻量的做法在每一层EdgeConv之后加一个通道注意力类似SE模块对特征通道做重加权。这个几乎不增加耗时通道数64全局池化两层全连接对抑制无关通道响应有效。我建议先上这个再考虑边权重的复杂版本。3.3 分割头的选择语义嵌入 vs 端到端偏移网络主干之后输出头有几条路可走我逐个说清楚取舍。方案A语义分割头 实例嵌入头。两个并行的一维卷积头语义头输出每个点的C类概率C是物体类别数背景嵌入头输出每个点的D维特征向量D一般取5到16。训练时语义用交叉熵嵌入用判别损失discriminative loss这个损失是三项之和变异项把同一实例内点的嵌入拉向该实例的均值距离项把不同实例的均值推开正则项约束均值别跑太远。推理时先按语义过滤掉背景再在嵌入空间做聚类mean shift或DBSCAN得到实例。这是最经典也最稳的路子好处是实例数不固定也能处理坏处是聚类参数带宽需要调而且聚类本身有耗时。方案B实例中心偏移回归。每个点回归一个指向其所属实例中心的偏移向量再配合语义分割。推理时把点按点偏移挪到中心附近聚类就变成一个简单的距离阈值分组速度更快也更鲁棒。缺点是对大物体、长条形物体中心点可能不在物体内部偏移量很大回归难度高。方案C直接回归实例ID类似分类。需要预设最大实例数不灵活抓取场景里桌上物体数量变化大我不推荐。我实际用得多的是方案A加一点方案B的思路嵌入头输出D维同时再输出一个3维的中心偏移用于精修。聚类用mean shift带宽不用固定值而是根据嵌入向量的局部分布自适应——具体做法是先算每个点到其第m近邻m取8嵌入距离的中位数用这个作为该点的局部带宽。这个自适应在稠密度不均的点云上很有用因为稀疏区域点的嵌入天然更分散。3.4 参数确定的计算过程很多人抄参数但不知道为什么这里把几个关键参数的推导过程写清楚。k值的感受野估算。假设点云在物体表面近似均匀分布平均点间距为d则面密度ρ≈1/d²。单层kNN覆盖的等效圆半径为 r₁ ≈ sqrt(k/(πρ)) d·sqrt(k/π)。取k16、d5毫米r₁≈5×2.26≈11.3毫米。再算相邻点的感受野——虽然下一层每个邻居各自又扩11.3毫米但邻居之间有大量重叠实际有效半径约等于2倍到3倍r₁重叠越多倍数越小。三层堆叠后有效半径大致在30到50毫米量级。这意味着如果你的目标物体尺寸在3厘米以下三层k16是够的如果目标是一个15厘米的大盒子中部点周围50毫米内可能都是近似平面特征区分度自然就低这就是需要k32分支的原因。体素下采样的尺寸选择。原始点云一帧约20万到30万点直接输入网络显存和耗时都吃不消。先用体素栅格下采样到1万到2万点。体素边长怎么定经验公式是取最小可分辨特征尺寸的三分之一到二分之一。抓取任务里最小特征通常是夹爪指尖宽度或者待抓物体的最小厚度取5毫米的话体素边长2毫米左右比较合适。但体素太小下采样效果不明显太大则小物体会直接消失。我的做法是先按目标物体最小尺寸的1/5取体素如果下采样后总点数超过3万再增大体素或者改用随机采样到固定值。固定点数比如16384是必须的因为批处理要求张量尺寸一致。判别损失的阈值。嵌入空间里同一实例的点嵌入距离要小于δ_v不同实例的均值距离要大于δ_d。在把坐标归一化到单位球之后我一般取δ_v0.05、δ_d0.3。这个比例大致是1:6参考的是原论文设定的1:3到1:6区间。比例太小比如1:2会导致类间分离不足、聚类时容易粘连比例太大1:10以上会让网络只关注把类间推开变异项失去约束同一实例内部散成几团出现碎片。损失配比。总损失是语义交叉熵、变异项、距离项、正则项的加权和。我用过的比较稳的一组是语义1.0、变异0.5、距离0.5、正则0.001。语义权重不能太小否则嵌入头拿不到好的特征正则项必须小它只是防止嵌入均值漂移过远的保险丝。这里有个实操细节前若干轮先只训语义头冻结嵌入头等语义分割收敛到一定水平比如miou过0.6再联合训练。原因很简单语义还没分清物体和背景的时候嵌入头会把背景点和物体点混在一起拉学出来的嵌入是脏的。这个两阶段策略在我复现时省了大量调参时间。4. 训练与调参从数据到收敛的实操流程4.1 数据准备与增强这类任务的公开数据往往不够贴合实际我一般是自己搭采集台。用深度相机固定在机械臂末端或者支架上从多个视角拍摄桌面场景每个场景摆5到10个物体随机堆叠、部分遮挡。标注是最费时的部分我的做法是分两步先用带三维框标注的半自动工具粗标再用一个已训练的小模型出预分割结果人工只做修正。一个场景从零标到能用大概15到20分钟修正的话3到5分钟。数据量上我的经验是至少300个场景、覆盖15到20类物体少于这个数模型在真实场景的泛化会明显掉。增强手段要挑不是所有的都能用。旋转绕重力轴z轴随机旋转是安全的因为桌面场景本身就有这个自由度但绕任意轴大角度旋转会产生物体悬空这种物理上不合理的构型虽然对纯几何网络影响不大但如果你的网络后面接抓取位姿生成训练和推理分布会不一致。缩放0.9到1.1之间小幅抖动可以大幅缩放会破坏法向量尺度关系。点云丢弃随机丢5%到15%的点模拟传感器噪声这个很有效能显著提升遮挡场景的鲁棒性。局部块缺失随机抠掉一个球形区域内的所有点模拟真实遮挡这个我认为是最有价值的增强直接对应被别的物体挡住一半的情况。要提醒一句关于类别不均衡桌面上背景点通常占70%以上如果直接训网络会倾向于把所有点判成背景。解决办法不是简单加权而是在采样时就控制每个batch里的实例数量保证每个batch至少包含2到3个有效实例并且对语义损失里的背景类降权我一般用0.3到0.5的系数。4.2 训练配方与显存耗时实测我给一组可以直接抄的配置。优化器Adam初始学习率1e-3用余弦退火到1e-5权重衰减1e-4不要用1e-2点云网络上会欠拟合。批大小8每个样本16384点训练150轮。前20轮只训语义头之后联合训练。BN层在点云上表现不错但要注意批内点数固定否则统计量会飘。下面是我在某台消费级显卡显存12GB上实测的数据供你估算资源配置项数值说明每样本点数16384下采样后固定批大小8显存占用约7.5GB单轮耗时约85秒300个场景约2400帧150轮总耗时约3.5小时单卡推理单帧耗时约35毫秒含预处理不含后处理主干头部参数量约2.1M单尺度版本约1.3M这些数不是绝对值显卡不同会有明显差异但比例关系可以参考。如果你的显存不够别急着减点数——先减批大小点数减了之后感受野估算要重算容易出问题。4.3 一个反复踩的坑kNN的实现这个必须单独拎出来说。kNN在点云网络里是最大的性能杀手也是最容易出错的地方。用PyTorch直接算两两距离、再topk在16384点上做一次是16384×16384的距离矩阵光这一个操作就要几百毫秒完全没法用。正确姿势是分块计算把点云按中心点分成若干块比如每块4096个中心点每块只算这块中心点与全部点的距离取topk再拼接。这样峰值显存可控速度也能快一个量级。另一个优化是用平方欧氏距离展开成 ||a||² ||b||² - 2a·b把距离计算变成矩阵乘法交给cuBLAS比逐元素算快得多。注意这个技巧有数值精度问题||a||²和||b||²很大时相减会损失精度导致本该最近的点排序出错。缓解办法是先做中心化让坐标均值接近0量级控制在个位数。还有个常见错误是把kNN写在了训练循环里每次都重算。实际上如果做了旋转增强每个样本的图都要重算这是没办法省的部分但如果没有增强同一份点云的图可以缓存。我在复现初期就吃过这个亏一轮训练跑了一分半排查后发现一半时间花在重复算kNN上。5. 从实例掩码到抓取位姿5.1 掩码后处理与实例精修网络出来的结果是一堆带标签的点不是干净的实例列表。后处理有两件事要做一是聚类二是精修。聚类用mean shift带宽用前面说的自适应方式。这里有个参数需要盯着最小簇点数。如果一个簇只有20个点基本可以判定是噪声或者远距离的稀疏区域误判直接丢掉。这个阈值跟点云总点数相关我一般取总点数的0.3%到0.5%。少于这个数的簇即使抓取位姿算出来点云太稀疏也做不了准确定位。精修这一步很多人省掉但我觉得很值。聚出来的簇边界上的点经常是模糊的——有的点语义置信度0.5出头模棱两可地落在两个实例之间。我的做法是把簇的边界点重新做一次基于几何距离的分配用簇内部点拟合一个局部平面或二次曲面把边界点按到各簇拟合面的距离重新指派。这个操作能让实例边界收紧一到两个体素对抓取的直接影响是夹爪不会夹到空气。还有一个更省事的做法用点级语义置信度做加权——把置信度低于0.6的边界点先剔除簇会收缩然后再用形态学方式补回来。5.2 抓取位姿生成与碰撞过滤拿到每个实例的点云后常见的两条路一是几何启发式二是学习式评分。几何启发式适合快速验证整套流程我一般先用它跑通。启发式的基本思路对实例点云做PCA最大特征值方向是物体主轴第二特征值方向是次轴第三特征值方向近似表面法向。夹爪的开合方向取次轴方向或者主轴取决于物体形状的平整程度接近方向取法向的反方向。抓取宽度用夹爪在开合方向上的投影跨度估计。然后做碰撞检查把夹爪模型按这个位姿放进去检查手指两侧和接近方向上有没有其他实例的点有就打分降低或者直接丢弃。这里有几个经验数值夹爪开口余量留10%到15%留太少会夹不稳留太多手指会顶到旁边的东西接近方向与桌面法向的夹角限制在60度以内超过这个角度的抓取成功率会明显下降因为夹爪会跟桌面打架手指接触区域的点密度要求至少每平方厘米5个点才认为定位可靠否则法向量估计误差太大。学习式评分的话我会用一个轻量网络输入是抓取位姿周围的局部点云转成规则的体素网格或者按夹爪坐标系重采样输出一个0到1的分数。这个网络训练数据不需要太多几千个标注抓取就够但它能显著减少碰撞和滑脱。5.3 时序预算怎么分把整条链路的时间拆开算一遍这个表我建议每个做抓取的人都画一下环节典型耗时备注深度图采集与转点云15毫秒相机曝光与传输预处理滤波、下采样、法向量20毫秒法向量最耗时主干推理35毫秒三尺度版本聚类后处理12毫秒mean shift位姿生成与碰撞检查10毫秒假设每实例10到20个候选总计约92毫秒约10帧每秒这个水平对于桌面静态抓取是够的。如果是传送带上动态抓取要求提到50毫秒以内那就得砍东西——我会优先砍多尺度分支省8毫秒、把聚类换成阈值分组省8毫秒、法向量用低精度估计省6毫秒。别一上来就想着换更小的骨干网络很多时候瓶颈不在网络而在后处理。6. 常见问题与排查实录6.1 训练阶段损失不降或者震荡。排查顺序先看输入归一化有没有做这是头号原因再看kNN是不是返回了重复点点云里有完全重合的点kNN会返回自身多次导致边特征全是零向量最后检查学习率点云网络对1e-2这个量级很敏感容易直接发散。语义分割收敛但实例粘连严重。看边缘处的嵌入距离分布如果两个相邻实例的嵌入均值距离小于δ_d说明距离项没起作用。可以把距离项权重临时调大验证但更根本的办法是加边缘感知的采样——训练时对语义标签边界附近的点做过采样让损失更多关注这些区域。实例数量少的时候正常多了就崩。这通常是正经的容量问题。一个簇里点数太多mean shift会把它和旁边稀疏的簇合并。检查一下带宽自适应是否生效必要时把带宽设成与实例点数相关。验证集好、实测差。最常见的三个原因验证集和实测的场景物体类别重合度高、实测的相机噪声特性差异大、实测的遮挡程度更高。我建议在采集数据时就有意分层把密集堆叠和稀疏摆放分开建子集分别看指标。6.2 推理与部署阶段推理时出现NaN。点云里如果有极少数点坐标是异常值深度相机在反光、透明表面的输出归一化之后会污染全局尺度。加一步鲁棒预处理算点云到质心的距离分位数剔除最小的1%和最大的1%这个几乎无成本但能挡掉绝大多数NaN。边缘区域分割抖动。同一场景连拍10帧实例边界来回跳变。原因是这些点的语义置信度就在0.5附近。解决办法有两个多帧融合把连续3到5帧的实例结果按点位置投票因为机械臂在动的时候场景没动或者加时序平滑对嵌入做指数滑动平均。前者效果好但需要相机静止后者简单但会引入延迟。长条形物体被切碎。比如一把螺丝刀中部细长、点稀疏聚类时容易断成两段。这是感受野和点密度共同的问题。缓解方式增大体素下采样后保留的点数别下采得太狠、在聚类时允许一定比例10%左右的点被归入最近簇而不重新开簇、或者干脆对每个语义类做一次区域生长补全。6.3 抓取执行阶段分割对了但抓不起来。这往往是分割掩码和抓取位姿之间的最后一厘米问题——实例边界收缩过度导致夹爪按这个收缩后的轮廓算了宽度实际物体比掩码宽手指夹到边缘滑脱。我的做法是给实例点云做一个2到3毫米的膨胀膨胀区域只用于位姿生成不用于最终判定。两个相邻物体总是一起被抓。检查碰撞检测的粒度很多实现只检查夹爪中心线和手指内侧忽略了手指根部和外侧。把夹爪简化成三到四个球形包围体逐个检查问题基本能解决。透明或高反光物体整段消失。这已经超出分割算法的范畴是传感器层面的问题。现实做法是对这类物体做特殊处理喷显像剂、换用不同曝光的多帧融合、或者干脆用二维视觉辅助定位。7. 我在复现与落地中的几点体会这部分的经验值不了多少钱但能省你不少时间。第一别一开始就改网络。我接手过一个项目前人把DGCNN改得面目全非效果还是不行。我从头用原始DGCNN跑了一遍只加了一个输入法向量指标就追平了他们的版本。很多时候问题在数据、在预处理、在后处理不在网络结构。先建立一条最朴素的基线把每个环节的耗时和精度都记录清楚再决定在哪加东西。第二评价指标要按实例看不要只看点级。点级miou到0.85很容易但实例级AP可能只有0.4。抓取任务关心的是这个实例有没有被完整切出来所以一定要看实例级指标IoU阈值从0.5到0.9的AP、实例召回率、以及一个我自己加的指标——可用抓取比例即分割后能得到有效抓取位姿的实例数占总实例数的比例。这个指标和实际成功率的相关性比AP高得多。第三关于那篇论文里的改进组合我的判断是法向量等几何描述子的注入和两阶段训练是最值得保留的性价比极高多尺度kNN有收益但要付时间成本看你平台复杂的注意力机制在抓取这种小数据集上收益不稳定容易过拟合我倾向于先用通道注意力这种轻量版本。至于那些要靠特殊损失函数才能训起来的模块除非你有一模一样的数据分布否则慎用。最后分享一个小技巧如果你手头有机械臂让它在采集数据时顺便做一次空抓——对每个生成的抓取位姿先不闭合夹爪只是移动过去观察夹爪与场景的碰撞情况。这些数据能直接告诉你分割误差和位姿误差各自贡献了多少失败比在仿真里猜靠谱得多。我用这个办法定位到过一次问题抓取失败的70%来自实例边界收缩而不是我以为的网络精度。改完膨胀策略之后成功率从六成出头提到了八成五。