PointNet、PointNet++原理解析

PointNet 算法结构

在这里插入图片描述

PointNet 原理解析

已知:
N个点,每个点的信息x,y,z。
MLP: MLP(Multi-Layer Perceptron),即多层感知器,是一种趋向结构的人工神经网络,映射一组输入向量到一组输出向量。
简单的可以用全连接网络实现,复杂的可以用卷积网络实现。
在这里插入图片描述

原理

(1)第一步 MLP

对每个点进行MLP操作,即:3~> MLP(3,C1) ~>C1其中3、C1是MLP的输入和输出维度,此时这个点的特征数由原来的3变成了C1 。
将点云的每个点都经过以上操作,得到:N * 3~>MLP(3 * N,C1) ~>N * C1
在这里插入图片描述
在这里插入图片描述

小结:没个点的特征由3变成了64,又称超维特征、冗余特征。

(2)第二步 Max Pool

将MLP得到的结果进行max pool操作,max pool的目的是为了:pointNet网络改变点的输入顺序不会影响最终输出的结果。
MLP得到的结果可以看作是N * C1的矩阵,max pool操作是对N * C1矩阵的C1列进行max操作,得到1 * C1的矩阵。即N * C1~>1 * C1 。
在这里插入图片描述
小结:max pool 是pointNet的算法核心。mean或min也能做到但max更好。

(3)第三步 分类器(分类任务)

将max pool的结果经过一个分类器,得到最后的分类结果,pointnet网络的作用是点云的分类。分类器一般用MLP网络来实现。
在这里插入图片描述

算法概括:PointNet = shared MLP + max pool

(1)PointNet考虑到了全局性特征的方向拼接处理,但是忽视了点云局部特征的捕获。
(2)PointNet本身已经具备对点云的全局特征提取能力。
在这里插入图片描述

PointNet 网络输入输出Shape

  • 可以看作,网络输入是具有C1维度特征的n个点,网络输出是具有C2特征维度的1个点,即:n1C1 ~> 1C2
  • tensor(B,n,C1) ~> tensor(B,1,C2),其中B为批数batch

分割任务

分割:将每个点进行分类,就可以做分割操作!!
网络结构:全局特征+每点自身的高纬度特征 ~> 分类器
在这里插入图片描述

PointNet++ = 局部特征提取(以set abstraction为单位) + PointNet + 分割任务+分类任务

优秀参考文献

从PointNet到PointNet++理论及pytorch代码
PointNet++详解与代码
基于PyTorch实现PointNet++

PointNet++ 网络结构

在这里插入图片描述

要弄清楚的几个问题

  1. PointNet不足之处?
    PointNet存在的一个缺点是无法获得局部特征,这使得它很难对复杂场景进行分析。
    在PointNet中,网络对每一个点做低维到高维的映射进行特征学习,然后把所有点映射到高维的特征通过最大池化最终表示全局特征。对点云数据做平移操作后,所有的数据都将发生变化,导致所有的特征,全局特征都不一样了。对于单个的物体还好,可以将其平移到坐标系的中心,把他的大小归一化到一个球中,但是在一个场景中有多个物体时则不好办,需要对哪个物体做归一化呢?
  2. PointNet++的改进?
    PointNet++中,作者通过两个主要的方法进行了改进,使得网络能更好的提取局部特征。
    第一,利用空间距离(metric space distances),使用PointNet对点集局部区域进行特征迭代提取,使其能够学到局部尺度越来越大的特征。
    第二,由于点集分布很多时候是不均匀的,如果默认是均匀的,会使得网络性能变差,所以作者提出了一种自适应密度的特征提取方法(MSG、MRG)。通过以上两种方法,能够更高效的学习特征,也更有鲁棒性。
  3. 如何实现局部特征提取?
    在PointNet++中局部特征提取的过程和CNN网络的特征提取过程类似,首先提取低级别的特征,随着感受野的增大,提取的特征level越来越高。
    实现局部特征提取需要解决两个关键的问题:第一,如何将点集划分为不同的区域;第二,如何利用特征提取器获取不同区域的局部特征。这两个问题实际上是相关的,要想通过特征提取器来对不同的区域进行特征提取,需要每个分区具有相同的结构。这里同样可以类比CNN来理解,在CNN中,卷积块作为基本的特征提取器,对应的区域都是(n, n)的像素区域。而在3D点集当中,同样需要找到结构相同的子区域,和对应的区域特征提取器。
    PointNet++算法中,作者使用了PointNet作为特征提取器,另外一个问题就是如何来划分点集从而产生结构相同的区域。作者使用邻域球来定义分区,每个区域可以通过中心坐标和半径来确定。中心坐标的选取,作者使用了最远点采样算法算法(FPS) 来实现。
  4. 鉴于点集分布很多时候是不均匀的情况,如何实现自适应密度的特征提取方法(MSG、MRG)?

参考文献
【1】https://blog.csdn.net/cg129054036/article/details/105545895

要弄清楚的几个概念

  • FPS
  • DP
  • SSG
  • MSG
  • MRG
  • sampling
  • grouping
  • sa、set absraction
  • PointNet
  • CNN的多层感受野的思想
  • MLP

set abstraction layers

每一组set abstraction layers主要包括3个部分:

  • Sample layer:主要是对输入点集进行采样,选出若干个中心点。
  • Grouping layer:利用上一步得到的中心点将点集划分成若干个区域。
  • PointNet layer:是对上述得到的每个区域进行编码,变成特征向量。

采样(最远点采样FPS)

  • 结果:点数发生变化,,特征数通道数不变。N(源点集点数)~> N1(采样后点集点数) ,这些采样点被称为源点集的中心点centroids。
  • 输入输出shape:tensor(B,N,C) ~> tensor(B,N1,C),其中B为批数batch,N、N1是采样前后点数,C是每个点的特征数。
  • 函数简介:
def farthest_point_sample(xyz, npoint):
    """ 
    Input:
        xyz: pointcloud data, [B, N, C]
        npoint: number of samples
    Return:
        centroids: sampled pointcloud data, [B, npoint, C]
    """  

在这里插入图片描述

Grouping layer

在源点集,人工设定半径r,以每个采样点为球心画球,目的是分组。为了方便batch操作,每一个局部区域内的点的数量是一致的,都为K,如果某个圆内的点的数量小于K, 则可以重复采样圆内的点,达到数量K;如果某个区域内的点的数量大于K, 则随机选择K个点,即可。group操作得到的结果如下图所示,可以形成很多小的局部区域。
在这里插入图片描述

sample and group 函数简介

输入输出shape:tensor[B, N, 3] ~> tensor[B, npoint, nsample, 3] ,或者 tensor[B, N, D] ~> tensor[B, npoint, nsample, 3+D]

def sample_and_group(npoint, radius, nsample, xyz, points, returnfps=False):
    """
    Input:
        npoint:
        radius:
        nsample:
        xyz: input points position data, [B, N, 3]
        points: input points data, [B, N, D]
    Return:
        new_xyz: sampled points position data, [B, npoint, nsample, 3]
        new_points: sampled points data, [B, npoint, nsample, 3+D]
    """ 

局部特征提取层 PointNet layer

  • 输入输出shape:tensor(B, M, K, C0) ~> tensor(B, M, C)
  • 过程:
    经过了sample和group操作,整个大点云被分成了很多个有overlap的小点云, 整个完整点云可表示为shape=(B, M, K, C0)的tensor, B表示批数,M表示中心点的数量, K表示每个中心点的球邻域内选择的点的数量, C0是特征维度, 初始输入点特征维度C0=3或C0=6(加上normal信息)。接下来就是利用PointNet对每个group点云(shape=(K, C0))进行特征提取,得到当前group点云的特征F(shape=( C )。每个group点云(K, C0)经过PointNet得到特征F©, 那么一个batch的数据shape=(B, M, K, C0), 经过PointNet模块后, 将会得到维度为(B, M, C)的特征。
    在这里插入图片描述

set abstraction

源点云tensor(B, N, C0) ~> sapling andgrouping ~> tensor(B, M, K, C1) ~> 每个group区域通过PointNet进行特征提取 ~> tensor(B, M, C1)
上面就是一次set abstraction操作了,PointNet++是有3次set abstraction操作的:

  • 第一次: (B, N, C0) ~> (B, M1, C1) , 其中C0 = 3 或 C0=6(加上normal信息);
  • 第二次: (B, M1, C1+3) ~> (B, M2, C2),其中加了3, 这是在学到特征的基础上又加了位置信息(x, y, z);
  • 第三次::(B, M2, C2+3) ~> (B, C3) ;

注意: 这里有一个细节问题, 可以看到C1和C2后面都加了3, 这是在学到特征的基础上又加了位置信息(x, y, z), 重新作为新的特征来送入PointNet网络。
示意图1
示意图1

PointNet++中的分类任务

在提取了点云的特征(C3,)之后, 接下来就和图像里的分类任务一样了,C3维的特征作为输入,然后通过通过两个全连接层和一个分类层(分类层的是输出节点等于类别数的全连接层),输出每一类的概率。损失函数采用的是交叉熵损失函数,对应PyTorch中的nn.CrossEntropy() 。

PointNet++中的分割任务

分割任务需要对点云中的每个点进行分类,而PointNet++中的set abstraction由于sampling操作减少了输入点云中的点的数量,如何进行上采样使点云数量恢复输入时的点云数量呢?
在图像分割任务中,为了恢复图像的分辨率, 往往采用反卷积或者插值的方式来操作呢, 在点云中该如何恢复点云的数量呢?
其实,在PointNet++中的set abstraction模块里,当前点云Q和下采样后的点云Q’的中的点位置信息一直是保存的,点云的上采样就是利用了这一特性。这里利用二维图直观的解释一下,下方左图中红色的倒三角形表示下采样后的点云Q’, 蓝色的点云表示下采样之前的点云Q, 点云里的上采样就是用PointNet学习后的点云Q’的特征表示下采样之前点云Q的特征。采用的方式是k近邻算法,论文中k=3。如图所示,对于Q中的每一个点O,在Q’中寻找其最近的k个点,基于距离加权(距离O近,其权重大; 距离O远, 其权重大)求和这k个点的特征来表示点O的特征,具体计算方式为:
在这里插入图片描述
上采样得到了C’维的特征, 而且点的数量已经恢复到了下采样之前的数量; 将C’维的特征与set abstraction中相同点数量的点云(对称位置)特征(C维)进行进行concat操作,进而进行多个 Conv1d + Bn + ReLU操作,来得到新的特征。
经过三次上采样操作后,点云恢复了初始输入点云中点的数量, 再经过一次conv1d + bn + relu层 和一个对点的分类层,最终得到对每个点的分类。如下图:
在这里插入图片描述

SSG、MSG, MRG架构

上述文章主要介绍了PointNet++的SSG(single scale grouping), 为了解决点云中密度分布不均匀的问题,作者提出了MSG(multi-scale grouping)和MRG(multi resolution grouping). 下面这张图是作者论文里的图(在ModelNet40数据集上的实验), 测试了PointNet, SSG, MSG, MRG的性能,横坐标表示的是在预测时点云中点的数量,纵坐标表示的是准确率。从图中可以看到, 在点的数量较多时,SSG, MRG, MSG性能相近,明显高于PointNet; 但随着点云中的点的数量下降,准确率明显下滑的有两条线,有轻微下降趋势的有四条线。明显下滑的两条线是没有采取DP策略的。 即使是PointNet网络在采取了DP策略后,其性能在点的数量小于600也会明显高于SSG.。由此可见,DP在解决点云密度不均匀时发挥了重要作用, 而MSG, MRG貌似显得没那么重要 ? 这里就简单介绍一下MSG的思想。
点云分布不一致时,每个子区域中如果在生成的时候使用相同的半径r,会导致有些区域采样点过少。

作者提到这个问题需要解决,并且提出了两个方法:Multi-scale grouping (MSG) and Multi-resolution grouping (MRG)。下面是论文当中的示意图。MSG、MRG详细讲解请参考https://blog.csdn.net/cg129054036/article/details/105545895
在这里插入图片描述
MSG、MRG详细讲解请参考https://blog.csdn.net/cg129054036/article/details/105545895

在这里插入图片描述
MSG是指在每次Set Abstraction的时候, 在对某个中心点centroid进行group操作的时候采用不同尺寸(例如0.1, 0.2, 0.4, SSG只有0.2)的半径, 来得到不同大小的局部区域,分别送到不同的PointNet网络中,最终把这些学习到的不同尺度的特征进行concat操作来代表当前中心点centroid的操作。

参考

点云如何数据增强 ?

点云不同于图像,图像中有随机裁剪、缩放、颜色抖动等数据增强方式。在点云里,应该如何做数据增强呢?
点云的数据增强主要包括: 随机旋转,随机平移,随机抖动等, 具体实现代码参考: https://github.com/zhulf0804/Pointnet2.PyTorch/blob/master/data/provider.py
参考

DP有什么用,是怎么实现的 ?

DP指的是在训练时随机丢弃一些输入点(DP means random input dropout during training),这样的训练方式对于预测低密度点云较为有效(相对于输入点云), 即在高密度点云中训练的模型,在低密度点云中进行预测,可以达到和训练集中旗鼓相当的效果。具体来说,人工设置超参数p(论文中p=0.95), 从[0, p]中随机出一个值dr(drouout ratio), 对于点云中的每一个点,随机产生一个0-1的值, 如果该值小于等于dr则表示该点被丢弃。这里有一个细节,某些点被丢弃之后,每个batch中的点的数量就不相同了,为了解决这个问题,所有被丢掉的点使用第一个点代替,这样就维持了每个batch中点的数量相同。
参考

PointNet++中的Tensor变化过程

骨干网络tensor结构

Input data
tensor(B, N, 6)
->
Set Abstraction.sample
input tensor(B, N, 6)
output tensor(B, 512, 3)
->
Set Abstraction.group
input tensor(B, 512, 3)
output tensor(B, 512, 32, 6)
->
Set Abstraction.PointNet
input tensor(B, 512, 32, 6)
output tensor(B, 512, 32, 128)
->
max Pooling
input tensor(B, 512, 32, 128)
output tensor(B, 512, 128)
->
Set Abstraction.sample
input tensor(B, 512, 128)
output tensor(B, 128, 3)
->
Set Abstraction.group
input tensor(B, 128, 3)
output tensor(B, 128, 64, 128 + 3)
->
PointNet(B, 128, 64, 256)
input tensor(B, 128, 64, 128 + 3)
output tensor(B, 128, 64, 256)
->
max Pooling
input tensor(B, 128, 64, 256)
output tensor(B, 128, 256)
->
Set Abstraction.sample
input tensor(B, 128, 256)
output tensor(B, 1, 3)
->
Set Abstraction.group
input tensor(B, 1, 3)
output tensor(B, 1, 128, 256 + 3)
->
Set Abstraction.PointNet
input tensor(B, 1, 128, 256 + 3)
output tensor(B, 1, 128, 1024)
->
max Pooling
input tensor(B, 1, 128, 1024)
output tensor(B, 1, 1024)
->
Features(B, 1, 1024)

分类模块

Features(B, 1024) -> FC(B, 512) -> FC(B, 256) -> Output(B, n_clsclasses)

分割模块

Features(B, 1, 1024) 全局特征
->
FP.unsapmling 上采样
input tensor(B, 1, 1024)
output tensor(B, 128, 1024)
->
FP.concat 特征拼接
input tensor(B, 128, 1024)
output tensor(B, 128, 1024+256) 全局特征+每个点的超维特征
->
FP.PointNet
input tensor(B, 128, 1024+256)
output tensor(B, 128, 256)
->
FP.unsampling
input tensor(B, 128, 256)
output tensor(B, 512, 256)
->
FP.concat
input tensor(B, 512, 256)
output tensor(B, 512, 256+128)
->
FP.PointNet
input tensor(B, 512, 256+128)
output tensor(B, 512, 128)
->
FP.unsampling
input tensor(B, 512, 128)
output tensor(B, N, 128)
->
FP.concat
input tensor(B, N, 128)
output tensor(B, N, 128+6)
->
FP.PointNet
input tensor(B, N, 128+6)
output tensor(B, N, 128)
->
Conv1d(B, N, 128)
->
Conv1d(B, N, n_segclasses)

PointNet、PointNet++ | 论文阅读笔记

摘要

  • PointNet 的不足:无法很好的提取局部点集特征。
  • 如何划分输入的3D点集,进而应用分层次的网络?
  • 如何连接不同尺度的特征,来应对点云密度的变化?
  • 本文提出新的网络架构,PointNet++

Introduction

  • 我们提出分一个分层次的神经网络,PointNet++,可以在不同的层次内(也即是不同半径内)直接处理点集。PointNet++ 的基本思想很简单。我们首先将输入点云划分为具有重叠的局部小区域。类似于 CNNs,我们从小的邻域内提取更为精细的特征,然后将局部的特征进一步聚合为大的区域,进而处理得到更高层次的特征。这个处理是重复的,直到我们获取了全部点集的特征。
  • PointNet++ 需要处理2个问题:如何将输入点集划分为小的邻域?如何学习局部邻域点集的特征?这两个问题是相关的,因为点集的划分会产生一系列一般的局部结构(common structure),那么局部特征学习器可以权重共享(正如卷积的设定一样)。我们选择 PointNet 作为局部特征学习器,它在处理无序点云上是非常有效的。此外,该网络对点云的波动具有稳定性。作为一个基础模块,PointNet 将局部点或特征集抽象成更高级层次的表示。这样,PointNet++ 可以递归的将 PointNet 应用于被网状划分的输入点集。

点集抽象层 Set Abstraction Levels

我们的分层结构是由一系列点集抽象层(Set Abstraction Levels)组成,参考 Fig2。在每一个层次,一组点被处理和抽象,并产生一组新的点集(具有更少的点)。点集抽象层包含三个关键层:Sampling Layer,Grouping Layer and PointNet Layer. Sampling Layer 从输入点集中采样一部分点,这些点就是局部邻域的中心。Grouping Layer 根据邻域中心,选择局部的邻域点集。 PointNet Layer 使用一个迷你的网络(Mini-PointNet)编码局部邻域的特征。

密度自适应层

如 Fig1 中的扫描点云一样,不同的区域密度也是不一样的(近处稠密,远处稀疏),这是个很常见的现象。
在这里插入图片描述

参考文献

(1)
pointNet
pointNet++

视频

斯坦福大学在读博士生祁芮中台:点云上的深度学习及其在三维场景理解中的应用_哔哩哔哩_bilibili

参考文献

【1】深蓝学院
【2】https://blog.csdn.net/weixin_43321489/article/details/127778251

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值