今天要聊的论文是斯坦福大学Charles等人在CVPR2017上发表的论文,提出了一种直接处理点云的深度学习网络——PointNet。这篇论文具有里程碑意义,标志着点云处理进入一个新的阶段。为什么会给这么高的评价呢?


因为在PointNet之前,点云没办法直接处理,因为点云是三维的、无序的,别说深度神经网络了,就是普通算法很多都不能奏效。于是人们想出来各种办法,比如把点云拍扁成图片(MVCNN),比如把点云划分成体素(类似游戏“我的世界”里的场景),再比如把点云划分成节点然后按顺序拉直(O-CNN)等等。总之,点云先要被处理成“非点云”。

这些想法怎么样呢?其实也挺不错的,也能取得不错的结果。比如MVCNN的有些指标就不输PointNet。

这时候我们就会觉得,冥冥中一定会有一种网络出现,摆脱上面这些操作。于是,PointNet出现了,从此点云处理领域分成“前PointNet时代”和“后PointNet时代”。接着,各种直接处理点云的网络也纷纷出现,如PointCNN、SO-Net,效果也是越来越好。

点云 实例分割 位姿估计 点云分割网络_2d

下面进入正题,看看PointNet有哪些创新点。

1、针对点云无序性——采用Maxpooling作为对称函数。最大池化操作就是对所有成员进行比较,把最大的留下来,其余舍弃掉,所以,不管顺序如何变化,最大值是不会改变的。

 

对称函数是什么意思?例如加法就是对称函数,1+2+3+4=10,换个顺序,2+4+3+1=10,不管顺序如何变化,对结果不会产生影响。

 

2、针对刚体变化——对齐网络T-net。T-net对性能的提升作用也还是有的,两个T-net加上regularization 贡献了2.1个百分点,但奇怪的是在PointNet++的代码中,已经看不到T-net了(这一点论文没有提及,github上也有人提问,但是作者没有回复)。

点云 实例分割 位姿估计 点云分割网络_点云 实例分割 位姿估计_02

3、特征提取阶段采用MLP(多层感知机,说白了就是全连接层),这种结构用到的运算只有乘法和加法,都是对称函数,所以不会受到排序影响。

 

实验效果

1、分类

数据集是ModelNet40,包含40类物体的CAD,通过采样获得点云。这里作者没有把MVCNN列出来,因为精度没有比过它,不过后来的改进版已经超过了。

点云 实例分割 位姿估计 点云分割网络_点云_03

2、物体分割:

点云 实例分割 位姿估计 点云分割网络_github_04

 

3、参数量与MVCNN的对比:明显占优。


点云 实例分割 位姿估计 点云分割网络_github_05



PointNet/PointCNN代码比较(变换矩阵部分)


PointNet与PointCNN从文章到代码都有很多相似之处,两者对比看待,或许更有助于我们理解。

众所周知,PointNet中使用了maxpooling和T-net,作者文章中起到关键作用的是maxpooling,而T-net对性能的提升作用也还是有的(两个T-net加上regularization

但是,与之相似的PointCNN中有个X变换矩阵,但X变换对于PointCNN的作用可就非常重要了,因为它连maxpooling都没有用。下面我们就对两者进行比较。

首先是PointNet中的T-net代码:


[python] view plain copy


1. def feature_transform_net(inputs, is_training, bn_decay=None, K=64):  
2. """ Feature Transform Net, input is BxNx1xK
3.         Return:
4.             Transformation matrix of size KxK """  
5. 0].value  
6. 1].value  
7.   
8. 64, [1,1],  
9. 'VALID', stride=[1,1],  
10. True, is_training=is_training,  
11. 'tconv1', bn_decay=bn_decay)  
12. 128, [1,1],  
13. 'VALID', stride=[1,1],  
14. True, is_training=is_training,  
15. 'tconv2', bn_decay=bn_decay)  
16. 1024, [1,1],  
17. 'VALID', stride=[1,1],  
18. True, is_training=is_training,  
19. 'tconv3', bn_decay=bn_decay)  
20. 1],#池化窗口是[num_point,1]  
21. 'VALID', scope='tmaxpool')  
22.   
23. 1])#变成两维  
24. 512, bn=True, is_training=is_training,  
25. 'tfc1', bn_decay=bn_decay)  
26. 256, bn=True, is_training=is_training,  
27. 'tfc2', bn_decay=bn_decay)  
28.   
29. 'transform_feat') as sc:  
30. 'weights', [256, K*K],  
31. 0.0),  
32.                                   dtype=tf.float32)  
33. 'biases', [K*K],  
34. 0.0),  
35.                                  dtype=tf.float32)  
36.         biases += tf.constant(np.eye(K).flatten(), dtype=tf.float32)  
37.         transform = tf.matmul(net, weights)  
38.         transform = tf.nn.bias_add(transform, biases)  
39.   
40.     transform = tf.reshape(transform, [batch_size, K, K])  
41. return transform
  1.   

代码主题部分,前三个conv2d用来升维,接着一个max_pool2d把1024个点的特征做了maxpooling,融合成一点。然后跟两个fully_connected把维度降到256,再然后是跟[256, K*K]的权值相乘再加K*K维的偏移,达到[batch_size, K*K],最后变形成[batch_size, K, K],大功告成,不容易啊。

接下来看PointCNN的X变换:

[python] view plain copy


1. ######################## X-transformation #########################  
2. 'X_0', is_training, (1, K), with_bn=False)  
3. #kernal size(1, K, 3), kernal num=K*K, so the output size is (N, P, 1, K*K). so this operator is in the neighbor point dimentional.  
4. 'X_1', is_training, with_bn=False)#in the center point dimensional ,P decrease to 1.  
5. 'X_2', is_training, with_bn=False, activation=None)#(N, P, 1, K*K)  
6. 'X')  
7. 'fts_X')  
8. ###################################################################

第一层是卷积层,让人很吃惊,卷积核是1*k 的,也就是在邻域维度上,直接把k个邻域点汇聚到一个点上,且用了K×K个卷积层,把特征维度升高到k*k,维度从(P,K,C)变成了(P,1,K×K);然后

,作者用了两个dense 层,保持了这个结构; 最后reshape 成(P,K,K),这就得到了X-transporm矩阵。


从体量和复杂程度上来看,后者胜出。

从作用效果来看,不太好评价。因为PointCNN是有局部特征的,这点和pointnet++思想一致。所以即便PointCNN性能超过了PointNet,也不能直接证明X-transporm就一定优于T-net了。

代码方面,其实T-net的前四层和X变换的第一层做的事情差不多,都是为了把多个点的特征融合到一组特征,为训练变换矩阵提供素材。但接下来就不同了,T-net只有一组K*K的weights权值,而PointCNN后面跟了两个dense层,维度都是K*K的,参数更多,因此猜测PointCNN训练变换矩阵应该会更加充分。后期可以通过实验验证以下。

最后歪个楼,我在测试PointNet++的代码时,ModelNet40的分类结果一直徘徊在90.1左右,达不到论文里提的90.7,跟作者邮件联系也没有得到很好的答案。所以我再想是不是作者本来的PointNet++代码里是有T-net的,但是放到github里的版本没加上。但这只是猜测,有待验证。

附上相关代码的链接:

PointNet2:https://github.com/charlesq34/pointnet2

PointCNN:https://github.com/yangyanli/PointCNN