RandLA-Net中特征学习提取模块解析

RandLA-Net实现了两个核心指标:一个是利用Random_sampling进行提速,二是设计特征提取模块解决Random_sampling带来的信息丢失问题。

下图为特征提取模块示意图:由三个模块组成,分别为LocSE,Attentive Pooling,Dilated Residual Block
RandLA-Net中特征学习提取模块解析_第1张图片

Local Spatial Encoding(局部空间编码)

给定点云P以及每个点的特征(例如原始RGB或中间学习的特征),此局部空间编码单元会明确嵌入所有相邻点的x-y-z坐标,从而使相应的点特征始终知道其相对位置空间位置。这使LocSE单元可以显式观察局部几何图案,有效地学习复杂的局部结构。特别地,该单元包括以下步骤:
RandLA-Net中特征学习提取模块解析_第2张图片

Finding Neighbouring Points.

对于采样出的中心点,首先通过K近邻(KNN)算法收集其相邻点。

Relative Point Position Encoding

对于中心点的每个最近的K个点,我们明确编码相对点位置,如下所示:
在这里插入图片描述

  • 一二是点的xyz位置
  • ⊕是串联操作
  • || ·||计算相邻点和中心点之间的欧几里得距离。
  • ri 是根据冗余点位置信息进行编码的。这倾向于帮助网络学习局部特征并在实践中获得良好的性能。

Point Feature Augmentation.

对于每个相邻点 ,将编码的相对点位置与它的对应近邻点特征串联在一起,从而获得增强的特征向量。

LocSE代码解析

relative_pos_encoding函数

 def relative_pos_encoding(self, xyz, neigh_idx):
        neighbor_xyz = self.gather_neighbour(xyz, neigh_idx)
        xyz_tile = tf.tile(tf.expand_dims(xyz, axis=2), [1, 1, tf.shape(neigh_idx)[-1], 1])
        relative_xyz = xyz_tile - neighbor_xyz
        relative_dis = tf.sqrt(tf.reduce_sum(tf.square(relative_xyz), axis=-1, keepdims=True))
        relative_feature = tf.concat([relative_dis, relative_xyz, xyz_tile, neighbor_xyz], axis=-1)
        return relative_feature

neighbor_xyz为获取的中心点的K个近邻点的xyz坐标
xyz_tile将中心点xyz进行扩维,relative_xyz算出中心点与近邻点之间的相对位置
relative_dis为中心点与近邻点之间的欧式距离
relative_feature为将中心点,近邻点,相对位置,欧氏距离全部串联起来,即完成局部空间编码

Attentive Pooling

该神经单元用于汇总近邻点特征的集合。现有论文通常使用最大/平均池来硬集成相邻特征,从而导致大部分信息丢失,相比之下,网络转向强大的注意力机制来自动学习重要的本地特征。
RandLA-Net中特征学习提取模块解析_第3张图片

Computing Attention Scores

给定一组局部特征Fi={f1i…fki…fKi} ,设计了一个共享函数g()来为每个功能学习唯一的注意力得分。基本上,函数g()包含一个共享MLP,后跟softmax,通过softmax来获取每一个近邻点特征所占的比率,让网络自动学习,更重要的特征则占用更多的位置,它的正式定义如下:
在这里插入图片描述
其中W是共享MLP的可学习权重.

Weighted Summation

学到的注意力分数可以看作是自动选择重要特征的softmask。正式地,这些特征的加权总和如下:
RandLA-Net中特征学习提取模块解析_第4张图片
总而言之,LocSE和Attentive Pooling单元学会聚合其K个最近点的几何图案和特征,并最终生成信息量丰富的特征向量。

Attentive Pooling代码解析

    def att_pooling(feature_set, d_out, name, is_training):  #d_out = d_out//2 = 16//2 = 8
        batch_size = tf.shape(feature_set)[0]
        num_points = tf.shape(feature_set)[1]
        num_neigh = tf.shape(feature_set)[2]
        d = feature_set.get_shape()[3].value   #16
        f_reshaped = tf.reshape(feature_set, shape=[-1, num_neigh, d])  #(BxN,K,16)
        att_activation = tf.layers.dense(f_reshaped, d, activation=None, use_bias=False, name=name + 'fc')
        att_scores = tf.nn.softmax(att_activation, axis=1)  
        f_agg = f_reshaped * att_scores
        f_agg = tf.reduce_sum(f_agg, axis=1) #(BxN,16)
        f_agg = tf.reshape(f_agg, [batch_size, num_points, 1, d])  #(B,N,1,16)
        f_agg = helper_tf_util.conv2d(f_agg, d_out, [1, 1], name + 'mlp', [1, 1], 'VALID', True, is_training) #(B,N,1,8)
        return f_agg

提取B、N、K、d,将近邻点特征变形为(BxN,K,d),经过一个简单的MLP后,利用softmax对K个近邻点分别打分,将特征与注意力得分相乘,再reduce_sum将所有近邻点的特征全部融合,重要的特征占大头,再经过share_MLP进行维度变形得到一个中心点的局部特征。

Dilated Residual Block(扩张残差块)

由于采用了Ran’do’m_sampling,必然会导致有用信息的丢失,那我们要做的是设计一个模块,即使某些点被丢失了,输入点云的几何结构也能够保留。这就需要我们扩大每个点的接收场,也就是使每个点所包含的局部点的特征范围更大。

RandLA-Net中特征学习提取模块解析_第5张图片

  • 如图所示,将多个LocSE和Attentive Pooling单元通过跳连接堆叠在一起,作为扩张残差块。
  • 为了进一步说明扩张残差块的功能,图4显示了红色3D点在第一次LocSE / Attentive Pooling操作之后观察到K个相邻点,然后在第二次之后能够从最多K^2个相邻点接收信息。
  • 换种更白话的方式,第一次中心点只能观察到周围近邻的5个点作为中心点的局部信息,而第二次操作过后,就将3个中心点的局部信息全部融合在一起了,相当于中间红点的局部特征区域,这就有效的扩大了点的接受域并通过特征传播扩大有效邻域的方法。
    RandLA-Net中特征学习提取模块解析_第6张图片

Dilated Residual Block代码解析

1.dialted_res_block

    def dilated_res_block(self, feature, xyz, neigh_idx, d_out, name, is_training):
        f_pc = helper_tf_util.conv2d(feature, d_out // 2, [1, 1], name + 'mlp1', [1, 1], 'VALID', True, is_training)
        f_pc = self.building_block(xyz, f_pc, neigh_idx, d_out, name + 'LFA', is_training)
        f_pc = helper_tf_util.conv2d(f_pc, d_out * 2, [1, 1], name + 'mlp2', [1, 1], 'VALID', True, is_training,
                                     activation_fn=None)
        shortcut = helper_tf_util.conv2d(feature, d_out * 2, [1, 1], name + 'shortcut', [1, 1], 'VALID',
                                         activation_fn=None, bn=True, is_training=is_training)
        return tf.nn.leaky_relu(f_pc + shortcut)

feature为原始提取出的中心点特征(包括xyz和color),经过building_block后已经将经过两次LocSE和Attentive Pooling的特征提取完成为f_pc,f_pc和原始feature各经过一层MLP后求和lrelu激活。

2.buliding_block

    def building_block(self, xyz, feature, neigh_idx, d_out, name, is_training):
        d_in = feature.get_shape()[-1].value
        f_xyz = self.relative_pos_encoding(xyz, neigh_idx)
        f_xyz = helper_tf_util.conv2d(f_xyz, d_in, [1, 1], name + 'mlp1', [1, 1], 'VALID', True, is_training)
        f_neighbours = self.gather_neighbour(tf.squeeze(feature, axis=2), neigh_idx)
        f_concat = tf.concat([f_neighbours, f_xyz], axis=-1)
        f_pc_agg = self.att_pooling(f_concat, d_out // 2, name + 'att_pooling_1', is_training)

        f_xyz = helper_tf_util.conv2d(f_xyz, d_out // 2, [1, 1], name + 'mlp2', [1, 1], 'VALID', True, is_training)
        f_neighbours = self.gather_neighbour(tf.squeeze(f_pc_agg, axis=2), neigh_idx)
        f_concat = tf.concat([f_neighbours, f_xyz], axis=-1)
        f_pc_agg = self.att_pooling(f_concat, d_out, name + 'att_pooling_2', is_training)
        return f_pc_agg

执行两次LocSE和Attentive Pooling操作

你可能感兴趣的:(深度学习,python,计算机视觉)