PointNet

PointNet vanilla

亮点

  • 端到端学习
  • 通用的框架
    • Object Classification
    • Object Part Segmentation
    • Semantic Scene Parsing

Challenges

  • 输入的点云是无序的
  • 需要做到对几何变换的invariance

C1:
作为输入的点云实际上就是point的集合,是无序的,但是目前的深度学习关注的还是一些regular input representation的,比如sequences, images, volumes,在之前的点云研究中,都是先将点云处理转化为其他的表示形式,然后再作为输入送入深度神经网络中,这实际上损失了一些信息。作者希望能够直接将点云集合作为输入送入神经网络,完成端到端的学习。

而要达到这个目的,就要做到模型对点云集合作为输入的顺序做到‘免疫’。

这个问题可以使用对称函数解决,直观地说,如果一个函数的输出与输入的顺序无关,那么就说这个函数是一个对称函数,比较常见的像:加法、最大值函数等。


这里h作者使用了多层感知机来提取点特征,但是在实际的implementation里用的还是1*1 convolutiong使用的是max pooling这个对称函数来最终得到全局特征,理论上f可以拟合任意的连续对称函数,但是数学证明我并没有看太懂。在经过f的作用之后,便得到了点云的全局特征,在分类任务上已经可以直接使用了,但是对于点云分割来说,还需要局部特征与全局特征进行融合。作者直接将习得的全局特征与之前习得的点特征进行串联,在此基础上,进一步提取点特征。

下面便是进行分类任务的代码,对应了网络架构图中点云输入通过一个input transform得到的nx3之后的网络:

def get_model(point_cloud, is_training, bn_decay=None):""" Classification PointNet, input is BxNx3, output Bx40 """batch_size = point_cloud.get_shape()[0].valuenum_point = point_cloud.get_shape()[1].valueend_points = {}input_image = tf.expand_dims(point_cloud, -1)# Point functions (MLP implemented as conv2d)net = tf_util.conv2d(input_image, 64, [1,3],padding='VALID', stride=[1,1],bn=True, is_training=is_training,scope='conv1', bn_decay=bn_decay)net = tf_util.conv2d(net, 64, [1,1],padding='VALID', stride=[1,1],bn=True, is_training=is_training,scope='conv2', bn_decay=bn_decay)net = tf_util.conv2d(net, 64, [1,1],padding='VALID', stride=[1,1],bn=True, is_training=is_training,scope='conv3', bn_decay=bn_decay)net = tf_util.conv2d(net, 128, [1,1],padding='VALID', stride=[1,1],bn=True, is_training=is_training,scope='conv4', bn_decay=bn_decay)net = tf_util.conv2d(net, 1024, [1,1],padding='VALID', stride=[1,1],bn=True, is_training=is_training,scope='conv5', bn_decay=bn_decay)# Symmetric function: max poolingnet = tf_util.max_pool2d(net, [num_point,1],padding='VALID', scope='maxpool')# MLP on global point cloud vectornet = tf.reshape(net, [batch_size, -1])net = tf_util.fully_connected(net, 512, bn=True, is_training=is_training,scope='fc1', bn_decay=bn_decay)net = tf_util.fully_connected(net, 256, bn=True, is_training=is_training,scope='fc2', bn_decay=bn_decay)net = tf_util.dropout(net, keep_prob=0.7, is_training=is_training,scope='dp1')net = tf_util.fully_connected(net, 40, activation_fn=None, scope='fc3')return net, end_points

C2:

为了不受几何变换,比如刚性变换的影响,作者借鉴了STN,但是采用了比之更加简单的方法:使用一个小型的神经网络T-Net去预测一个仿射变换矩阵,然后直接将输入与这个矩阵相乘。

下面是T-Net的具体实现,第一个net对应的是论文中网络架构图中的input transform,第二个net对应的是论文中的feature transform,输入不同,网络结构和参数自然有一些变化。

def input_transform_net(point_cloud, is_training, bn_decay=None, K=3):""" Input (XYZ) Transform Net, input is BxNx3 gray imageReturn:Transformation matrix of size 3xK """batch_size = point_cloud.get_shape()[0].valuenum_point = point_cloud.get_shape()[1].valueinput_image = tf.expand_dims(point_cloud, -1)net = tf_util.conv2d(input_image, 64, [1,3],padding='VALID', stride=[1,1],bn=True, is_training=is_training,scope='tconv1', bn_decay=bn_decay)net = tf_util.conv2d(net, 128, [1,1],padding='VALID', stride=[1,1],bn=True, is_training=is_training,scope='tconv2', bn_decay=bn_decay)net = tf_util.conv2d(net, 1024, [1,1],padding='VALID', stride=[1,1],bn=True, is_training=is_training,scope='tconv3', bn_decay=bn_decay)net = tf_util.max_pool2d(net, [num_point,1],padding='VALID', scope='tmaxpool')net = tf.reshape(net, [batch_size, -1])net = tf_util.fully_connected(net, 512, bn=True, is_training=is_training,scope='tfc1', bn_decay=bn_decay)net = tf_util.fully_connected(net, 256, bn=True, is_training=is_training,scope='tfc2', bn_decay=bn_decay)with tf.variable_scope('transform_XYZ') as sc:assert(K==3)weights = tf.get_variable('weights', [256, 3*K],initializer=tf.constant_initializer(0.0),dtype=tf.float32)biases = tf.get_variable('biases', [3*K],initializer=tf.constant_initializer(0.0),dtype=tf.float32)biases += tf.constant([1,0,0,0,1,0,0,0,1], dtype=tf.float32)transform = tf.matmul(net, weights)transform = tf.nn.bias_add(transform, biases)transform = tf.reshape(transform, [batch_size, 3, K])return transform
def feature_transform_net(inputs, is_training, bn_decay=None, K=64):""" Feature Transform Net, input is BxNx1xKReturn:Transformation matrix of size KxK """batch_size = inputs.get_shape()[0].valuenum_point = inputs.get_shape()[1].valuenet = tf_util.conv2d(inputs, 64, [1,1],padding='VALID', stride=[1,1],bn=True, is_training=is_training,scope='tconv1', bn_decay=bn_decay)net = tf_util.conv2d(net, 128, [1,1],padding='VALID', stride=[1,1],bn=True, is_training=is_training,scope='tconv2', bn_decay=bn_decay)net = tf_util.conv2d(net, 1024, [1,1],padding='VALID', stride=[1,1],bn=True, is_training=is_training,scope='tconv3', bn_decay=bn_decay)net = tf_util.max_pool2d(net, [num_point,1],padding='VALID', scope='tmaxpool')net = tf.reshape(net, [batch_size, -1])net = tf_util.fully_connected(net, 512, bn=True, is_training=is_training,scope='tfc1', bn_decay=bn_decay)net = tf_util.fully_connected(net, 256, bn=True, is_training=is_training,scope='tfc2', bn_decay=bn_decay)with tf.variable_scope('transform_feat') as sc:weights = tf.get_variable('weights', [256, K*K],initializer=tf.constant_initializer(0.0),dtype=tf.float32)biases = tf.get_variable('biases', [K*K],initializer=tf.constant_initializer(0.0),dtype=tf.float32)biases += tf.constant(np.eye(K).flatten(), dtype=tf.float32)transform = tf.matmul(net, weights)transform = tf.nn.bias_add(transform, biases)transform = tf.reshape(transform, [batch_size, K, K])return transform

PointNet++

PointNet++主要就是对PointNet的改进。由于PointNet不能很好地捕捉由度量空间引入的局部结构,也就限制了它识别细粒度类别的能力和对复杂场景的泛化能力。

PointNet的基本思想是对输入点云中的每一个点学习其对应的空间编码,之后再利用所有点的特征得到一个全局的点云特征,这里欠缺了对局部特征的提取和处理,但是探究局部特征已经在CNN中被证明很重要,传统的二维CNN接受规则输入,并且在不同层捕获不同尺度的特征。

PointNet++的思路很简单:首先通过距离度量将点云集合划分成一些重叠的局部区域,然后从邻域内提取局部特征,然后从这些局部特征中提取出更高层的特征。这一过程会不断重复直到得到整个点云集合的全局特征。

PointNet++的分层模型由一系列的abstraction level组成,而abstraction level包括三个部分:Sampling layer, Grouping layer, PointNet layer。其中Sampling layer从输入的点云中选择出一个点集合,也就是那些局部区域的中心点;Grouping layer通过寻找中心点的邻近点组成局部区域;而PointNet则被用来提取特征。

Chanllenges

2 Hows

  • how to abstract sets of points or local features through a local feature learner
  • how to generate the partitioning of the point set

C1
很自然地,作者使用了PointNet作为特征提取的手段。

C2
如何进行点云划分?

点球模型→\rightarrow→选中心点(Sampling layer),选半径(Grouping layer)。

Sampling layer: 如何选中心点?使用FPS算法(Farthest Point Sampling):先随机选择一个点,然后再选择离这个点最远的点作为起点,再继续迭代,直到选出全部需要的点为止。

Grouping layer: 如何选半径?这就牵扯到另外一个问题:密度适应。由于点云中密度并不是处处相等的,所以不能都设置为相同的半径,这样可能会因为有的中心点邻域内密度较小导致采样不到足够多的点而提取不到有用的特征。所以,作者提出了一种尺度(密度)适应的方法。

这里作者提出了两种方案:MSG(Multi-scale Gourping)和MRG(Multi-resolution layer)

一图胜千言,作者画的示意图很棒,能够让人很轻松地get到作者的意思。

  1. MSR
    简单粗暴地设置几个不同的尺度,分别在这些尺度下提取特征,然后将不同尺度的特征进行concat。但是不同尺度的融合作者也是有讲究的,对每个训练集的点,随机选择一个概率进行dropout,在测试时,使用所有的点。
  2. MGR
    MSR因为是对所有的中心点的领域进行不同尺度的特征提取,因此计算开销很大。MGR的提出就是为了缓和计算开销的问题。图b中左边灰色的vector是由subregion使用abstraction level得到的特征,右边是由所有的raw points得到的点特征。左边的可以看作是比较全局的部分,右边的可以看作是比较局部的部分,通过这两个部分的结合,能够比较好地控制全局和局部的关系。当区域密度比较小的时候,说明局域特征没有全局特征可靠,需要赋给全局特征一个较大的权重,反之亦然。

由PointNet++的网络结构可以看到,对于分类任务,和PointNet是一样的,但是分割任务就有些不同了。因为PointNet++在abstraction layers中,进行了点采样,但是segementation任务中需要所有的点。一种解决办法是在abstraction layers中,把点云中所有的点都作为中心点,但显然这是不切实际的。另一种方法是将下采样的点特征传播回原始的数据点。这里使用了类似于FCN的across level skip links,同时进行KNN插值(feature values)。先将高层的NlN_lNl​特征值插值到低层的Nl−1N_{l-1}Nl−1​相应坐标,然后再和set abstraction layer的特征进行串联,送到类似于1*1 convolutionalunit pointnet中,最后通过全连接层和relu来更新点特征。

KNNKNNKNN中的权重用的是: inverse distance weighted average based on k nearest neighbors

PointNet、PointNet++相关推荐

  1. 点云3D目标检测学习(1):pointnet、pointnet++模型

    3D目标检测学习笔记 开始正式进入3D目标检测的学习!!! 1.点云数据 无序性:只是点而已,排列顺序不影响 近密远疏 非结构化数据,直接CNN有点难 2.PointNet CVPR2017 Poin ...

  2. 3D点云(3D point cloud)及PointNet、PointNet++

    文章目录 一.什么是3D点云 二.基于3D点云的一些任务 三.如何提取3D点云数据的特征:PointNet (1)在PointNet之前也有工作在做点云上的深度学习 (2)PointNet (1)置换 ...

  3. PointNet、PointNet++ 基于深度学习的3D点云分类和分割

    前言 PointNet是直接对点云进行处理的,它对输入点云中的每一个点,学习其对应的空间编码,之后再利用所有点的特征得到一个全局的点云特征.Pointnet提取的全局特征能够很好地完成分类任务,但局部 ...

  4. PointNet++理解(PointNet++实现第2步)

    PointNet++实现第2步--PointNet++理解 一.PointNet的局限性(PointNet++出现的原因) 对每一个点映射到高维空间,再通过max结合.由于其网络直接暴力地将所有的点最 ...

  5. PointNet和PointNet++论文解读

    一.PointNet 论文题目:PointNet: Deep Learning on Point Sets for 3D Classification and Segmentation (CVPR 2 ...

  6. 从PointNet到PointNet++理论及代码详解

    从PointNet到PointNet++理论及代码详解 1. 点云是什么 1.1 三维数据的表现形式 1.2 为什么使用点云 1.3 点云上以往的相关工作 2. PointNet 2.1 基于点云的置 ...

  7. 【3D计算机视觉】从PointNet到PointNet++理论及pytorch代码

    从PointNet到PointNet++理论及代码详解 1. 点云是什么 1.1 三维数据的表现形式 1.2 为什么使用点云 1.3 点云上以往的相关工作 2. PointNet 2.1 基于点云的置 ...

  8. 最全PointNet和PointNet++要点梳理总结

    一.基本简介   本篇博文主要是对 PointNet,PointNet++ 论文的要点进行梳理和总结.认真阅读本博文后,不仅能够深刻理解论文的核心算法思想,而且对模型训练数据.模型的训练流程也能了然于 ...

  9. Pointnet与Pointnet++论文笔记

    Pointnet与Pointnet++论文笔记 近期由于课题需要,研读了Pointnet系列文章,在此总结个人心得,并结合了部分博客进行阐述,不足之处希望各位批评指正,也欢迎各位同学来进行学习交流. ...

最新文章

  1. vue中v-model是个啥?
  2. 数学建模资料分享群——2群
  3. Android 4.0新增WiFiDirect功能
  4. 这是“我”的故事 —— 董彬
  5. qchart折现图_Qt开发技术:QCharts(二)QCharts折线图介绍、Demo以及代码详解
  6. ASP.NET URL编码处理
  7. ajax请求完之前的loading加载
  8. 20 ViewPager Demo4自动轮播
  9. nodejs实战mysql_node.js实战:手把手教你使用mysql
  10. 试验设计与因果分析感想
  11. ai可以滚轮缩放吗_Illustrator CC for MAC按住alt键滑动鼠标无法缩放?
  12. 外贸企业管理系统解决方案丨汇信
  13. 做网站如何选阿里云服务器呢?
  14. java kryo_在java中使用kryo框架来实现高效序列化与反序列化 | 学步园
  15. flutter之: GetX 的 路由管理
  16. iOS 聊天表情键盘
  17. 微信小程序--------商品物流跟踪模板
  18. delphi控件使用
  19. 使用CSS中clip-path属性实现奥运五环
  20. centos系统安装字体

热门文章

  1. MT2012_竹鼠的白色季节
  2. 几款好的markdown编辑器
  3. ICSAPP 课后习题
  4. 创基USB HUB集线器连接扩展一线通
  5. 怎样打印计算机桌面,如何进行屏幕打印,如打印桌面等
  6. 媒体报道丨激光雷达老司机踏上创业路,饮冰科技如何杀出重围?
  7. c语言isnan,关于c ++:隐藏了C ++ 14 / C ++ 11中中的isnan? | 码农家园
  8. 【优化调度】基于遗传算法实现产品自动排序问题matlab代码
  9. 公司内网批量安装python依赖包
  10. python折痕检测_无纺布折痕检测(3)· 基于灰度投影的折痕检测