- 标题:"VoxelNet: End-to-End Learning for Point Cloud Based 3D Object Detection"
- 作者: Yin Zhou, Oncel Tuzel
- 年份:2018
- 期刊:Proceedings of the IEEE conference on computer vision and pattern recognition
目录
1. 前言
为了和RPN(region proposal network)进行交互,VoxelNet之前的大多方法依赖于将点云转换为手工设计的表征形式,如鸟瞰图,前视图;这或多或少损失了点云的原始信息。VoxelNet设计了一个端到端的检测流程,使点云无需转换为手工表征形式,即可进行检测。
2. 总体流程
3. 具体实现
原始的4维点云[x,y,z,r]经过以下顺序执行,得到最终的目标的检测框大小和位置。
3.1 Feature Learning Network
3.1.1 Voxel Partion:
作用: 原始点云分割
定义:
- 三维空间里点云在[Z,Y,X] 的分布范围为[D,H,W]
- 定义体素网格的大小[ v D v_D vD, v H v_H vH, v W v_W vW]
用体素将[D,H,W]范围内的点云分割开,则:
- 体素坐标值的范围是:[ D ′ = D / v D D'=D/v_D D′=D/vD, H ′ = H / v H H'=H/v_H H′=H/vH, W ′ = W / v W W'=W/v_W W′=W/vW]
3.1.2 Random Sample:
作用: 随机采样体素中的点
定义:
- 常数T,在每个体素网格中随机抽取不超过T个数量的点云
优点:
2. 节约计算资源
3. 通过减少采样误差和增加训练时数据的多样性减少由于不同体素网格中点云数量不均衡的影响
3.1.3 Stacked Voxel Feature Encoding
输入: 上述随机采样后每个体素中的点
定义:
- V = { p i = [ x i , y i , z i , r i ] T ∈ R 4 } i ∈ 1.... t V = \lbrace p_i =[ x_i,y_i,z_i,r_i ]^T ∈R^4 \rbrace _{i∈1....t} V={pi=[xi,yi,zi,ri]T∈R4}i∈1....t, 为点云数量t<=T的非空体素,其中 p i = [ x i , y i , z i , r i ] T p_i =[ x_i,y_i,z_i,r_i ]^T pi=[xi,yi,zi,ri]T为体素中第i个点云的数据, x i , y i , z i , r i x_i,y_i,z_i,r_i xi,yi,zi,ri分别为点云 x , y , z x,y,z x,y,z坐标和点云的反射率。
- 计算 V V V中点云的中心值 ( v x , v y , v z ) (v_x,v_y,v_z) (vx,vy,vz),计算体素中的每个点相对中心值的偏移量从而对 V V V中的点云数据进行增强,增强后 V i n = { p i ^ = [ x i , y i , z i , r i , x i − v x , y i − v y , z i − v z ] T ∈ R 7 } i ∈ 1.... t V_{in} = \lbrace \hat{p_i} =[ x_i,y_i,z_i,r_i, x_i-v_x,y_i-v_y,z_i-v_z]^T ∈R^7 \rbrace _{i∈1....t} Vin={pi^=[xi,yi,zi,ri,xi−vx,yi−vy,zi−vz]T∈R7}i∈1....t,增强后的点也称为point-wise
- 增强后的 p i ^ \hat{p_i} pi^ 通过FCN network 得到Point-wise Feature( 即 f i ∈ R m ) 即f_i∈R^m) 即fi∈Rm),其中FCN包含线性层(liner layer),BN层(batch normalization layer),还有ReLU激活层。
- 对体素中的每一个Point-wise Feature ( f i ∈ R m ) (f_i∈R^m) (fi∈Rm)进行Element-wise MaxPooling操作,得到the locally aggregated feature(即 f i ^ ∈ R m ) \hat {f_i}∈R^m) fi^∈Rm)
- 对Point-wise Feature( 即 f i ∈ R m ) 即f_i∈R^m) 即fi∈Rm)和the locally aggregated feature(即 f i ^ ∈ R m ) \hat {f_i}∈R^m) fi^∈Rm)进行堆叠操作得到最终的 f i o u t = [ f i , f i ^ ] ∈ R 2 m f^{out}_i=[f_i,\hat {f_i}]∈R^{2m} fiout=[fi,fi^]∈R2m,此时每个体素包含的点的形式变为$V_out = { f ^ i o u t } i . . . t \lbrace \hat f^{out}_i\rbrace_{i...t} {f^iout}i...t
PS:其中的3,4,5即为VFE操作
- 上述的 f i o u t f^{out}_i fiout作为下一个VFE的输入,再经过若干次VFE得到Point-wise Feature-n
- 对体素中的所有点进行FCN,和Element-wise MaxPooling,得到最后的Voxel-wise Feature
所有的体素中的点都进行1-7步骤的操作后,可得到稀疏向量表示,向量的维度为 C C C X D ′ D' D′ X H ′ H' H′ X W ′ W' W′(C为每个体素中采样得到的点的数量,有很多体素为空,故为稀疏矩阵)
代码实现:
class VFE_Layer(tf.keras.layers.Layer):
"""
A VFE layer class
Args :
c_out : int, the dimension of the output after VFE, must be even
"""
def __init__(self, c_out):
super(VFE_Layer, self).__init__()
self.units = c_out//2
self.fcn = tf.keras.layers.Dense(self.units, activation="relu")
self.bn = tf.keras.layers.BatchNormalization(trainable=True)
def call(self, input, mask, training=False):
"""
Call method of the class
Args:
input : Tensor (4D tensor in our case), [Batch_size, max_num_voxels, max_num_pts, out_dim]
(out_dim = 7, at the beginning of the network)
Returns:
output : Tensor with the same shape as input, except the last dim which is c_out
"""
fcn_out = self.bn(self.fcn(input), training=training)
max_pool = tf.reduce_max(fcn_out, axis=2, keepdims=True) # [batch_size, max_num_voxels, 1, out_dim//2]
tiled_max_pool = tf.tile(max_pool, [1,1,tf.shape(fcn_out)[2],1]) # [batch_size, max_num_voxels, max_num_pts, out_dim//2]
output = tf.concat([fcn_out, tiled_max_pool], axis=-1) # [batch_size, max_num_voxels, max_num_pts, out_dim//2]
mask = tf.tile(mask, [1,1,1, 2*self.units])
return tf.multiply(output, tf.cast(mask, tf.float32))
3.2 Convolutional Middle Layers
VoxelNet中按照检测类别的不同,设计了不同的Convolution Middle Layer,下面以车辆类别为例讲解,其他类别细节不同,但整体架构一样。
约定:
- VFE-i( c i n c_{in} cin, c o u t c_{out} cout):第i个VFE层,该层的输入维度为 c i n c_{in} cin,输出维度为 c o u t c_{out} cout
- ConvMD( c i n c_{in} cin, c o u t c_{out} cout, k k k, s s s, p p p):MD卷积,卷积的输入输出维度为 c i n c_{in} cin, c o u t c_{out} cout, k k k=kernel size, s s s=stride, p p p=padding
细节设置:
- 在Z,Y,X方向,选取落在[-3,1],[-40,40],[0,70.4]范围内的点云
- 在Z,Y,X方向,体素的大小设置为[ v D v_D vD, v H v_H vH, v W v_W vW]=[0.4,0.2,0.2],如此体素坐标范围[100,400,352]
- 每个非空体素中随机采样的点云数量不超过T<=35
- 使用两层VFE:VFE-1(7,32),VFE-2(32,128)
- 最后的FCN层将VFE-2的输出映射至128维,故最后得到128 x 10 x 400 x352 维度的稀疏矩阵(voxel-wise feature)
- 使用三个连续的3D卷积处理上述得到的稀疏矩阵,
Conv3D(128,64,3,(2,1,1),(1,1,1)),
Conv3D(64,64,3,(1,1,1),(0,1,1)),
Conv3D(64,64,3,(2,1,1),(1,1,1));
产生 64 64 64 X 2 2 2 X 400 400 400 X 352 352 352维度的4D张量,通过reshape,以 128 128 128 X 400 400 400 X 352 352 352的维度作为RPN结构的输入,其中128,400,352分别对应3D张量的输入channel,高和宽
3.3 Region Proposal Network
3.4 Loss Function
损失函数较为简单,参考原文
4.彩蛋
原有的稀疏Voxel不利于GPU进行并行计算,作者通过以下方式,将稀疏Voxel转换为稠密Voxel,提高GPU运行速度。
具体实现:
初始化一个
K
K
K X
T
T
T X
7
7
7 维度的张量,其中
K
K
K是非空体素的最大个数,
T
T
T是上述的最大随机采样个数,7代表上述point-wise的维度(
[
x
i
,
y
i
,
z
i
,
r
i
,
x
i
−
v
x
,
y
i
−
v
y
,
z
i
−
v
z
]
T
[ x_i,y_i,z_i,r_i, x_i-v_x,y_i-v_y,z_i-v_z]^T
[xi,yi,zi,ri,xi−vx,yi−vy,zi−vz]T)。