文章目录

  • 声明
  • 引文
    • 1.点云数据格式
    • 2. 点云的特点
      • 2.1.1 点云的置换不变性
      • 2.1.2 点云的相互关系
      • 2.1.3 点云的旋转不变性
    • 3. 传统处理方式
  • Abstract
    • 点云数据的特性补充
  • 1. Introduction
  • 2. Related Work
  • 3. Problem Statement
  • 4. Deep Learning on Point Sets
    • 4.2. PointNet Architecture
    • 4.3 Theoretical Analysis(理论分析)
    • 5.2 Architecture Design Analysis 结构设计分析
  • 6. Conclusion
  • 7. 附个人总结
    • 1. motivation
    • 2. PointNet Architecture
    • 3. The most important points
    • 4. theorem
  • 8.代码解读
    • 1. Feature learning
    • 2. Classification Network
    • 3. Segmentation Network
    • input transform
    • feature transform
    • 主体部分
    • 分类任务
    • 分割任务
  • Reference

声明

本文借鉴了各大佬的讲解,相关引用已附最后 Reference 部分,在此表达深深的感谢,如有侵权,本人立刻删除。

原文地址: https://arxiv.org/abs/1612.00593
代码实现: https://github.com/charlesq34/pointnet

引文

~~~~     点云(point cloud)是一种非常重要的几何数据结构。由于点云的无规律性(irregular format),大部分研究者将点云转换为规律的3D体素网格(3D voxel grids)或者一组不同视角的2D图像。这种转换数据的方式,增加了数据的规模,同时也会带来一系列问题。在本篇论文中,我们设计了一种可以直接处理点云的神经网络,并且考虑了输入点云序列不变性的特征。我们的网络,PointNet,提供了统一的应用架构,可以用于分类(classification),块分割(part segmentation),语义理解(semantic parsing)。尽管网络很简单,但是非常有效。从实验结果上看,它超越了经典的方法,至少也达到同样的水平。理论上,我们进行了分析,包括网络学习了什么,以及当数据被一定程度的干扰后,网络为什么能保持稳定。

1.点云数据格式

点云数据:(num_points, num_channels)的张量
num_points: 点云的数量
num_channels = 3: 表示每个点的坐标为(x, y, z)

在介绍点云之前,我们先来看一下,要展现一个3D物体,都有哪些表现形式:

  • Point Cloud(点云): 它由N个D维特征的点组成,当D=3的时候一般表示的是位置坐标(x,y,z),当然D也可以大于3,这时可以包括一些法向量、强度等特征。
  • Mesh(面片): 由N个三角面片和正方形面片组成。
  • Volumetric(体素): 由N个特定大小的三维栅格来表征物体。
  • Multi-View Images or RGB(D)(多视角图像或者深度图像)


点云相对于其他表示方式有诸多优势,也越来越受到雷达自动驾驶研究人员的青睐。点云数据主要有以下两个优点:

  • 点云更接近于设备的原始表征(即雷达扫描物体后输出的数据就是点云)
  • 点云的表达方式更加简单,不需要额外的转换过程(耗时),也不存在额外的量化损失(失真)

2. 点云的特点

  1. 无序性 => 对称函数 maxpooling
  2. 点不是孤立的,需要考虑局部结构 => 局部全局特征结合 concat
  3. 仿射变换无关性 => T-Net 网络学习出旋转变换矩阵

2.1.1 点云的置换不变性

~~~~~~       无序性(Unordered) 与图像中的像素数组或者体素网格中的体素数组不同,点云是一系列无序点的集合。换句话说,神经网络在处理 N 个 3D 点时,应该对 N! 种输入顺序具有不变性(即:不同的输入顺序,网络学习的结果应该相差不大)。

~~~~~~       由于点云数据是无序排列的,当一个 N × D 的点云数据在N的维度上随意的打乱之后,其表述的任然是同一个物体,并不会影响物体的整体表达,这就称为点云的置换不变性(图2.1)。针对点云具有置换不变性的特点,其设计的网络必须是一个对称函数:

作者利用 max 函数设计一个很简单的点云网络,如下:

~~~~~~       但是这样的网络有一个问题,就是每个点的特征损失严重,输出的全局特征仅仅继承了三个坐标轴上最大的那个特征。为了减少特征损失,作者先将点云上的每一个点映射到一个高维的空间(例如1024维),其目的是为了再次做 MAX 操作时,输出的全局特征能够包含更多的有用特征,来弥补损失(图2.3):

~~~~~~       对于这样一个网络,作者在论文中给出了理论证明(图2.4)。其大意就是:任意一个在 Hausdorff 空间上连续的函数,都可以被这样的网络PointNet(vanilla) 无限的逼近。

2.1.2 点云的相互关系

~~~~~~       点之间的相互关系(Interaction Among Points) 来自空间的点在一定的度量距离内。这就意味着,点集中大部分点不是孤立的,邻域点一定属于一个有意义的子集。因此,网络需要从近邻点学习到局部结构,以及局部结构的相互关系。

2.1.3 点云的旋转不变性

~~~~~~       变换不变性(Invariance Under Transformations) 作为一个几何目标,点云的旋转不变性是指,将点云数据整体经过一定的刚性变化(旋转或平移),其中所有点的坐标(x、y、z)都变了,但它仍然代表同一个物体。

~~~~~~       因此对于前面提到的 PointNet(vanilla)网络,如果先后输入的同一个物体,但因为传感器等其他因素导致物体经过一定程度的旋转,原来的网络可能就不一定能很好地将其识别出来。为了解决这个问题,作者在论文中引入了一个 T-Net 网络去学习点云的旋转,将物体校准(是否是矫正为成正对方向,还需要再讨论),然后再将校准后的物体输入到前面设计的PointNet(vanilla)中进行分类或者分割即可

如图所示,旋转矫正网络的结构比较简单。网络输入的是一个 N × K 的点云矩阵,将其乘以一个 K × K 的旋转矩阵就可以将其矫正(这样描述不知道是否恰当),网络输出任然是一个 N × K 的点云矩阵。其中 K × K 的旋转矩阵是通过 T-Net 网络自己学习得到的。为了学习到这样一个旋转矩阵,作者设计了一个正则化惩罚项损失函数,使其尽可能接近于一个正交矩阵(原因还需进一步探究)。

3. 传统处理方式

1、将点云数据投影到二维平面。 此种方式不直接处理三维的点云数据,而是先将点云投影到某些特定视角再处理,如前视视角和鸟瞰视角。同时,也可以融合使用来自相机的图像信息。通过将这些不同视角的数据相结合,来实现点云数据的认知任务。比较典型的算法有 MV3D 和 AVOD。

2、将点云数据划分到有空间依赖关系的 voxel。 此种方式通过分割三维空间,引入空间依赖关系到点云数据中,再使用 3D 卷积等方式来进行处理。这种方法的精度依赖于三维空间的分割细腻度,而且 3D 卷积的运算复杂度也较高。

不同于以上两种方法对点云数据先预处理再使用的方式,PointNet系列论文提出了直接在点云数据上应用深度学习模型的方法。

Abstract

~~~~~~       点云(point cloud)是一种非常重要的几何数据结构。由于点云的无规律性(irregular format),大部分研究者将点云转换为规律的 3D 体素网格(3D voxel grids)或者一组不同视角的 2D 图像。这种转换数据的方式,增加了数据的规模,同时也会带来一系列问题。在本篇论文中,我们设计了一种可以直接处理点云的神经网络,并且考虑了输入点云序列不变性的特征。我们的网络,PointNet,提供了统一的应用架构,可以用于分类(classification),块分割(part segmentation),语义理解(semantic parsing)。尽管网络很简单,但是非常有效。从实验结果上看,它超越了经典的方法,至少也达到同样的水平。理论上,我们进行了分析,包括网络学习了什么,以及当数据被一定程度的干扰后,网络为什么能保持稳定。

摘要介绍的主要内容:

1.点云数据的特征:无规律性,无序性。

2.本文提出网络 PointNet, 可以直接处理原始点云,无需转换输入点云为3D体素或者多个视角的2D图像。

3.该网络用于提取点云特征,架构统一,可以适应不同的3D识别任务。

4.最后对网络学习的内容和网络的鲁棒性进行理论分析和实验验证。

点云数据的特性补充

1.点云的无序性
~~~~~~       这个要对比图像数据来理解,一团点云数据中有很多个点数据,这些点在点云文件里无论以什么顺序出现,它们指代的信息并不改变。相反,一张图片里的点在图像里已经按照固有的顺序排列好了。论文里利用了 maxpooling 这个对称函数来提取点云的数据特征。

2.点与点之间的空间关系
~~~~~~       每个点都包含了空间坐标信息,这些信息之间构成一定的集合空间关系,为了利用这种关系,论文作者提出了将局部特征和全局特征进行串联的方式来聚合信息。

3.不变性
~~~~~~      一团点云数据进行旋转和平移,它代表的目标不会发生改变。论文在进行特征提取之前,先对点云数据进行对齐来保证不变性。 通过训练一个小型的网络得到一个旋转矩阵,用这个矩阵与点云数据相乘来实现对齐操作。

1. Introduction

~~~~~~       本篇论文中,我们探究了深度神经网络处理诸如点云(Point Cloud)或者网格(Mesh)等 3D 几何数据的能力。为了能够进行权重共享或者其它核优化,传统的神经网络需要输入高度规律的数据,比如图像块或者 3D 体素网格。因为点云或者网格不是规律的数据,因此常被处理为 3D 体素网格,或者多视角 2D 图像,然后输入到传统的网络。这样的数据处理方式,增大了数据的规模,量化过程中,会掩盖数据本身的特性。


~~~~~~      基于这些原因,我们关注不同于体素或者图像的数据表达方式(使用原始点云数据,比如(x, y, z)坐标),并提出新的神经网络——PointNet. 点云是简单并且统一的结构,也就避免了组合的不规律性以及拓扑的复杂性,因此,容易被网络学习。当然,也不能忽略点云本身仅仅是一系列点,因此具有序列不变性,网络中添加特定得对称计算是有必要的。刚性变换不变性也需要考虑。

~~~~~~      我们的 PointNet 是统一的结构,输入是点云,输出是整个输入的类别标签或者每个输入点的分割或者分块的标签。我们的网络非常的简单,在最初的几个阶段,每一个点都是被独立、同等的处理。每个点只包含(x,y,z)坐标,也可以加入额外的特征维度,比如法线,或者其它局部或者全局特征。

~~~~~~       本文方法的关键是使用了一个简单的对称函数(max-pooling)。网络能够高效地学习最优函数或准则集合,它们可以从点云中选择感兴趣点或者信息点,并且编码了选择有效点的原因。网络最后的全连接层将这些学习的最优值聚合为全局特征描述子,并用于分类,分割等任务。

~~~~~~       因为输入的点是独立的,所以可以很容易应用刚性变换或者仿射变换。那么,我们可以在数据送入网络(PointNet)之前,对数据进行数据依赖的空间转换,目的是为了规范化输入数据,进而进一步改善训练结果。

~~~~~~       我们对提出的算法进行理论分析和实验评估。结果显示,我们的模型可以逼近任意连续的函数集。更加有趣的是,我们的网络可以学习一些关键的稀疏点,它们可以表达整个输入点云。根据可视化的结果,这些稀疏点分布在目标的骨骼部位(可以认为是足够表征目标的关键点)。理论上,我们解释了为什么PointNet 对于输入数据小的波动,添加噪声点或者删除部分点,仍然具有高度稳定性。

~~~~~~       对于当前的分类,Part 分割以及场景分割等任务,我们训练了 PointNet,并与经典算法(基于多视角图像或者体素)进行比对。我们的算法不仅更快,而且效果更好。

我们的主要贡献如下:

  1. 我们设计了新的神经网络架构,可以直接处理无序的3D点云。
  2. PointNet 可以进行3D形状的分类,Part分割,场景理解等任务。
  3. 我们从理论和实验分析了网络的鲁棒性和高效率。
  4. 我们可视化了网络部分节点学习的3D特征,为算法高效的表现提供了证明。

    使用神经网络处理无序的点云所面临的问题是非常基础和普遍的,我们期望该算法能够迁移到其它应用领域。

图1 PointNet的应用。我们提出了一种新的网络架构,它使用原始点云(点集),而无需体素化或渲染。它是一个学习全局和局部点特征的统一体系结构,为许多3D识别任务提供了一种简单、高效和有效的方法。

2. Related Work

「点云特征」 大多数现有的点云功能都是针对特定任务手工制作的。点特征通常对点的某些统计属性进行编码,并被设计为对某些转换保持不变,这些转换通常被分类为内在的 [2, 21, 3] 或外在的 [20, 19, 14, 10, 5]。它们也可以分为局部特征和全局特征。对于特定任务,找到最佳特征组合并非易事。


~~~~~~       「3D 数据的深度学习」 3D 数据具有多种流行的表示形式,引导了各种学习方法。Volumetric CNNs:[28,17,18] 是将 3D 卷积神经网络应用于体素化形状的先驱。然而,由于数据稀疏性和 3D 卷积的计算成本,体积表示受到其分辨率的限制。FPNN[13] 和 Vote3D[26] 提出了处理稀疏问题的特殊方法;然而,他们的操作仍然在稀疏的体积上,处理非常大的点云对他们来说是一个挑战。MultiviewCNNs:[23, 18] 尝试将 3D 点云或形状渲染为 2D 图像,然后应用 2D 卷积网络对它们进行分类。通过精心设计的图像CNN,这一系列方法已经在形状分类和检索任务上取得了主导性能[21]。然而,将它们扩展到场景理解或其他 3D 任务(如点分类和形状补全)是很重要的。Spectral CNNs:一些最新的工作[4,16]在网格上使用谱 CNN。然而,这些方法目前仅限于流形网格,如 organic 物体,如何将它们扩展到非等距形状,如家具,并不明显。基于特征的 DNN:[6, 8] 首先将 3D 数据转换为向量,通过提取传统的形状特征,然后使用全连接网络对形状进行分类。我们认为它们受到所提取特征的表示能力的限制。

~~~~~~       「无序集合的深度学习」 从数据结构的角度来看,点云是一组无序的向量。 虽然深度学习的大多数工作都集中在常规的输入表示上,比如序列(在语音和语言处理中)、图像和体积(视频或3D数据),但在点集的深度学习方面做的工作并不多。

~~~~~~       Oriol Vinyals 等人[25]最近的一项工作研究了这个问题。他们使用一个具有注意力机制的 read-process-write 网络来处理无序的输入集,并表明他们的网络有能力对数字进行排序。然而,由于他们的工作集中在通用集合和 NLP 应用程序上,因此集合中缺乏几何体的作用。

3. Problem Statement

~~~~~~       我们设计了一个深度学习框架,直接使用无序点集作为输入。点云是一组 3D 点的集合,{ Pi ∣ i = 1, 2 ,…, n},每一个点是其(x,y,z)坐标加上额外的通道(颜色,法向量等)特征的向量。为了简化以及便于陈述,除非有特别说明,否则我们的 3D 点集只有(x,y,z)3 个通道。

~~~~~~       对于目标分类任务,输入点云要么直接从形状采样,要么从场景点云预分割。 我们提出的深度网络输出所有 k 个候选类的 k 个分数。对于语义分割,输入可以是用于部分区域分割的单个目标,也可以是用于目标区域分割的三维场景的子体积。 我们的模型将为每个 n 点和每个 m 语义子类别输出 n × m 分数。

4. Deep Learning on Point Sets


4.2. PointNet Architecture


~~~~~~       我们的完整网络架构如图 2 所示,其中分类网络和分割网络共享很大一部分结构。 请阅读图 2 中 pipeline 的说明。

~~~~~~       我们的网络有三个关键模块:作为对称函数聚合所有点信息的 max pooling 层局部和全局信息组合结构以及用于对齐输入点和点要素的两个联合对齐网络

~~~~~~       我们将在下面单独的段落中讨论这些设计选择背后的原因。

图2 PointNet 架构。分类网络将 n 个点作为输入,应用输入和特征变换,然后通过最大池化聚合点特征。输出是 k 个类别的分类分数。分割网络是分类网络的扩展。它连接全局和局部特征并输出每点分数。 “mlp” 代表多层感知器,括号中的数字是层大小。 BatchNorm 用于所有带有 ReLU 的层。Dropout 层用于分类网络中的最后一个 mlp。

~~~~~~~        「无序输入的对称函数」 为了使模型对输入排列不变,存在三种策略:1)将输入的内容整理成一个规范的顺序。2)将输入作为一个序列来训练RNN,但通过各种排列组合来增加训练数据。3) 使用简单的对称函数来聚集来自每个点的信息。这里,对称函数将 n 个向量作为输入,并输出一个对输入顺序不变的新向量。例如,+ 和 * 运算符是对称二元函数。


~~~~~~       虽然排序听起来是一个简单的解决方案,但在高维空间中,事实上并不存在一个在一般意义上对点扰动稳定的排序。这很容易通过矛盾表现出来。如果存在这样的排序策略,它定义了一个高维空间和实线之间的双射映射。不难看出,要求排序对于点扰动是稳定的,相当于要求该地图在维度减小时保持空间接近度,这是一般情况下无法完成的任务。因此,排序并不能完全解决排序问题,而且随着排序问题的持续,网络很难从输入到输出获得一致的映射。如实验所示(图5),我们发现将 MLP 直接应用于分类后的点集表现不佳,尽管比直接处理未分类的输入稍好。

~~~~~~       使用RNN 的想法将点集视为一个序列信号,并希望通过用随机排列的序列训练 RNN,RNN 将变得对输入顺序不变。然而,在 “OrderMatters”[25] 中,作者已经表明顺序确实很重要,不能完全省略。虽然RNN 对于小长度(几十个)的序列的输入排序具有相对较好的鲁棒性,但它很难扩展到数千个输入元素,而这是点集的常见大小。根据经验,我们还表明,基于 RNN 的模型不如我们提出的方法表现好(图5)。「我们的想法是通过对集合中的变换元素应用对称函数来近似定义在点集上的一般函数:」

~~~~~~       根据经验,我们的基本模块非常简单:「我们用多层感知器网络近似,用单变量函数和最大池化函数的组合来估算 g。」 实验证明,这种方法效果良好。通过的集合,我们可以学习一些来获取集合的不同属性。

~~~~~~       虽然我们的关键模块看起来很简单,但它具有有趣的特性(见第 5.3 节),可以在一些不同的应用中实现强大的性能(见第 5.1 节)。由于我们模块的简单性,我们也能够像第 4.3 节那样提供理论分析。

~~~~~~       「局部和全局信息聚合」 上述部分的输出形成一个向量 [f1 ,…, fk],它是输入集的全局表示。 我们可以很容易地在形状全局特征上训练 SVM 或多层感知器分类器进行分类。然而,点分割需要结合局部和全局信息。我们可以通过简单而高效的方式实现这一点。

我们的解决方案如图 2(分段网络)所示。 「 在计算全局点云特征向量后,我们通过将全局特征与每个点特征连接起来,将其反馈给每个点特征。 然后,我们基于组合点特征提取新的每点特征——这一次,每点特征同时感知局部和全局信息。」

~~~~~~       通过这种修改,我们的网络能够预测依赖于局部几何和全局语义的每个点的数量。例如,我们可以准确预测每个点的法线(补充图中的图),验证网络是否能够汇总来自点的局部邻域的信息。在实验环节中,我们还展示了我们的模型在形状部分分割和场景分割方面的最新性能。

~~~~~~       「联合校准网络」 如果点云经过某些几何变换,例如刚体变换,点云的语义标记必须是不变的。因此,我们期望通过我们的点集学习的表示对这些变换是不变的。

~~~~~~       一种自然解决方案是在特征提取之前将所有输入集对齐到规范空间。Jaderberg 等人 [9] 引入了空间 transformer 的概念,通过采样和插值来对齐二维图像,由一个专门的层在 GPU 上实现。

~~~~~~       与 [9] 相比,我们的点云输入形式使我们能够以更简单的方式实现这一目标。我们不需要创造任何新的层,也没有像图像中那样引入别名。我们通过小型网络 (图2中的 T-net ) 预测仿射变换矩阵,并将该变换直接应用于输入点的坐标。微型网络本身类似于大网络,并且由点独立特征提取、最大池化和全连接层的基本模块组成。关于 T-net 的更多细节在附录中。

~~~~~~       这个想法也可以进一步扩展到特征空间的对齐。我们可以在点要素上插入另一个对齐网络,并预测要素变换矩阵来对齐来自不同输入点云的要素。然而,特征空间中的变换矩阵比空间变换矩阵维数高得多,这大大增加了优化的难度。因此,我们在 softmax 训练损失中增加了一个正则项。我们将特征变换矩阵约束为接近正交矩阵:


其中 A 是由微型网络预测的特征对准矩阵。正交变换不会丢失输入中的信息,因此是所期望的。我们发现,通过加入正则项,优化变得更加稳定,我们的模型实现了更好的性能。

补充: 联合对齐模块(Joint Alignment Network):分别对齐输入数据和点集特征

  1. 该模块的作用: 点云的预测结果应该对特定的变换具有不变性,比如刚性变换。为此,本文提出 T-Net 变换矩阵,将输入以及不同点的特征进行对齐,使得网络学习的表达也具有这种特性。
  2. 对齐模块的结构: 下面,我们将展示输入和特征对齐模块具体的结构,包括每一层的输入和输出。

4.3 Theoretical Analysis(理论分析)

~~~~~~       「通用近似」 我们首先展示了我们的神经网络对连续集函数的通用近似能力。通过集合函数的连续性,直观地,对输入点集的小扰动应该不会极大地改变函数值,例如分类或分割分数。



图 3 部分分割的定性结果。我们可视化所有16个目标类别的 CAD 部分分割结果。我们展示了部分模拟 Kinect 扫描(左块)和完整 ShapeNet CAD 模型(右块)的结果。





~~~~~~       这个定理的证明可以在我们的补充材料中找到。关键思想是,在最坏的情况下,网络可以通过将空间划分为相等大小的体素,来学习将点云转换为体积表示。然而,在实践中,网络学会了一种更智能的策略来搜寻空间,正如我们将在 point 函数可视化中看到的。






~~~~~~       结合 h 的连续性,这解释了我们的模型在点扰动、腐败和额外的噪声点方面的稳健性。类似于机器学习模型中的稀疏性原理,获得了鲁棒性。直观地说,我们的网络学习通过一组稀疏的关键点来总结形状。在实验部分,我们看到关键点构成了一个目标的骨架。

5.2 Architecture Design Analysis 结构设计分析

~~~~~~       在本节中,我们通过控制实验来验证我们的设计选择。我们还显示了我们的网络的超参的影响。

~~~~~~       「与其他顺序不变方法的比较」 如 4.2 节所述,至少有三种选择来处理无序的集合输入。我们使用 ModelNet40 形状分类问题作为比较这些选项的测试平台,以下两个操作实验也将使用此任务。


~~~~~~       我们比较的基线(如图 5 所示)包括未排序和排序点上的多层感知器( n × 3 阵列)、将输入点视为序列的 RNN 模型,以及基于对称函数的模型。我们实验的对称操作包括最大池化、平均池化和基于注意力的加权和。注意力方法类似于 [25] 中的方法,其中从每个点特征预测标量分数,然后通过计算 softmax 对分数进行归一化。然后根据归一化分数和点特征计算加权和。如图5所示,max pooling 操作以较大的优势获得了最佳性能,这验证了我们的选择。

~~~~~~       「输入和特征转换的有效性」 在表 5 中,我们展示了我们的输入和特征转换(用于对齐)的积极效果。有趣的是,最基本的架构已经取得了相当合理的结果。使用输入转换可以提高 0.8% 的性能。正则化损失是高维变换工作所必需的。通过结合变换和正则项,我们获得了最佳性能。

~~~~~~       「鲁棒性测试」 我们展示了我们的PointNet,虽然简单有效,但对各种输入损坏具有鲁棒性。我们使用与图5的最大池化网络相同的架构。输入点被归一化为一个单位球体。结果如图6所示。

6. Conclusion

~~~~~~       在这项工作中,我们提出了一种直接处理点云的新型深度神经网络 PointNet。我们的网络为许多 3D 识别任务提供了统一的方法,包括目标分类、部分分割和语义分割,同时在标准基准上获得与现有技术相当或更好的结果。我们还提供理论分析和可视化,以了解我们的网络。

7. 附个人总结

1. motivation

~~~~~~       典型的卷积体系结构需要高度规则的输入数据格式,由于点云或网格不是规则格式,研究人员通常将这些数据转换为规则的 3D 体素网格或图像集合,然后再将其提供给深层网络体系结构。然而,这种数据表示转换使结果数据变得不必要地庞大,同时还引入了量化伪像,这可能会模糊数据的自然不变性。

~~~~~~       出于这个原因,我们将重点放在使用简单的点云来表示3D几何形状上

2. PointNet Architecture

图2 PointNet 架构。分类网络将 n 个点作为输入,应用输入和特征变换,然后通过最大池化聚合点特征。输出是 k 个类别的分类分数。分割网络是分类网络的扩展。它连接全局和局部特征并输出每点分数。 “mlp” 代表多层感知器,括号中的数字是层大小。 BatchNorm 用于所有带有 ReLU 的层。Dropout 层用于分类网络中的最后一个 mlp。

该网络有三个关键模块

  1. 对称函数(Symentric Function),作为从所有点聚合信息的对称函数的最大池化层

    我们的想法是通过对集合中变换的元素应用对称函数来近似定义在点集上的一般函数,通过MLP来近似 h, g 由一个单变量函数和最大池化函数组合构成
 x = torch.max(x, 2, keepdim=True)[0] # 返回第 3 维的最大值,并保持输入输出维度不变,只是维度上的数据变为了最大值 (B, 1024, 1)

a. 如上述代码所示,输入为【B x 1024 × N】,池化层核的大小为【num_point,1】==>【1024,1】,在没有有填充的情况下(padding=VALID),对 H,W 维度进行最大池化操作,【1024,1】转换为 【1,1】。

b. 对称函数正是为了解决 3D 点集无序性输入的问题。

c. 对称函数将所有独立的点特征聚合为全局的点集特征,进而进行后续的3D 识别任务。

补充:Pointnet 网络主要使用对称函数解决点的无序性问题,对称函数就是指对输入顺序不敏感的函数。如加法、点乘、max pooling 等操作。假设输入特征为 N x D,N 表示点数,D 表示维度数,在 max pooling 作用下,取出每个维度上最大值的 1 x D 的向量,每一维特征都与其顺序无关,这样便保证了对于点云输入顺序的鲁棒性。

  1. 组合局部信息和全局信息的结构

    计算全局点云特征向量后,通过将全局特征与每个点特征连接起来,将其反馈给逐点特征。然后,我们基于组合点特征提取新的逐点特征–这一次,逐点特征同时知道局部和全局信息。

  2. 联合对齐模块(Joint Alignment Network):分别对齐输入数据和点集特征,将输入点和点特征对齐的结构
    该模块的作用: 点云的预测结果应该对特定的变换具有不变性,比如刚性变换。为此,本文提出 T-Net 变换矩阵,将输入以及不同点的特征进行对齐,使得网络学习的表达也具有这种特性。
    对齐模块的结构: 下面,我们将展示输入和特征对齐模块具体的结构,包括每一层的输入和输出。

    点云对齐:

    特征对齐:

旋转平移不变性: 点云数据所代表的目标对某些空间转换应该具有不变性,如旋转和平移。论文作者提出了在进行特征提取之前,先对点云数据进行对齐的方式来保证不变性。对齐操作是通过训练一个小型的网络来得到转换矩阵,并将之和输入点云数据相乘来实现。Pointnet 的解决方法是学习一个变换矩阵 T,即 T-Net 结构。由于 loss 的约束,使得 T 矩阵训练会学习到最有利于最终分类的变换,如把点云旋转到正面。论文的架构中,分别在输入数据后和第一层特征中使用了 T矩 阵,大小为3x3和64x64。其中第二个T矩阵由于参数过多,考虑添加正则项,使其接近于正交矩阵,减少点云的信息丢失。

细节探究

① 经过一维卷积
假设有 2500 个样本点,每个样本点的数据为(x, y, z), 即样本的尺寸为 2500 × 3,代码运算时首先需要转置,变为 3 × 2500,假设 batchsize = 1,输入尺寸就是1 × 3 × 2500

第一步卷积操作,输入通道 = 3,输出通道 = 64,卷积核大小为 1 (tensorflow 中为 3 × 1, 3 由输入通道决定),实际上是使用 64 个 3 × 1 的卷积核进行卷积,输出尺寸应该是 1 × 64 × 2500

如果把 batch size 记为 n,样本在网络中的变化就是 n × 3 × 2500 ==> n × 64 × 2500 ==> n × 128 × 2500 ==> n × 1024 × 2500 ==> n × 1024 × 1(max pooling 后,这里并不是对每个点的特征向量做 max pooling,而是特征向量为基准,对所有点对应的维度做 max pooling) ==> n × 512 × 1 ==> n × 256 × 1 ==> n × 16 × 1 (本次实验样本共有16类)

② 再看网络结构

mlp 是通过共享权重的卷积实现的,第一层卷积核大小是 1 x 3(因为每个点的维度是(x, y, z)),之后的每一层卷积核大小都是 1 x 1。特征提取层只是把每个点连接起来而已。经过两个空间变换网络和两个 mlp 之后,对每一个点提取 1024 维特征,经过 maxpool 变成 1 x 1024 的全局特征。再经过一个 mlp(代码中运用全连接)得到 k 个 score。分类网络最后接的 loss 是softmax。

3. The most important points

① 空间变换网络解决旋转问题
~~~~~~       pointnet 采用了两次 STN,原理个人理解主要是通过控制最后的 loss 来对变换矩阵进行调整,第一次 input transform 是对空间中点云进行调整,直观上理解是旋转出一个更有利于分类或分割的角度,比如把物体转到正面;第二次 feature transform 是对提取出的 64 维特征进行对齐,即在特征层面对点云进行变换。

② maxpooling 解决无序性问题
~~~~~~       当一个 N × D 在 N 的维度上随意的打乱之后,其表述的其实是同一个物体。因此针对点云的置换不变性(无序性),其设计的网络必须是一个对称的函数:

我们经常看到的 SUM 和 MAX 等函数其实都是对称函数

因此我们可以利用 max 函数设计一个很简单的点云网络,如下:

~~~~~~       那么为什么要最后变换到 1024 维后再做 MAX 操作呢,这是因为在 3 维上,输出的全局特征仅仅继承了三个坐标轴上最大的那个特征,每个点损失的特征太多了,因此我们不妨先将点云上的每一个点映射到一个高维的空间(例如 1024 维),目的是使得再次做 MAX 操作,损失的信息不会那么多。

4. theorem

定理 1
证明了PointNet的网络结构能够拟合任意的连续集合函数。


定理2 (a) 说明对于任何输入数据集,都存在一个关键集和一个最大集,使得对和之间的任何集合,其网络输出都和一样。这也就是说,模型对输入数据在有噪声和有数据损坏的情况都是鲁棒的。

定理2 (b) 说明了关键集的数据多少由 maxpooling 操作输出数据的维度 K 给出上界(框架图中为1024)。这个角度来讲,PointNet 能够总结出表示某类物体形状的关键点,基于这些关键点 PointNet 能够判别物体的类别。这样的能力决定了 PointNet 对噪声和数据缺失的鲁棒性。

8.代码解读

PointNet 网络框架主要完成了两个任务,一个是 Classification、一个是Segmentation。其网络的关键流程介绍如下:

1. Feature learning

  • 网络输入的是 n × 3 的点云数据,其中 n 是点云的个数,3 是每个点的特征维度,在这里特指点云的坐标 (x、y、z)
  • 经过 input transform 模块(乘以由 T-Net 学习得到的 3 × 3 旋转矩阵),将输入点云进行矫正(input transform),输出为矫正后的 n × 3 点云数据。
  • 再通过两层(3 → 64 、 64 → 64 MLP(多层感知机)将其映射到 64 维的空间上,输出为 n × 64 的点云矩阵。其中 MLP 是通过共享卷积层实现,具体实现方式将在第四章详细讨论。 经过 feature transform 模块(乘以由 T-Net 学习得到的 64 × 64 旋转矩阵),将输入的点云特征进行“矫正”,输出为矫正后的 n × 64 点云数据。
  • 再通过类似的三层MLP网络(64 → 64 、 64 → 128 、 128 → 1024)将每个点的特征映射到更高维(1024)的特征空间上。
  • 经过 max pool 层,max 操作沿着 element-wise 方向将 n × 1024 的点云特征变成 1 × 1024 的全局特征。

2. Classification Network

  • 通过三层MLP(1024 → 512 、 512 → 256 、 256 → k)最终输出 k 个类别的分数。其中的 MLP 层是通过全连接网络来实现的。

3. Segmentation Network

  • 将经过 feature transform 模块输出的 n × 64 点云特征与 1 × 1024 全局特征拼接成 n × 1088 点云特征,这里的拼接方式是首先将 1 × 1024 全局特征复制为 n × 1024 点云特征,再与 n × 64 的点云特征进行拼接。
  • 分别经过三层MLP网络(1088 → 512 、 512 → 256 、 256 → 128)、两层MLP网络(128 → 128 、 128 → m)进行特征学习,最终输出为每个 point 对应于 m 个 part 的类别分数。值的注意的是当 m>1 时是属于 part segmentation 范畴,当 m=1 属于 point segmentation。

~~~~~~       首先我先来讲解分类网络,图中深色部分,首先输入点经过一个transform,再经过多层感知机,再经过一个feature transform,再经过多层感知机和max pooling,最后经过多层感知机获得分类结果,网络结构是比较清晰的,下边一块一块看:

input transform

~~~~~~       首先这一层的目的是对输入的每一个点云,在这里是 2500 个三坐标点,目的是要获得一个 3 × 3 的变换矩阵,获得这个矩阵的原因是:要对点云的姿态进行校正,而该变换矩阵就是根据点云特性,做出一个刚体变换,使点云处于一个比较容易检测的姿态。先对输入经过三级卷积核为 1 × 1 的卷积处理得到 1024 通道的数据,再经过全连接处映射到九个数据,最后调整为 3 × 3,位姿改变,使改变后的位姿更适合分类/分割

# 对输入进行 Transformer
class STN3d(nn.Module):def __init__(self, channel):super(STN3d, self).__init__()# 输入数据为 (B,3,N),首先通过 1 × 1 的卷积核得到 1024 通道的数据self.conv1 = torch.nn.Conv1d(channel, 64, 1)self.conv2 = torch.nn.Conv1d(64, 128, 1)self.conv3 = torch.nn.Conv1d(128, 1024, 1)# 通过全连接层输出 9 个数据self.fc1 = nn.Linear(1024, 512)self.fc2 = nn.Linear(512, 256)self.fc3 = nn.Linear(256, 9)self.relu = nn.ReLU()# 分别对卷积层和全连接层做批归一化,防止梯度问题self.bn1 = nn.BatchNorm1d(64)self.bn2 = nn.BatchNorm1d(128)self.bn3 = nn.BatchNorm1d(1024)self.bn4 = nn.BatchNorm1d(512)self.bn5 = nn.BatchNorm1d(256)def forward(self, x):batchsize = x.size()[0]x = F.relu(self.bn1(self.conv1(x))) # (B, 64, N)x = F.relu(self.bn2(self.conv2(x))) # # (B, 128, N)x = F.relu(self.bn3(self.conv3(x))) # (B, 1024, N)# 相当于进行 maxpool , 一组点仅保留一个 feature,实现对称x = torch.max(x, 2, keepdim=True)[0] # 返回第 3 维的最大值,并保持输入输出维度不变,只是维度上的数据变为了最大值 (B, 1024, 1)# 这里每组点经过处理后只有 1024 个特征,然后 -1, 是 batchsize ,会自动填补x = x.view(-1, 1024) # 展平进行全连接 (B, 1024)# 通过全连接产生 9 个输出x = F.relu(self.bn4(self.fc1(x)))x = F.relu(self.bn5(self.fc2(x)))x = self.fc3(x)# 最终处理为 3 × 3 的大小,即(B, 3, 3)x = x.view(-1, 3, 3)return x

feature transform

~~~~~~       从输入数据中获取一个 64 × 64 的变换矩阵,这个也是对特征的一种校正,一种广义的位姿变换,代码与上述几乎没有差别,对 64 维特征进行对齐

# feature transform ,这个和上面没有区别,只是输出为 64 × 64 的大小
class STNkd(nn.Module):def __init__(self, k=64):super(STNkd, self).__init__()self.conv1 = torch.nn.Conv1d(k, 64, 1)self.conv2 = torch.nn.Conv1d(64, 128, 1)self.conv3 = torch.nn.Conv1d(128, 1024, 1)self.fc1 = nn.Linear(1024, 512)self.fc2 = nn.Linear(512, 256)self.fc3 = nn.Linear(256, k * k)self.relu = nn.ReLU()self.bn1 = nn.BatchNorm1d(64)self.bn2 = nn.BatchNorm1d(128)self.bn3 = nn.BatchNorm1d(1024)self.bn4 = nn.BatchNorm1d(512)self.bn5 = nn.BatchNorm1d(256)self.k = kdef forward(self, x):batchsize = x.size()[0]x = F.relu(self.bn1(self.conv1(x)))x = F.relu(self.bn2(self.conv2(x)))x = F.relu(self.bn3(self.conv3(x)))x = torch.max(x, 2, keepdim=True)[0]x = x.view(-1, 1024)x = F.relu(self.bn4(self.fc1(x)))x = F.relu(self.bn5(self.fc2(x)))x = self.fc3(x)# (B, 64, 64)x = x.view(-1, self.k, self.k)return x

主体部分

~~~~~~       max pooling 之前的剩余部分,首先经过 STN3d 获得 3 × 3 矩阵,乘以点云做完位姿变换,再经过多层感知机(实际上多层感知机与卷积核边长为 1 的卷积操作本质是一样的),再乘以经过 STNkd 获得的 64 × 64 的矩阵,完成位姿变换,再经过多层感知机(这里同样用边长为 1 的卷积核的卷积操作),得到 n × 1024 的矩阵,n 为每批次读入的数据文件个数。下边这个类中调用了前边两个类。

# 整个模型框架的完善
class PointNetfeat(nn.Module):def __init__(self, global_feat=True, feature_transform=False):super(PointNetfeat, self).__init__()self.stn = STN3d()self.conv1 = torch.nn.Conv1d(3, 64, 1)self.conv2 = torch.nn.Conv1d(64, 128, 1)self.conv3 = torch.nn.Conv1d(128, 1024, 1)self.bn1 = nn.BatchNorm1d(64)self.bn2 = nn.BatchNorm1d(128)self.bn3 = nn.BatchNorm1d(1024)self.global_feat = global_featself.feature_transform = feature_transformif self.feature_transform:self.fstn = STNkd(k=64)def forward(self, x):# N :点云的数量,这里需要注意输入为 (B, 3, N)n_pts = x.size()[2]# 第一步转换得到# (B,3,3)trans = self.stn(x)# 首先进行转置,变为(B, N, 3),方便进行矩阵乘法x = x.transpose(2, 1)# 计算机 trans 和 x 两个矩阵的乘法,#(B,N,3))x = torch.bmm(x, trans)# 乘完以后再变换回来, (B,3,N)x = x.transpose(2, 1)# 接后面的 mlp,# (B,64,N)x = F.relu(self.bn1(self.conv1(x)))# 第二步: feature transform同样,只是改变最终的输出维度if self.feature_transform:# 在特征在做评议旋转不变trans_feat = self.fstn(x)x = x.transpose(2, 1)x = torch.bmm(x, trans_feat)x = x.transpose(2, 1)# (B,64,N)else:trans_feat = None# 将值保存下来,作为后面的拼接,(B, 64, N)pointfeat = x# 第三步一直到 max poolx = F.relu(self.bn2(self.conv2(x)))x = self.bn3(self.conv3(x))x = torch.max(x, 2, keepdim=True)[0]# (B, 1024)x = x.view(-1, 1024)if self.global_feat:# 返回维度 x (B,1024),return x, trans, trans_featelse:# (通道数的重复倍数,列的重复倍数,行的重复倍数)(B, 1024, N)x = x.view(-1, 1024, 1).repeat(1, 1, n_pts)# 对第 1 个维度进行拼接, 即上述 feature transformer 中的 (B, 64, N), 拼接上 maxpooling (B, 1024, N) 后的 (B, 1088, N)return torch.cat([x, pointfeat], 1), trans, trans_feat

分类任务

进行最大池化和多层感知机进行分类了,经过全连接分成k类,根据概率来判别究竟属于哪一类

class PointNetCls(nn.Module):def __init__(self, k=2, feature_transform=False):super(PointNetCls, self).__init__()self.feature_transform = feature_transform# (B,1024)self.feat = PointNetfeat(global_feat=True, feature_transform=feature_transform)self.fc1 = nn.Linear(1024, 512)self.fc2 = nn.Linear(512, 256)self.fc3 = nn.Linear(256, k)# 防止过拟合self.dropout = nn.Dropout(p=0.3)# 归一化防止梯度爆炸与梯度消失self.bn1 = nn.BatchNorm1d(512)self.bn2 = nn.BatchNorm1d(256)self.relu = nn.ReLU()def forward(self, x):# 完成网络主体部分x, trans, trans_feat = self.feat(x)# 经过三个全连接层(多层感知机)映射成k类x = F.relu(self.bn1(self.fc1(x)))x = F.relu(self.bn2(self.dropout(self.fc2(x))))x = self.fc3(x)# 返回的是该点云是第ki类的概率return F.log_softmax(x, dim=1), trans, trans_feat

分割任务

分割网络是借用了分类网络的两部分,分别是64通道和1024通道,堆积在一起形成1088通道的输入,经过多层感知机输出了结果m通道的结果,m代表类的个数,也就是每个点属于哪一类,实际上分割是在像素级或者点级的分类,本质上是一样的

class PointNetDenseCls(nn.Module):def __init__(self, k=2, feature_transform=False):super(PointNetDenseCls, self).__init__()self.k = kself.feature_transform = feature_transformself.feat = PointNetfeat(global_feat=False, feature_transform=feature_transform) # (B, 1088, N)self.conv1 = torch.nn.Conv1d(1088, 512, 1) # (B, 512, N)self.conv2 = torch.nn.Conv1d(512, 256, 1) # (B, 256, N)self.conv3 = torch.nn.Conv1d(256, 128, 1) # (B, 128, N)self.conv4 = torch.nn.Conv1d(128, self.k, 1) # (B, k, N)self.bn1 = nn.BatchNorm1d(512)self.bn2 = nn.BatchNorm1d(256)self.bn3 = nn.BatchNorm1d(128)def forward(self, x):batchsize = x.size()[0]n_pts = x.size()[2]x, trans, trans_feat = self.feat(x)x = F.relu(self.bn1(self.conv1(x)))x = F.relu(self.bn2(self.conv2(x)))x = F.relu(self.bn3(self.conv3(x)))x = self.conv4(x) # (B, k, N)# transpose() 交换 1 和 2 两个维度x = x.transpose(2, 1).contiguous() # contiguous 是由于 transpose 变换后实际上再内存中并没有改变,加上这一句可以使得内存中也发生变化x = F.log_softmax(x.view(-1, self.k), dim=-1) # torch.Size([B, K])x = x.view(batchsize, n_pts, self.k) # (B, n, m)return x, trans, trans_feat

Reference

1. 点云的无序性_三维点云分类与分割-PointNet

2. PointNet模型的Pytorch代码详解

3. PointNet: Deep Learning on Point Sets for 3D Classification and Segmentation

4. PointNet: Deep Learning on Point Sets for 3D Classification and Segmentation

5. 三维点云网络 PointNet 代码讲解强推 ☆☆☆

6. 3D点云 | 基于深度学习处理点云数据入门经典:PointNet、PointNet++ 文章总结,强推 ☆☆☆

【论文精读 | 细节分析 | 代码实现】PointNet: Deep Learning on Point Sets for 3D Classification and Segmentation相关推荐

  1. [LiteratureReview]PointNet Deep Learning on Point Sets for 3D Classification and Segmentation

    [LiteratureReview]PointNet: Deep Learning on Point Sets for 3D Classification and Segmentation 出处:20 ...

  2. 点云网络的论文理解(一)-点云网络的提出 PointNet : Deep Learning on Point Sets for 3D Classification and Segmentation

    1.摘要 1.1逐句翻译 Point cloud is an important type of geometric data structure. 点云是一种重要的数据结构. Due to its ...

  3. 【论文阅读】3D点云 -- PointNet: Deep Learning on Point Sets for 3D Classification and Segmentation

    前言 本博客详解遵从论文讲述的顺序.但我们要明确该论文的要点,以更好的阅读论文:针对点云的3个特性,pointnet设计的应对方法,以及设计理念. 点云的无序性:网络使用了对称函数 (maxpooli ...

  4. PointNet: Deep Learning on Point Sets for 3D Classification and Segmentation

    基本简介 论文下载地址:https://arxiv.org/abs/1612.00593 代码开源地址:https://github.com/charlesq34/pointnet 作者以及论文信息如 ...

  5. PointNet: Deep Learning on Point Sets for 3D Classification and Segmentation 中文翻译

    点云是一种重要的几何数据结构. 由于其不规则的格式,大多数研究人员将这些数据转换为常规3D体素网格或图像集合. 然而,这会使数据不必要地大量增加并导致问题. 在本文中,我们设计了一种直接消耗点云的新型 ...

  6. 阅读笔记 PointNet: Deep Learning on Point Sets for 3D Classification and Segmentation

    一.背景 点云是三维坐标系统中的一组三维向量的集合,是表示物体外表的一个形状,接近物体原始特征 我们的卷积神经网络通常需要规则的数据形式作为输入,但由于点云是非规则数据类型所以通常的做法大都先对点云进 ...

  7. 【面向代码】学习 Deep Learning Convolution Neural Network(CNN)

    转载自: [面向代码]学习 Deep Learning(三)Convolution Neural Network(CNN) - DarkScope从这里开始 - 博客频道 - CSDN.NET htt ...

  8. 转【面向代码】学习 Deep Learning(二)Deep Belief Nets(DBNs)

    [面向代码]学习 Deep Learning(二)Deep Belief Nets(DBNs) http://blog.csdn.net/dark_scope/article/details/9447 ...

  9. 重读经典(点云深度学习开山之作):《Deep learning on point clouds for 3D scene understanding》(持续更新中)

    本文介绍的是 PointNet 作者的博士论文:3D场景理解中的点云深度学习.从上图可以看到,整个博士论文主要贡献有两块:一是点云深度学习的网络架构(PointNet 和 PointNet++):二是 ...

最新文章

  1. 产品思维-产品初期准备
  2. 国内用得最多的框架,它排第一!
  3. Leetcode:Intersection of Two Linked Lists
  4. 一张脑图说清 Nginx 的主流程
  5. PAT甲级1134 Vertex Cover :[C++题解]顶点覆盖、图论、用结构体存边,bool数组判断
  6. MySQL子查询介绍
  7. phpcms模型缓存更新原理分析(转)
  8. Python基础-使用paramiko
  9. npm 查看登陆账号_自定义npm 及问题整理
  10. Windows Server 2008 R2 企业版操作说明手册
  11. Vue组件动态(异步)传值
  12. axure 折线图部件_在Axure中怎么做柱状图、折线图啊?
  13. 数据可视化|用散点图进行数据分析
  14. windows,远程开机,远程唤醒(WOL,Wake-on-LAN)
  15. bcc语料库下载_语料库汇总
  16. netstat -ano 查看端口是否被占用
  17. Authing 新增 AWS、钉钉、腾讯 QQ 、百度、新浪微博等多种身份源|功能更新
  18. android u盘 uuid,Android4.4KitKat支持u盘功能
  19. python定义多项式除法_python如何进行多项式的加减乘除
  20. STM32F411RE项目开发-1-点亮LD2小灯

热门文章

  1. android盲人模式功能,华为P9盲人模式功能介绍 华为P9手机 talkback使用图文教程...
  2. 微信指数:微信官方提供的基于微信大数据分析的移动端指数
  3. vue工作笔记 随手记
  4. 当装好anaconda的python3.7环境后,如何使的spyder运行在其中,anaconda中打不开spyder怎么办,spyder中导入不了opencv模块怎么办
  5. win10 smtp邮件服务器,Win10 内置邮箱 SMTP 同步文件夹错乱问题。
  6. 暨南大学计算机考试准考证号,暨南大学珠海校区17年3月计算机二级考试准考证打印...
  7. 三菱FX3U——SFC=状态初始化指令IST
  8. 小米千元新机曝光!骁龙845+水滴屏+屏下指纹,网友:可真香
  9. 多因子模型之因子(信号)测试平台----alphalens(一)
  10. cpu要和gpu搭配吗_显卡和CPU搭配有要求吗 CPU和显卡怎么搭配最好? (全文)