点云深度学习系列博客(一): 点云特征学习网络PCPNet

目录

        一. 简介

        二. 基础结构

        三. 项目代码

        四. 实验结果

        总结

Reference


最近开始研究点云分析的相关项目,经过文献调研我发现,近几年比较热的方法,基本都是基于深度学习框架设计的。正好我计划在2022年切入点云深度学习这个研究方向,于是我决定创建一个博客专题,翻译和编辑一批具有代表性意义的点云深度学习研究报告,即方便为我自己的研究计划提供素材,又希望能够帮助到有需要的小伙伴参考与学习。如果你对这个专题感兴趣,希望能够关注我的博客,那将是对我创作的最大支持。

作为博客专题的开篇之作,我挑选了一篇极具代表性的工作,即PCPNET来讲解。一方面,该工作和我目前正在推进的一个项目密切相关,具有极大的参考价值;另一方面,该项工作被著名的点云去噪算法PointCleanNet引入并作为基础训练结构,其被证明在点云去噪任务中能够获得非常优秀的性能。因此,我们将该项工作作为开篇,来开启点云深度学习的研究之旅。


一. 简介

对于基于点云的形状分析任务来说,实现对局部形状特征(法向、曲率等)的有效表示是一个基础性问题。局部形状特征的表示受到很多干扰因素影响,包括噪声,动态采样密度,复杂的几何细节以及缺损部分等。这些干扰因素无疑对点云的局部形状特征表示产生影响,进而影响相关应用的性能。要解决这个问题,一般都是利用点云内各个点的局部邻域估计,建立一个隐式曲面表示,以实现对局部特征的模拟。但是,这里存在两个难点:1)点云本身并没有邻接关系,这提高了获得点云的准确1-邻域或局部连续结构的难度;2)实现对局部邻域的估计,一般需要复杂的参数控制,以解决密度与几何特征保持带来的问题,这使得算法的通用性变差,同样的模型,在某些数据上结果不错,但是换了不一样的数据,性能可能会大打折扣。受到文献[2]和[3]的启发,Guerrero在2018年提出一个基于数据驱动的点云神经网络模型,即PCPNet。PCPNet通过建立点云局部区域的深度分析,获得具有较高鲁棒性与精确性的局部形状特征估计结果。该模型最大的优点是不再受限于传统方法基于局部邻域估计与隐式曲面建模的方案,规避了待处理点云本身的质量缺陷,利用外部数据的经验来指导特征分析,以获得性能提升。


二. 基础结构

整体来说,PCPNet的特征训练部分类似于PointNet++,即通过提取一个点以及对应半径范围内的邻点以建立训练Patch。基于Patch,实现对局部几何特征的估计。

第一步,先将输入的点云变换为一个标准的姿态,基于一个空间变换网络[4]来实现。

第二步,对点应用对称函数,解决无序问题。PointNet中已经给出了解决方案: 

Hl是patch的一个特征。hl被称为对称方程。方程是标量方程,定义在局部的patch上。Hl可以被直观的理解为顶贴故意在hl上的一个密度估计。相比于pointnet,对称方程为:

FNN2是一个三层的全连接层,函数g能够被理解为一个不太复杂的点集函数。这个计算过程类似于原始pointnet中的h。

第三步,STN2是一个第二个空间变换器,作用于g上。

最后,求和hl,获得:

网络结构如下图所示:

图 2.1 PCPNet算法流程图  


三. 项目代码

项目主页:PCPNet: Learning Local Shape Properties from Raw Point Clouds

代码链接:GitHub - paulguerrero/pcpnet: Pytorch implementation of PCPNet

简单的说一下配置,原项目基于python3.6编写的,python建议0.4.0+,我使用的是0.4.1,可以直接用conda命令完成下载:conda install pytorch=0.4.1 cuda90 -c pytorch

其他的一些包版本参考下图:

 项目的核心代码为pcpnet.py,存储了PCPNet网络层的结构,主要的类包括:

class STN(nn.Module)
class QSTN(nn.Module)
class PointNetfeat(nn.Module)
class PCPNet(nn.Module)
class MSPCPNet(nn.Module)

这里的MSPCONet使用的是多尺度训练方法。默认的化还是使用单一尺度的PCPNet

因为我对Pytorch也是刚开始学,很多的细节也不太懂。我只是简单的梳理了一下结构,大致的网络模型大家的逻辑整理如下:

#feat部分应该是从STN1到FNN2的主体结构
self.feat = PointNetfeat(
            num_points=num_points,
            num_scales=1,
            use_point_stn=use_point_stn,
            use_feat_stn=use_feat_stn,
            sym_op=sym_op,
            get_pointfvals=get_pointfvals,
            point_tuple=point_tuple)

#从这里考试应该是将特征对称化后,到经过FNN3输出的部分
self.fc1 = nn.Linear(1024, 512)
self.fc2 = nn.Linear(512, 256)
self.fc3 = nn.Linear(256, output_dim)
self.bn1 = nn.BatchNorm1d(512)
self.bn2 = nn.BatchNorm1d(256)
self.do1 = nn.Dropout(p=0.3)
self.do2 = nn.Dropout(p=0.3)

PointNetfeat里边应该包含的就是使用PointNet的部分层,按照论文所说,应该是从STN1到FNN2的部分。FNN就是MLP。接下来展示PointNetfeat的核心代码:

class PointNetfeat(nn.Module):
    def __init__(self, num_scales=1, num_points=500, use_point_stn=True, use_feat_stn=True, sym_op='max', get_pointfvals=False, point_tuple=1):
        super(PointNetfeat, self).__init__()
        self.num_points = num_points
        self.num_scales = num_scales
        self.use_point_stn = use_point_stn
        self.use_feat_stn = use_feat_stn
        self.sym_op = sym_op
        self.get_pointfvals = get_pointfvals
        self.point_tuple = point_tuple
      
#这里对应的就是原文的STN1和STN2
        if self.use_point_stn:
            # self.stn1 = STN(num_scales=self.num_scales, num_points=num_points, dim=3, sym_op=self.sym_op)
            self.stn1 = QSTN(num_scales=self.num_scales, num_points=num_points*self.point_tuple, dim=3, sym_op=self.sym_op)

        if self.use_feat_stn:
            self.stn2 = STN(num_scales=self.num_scales, num_points=num_points, dim=64, sym_op=self.sym_op)

#这里对应的就是原文的FNN1
        self.conv0a = torch.nn.Conv1d(3*self.point_tuple, 64, 1)
        self.conv0b = torch.nn.Conv1d(64, 64, 1)
        self.bn0a = nn.BatchNorm1d(64)
        self.bn0b = nn.BatchNorm1d(64)

#这里对应的就是原文的FNN2,k=1024
        self.conv1 = torch.nn.Conv1d(64, 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)

        if self.num_scales > 1:
            self.conv4 = torch.nn.Conv1d(1024, 1024*self.num_scales, 1)
            self.bn4 = nn.BatchNorm1d(1024*self.num_scales)

#这里对应的是对特征的对称化方法,取最大或求和
        if self.sym_op == 'max':
            self.mp1 = torch.nn.MaxPool1d(num_points)
        elif self.sym_op == 'sum':
            self.mp1 = None
        else:
            raise ValueError('Unsupported symmetric operation: %s' % (self.sym_op))

似乎这里的顺序和文章中网络的结构顺序有点不一致,但是实际没有影响,因为真正控制参数优化的代码在forward函数里:

import torch.nn.functional as F

# mlp (64,64)
x = F.relu(self.bn0a(self.conv0a(x)))
x = F.relu(self.bn0b(self.conv0b(x)))

# feature transform
if self.use_feat_stn:
   trans2 = self.stn2(x)
   x = x.transpose(2, 1)
   x = torch.bmm(x, trans2)
   x = x.transpose(2, 1)
else:
   trans2 = None

# mlp (64,128,1024)
x = F.relu(self.bn1(self.conv1(x)))
x = F.relu(self.bn2(self.conv2(x)))
x = self.bn3(self.conv3(x))

# mlp (1024,1024*num_scales)
if self.num_scales > 1:
    x = self.bn4(self.conv4(F.relu(x)))

if self.get_pointfvals:
    pointfvals = x
else:
    pointfvals = None # so the intermediate result can be forgotten if it is not needed


四. 实验结果

这个给出原文的两幅实验图作为参考。根据量化的误差色温图可以看到,PCPNet对于局部特征估计任务能够提供不错的计算结果。 


总结

总体来说,PCPNet还是基于PointNet建立点云分析框架,以实现对点云的局部几何特征的提取与训练。自然该框架继承了PointNet甚至PointNet++点云分析的优点。但是,我认为该框架对于噪声的处理没有引用额外的模块,这就让整个网络对于噪声数据处理的泛化性能力有所损失。当然,这间接推动了PointCleanNet的提出。即使如此,PCPNet想比传统的MLS或其他局部几何特征分析来说,依然能够获得显著的性能提升。


Reference

[1] P. Guerrero, Y. Kleiman, M. Ovsjanikov, et al. Pcpnet learning local shape properties from raw point clouds[C]//Computer Graphics Forum. 2018, 37(2): 75-85.

[2] A. BOULCH, R. MARLET. Deep learning for robust normal estimation in unstructured point clouds. Computer Graphics Forum 35, 5(2016), 281–290. 

[3] QI C. R., YI L., SU H., GUIBAS L. J.: Pointnet++: Deep hierarchical feature learning on point sets in a metric space. arXiv preprint arXiv:1706.02413 (2017). 3

[4] M. JADERBERG, K. SIMONYAN K, A. ZISSERMAN, K. KAVUKCUOGLU. Spatial transformer networks. In Proc. NIPS. 2015, pp. 2017–2025. 4.

  • 8
    点赞
  • 70
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序猿老甘

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值