第一章 【论文阅读】PointNet论文解读
第二章 【论文阅读】PointNet++论文解读以及代码分析(超全)
上一篇文章主要介绍了点云处理的经典之作PointNet的整体思想和框架,本篇文章将介绍其团队基于PointNet改进的PointNet++。文章核心的一点就是提出了多层次特征提取结构。具体而言就是在输入点集中利用farthest point sampling选择一些点作为中心点,然后围绕每个中心点选择周围的点组成一个区域,将每个区域作为PointNet的一个输入样本,这样就得到了一组该区域的特征。之后中心点不变,扩大区域,把上一步得到的那些特征作为输入再送入PointNet,循环反复,不断提取局部特征,扩大局部范围,最后得到一组全局的特征,然后进行分类或者分割。文章还提出了多尺度方法解决样本中点云密度不均匀的问题,增加模型的鲁棒性。
PointNet++代码
PointNet存在的一个缺点就是无法获取局部特征。在PointNet中,要不就是对单个点进行 1 × 1 1×1 1×1卷积操作,要不就是对所有点进行最大池化获得全局特征,虽然每个点都映射到了高维空间中,但还是丢失了很多局部信息,如下图:
从很多实验结果可以看出,PointNet对于场景的分割效果十分一般,所以提取局部区域特征就成了改进的一个方向。为了解决这一问题,PointNet++提出了首先选取一些比较重要的点作为每个局部区域的中心点,然后再中心点的周围选取k个近邻点,再将k个近邻点作为一个局部点云丢入PointNet中提取特征。
为了解决PointNet网络无法提取局部特征的问题,在PointNet++中,作者借鉴了CNN的多层感受野的思想。首先,在整个点云的局部采样并划分为具有重叠的局部区域,在局部区域中通过PointNet提取局部特征,然后扩大范围,在这些局部特征的基础行提取更高层次的特征,直到提取整个点云集的全局特征,整个过程和CNN网络提取特征的过程类似。
PointNet++在PointNet的基础上加入了多层次结构,使得网络能够在越来越大的区域上提供更高级别的特征,每一次提取就称为set abstraction,主要包括3个部分:Sampling layer, Grouping layer and PointNet layer。
通过使用多层次结构提取局部特征,在点云的分类和分割效果有了一定的提升,但是其在点云缺失的鲁棒性上变得更差了。其原因在于激光收集点云数据的时候总是在近的地方密集,在远的地方稀疏。因此一旦缺失部分点云数据,网络的性能就会受到极大影响,见下图。
在论文中,作者给出了对比实验,可以看出当点云缺失个数达到20%时,PointNet++的性能还不如PointNet。因此,通过固定范围选取的固定个数的近邻点是不合适的,pointnet++提出了两个解决方案,多尺度分组(MSG)和多分辨率分组(MRG)。
1. Multi-scale grouping (MSG)
MSG方法如上图左,就是在每一个分组层都通过多个尺度(设置多个半径值)来确定每一个中心点的领域范围,每一个范围都经过PointNet提取特征,再将得到的多个范围的特征concatenate起来,得到一个多尺度的新特征。
2. Multi-resolution grouping (MRG)
在MSG方法中,每一个中心点都需要多个patch的选取和卷积,计算量大,所以提出了MRG方法。如上图右所示,新特征由两部分concatenate得到,左边特征向量是通过较低层即 L i − 1 L_{i-1} Li−1层经过PointNet提取得到,右边特征向量是对当前层中心点对应的patch进行PointNet得到。当点云密度不均时,可以通过判断当前patch的点云密度给予左右两个特征向量不同的权重。例如,当patch中密度过小,左边特征向量中包含的点更稀疏,容易受到抽样不足的影响,因此提高右边特征向量的权重。
作者在论文中给出了分类实验结果对比图(见上图),可以看出多尺度(MSG, MRG)和单一尺度(SSG)相比分类准确率没有什么提升,但当点云很稀疏的时候,使用MSG可以保持很好的robustness。random input dropout(DP)对于robustness也很大。
分类网络比较简单,对于经过两次SA后得到的特征图经过一个PointNet提取全局特征然后通过全连接网络得到分类结果,见下图。
分割网络较为复杂,需要获得所有原始点的点特征,作者采用基于距离插值的分层传播策略和跨层跳跃链接来实现。在某一层的特征传播过程中,从 N l × ( d + C ) N_{l}×(d + C) Nl×(d+C)向 N l − 1 N_{l-1} Nl−1个点传播特性,这里 N l − 1 N_{l-1} Nl−1和 N l N_{l} Nl是点集抽象层 l l l的输入和输出的点集数量,并且 N l ≤ N l − 1 N_{l} ≤ N_{l-1} Nl≤Nl−1。
这里大概可以这么理解,输入xyz和feature经过一个SA后得到了输出new_xyz和new_feature。在上采样过程(FP)中,要将得到的new_xyz和new_feature再反过来加在输入上,也就是下图所示的 N 1 × ( d + C 1 ) → S A → N 2 × ( d + C 2 ) → i n t e r p o l a t e → N 1 × ( d + C 2 + C 1 ) → u n i t p o i n t n e t → N 1 × ( d + C 3 ) N_{1}×(d + C_{1}) →SA→N_{2}×(d + C_{2})→interpolate→N_{1}×(d + C_{2}+C_{1})→unit pointnet→N_{1}×(d + C_{3}) N1×(d+C1)→SA→N2×(d+C2)→interpolate→N1×(d+C2+C1)→unitpointnet→N1×(d+C3)。
文章中通过k近邻法(KNN,默认p=2,k=3)来反向加权求平均实现特征传播,具体公式如下:
简单来说就是距离越远的点权重越小,下面给出Upsampling操作的计算过程,由几个FP子网络构成。
这样就得到了每个原始点的点特征,最后通过计算得到每个原始点对应的分类。
首先来看分类网络的整体网络结构,以pointnet2_cls_msg为例。
分类网络比较简单,首先是3个SA,前两个SA规定中心点分别为512和128,最后一个SA提取全局特征,得到结果为 ( B × 1024 ) (B×1024) (B×1024),其中B为batch size,然后使用4层全连接网络 ( 1024 → 512 → 256 → n u m c l a s s ) (1024→512→256→num_class) (1024→512→256→numclass)得到分类结果,这里要注意中间隐层采用了dropout增加robustness,最后通过log_softmax()计算出每个样本的预测值。
分割网络的整体网络也是非常规整,以pointnet2_sem_seg_msg为例。
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210119221917952.png
分割网络首先通过4个SA提取局部特征,最后输出为 B × 1024 × 16 B×1024×16 B×1024×16,1024为特征通道数,16为中心点数;然后通过4个FP进行上采样,最后输出为 B × 128 × N B×128×N B×128×N,128是特征通道数,N是样本点云数量;最后通过简单的mlp和log_softmax获取样本中每个点的类别,实现分割。
PointNetFeaturePropagation函数是FP层的具体实现,可以看到代码中使用了k近邻法(KNN,默认p=2,k=3)来反向加权求平均实现上采样特征传播。
本文详细阐述了PointNet++的设计思路、网络结构以及对部分代码进行了解析。PointNet系列是近些年来所有点云分割网络的baseline,希望本篇文章能够对你理解PointNet++有所帮助。欢迎各位小伙伴一起交流学习!
Reference
PointNet++ 论文及代码解读
【3D计算机视觉】从PointNet到PointNet++理论及pytorch代码
论文笔记:PointNet++论文代码讨论
3D点云数据分析:pointNet++论文分析及阅读笔记
【代码阅读】PointNet++具体实现详解