【3D计算机视觉】RS-CNN——基于邻域集合关系推断的点云卷积神经网络

论文:https://arxiv.org/abs/1904.07601 CVPR2019 oral
Pytorch代码:https://github.com/Yochengliu/Relation-Shape-CNN
作者说8月会上传,因此自己复现了一下(由于自己实现的结果一般就不开源了)

一、论文背景

近年来,3D 点云分析在自动驾驶和机器人等领域有着诸多的应用,因此得到了各界广泛的关注。主流的点云分析任务都需要对点云的 3D 形状进行高级别的理解,比如点云识别。但从不规则分布的 3D 点中很难推理学习其隐含的 3D 形状。随着以卷积神经网络(CNN)为代表的深度学习方法的兴起,大量的研究工作致力于将 CNN 在图像分析上的巨大成功复制到点云处理领域。然而由于点云数据的不规则性,经典的图像网格卷积难以适用。

一般来说,在点云上进行卷积学习主要面临三大挑战:

  • 点云由无序的点集构成,因此卷积需要对点的输入顺序具有置换不变性。

  • 点云分布于 3D 几何空间,因此卷积应当对点云的刚体变换具有鲁棒性,比如平移、旋转等。

  • 点云形成一个隐含的形状,因此卷积得到的表征应当具备有区分力的。

上面的第一个挑战可以通过pointnet提出的对称函数去解决,而后面两个挑战基本上就是近些年来大家不断探讨和改进的地方了。本文提出 Relation-Shape CNN(RS-CNN)来缓解上述挑战。RS-CNN 的核心是从几何关系中推理学习 3D 形状,因为在本文看来,3D 点之间的几何关系能够有表现力的编码其隐含的形状信息。所提出的 RS-CNN 在点云分类、部件分割和法向估计三个任务上均达到了最佳水平。并且得益于对几何关系的建模,RS-CNN 能够自然地实现置换不变性以及刚体变换鲁棒性。为了验证 RS-CNN 的几何形状推理能力,本文还在 3D 点云的 2D 投影空间中做了测试,实验表明,RS-CNN 依然具备优秀的形状识别性能。

二、模型设计

2.1 模型创新

本文主要是设计了一种在点云上面可以运用的卷积方式,并且刷新了点云分类、部件分割和法向量估计等很多任务的成绩。

2.2 模型表达

这篇文章认为对于一个局部的点云子集,可以构建一个如下的j卷积操作:
在这里插入图片描述
其中 T T T为转换函数,使得每个点上的特征都进行了改变, A A A为聚集函数,使得所有的特征聚集成一个点的特征,而 σ \sigma σ为激活函数。 N ( x i ) N(x_i) N(xi)为点 x i x_i xi的邻域的点的集合。

我们可以先来对比一下传统图像上的2DCNN:
在这里插入图片描述
假设卷积核是 3 × 3 3\times 3 3×3的。转换函数 T T T相当于将卷积核对应位置的值乘在了图像的对应位置,比如说卷积核左上角乘以图像对应的左上角,然后聚集函数 A A A相当于相加求和的操作。因此在点云上也是一样,只不过乘上去的这个值(卷积核的值)不是随机初始化的,而是通过这个位置的点与中心点(即i和j)之间的一些关系算出来的:
在这里插入图片描述
其中 h i j h_{ij} hij就是点云中 x i x_i xi x j x_j xj的关系,这个关系可以人为地先验给出,可以是XYZ的距离(欧氏距离),也可以是特征维度上的距离,等等…因此最后模型的表达式可以写成这个样子:
在这里插入图片描述

2.3 模型结构

讲完数学公式再来看这个图就很清楚了:
在这里插入图片描述
我们能看到模型实际上包含了三个操作:

  • 先随机采样,对于每一个采样点建立一个邻域,并在里面挑选足够的邻居点,即上图的最左边的球就是由采样点得到的邻域集合。具体的采样细节同pointnet++,使用了最远点采样(FPS)加球星区域随机采样(ball query )。
  • 第二个操作即计算每个邻域中邻居点与中心点之间的关系,即上图左侧那条紫色的线,这个关系首先是low level的先验关系,即两个点之间的欧式距离、特征维度的距离;再通过这样的先验关系带入神经网络中算出高维high level的关系,即模型的这一部分,它的输出维度是和点云第j个点一样的维度,因此可以直接乘在第j个点上作为转换函数 T T T
    在这里插入图片描述
    然后可以通过聚合函数 A A A将邻域的点全部聚集到中心点上,类似于CNN的卷积操作。
    在这里插入图片描述
  • 第三个部分就是聚合后点的维度增加,这个也模仿了CNN中卷积之后通道数不断增加,即上图的这一部分
    在这里插入图片描述

至此就完成了所有的卷积操作,其实这篇文章的想法比较像GATConv在graph上的操作,都是通过有关系(也就是文章中的relation)的两个结点的一些特征去计算点与点之间的关系权重,再利用这样的关系权重去更新中心皆点的特征,具体的文章可以参考我写的Graph Attention Networks网络结构+代码

三、实验效果

3.1 实验结果

虽然想法比较简单,但是这篇文章的实验结果还是很出色的,在分类和分割上基本上碾压了所有的现有算法:
在这里插入图片描述
在这里插入图片描述

3.2 模型参数

同样文章也给出了不同的参数设定的实验效果,例如点与点之间的关系选择,会发现同时使用欧氏距离、特征距离与点本身的特征,效果会最好:
在这里插入图片描述
聚集函数的选择上max pooling效果最好:
在这里插入图片描述
邻域内点的选择上随机筛选会优于KNN筛选:
在这里插入图片描述

3.3 模型鲁棒性

最后文章还做了一些旋转鲁棒性、缺失鲁棒性和投影的实验,特别说一下这个投影,就是将一些3D点云映射到2D,运用学习出来的网络,都用到92%左右的正确率,说明这个卷积确实是学到了一些东西:
在这里插入图片描述
在这里插入图片描述

四、代码

Relation-Shape CNN层的结构大致如下

class RSConv(nn.Module):
    def __init__(self, in_channel, out_channel, hidden_channel):
        super().__init__()
        self.in_channel = in_channel
        self.out_channel = out_channel
        '''
        Relation convs, 3-layer mlp. 
        The input channel is 10.
        The output channel is the same as the input feature channel
        '''
        mlp_convs = []
        last_channel = 10
        mlp_layers = [hidden_channel,in_channel]
        rasing_layers = [out_channel]
        for i, num_channel in enumerate(mlp_layers):
            mlp_convs.append(nn.Conv2d(in_channels=last_channel, out_channels=num_channel, kernel_size=1))
            if i < len(mlp_layers) - 1:
                mlp_convs.append(nn.ReLU())
                mlp_convs.append(nn.BatchNorm2d(num_channel))
            last_channel = num_channel
        self.mlp_convs = nn.Sequential(*mlp_convs)
        '''
        Channel-raising mapping. Map the input channel to the output channel.
        '''
        channel_raising = []
        last_channel = in_channel
        for num_channel in rasing_layers:
            channel_raising.append(nn.Conv2d(in_channels=last_channel, out_channels=num_channel, kernel_size=1))
            channel_raising.append(nn.ReLU())
            channel_raising.append(nn.BatchNorm2d(num_channel))
            last_channel = num_channel
        self.channel_raising = nn.Sequential(*channel_raising)

    def forward(self, centroid_xyz, neighbors):
        """
        :param centroid_xyz: [B, npoint, C]
        :param neighbors: [B, npoint, nsample, C+D]
        :return:
        """
        C = centroid_xyz.shape[-1]
        nsample = neighbors.shape[2]
        assert C == 3

        '''Calculate relation h'''
        neighbors_xyz = neighbors[:, :, :, :C]  # [B, npoint, nsample, C]
        centroid_xyz = centroid_xyz.unsqueeze(dim=2)  # [B, npoint, 1, C]
        delta = centroid_xyz - neighbors_xyz  # [B, npoint, nsample, C]
        euclidean = torch.sqrt((delta ** 2).sum(dim=-1, keepdim=True))  # [B, npoint, nsample, 1]
        h = torch.cat([euclidean, delta, centroid_xyz.repeat(1, 1, nsample, 1), neighbors_xyz],
                      dim=-1)  # [B, npoint, nsample, 10]
        h = h.permute(0, 3, 1, 2)  # [B, 10, npoint, nsample]

        '''Apply RS-convolution'''
        h = self.mlp_convs(h)
        neighbors = neighbors.permute(0, 3, 1, 2)  # [B, C+D, npoint, nsample]
        aggregated = F.relu(torch.max(neighbors * h, dim=-1, keepdim=True)[0])  # [B, C+D, npoint, 1]

        '''Channel raising'''
        raised = self.channel_raising(aggregated) # [B, out_channel, npoint, 1]
        raised = raised.squeeze(dim=-1)  # [B, out_channel, npoint]
        return raised

评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值