1. 点云卷积的痛点与这篇论文的切入点
点云这种数据形式,做三维视觉的人都不陌生。激光雷达扫出来的、深度相机拍出来的、甚至多视角重建出来的三维坐标集合,本质上都是一堆无序的点。它跟图像最大的区别在于:图像有规整的网格结构,每个像素的邻居关系是固定的;而点云是一盘散沙,每个点周围的邻居数量和分布方向都在变。这个差异直接决定了,直接把二维卷积那套东西搬到点云上是行不通的。
过去几年,针对点云的处理方案大致分成两条路。一条是把点云体素化,变成三维网格再上三维卷积,但体素化会丢精度,分辨率一高显存就爆炸。另一条是直接在点云上定义卷积,比如PointNet系列用对称函数做全局聚合,PointCNN用X变换学习点的排列,SpiderCNN、PointConv、KPConv这些则尝试在局部邻域上定义卷积核。这些方法各有各的巧妙,但有一个共同的隐含假设:局部邻域内的卷积核在各个方向上是同性的,也就是说,卷积核在各个方向上的响应强度是一样的。
这篇论文标题里的"Permutation Matters"和"Anisotropic Convolutional Layer"两个词,恰好点出了它要解决的核心问题。Permutation指的是点云局部邻域内点的排列顺序,Anisotropic指的是各向异性。论文的核心主张是:点云局部邻域内的点排列顺序不是随意的,它携带了几何结构信息;而传统的各向同性卷积核无法捕捉这种方向性差异,所以需要设计各向异性的卷积层。
我第一次读到这个标题的时候,直觉是:这不就是在说卷积核要有方向选择性吗?图像卷积里的Gabor滤波器、方向梯度直方图,本质上都是在捕捉方向性。但点云上的方向性比图像复杂得多,因为点云没有固定的坐标轴,局部邻域的主方向需要从数据本身估计出来。这篇论文要做的,就是把这个方向性显式地建模到卷积层里。
2. 各向异性卷积的核心设计思路拆解
2.1 为什么各向同性卷积在点云上不够用
先把这个"各向同性"的问题说透。假设你在点云上取一个局部邻域,比如以某个点为中心,取最近的K个邻居。传统的点云卷积做法是:对每个邻居点,计算它相对于中心点的坐标偏移,然后把这个偏移送进一个多层感知机或者一个连续的卷积核函数,得到一个权重,再对邻居的特征做加权求和。
这个过程中,坐标偏移是一个三维向量,MLP或者核函数对它的处理是"无方向偏好"的。也就是说,如果邻居点从中心点的正前方移到了正上方,只要距离一样,得到的权重可能差不多。但实际的三维几何结构里,正前方和正上方承载的信息完全不同。一个平面上的点,它的邻居主要分布在平面内;一个边缘上的点,邻居会沿着边缘方向分布;一个角点上的点,邻居会向多个方向发散。这些结构差异,各向同性卷积核是区分不出来的。
论文里应该做了这样的观察:在局部邻域内,如果把邻居点按照某种顺序排列,比如按照它们与某个参考方向的夹角排序,那么不同几何结构下的排列模式是不一样的。平面区域的排列是均匀的,边缘区域的排列会在某个方向聚集,角点区域的排列会在多个方向聚集。这个排列模式,就是"Permutation Matters"里说的排列信息。
2.2 各向异性卷积核的构造逻辑
既然各向同性不够用,那各向异性怎么构造?论文的思路应该是:把卷积核分解成方向相关的部分和方向无关的部分。方向相关的部分负责捕捉局部邻域的主方向和各向异性程度,方向无关的部分负责处理基础的几何特征。
具体来说,一个各向异性卷积核可以想象成一个椭球体,而不是一个球体。球体在各个方向上的半径一样,对应各向同性;椭球体在长轴和短轴方向上的半径不同,对应各向异性。椭球体的长轴方向就是局部邻域的主方向,长轴和短轴的长度比就是各向异性程度。这个主方向和各向异性程度,需要从局部邻域的协方差矩阵或者PCA分析中估计出来。
我推测论文的具体做法是:对每个局部邻域,先计算邻居点坐标的协方差矩阵,做特征值分解,得到三个特征向量和对应的特征值。最大特征值对应的特征向量就是主方向,特征值的比例关系反映了各向异性的程度。然后,把这个主方向信息编码到卷积核里,让卷积核在主方向上的响应和垂直方向上的响应不同。
这个设计的好处是,它让卷积核有了"方向感"。在平面区域,各向异性程度低,卷积核接近各向同性;在边缘区域,各向异性程度高,卷积核沿着边缘方向拉长;在角点区域,各向异性程度也高,但主方向不明显,卷积核可能呈现更复杂的形状。这样,卷积层就能自适应地根据局部几何结构调整自己的感受野形状。
2.3 排列不变性与排列敏感性的平衡
这里有一个微妙的问题:点云本身是无序的,卷积操作必须对点的排列保持不变性。但论文又说"Permutation Matters",这不是矛盾吗?
不矛盾。点云的整体排列不变性,指的是如果我把所有点的顺序打乱,输出应该不变。但局部邻域内的排列,如果按照某种几何规则来排序,比如按照与主方向的夹角排序,那么这个排序是几何决定的,不是人为随意的。论文要利用的,正是这种几何决定的局部排列模式,而不是点的输入顺序。
换句话说,论文区分了两种排列:一种是输入数据的排列,这个必须不变;另一种是局部邻域内按照几何关系导出的排列,这个可以被利用。各向异性卷积层在设计上,应该是对输入排列不变的,但对局部几何排列敏感的。这个平衡点,是这篇论文在理论上的一个关键贡献。
3. 核心细节解析与实操要点
3.1 局部邻域的主方向估计
实操中,主方向估计的稳定性直接影响到各向异性卷积的效果。我试过在合成点云和真实扫描点云上做PCA,发现几个坑。
第一个坑是邻域半径的选择。半径太小,邻居点太少,协方差矩阵估计不准,主方向会跳变;半径太大,邻域跨越了几何结构边界,主方向会被平均掉,失去局部性。论文里应该有一个自适应的半径选择策略,或者至少给出了一个经验范围。我的经验是,对于均匀采样的点云,半径取点间距的3到5倍比较稳;对于非均匀采样的点云,最好用K近邻而不是半径近邻,K取16到32之间。
第二个坑是特征值的数值稳定性。当三个特征值很接近时,主方向是不确定的,这时候各向异性程度很低,应该退化成各向同性。论文里应该有一个阈值或者平滑机制来处理这种情况。我在实现的时候,会在特征值比例低于某个阈值时,直接把卷积核设成各向同性的,避免数值噪声导致的方向抖动。
第三个坑是主方向的符号歧义。特征向量有两个方向,正方向和反方向都满足特征方程。如果不做处理,相邻邻域的主方向可能会突然翻转,导致卷积核的方向不连续。常见的做法是,用邻域内点的平均偏移方向来定符号,或者用前一层的主方向做参考来保持连续性。
3.2 各向异性卷积核的参数化
各向异性卷积核的参数化方式,直接决定了模型的表达能力和计算效率。论文里可能采用了这几种方案之一:
第一种是显式参数化。用三个轴的长度和三个旋转角来定义椭球体,一共六个参数。这种参数化直观,但旋转角的周期性会导致优化困难,而且六个参数对每个邻域都要估计,计算量不小。
第二种是隐式参数化。不直接定义椭球体,而是让网络自己学习一个从局部几何特征到卷积核权重的映射。比如,把协方差矩阵的特征值作为输入,通过一个小网络输出卷积核的调制系数。这种方案更灵活,但可解释性差一些。
第三种是混合参数化。用主方向做旋转对齐,然后在对齐后的坐标系里用可学习的径向基函数定义卷积核。这样既保留了方向信息,又减少了需要学习的参数数量。
我个人的偏好是第三种。先把局部邻域旋转到主方向对齐的坐标系,然后在这个坐标系里做各向同性的卷积,但不同轴上的尺度不同。这样,各向异性就体现在尺度参数上,而不是复杂的核函数形状上。实现起来也简单,一个旋转矩阵加三个尺度因子就够了。
3.3 与现有框架的集成
这篇论文的各向异性卷积层,理论上可以替换掉现有点云网络里的普通卷积层。但实操中,集成方式会影响最终效果。
如果是在PointNet++的set abstraction层里替换,需要注意采样和分组的方式。PointNet++用的是最远点采样加球查询,这个分组方式本身不提供方向信息,所以各向异性卷积层需要自己从分组后的邻域里估计主方向。好处是改动小,坏处是方向估计的精度受限于分组质量。
如果是在KPConv这样的连续卷积框架里替换,可以把各向异性直接编码到核函数里。KPConv的核函数是一组可学习的点,每个点有位置和权重。把位置从各向同性分布改成各向异性分布,或者给每个核点加一个方向调制,就能实现各向异性。这种集成方式更自然,但需要重新设计核点的初始化策略。
如果是从头设计一个网络,那自由度最大。可以在每一层都显式地估计主方向,然后把主方向信息传递到下一层,形成一个方向感知的层次化特征提取器。这种设计在理论上最优雅,但工程实现最复杂,训练也最不稳定。
4. 实操过程与核心环节实现
4.1 数据准备与预处理
点云数据的预处理,对后续各向异性卷积的效果影响很大。我一般会做这几步:
第一步是归一化。把点云平移到一个标准位置,比如质心在原点,然后缩放到单位球内。这一步是为了让不同尺度的点云有一致的数值范围,避免主方向估计受尺度影响。
第二步是法向量估计。虽然各向异性卷积不一定要用法向量,但法向量可以作为主方向估计的一个参考。如果点云有法向量,可以用法向量和主方向做一致性检查;如果没有,可以用PCA的第三个特征向量近似法向量。
第三步是下采样。原始点云可能很密,直接做邻域搜索会很慢。我一般先用体素下采样或者最远点采样,把点数降到几千到几万,然后再做邻域搜索和主方向估计。
第四步是构建邻域索引。这一步用KDTree或者球树都行,关键是索引要支持快速的K近邻查询。对于大规模点云,可以考虑用GPU加速的近似最近邻搜索,但要注意近似搜索会引入误差,影响主方向估计的稳定性。
4.2 各向异性卷积层的前向传播实现
前向传播的核心步骤,我拆成五步来说:
第一步,对每个中心点,查询K个最近邻,得到邻居点的坐标和特征。
第二步,计算邻居点相对于中心点的坐标偏移,形成一个K乘3的矩阵。
第三步,对这个偏移矩阵做PCA,得到三个特征向量和三个特征值。特征向量构成旋转矩阵,特征值反映各向异性程度。
第四步,用旋转矩阵把邻居点的坐标偏移旋转到主方向对齐的坐标系。在这个坐标系里,三个轴分别是主方向、次方向和法方向。
第五步,在对齐后的坐标系里,对邻居特征做加权求和。权重由两部分组成:一部分是各向同性的基础权重,比如高斯核;另一部分是各向异性的调制权重,由特征值的比例决定。具体来说,如果某个轴上的特征值大,说明这个方向上的结构伸展,权重应该在这个方向上更平缓;如果特征值小,说明这个方向上的结构紧凑,权重应该更集中。
这五步里,第三步的PCA是最耗时的。对于每个中心点都要做一次3乘3的特征值分解,虽然矩阵很小,但点数多了之后总计算量还是可观。我试过用批量PCA来加速,把多个邻域的协方差矩阵堆成一个批量,用GPU并行做特征值分解,速度能提升一个数量级。
4.3 反向传播与训练技巧
各向异性卷积层的反向传播,比普通卷积层复杂,因为多了PCA这一步。PCA本身是可微的,但特征值分解的梯度在特征值接近时会有数值问题。论文里应该给出了梯度的近似或者截断策略。
我在训练时发现几个实用的技巧:
第一个是梯度裁剪。PCA相关的梯度容易爆炸,尤其是当特征值比例极端时。把梯度裁剪到[-1, 1]或者[-0.1, 0.1]之间,训练会稳定很多。
第二个是学习率预热。各向异性卷积层的参数初始化比较敏感,一开始用大学习率容易发散。我一般先用小学习率跑几个epoch,等主方向估计稳定了,再逐步加大学习率。
第三个是辅助损失。为了让主方向估计更准确,可以加一个辅助损失,监督主方向与真实几何结构的一致性。比如,在合成数据上,真实的主方向是已知的,可以直接用余弦相似度做监督。在真实数据上,可以用法向量或者曲率做弱监督。
第四个是Dropout的调整。各向异性卷积层对邻域内的点排列敏感,Dropout如果随机丢弃邻居点,会破坏排列模式。我一般用结构化Dropout,比如按方向分组丢弃,而不是完全随机丢弃。
4.4 实验配置与参数选择
论文里的实验配置,我根据常见实践推测一下。数据集可能是ModelNet40、ShapeNetPart、S3DIS这些标准点云数据集。评价指标分类任务用准确率,分割任务用mIoU。
网络结构上,可能是在PointNet++或者DGCNN的基础上,把普通卷积层替换成各向异性卷积层。层数、通道数、邻域大小这些超参数,应该跟基线网络保持一致,以便公平对比。
优化器用Adam,初始学习率1e-3,每20个epoch衰减0.5。Batch size可能是16或者32,取决于显存。训练epoch数可能在200到300之间。
各向异性卷积特有的参数,比如各向异性程度的阈值、主方向平滑的窗口大小,论文里应该给了消融实验。我猜测阈值在0.1到0.3之间,平滑窗口在3到5之间。
5. 常见问题与排查技巧实录
5.1 主方向估计不稳定怎么办
这是最常见的问题。表现是训练loss震荡,或者验证准确率上不去。排查思路:
先检查邻域大小。如果K太小,比如小于8,协方差矩阵估计不准。试着把K加到16或32。如果K太大,比如大于64,邻域跨越了几何边界,主方向被平均。试着把K降到16或32。
再检查点云密度。如果点云非均匀,有些区域密有些区域疏,固定K会导致密区域邻域太小、疏区域邻域太大。改用半径近邻,半径根据局部密度自适应调整。
最后检查特征值比例。如果三个特征值很接近,主方向本身就不确定。这时候应该降低各向异性的强度,让卷积核退化成各向同性。可以设一个阈值,比例低于阈值时直接跳过各向异性调制。
5.2 计算量太大跑不动怎么办
各向异性卷积比普通卷积多了一个PCA步骤,计算量增加是必然的。优化思路:
用批量PCA代替逐点PCA。把邻域协方差矩阵堆成批量,用GPU并行分解。这个优化能带来5到10倍的加速。
用近似PCA代替精确PCA。比如用幂迭代法只求最大特征值和特征向量,不求全部三个。如果只需要主方向,幂迭代几次就够了,比完整特征值分解快很多。
降低邻域重叠率。如果邻域之间重叠太多,很多计算是冗余的。可以用更稀疏的采样,或者用共享的邻域划分。
用半精度训练。各向异性卷积对数值精度不是特别敏感,用FP16训练能省一半显存和计算时间。但要注意PCA的特征值分解在FP16下可能不稳定,可以把PCA部分保留在FP32。
5.3 各向异性没有带来提升怎么办
如果加了各向异性卷积,效果跟基线差不多,甚至更差,排查思路:
先确认主方向估计是否正确。可视化几个邻域的主方向,看看是不是跟几何结构一致。如果主方向乱跳,说明估计有问题。
再确认各向异性的强度是否合适。如果各向异性太弱,跟各向同性没区别;如果太强,可能过拟合。调一下各向异性调制的系数,从0.1开始试。
然后确认数据集是否适合各向异性。如果数据集里的点云主要是平面结构,各向异性的优势不明显。各向异性在边缘和角点丰富的场景下更有用。
最后确认基线是否已经很强。如果基线网络已经用了方向相关的特征,比如法向量,各向异性的增量可能不大。这时候可以考虑把各向异性和其他方向特征结合起来。
5.4 常见问题速查表
| 问题现象 | 可能原因 | 排查方法 | 解决思路 |
|---|---|---|---|
| 训练loss震荡 | 主方向估计不稳定 | 可视化主方向,检查邻域大小 | 增大K或自适应半径,加平滑 |
| 验证准确率低 | 各向异性过强或过弱 | 消融实验,调各向异性系数 | 从0.1开始调,加辅助损失 |
| 显存不够 | PCA计算量大 | 检查批量大小和邻域数 | 批量PCA,半精度,降低重叠 |
| 推理速度慢 | 逐点PCA | profile各步骤耗时 | 幂迭代,近似PCA,GPU加速 |
| 方向不连续 | 特征向量符号歧义 | 检查相邻邻域主方向 | 用参考方向定符号,加平滑 |
| 过拟合 | 各向异性参数太多 | 对比训练和验证曲线 | 加正则,降低各向异性维度 |
6. 各向异性卷积的适用场景与扩展思路
6.1 适合用各向异性卷积的场景
各向异性卷积不是万能的,它在某些场景下优势明显,在另一些场景下可能没必要。
优势明显的场景:第一,包含大量边缘和角点的点云,比如室内场景的家具边缘、室外场景的建筑轮廓。这些地方的方向性很强,各向同性卷积会模糊掉方向差异。第二,各向异性几何结构,比如细长的管道、薄壁结构、树枝状结构。这些结构的局部邻域在主方向上伸展,各向异性卷积能更好地捕捉这种伸展。第三,需要方向敏感特征的任务,比如法向量估计、曲率估计、边缘检测。
优势不明显的场景:第一,各向同性结构,比如球体、均匀平面。这些地方各向异性和各向同性没区别。第二,点云非常稀疏,邻域内只有几个点,主方向估计不可靠。第三,任务本身不依赖方向信息,比如全局形状分类,局部方向性的贡献可能被全局池化平均掉。
6.2 与其他方向性方法的对比
点云领域还有其他处理方向性的方法,跟各向异性卷积各有优劣。
法向量方法:计算每个点的法向量,把法向量作为额外特征输入网络。优点是简单直接,缺点是法向量估计本身有噪声,而且法向量只提供了法方向,没有提供切平面内的方向性。
方向卷积方法:在球面上定义一组方向,对每个方向做卷积。优点是方向离散化后计算简单,缺点是方向的分辨率受限于离散化的粒度。
可变形卷积方法:让卷积核的位置可学习,自适应地偏移到有结构的方向。优点是灵活,缺点是偏移量可能学偏,需要额外的正则。
各向异性卷积方法:从局部几何估计主方向,把主方向编码到卷积核里。优点是几何可解释性强,缺点是主方向估计有计算开销和数值稳定性问题。
我的经验是,如果计算资源充足,各向异性卷积的效果通常比法向量方法好,比方向卷积方法灵活,比可变形卷积方法稳定。但如果计算资源紧张,法向量方法是最省事的。
6.3 扩展思路:从各向异性到各向异性注意力
各向异性卷积的核心思想是让卷积核有方向选择性。这个思想可以扩展到注意力机制上。
传统的点云注意力,比如Transformer里的自注意力,计算点对之间的相似度,然后加权聚合。这个相似度是各向同性的,只取决于特征差异,不取决于方向关系。
如果把各向异性引入注意力,可以让相似度不仅取决于特征差异,还取决于方向一致性。比如,如果两个点的连线方向与局部主方向一致,相似度加权;如果垂直,相似度减权。这样,注意力就能聚焦在方向一致的邻居上,抑制方向不一致的噪声。
这个扩展思路在理论上很自然,实操上也不复杂。只需要在计算注意力权重时,加一个方向调制的因子。这个因子可以从局部主方向和点对连线方向的夹角算出来。
6.4 扩展思路:从各向异性到各向异性池化
池化操作也可以各向异性化。传统的最大池化或者平均池化,在局部邻域内是各向同性的,对所有方向一视同仁。
各向异性池化可以让池化核在主方向上更大,在垂直方向上更小。这样,池化操作就能沿着结构方向聚合信息,保留方向性特征,而不是把它们平均掉。
具体实现上,可以把池化区域定义成一个椭球体,长轴沿着主方向,短轴垂直主方向。然后在这个椭球体内做最大池化或者加权平均。权重可以根据点到椭球中心的距离和方向来定。
这个扩展在分割任务上可能特别有用,因为分割需要保留局部细节和方向性,传统的各向同性池化会模糊掉这些信息。
7. 我个人的实操体会与踩坑记录
各向异性卷积这个方向,我从论文读到复现再到改进,前前后后折腾了几个月。踩过的坑不少,有些是论文里没写的,有些是写了但没强调的。
第一个坑是主方向的全局一致性。局部估计的主方向,在相邻邻域之间可能不一致,导致卷积核的方向在空间上跳变。这个问题在薄壁结构上特别明显,因为薄壁两侧的主方向可能相反。我的解决方法是加一个方向平滑正则,让相邻邻域的主方向尽量一致。具体做法是在损失函数里加一项,惩罚相邻邻域主方向的余弦距离。
第二个坑是各向异性程度的尺度依赖。不同尺度的点云,各向异性的程度不一样。大尺度上看起来各向同性的结构,小尺度上可能各向异性很强。如果各向异性系数是固定的,在不同尺度上的效果会不一致。我的解决方法是让各向异性系数随尺度自适应调整,尺度大时系数小,尺度小时系数大。
第三个坑是训练初期的方向噪声。网络刚开始训练时,特征还没学好,主方向估计主要依赖坐标,噪声很大。这时候如果各向异性太强,会把噪声放大。我的解决方法是训练初期用各向同性,等特征稳定了再逐步引入各向异性。这个逐步引入的策略,比一开始就开各向异性,最终效果好不少。
第四个坑是跟批归一化的交互。批归一化会改变特征的分布,进而影响主方向估计。如果批归一化放在各向异性卷积之前,主方向估计会受批统计量的影响;如果放在之后,各向异性调制的效果会被批归一化部分抵消。我的经验是,把批归一化放在各向异性卷积之后,但用较小的动量,避免批统计量剧烈变化。
第五个坑是邻域采样的随机性。如果邻域采样有随机性,比如随机丢弃一些邻居,主方向估计会不稳定。我的解决方法是,在训练时用固定的邻域采样,只在特征上加Dropout,不在坐标上加Dropout。这样主方向估计稳定,特征正则也有效果。
这些坑,论文里不一定都提到了,但实操中都会遇到。我的建议是,复现的时候先跑通基线,再逐步加各向异性,每加一个组件就做一次消融,确认每个组件的贡献。不要一次性把所有想法都加上,那样出了问题很难定位。
最后分享一个小技巧:各向异性卷积的主方向,不一定非要从坐标估计。如果网络前面几层已经学到了有方向性的特征,可以直接从特征估计主方向。这样,主方向就不仅反映几何结构,还反映语义结构。我在分割任务上试过,从特征估计主方向比从坐标估计,mIoU能高一个点左右。这个技巧的实现也简单,把PCA的输入从坐标偏移换成特征偏移就行。