1. 从点云无序性说起:为什么特征提取在3D语义分割里格外棘手
点云语义分割这个方向,做过的人都知道,真正难的地方从来不是网络有多深,而是数据本身太"野"了。一张RGB图像是规整的网格,每个像素都有固定的邻居,卷积核滑过去就行;但点云是一堆散落在三维空间里的坐标,没有顺序、没有网格、密度还不均匀。你把这堆点随机打乱顺序,它表达的仍然是同一个场景,可对网络来说输入完全变了。这种置换不变性(permutation invariance)是点云处理的第一道门槛。
RandLA-Net这个工作之所以在点云语义分割领域被反复提起,核心原因就是它在"大场景"这个设定下把效率和精度同时拉到了一个可用的水平。所谓大场景,指的是几十米甚至上百米范围的室外扫描,点数动辄十万到百万级。传统方法要么先做体素化,要么先做最远点采样(FPS),前者会丢细节,后者计算量随点数平方增长,百万点根本跑不动。RandLA-Net选择了一条更直接的路:随机采样降点,然后用一个专门设计的模块把丢掉的信息补回来。
这个"补回来"的模块,就是本文要拆解的核心——特征学习提取模块。它的正式名字叫 Local Feature Aggregation,简称 LFA。很多人读RandLA-Net的论文时,把注意力都放在了随机采样上,觉得"随机"两个字很反直觉,反而忽略了这个模块才是真正决定精度上限的部分。随机采样本身不产生任何特征,它只是把点变少;真正让网络在点变少之后还能理解局部几何结构的,是LFA里那套精心设计的局部特征聚合机制。
我先把结论摆在这里:LFA模块由三个子组件串联而成——局部空间编码(Local Spatial Encoding,LocSE)、注意力池化(Attentive Pooling)、扩张残差块(Dilated Residual Block)。这三个东西各司其职,LocSE负责把每个点的相对几何位置编码进特征,注意力池化负责从邻居里挑出重要的信息,扩张残差块负责在增大感受野的同时不丢原始特征。下面我会逐个拆开讲,包括它们各自解决什么问题、内部怎么算、实际写代码时哪些地方容易出错。
适合读这篇的人:正在复现RandLA-Net的、想改造LFA模块做自己任务的、或者单纯想搞明白"点云局部特征到底怎么聚合"的。我会尽量把公式背后的直觉讲清楚,而不是只贴一堆符号。
2. LocSE局部空间编码:把"邻居在哪"变成网络能读懂的信号
2.1 为什么原始坐标不能直接喂给网络
最朴素的想法是:对每个中心点,找它最近的K个邻居,把这K个邻居的坐标和特征拼起来,送进MLP。这个做法在很多早期点云网络里确实用过,但它有个致命问题——它编码的是绝对位置,而不是相对关系。
举个例子。同一个墙角,出现在场景的东边和西边,绝对坐标完全不同,但局部几何结构是一模一样的。如果网络只看绝对坐标,它就得分别学习"东边的墙角"和"西边的墙角",泛化能力极差。更糟的是,绝对坐标的数值范围可能很大(几十米),直接送进网络会让训练非常不稳定。
所以LocSE的第一步,是把绝对坐标转成相对坐标。对中心点p_i和它的第k个邻居p_i^k,计算相对位置:
Δp_i^k = p_i ⊕ (p_i^k - p_i) ⊕ ||p_i^k - p_i||这里的⊕是拼接操作。注意它拼了三样东西:中心点自己的坐标、相对位移向量、以及相对距离的标量。为什么要拼中心点坐标?因为有些语义确实和绝对位置相关,比如"地面"通常在某