代码:VoxelNet: https://github.com/skyhehe123/VoxelNet-pytorch
论文:VoxelNet End-to-End Learning for Point Cloud Based 3D Object Detection
1. 解决了什么问题?
对点云做 3D 检测是许多应用得以落地的关键,如自动驾驶和扫地机器人等。与图像检测相比,LiDAR 能提供可靠的深度信息,准确地定位目标,描述物体的形状。但由于多种因素,如 3D 空间的非均匀采样、传感器的有效范围、遮挡和相对位姿,LiDAR 点云一般是非常稀疏的,点云密度也会剧烈变化。为了解决上述问题,我们要人为设计一种特征表示。
2. 提出了什么方法?
本文摒弃了 3D 点云的特征工程,提出了 VoxelNet,该 3D 检测网络以端到端的形式,同时学习提取点云的特征和预测 3D 边框。VoxelNet 将 3D 点云划分为相同空间大小的 3D 体素,然后通过体素特征编码层(VFE)将每个体素内的点云变换成统一的特征表示。通过多个 VFE 层,就能学到复杂的特征来描述局部的 3D 形状信息。最后,再将该特征输入 RPN,生成预测结果。
2.1 VoxelNet 架构
如下图所示,VoxelNet 包括三个功能模块:特征学习网络、卷积中间层和 RPN。特征学习网络的输入是原始点云,将空间划分成体素,将每个体素内的点变换成向量表示,以此描述物体的形状信息。该空间用稀疏的 4D 张量表示。然后,将稀疏的 4D 张量输入卷积中间层,聚合空间上下文信息。最终,用一个 RPN 输出 3D 检测结果。
2.1.1 特征学习网络
Voxel Partition
给定点云,将 3D 空间划分为相同体积大小的体素。假设点云包括的是大小为
D
,
H
,
W
D, H, W
D,H,W 的 3D 空间,分别对应
Z
,
Y
,
X
Z, Y, X
Z,Y,X 轴。定义每个体素的大小是
v
D
,
v
H
,
v
W
v_D, v_H, v_W
vD,vH,vW。则 3D 体素网格的大小是
D
′
=
D
/
v
D
,
H
′
=
H
/
v
H
,
W
′
=
W
/
v
W
D'=D/v_D, H'=H/v_H, W'=W/v_W
D′=D/vD,H′=H/vH,W′=W/vW。这里,我们假设
D
,
H
,
W
D, H, W
D,H,W 是
v
D
,
v
H
,
v
W
v_D, v_H, v_W
vD,vH,vW 的倍数。
Grouping
根据点云所在的体素,将它们分组。由于距离、遮挡、目标姿态以及非均匀采样,LiDAR 点云会非常稀疏,点云的密度也会剧烈变化。因此,分组后,一个体素可能包含不同个数的点。如上图所示,体素-
1
1
1里面的点个数明显多于体素-
2
2
2和体素-
4
4
4,体素-
3
3
3里面没有点。
Random Sampling
通常,一个高清晰度的点云会包括约
10
10
10 万个点。直接处理所有的点会带来极高的计算成本,而且空间中点云密度差异大也会使检测结果带有偏见。因此,如果某体素内的点的个数超过了
T
T
T,我们就随机采样
T
T
T 个点。该策略既可以节约计算成本,也可缓解体素内点云数量的不均衡性,减轻采样偏见的问题。
Stacked Voxel Feature Encoding
本文关键的创新就是 stacked VFE 层。上图展示了每个体素的层级特征编码过程。本文在后续部分用 VFE Layer-1 来介绍。下图展示了 VFE Layer-1 的结构。
用 V = { p i = [ x i , y i , z i , r i ] T ∈ R 4 } i = 1... t \mathbf{V}=\left\{\mathbf{p}_i=[x_i,y_i,z_i,r_i]^T\in\mathbb{R}^4\right\}_{i=1...t} V={pi=[xi,yi,zi,ri]T∈R4}i=1...t 表示一个包含了 t ≤ T t\leq T t≤T 个 LiDAR 点的非空体素, p i \mathbf{p}_i pi 为第 i i i 个点的 X Y Z XYZ XYZ 坐标, r i r_i ri 是反射率。
- 首先计算 V \mathbf{V} V 内所有点的 centroid,作为局部均值,记作 ( v x , v y , v z ) (v_x,v_y,v_z) (vx,vy,vz)。
- 然后用相对于 centroid 的偏移量来增广每个点 p i \mathbf{p}_i pi,得到输入特征的集合 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 \mathbf{V}_{in}=\left\{\hat{\mathbf{p}}_i=[x_i,y_i,z_i, r_i, x_i- v_x, y_i - v_y, z_i - v_z]^T \in \mathbb{R}^7\right\}_{i=1...t} Vin={p^i=[xi,yi,zi,ri,xi−vx,yi−vy,zi−vz]T∈R7}i=1...t.
- 然后,用全连接网络将 V i n \mathbf{V}_{in} Vin 里的每个 p i \mathbf{p}_i pi 变换到特征空间,在特征空间内从点特征 f i ∈ R m \mathbf{f}_i\in\mathbb{R}^m fi∈Rm 聚合信息,编码每个体素的表面形状。该全连接网络包括一个线性层、BN 层和 ReLU 层。得到点特征表示后,对所有的 f i \mathbf{f}_i fi 做 MaxPool \text{MaxPool} MaxPool 操作,得到 V \mathbf{V} V 的局部聚合特征 f ~ ∈ R m \tilde{\mathbf{f}}\in \mathbb{R}^m f~∈Rm。最后,用 f ~ \tilde{\mathbf{f}} f~ 来增强每个 f i \mathbf{f}_i fi,得到 f i o u t = [ f i T , f ~ T ] T ∈ R 2 m \mathbf{f}_i^{out}=[\mathbf{f}_i^T, \tilde{\mathbf{f}}^T]^T \in \mathbb{R}^{2m} fiout=[fiT,f~T]T∈R2m,该操作是 pointwise concat。因此,我们就得到了输出特征集合 V o u t = { f i o u t } i . . . t \mathbf{V}_{out}=\left\{\mathbf{f}_i^{out}\right\}_{i...t} Vout={fiout}i...t。
所有的非空体素的编码方式都一样,共享全连接网络的参数。
使用 VFE- i ( c i n , c o u t ) i(c_{in},c_{out}) i(cin,cout) 来表示第 i i i 个 VFE 层,它将维度为 c i n c_{in} cin 的输入特征变换到维度是 c o u t c_{out} cout的输出特征。线性层学习一个大小是 c i n × ( c o u t / 2 ) c_{in}\times (c_{out}/2) cin×(cout/2) 的矩阵,pointwise concat 操作输出的维度就是 c o u t c_{out} cout。
由于输出特征结合了点特征和局部聚合特征,stacking VFE 层就编码了体素内各点之间的关系,最终的特征表示就能描述形状的信息。通过将 VFE- n n n 的输出变换到 R C \mathbb{R}^C RC空间,得到体素特征,然后使用逐元素的 MaxPool \text{MaxPool} MaxPool操作,其中 C C C是体素特征的维度。
Sparse Tensor Representation
只对非空体素做处理,我们得到一组体素特征,每个特征都关联着唯一的非空体素。该组体素特征可用一个稀疏的 4D 张量表示,大小是
C
×
D
′
×
H
′
×
W
′
C\times D'\times H'\times W'
C×D′×H′×W′。尽管点云包含约
10
10
10万个点,但超过
90
%
90\%
90%的体素通常是空的。将非空体素表示为稀疏的张量,极大地降低了内存占用和计算成本,实现起来效率就比较高。
2.1.2 卷积中间层
我们用
Conv
M
D
(
c
i
n
,
c
o
u
t
,
k
,
s
,
p
)
\text{Conv}M\mathbf{D}(c_{in},c_{out},\mathbf{k,s,p})
ConvMD(cin,cout,k,s,p)来表示
M
M
M维的卷积操作,
c
i
n
,
c
o
u
t
c_{in},c_{out}
cin,cout是输入和输出通道数,
k
,
s
,
p
\mathbf{k,s,p}
k,s,p是
M
M
M维向量对应的卷积核大小、步长和 padding 大小。这里
M
=
3
M=3
M=3。如果对于
M
M
M 维向量,卷积核大小都是一样的,则用一个标量
k
k
k 来表示,即
k
=
(
k
,
k
,
k
)
\mathbf{k}=(k,k,k)
k=(k,k,k)。
假设输入的张量形状是
(
N
,
C
i
n
,
D
i
n
,
H
i
n
,
W
i
n
)
(N,C_{in},D_{in},H_{in},W_{in})
(N,Cin,Din,Hin,Win),输出的张量形状是
(
N
,
C
o
u
t
,
D
o
u
t
,
H
o
u
t
,
W
o
u
t
)
(N,C_{out},D_{out},H_{out},W_{out})
(N,Cout,Dout,Hout,Wout),计算过程如下:
D
o
u
t
=
⌊
D
i
n
+
2
×
padding
[
0
]
−
dilation
[
0
]
×
(
kernel_size
[
0
]
−
1
)
−
1
stride
[
0
]
+
1
⌋
D_{out}=\lfloor \frac{D_{in}+2\times \text{padding}[0]-\text{dilation}[0]\times(\text{kernel\_size}[0]-1)-1}{\text{stride}[0]} +1\rfloor
Dout=⌊stride[0]Din+2×padding[0]−dilation[0]×(kernel_size[0]−1)−1+1⌋
H
o
u
t
=
⌊
H
i
n
+
2
×
padding
[
1
]
−
dilation
[
1
]
×
(
kernel_size
[
1
]
−
1
)
−
1
stride
[
1
]
+
1
⌋
H_{out}=\lfloor \frac{H_{in}+2\times \text{padding}[1]-\text{dilation}[1]\times(\text{kernel\_size}[1]-1)-1}{\text{stride}[1]} +1\rfloor
Hout=⌊stride[1]Hin+2×padding[1]−dilation[1]×(kernel_size[1]−1)−1+1⌋
W
o
u
t
=
⌊
W
i
n
+
2
×
padding
[
2
]
−
dilation
[
2
]
×
(
kernel_size
[
2
]
−
1
)
−
1
stride
[
2
]
+
1
⌋
W_{out}=\lfloor \frac{W_{in}+2\times \text{padding}[2]-\text{dilation}[2]\times(\text{kernel\_size}[2]-1)-1}{\text{stride}[2]} +1\rfloor
Wout=⌊stride[2]Win+2×padding[2]−dilation[2]×(kernel_size[2]−1)−1+1⌋
每个卷积中间层都包括 3D 卷积、BN 层和 ReLU 层。卷积中间层的感受野是逐渐增大的,在形状描述信息内增加上下文信息,以此聚合体素特征。
2.1.3 RPN
RPN 已经成为先进的目标检测方法必备的构建模块。本文,作者对 RPN 做了几点改进,将它和特征学习网络与卷积中间层结合,以端到端的方式训练。
RPN 的输入是卷积中间层的特征图,结果如下图所示。网络有三个全卷积模块。每个模块的第一层会通过步长 2 2 2的卷积来下采样特征图,后面是步长为 1 1 1的一组卷积。每个卷积层后面跟着一个 BN 层和 ReLU 操作。然后将每个模块的输出上采样到固定大小,然后 concat 到一起,得到高分辨率的特征图。最后,将特征图映射到概率得分图和回归图。
2.2 损失函数
{ a i p o s } i = 1... N p o s \left\{a_i^{pos}\right\}_{i=1...N_{pos}} {aipos}i=1...Npos表示 N p o s N_{pos} Npos个正的 anchors, { a j n e g } j = 1... N n e g \left\{a_j^{neg}\right\}_{j=1...N_{neg}} {ajneg}j=1...Nneg表示 N n e g N_{neg} Nneg个负的 anchors。用 ( x c g , y c g , z c g , l g , w g , h g , θ g ) (x_c^g, y_c^g, z_c^g, l^g, w^g, h^g, \theta^g) (xcg,ycg,zcg,lg,wg,hg,θg)表示一个 ground-truth 3D 框,其中 x c g , y c g , z c g x_c^g,y_c^g,z_c^g xcg,ycg,zcg表示中心位置, l g , w g , h g l^g, w^g, h^g lg,wg,hg表示边框的长度、宽度和高度, θ g \theta^g θg是围绕 Z Z Z轴的偏航角。用 ( x c a , y c a , z c a , l a , w a , h a , θ a ) (x_c^a, y_c^a, z_c^a, l^a, w^a, h^a, \theta^a) (xca,yca,zca,la,wa,ha,θa) 表示一个正的 anchor,定义残差向量 u ∗ ∈ R 7 \mathbf{u}^\ast \in\mathbb{R}^7 u∗∈R7包含7个回归目标,分别对应中心位置 Δ x , Δ y , Δ z \Delta{x},\Delta{y}, \Delta{z} Δx,Δy,Δz,三个尺寸 Δ l , Δ w , Δ h \Delta{l},\Delta{w}, \Delta{h} Δl,Δw,Δh,以及旋转角度 Δ θ \Delta{\theta} Δθ,计算如下:
Δ
x
=
x
c
g
−
x
c
a
d
a
,
Δ
y
=
y
c
g
−
y
c
a
d
a
,
Δ
z
=
z
c
g
−
z
c
a
h
a
\Delta{x}=\frac{x_c^g-x_c^a}{d^a}, \Delta{y}=\frac{y_c^g-y_c^a}{d^a},\Delta{z}=\frac{z_c^g-z_c^a}{h^a}
Δx=daxcg−xca,Δy=daycg−yca,Δz=hazcg−zca
Δ
l
=
log
l
g
l
a
,
Δ
w
=
log
w
g
w
a
,
Δ
h
=
log
h
g
h
a
\Delta{l}=\log{\frac{l^g}{l^a}}, \Delta{w}=\log{\frac{w^g}{w^a}},\Delta{h}=\log{\frac{h^g}{h^a}}
Δl=loglalg,Δw=logwawg,Δh=loghahg
Δ
θ
=
θ
g
−
θ
a
\Delta{\theta}=\theta^g-\theta^a
Δθ=θg−θa
其中, d a = ( l a ) 2 + ( w a ) 2 d^a=\sqrt{(l^a)^2+(w^a)^2} da=(la)2+(wa)2 是 anchor box 的对角线长度。这里,我们目的是直接预测带朝向的 3D 框,用对角线 d a d^a da来归一化 Δ x \Delta{x} Δx和 Δ y \Delta{y} Δy。损失函数如下:
L = α 1 N p o s ∑ i L c l s ( p i p o s , 1 ) + β 1 N n e g ∑ j L c l s ( p j n e g , 0 ) + 1 N p o s ∑ i L r e g ( u i , u i ∗ ) L=\alpha \frac{1}{N_{pos}}\sum_i L_{cls}(p_i^{pos},1)+\beta\frac{1}{N_{neg}}\sum_j L_{cls}(p_j^{neg},0)+\frac{1}{N_{pos}}\sum_i L_{reg}(\mathbf{u}_i,\mathbf{u}_i^\ast) L=αNpos1i∑Lcls(pipos,1)+βNneg1j∑Lcls(pjneg,0)+Npos1i∑Lreg(ui,ui∗)
其中, p i p o s p_i^{pos} pipos和 p j n e g p_j^{neg} pjneg表示正负样本 a i p o s a_i^{pos} aipos 和 a i n e g a_i^{neg} aineg 的 softmax 输出,而 u i ∈ R 7 \mathbf{u}_i\in \mathbb{R}^7 ui∈R7 和 u i ∗ ∈ R 7 \mathbf{u}_i^\ast \in \mathbb{R}^7 ui∗∈R7 表示正样本 a i p o s a_i^{pos} aipos 的回归预测和 ground-truth。前两项损失是归一化的分类损失, L c l s L_{cls} Lcls 是二元交叉熵损失, α > 0 , β > 0 \alpha > 0, \beta > 0 α>0,β>0 用于平衡正负样本。 L r e g L_{reg} Lreg是回归损失,使用的是 SmoothL1 函数。
2.3 高效实现
GPU 对于密集张量做了特殊优化,但要想直接应用到点云上有个问题,即点云是稀疏分布的,每个体素内的点云个数都不一样。作者设计了一个方法将点云转换为密集张量的结构,从而 stacked VFE 操作可以做到对点云和体素的并行计算。
在下图中,作者介绍了该方法。首先,初始化一个
K
×
T
×
7
K\times T\times 7
K×T×7的张量,存储体素输入特征缓存,
K
K
K是非空体素的最大个数,
T
T
T是每个体素内点的最大个数,
7
7
7是每个输入点的编码维度。在开始处理前,随机化这些点。对点云内的每个点,检查它对应的体素是否存在。这个查询操作实现起来很高效,复杂度为
O
(
1
)
O(1)
O(1)。在哈希表中,哈希 key 是每个体素的坐标。如果一个体素已经初始化过了,如果它有
<
T
<T
<T个点,就将点插入到该体素位置。如果体素没有初始化,则初始化一个新的体素,将体素坐标存储在体素坐标缓存里面,并把点插入到这个体素位置。过一遍所有的点表就可以构建出体素的输入特征和坐标缓存,因此复杂度是
O
(
n
)
O(n)
O(n)。为了进一步提升效率,我们可以忽略掉那些点较少的体素,只存储有限个数的体素(
K
K
K)。
体素输入缓存构建完成后,stacked VFE 只涉及了点操作和体素操作,可以在 GPU 上并行实现。最后,通过存储的坐标缓存,我们将稀疏的体素结构重新组织成密集的体素网格。后续卷积中间层和 RPN 就在这个密集的体素网格上操作,可以用 GPU 高效实现。
3. 训练细节
3.1 网络细节
在 KITTI 数据集上做的实验。
Car Detection
对于该任务,点云的范围是 [ − 3 , 1 ] × [ − 40 , 40 ] × [ 0 , 70.4 ] [-3,1]\times [-40,40]\times [0,70.4] [−3,1]×[−40,40]×[0,70.4] 米,分别对应 Z , Y , X Z,Y,X Z,Y,X轴。舍弃那些投影到图像边界以外的点云。体素大小设置为 v D = 0.4 , v H = 0.2 , v W = 0.2 v_D=0.4, v_H=0.2, v_W=0.2 vD=0.4,vH=0.2,vW=0.2 米,这样就有 D ′ = 10 , H ′ = 400 , W ′ = 352 D'=10, H'=400, W'=352 D′=10,H′=400,W′=352。在每个非空体素内,随机选取 T = 35 T=35 T=35 个点。使用两个 VFE 层 VFE-1( 7 , 32 7, 32 7,32) 和 VFE-2( 32 , 128 32,128 32,128)。最后全连接网络将 VFE-2 的输出映射到 R 128 \mathbb{R}^{128} R128 空间。因此,该特征学习网络就产生一个稀疏张量,大小是 128 × 10 × 400 × 352 128\times 10\times 400\times 352 128×10×400×352。为了聚合体素特征,使用三个卷积中间层, 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 ) ) \text{Conv3D}(128, 64, 3, (2,1,1), (1,1,1)), \text{Conv3D}(64, 64, 3, (1,1,1), (0,1,1)), \text{Conv3D}(64, 64, 3, (2,1,1), (1,1,1)) 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)),输出一个 4D 张量,形状是 64 × 2 × 400 × 352 64\times 2\times 400\times 352 64×2×400×352。
Reshape 后,输入 RPN 的特征图大小是 128 × 400 × 352 128\times 400\times 352 128×400×352,维度分别是 3D 张量的通道数、高度和宽度。上图展示了细节信息。本文只使用了一个 anchor 大小, l a = 3.9 , w a = 1.6 , h a = 1.56 l^a=3.9, w^a=1.6, h^a=1.56 la=3.9,wa=1.6,ha=1.56 米,中心点高度是 z c a = − 1.0 z_c^a=-1.0 zca=−1.0 米,有两个偏航角 0 0 0 和 90 90 90 度。Anchor 匹配策略如下:如果它和某个 ground-truth 框的 IoU 是最大的,或者它们的 IoU > 0.6 >0.6 >0.6,则它就是正样本。如果它和所有的 ground-truth 框的 IoU 都 < 0.45 < 0.45 <0.45,则它就是负样本。忽略那些与任何 ground-truth 都 0.45 < IoU ≤ 0.6 0.45<\text{IoU}\leq 0.6 0.45<IoU≤0.6的样本。另外,在 L = α 1 N p o s ∑ i L c l s ( p i p o s , 1 ) + β 1 N n e g ∑ j L c l s ( p j n e g , 0 ) + 1 N p o s ∑ i L r e g ( u i , u i ∗ ) L=\alpha \frac{1}{N_{pos}}\sum_i L_{cls}(p_i^{pos},1)+\beta\frac{1}{N_{neg}}\sum_j L_{cls}(p_j^{neg},0)+\frac{1}{N_{pos}}\sum_i L_{reg}(\mathbf{u}_i,\mathbf{u}_i^\ast) L=αNpos1∑iLcls(pipos,1)+βNneg1∑jLcls(pjneg,0)+Npos1∑iLreg(ui,ui∗) 中, α = 1.5 , β = 1 \alpha=1.5, \beta=1 α=1.5,β=1。
Pedestrian and Cyclist Detection
输入范围是 [ − 3 , 1 ] × [ − 20 , 20 ] × [ 0 , 48 ] [-3,1]\times [-20, 20]\times [0,48] [−3,1]×[−20,20]×[0,48] 米,分别对应 Z , Y , X Z,Y,X Z,Y,X轴。使用与 Car 相同的体素大小,就有 D = 10 , H = 200 , W = 240 D=10, H=200, W=240 D=10,H=200,W=240。设置 T = 45 T=45 T=45 以获取更多的 LiDAR 点,更好地描述形状信息。特征学习网络和卷积中间层和 Car 检测任务用的是一样的。在 RPN 中,修改了 block 1 \text{block 1} block 1,将第一个 2D 卷积的步长大小从 2 2 2改为了 1 1 1。这样在样本匹配时,分辨率就更细致一些,对于行人和骑车人来说更必要。Anchor 大小为 l a = 0.8 , w a = 0.6 , h a = 1.73 l^a=0.8, w^a=0.6, h^a=1.73 la=0.8,wa=0.6,ha=1.73 米,中心点高度是 z c a = − 0.6 z_c^a=-0.6 zca=−0.6 米。Anchor 匹配策略如下:如果它和某个 ground-truth 框的 IoU 是最大的,或者它们的 IoU > 0.5 >0.5 >0.5,则它就是正样本。如果它和所有的 ground-truth 框的 IoU 都 < 0.35 < 0.35 <0.35,则它就是负样本。忽略那些与任何 ground-truth 都 0.35 < IoU ≤ 0.5 0.35<\text{IoU}\leq 0.5 0.35<IoU≤0.5的样本。
训练时,使用 SGD 优化器,前 150 150 150个 epochs,它的学习率是 0.01 0.01 0.01,后面的 10 10 10 个 epochs 学习率衰减至 0.001 0.001 0.001。Batch size 为 16 16 16。
3.2 数据增强
因为只有不足 4000 4000 4000个点云,从头训练的话会造成过拟合。于是,作者引入了三种数据增强方法。增强训练数据非常快,所以无需存储在磁盘上。
M = { p i = [ x i , y i , z i , r i ] T ∈ R 4 } i = 1 , . . . , N \mathbf{M}=\left\{ \mathbf{p}_i=[x_i,y_i,z_i,r_i]^T\in\mathbb{R}^4\right\}_{i=1,...,N} M={pi=[xi,yi,zi,ri]T∈R4}i=1,...,N 是所有的点云,包括 N N N个点。将 3D 框 b i \mathbf{b}_i bi记作 ( x c , y c , z c , l , w , h , θ ) (x_c,y_c,z_c,l,w,h,\theta) (xc,yc,zc,l,w,h,θ),其中 x c , y c , z c x_c,y_c,z_c xc,yc,zc是中心位置, l , w , h l,w,h l,w,h是长宽高, θ \theta θ是偏航角。 b i \mathbf{b}_i bi 内所有的 LiDAR 点记作 Ω i = { p ∣ x ∈ [ x c − l / 2 , x c + l / 2 ] , y ∈ [ y c − w / 2 , y c + w / 2 ] , z ∈ [ z c − h / 2 , z c + h / 2 ] , p ∈ M } \Omega_i=\left\{\mathbf{p}|x \in [x_c-l/2, x_c + l/2], y\in [y_c-w/2, y_c+w/2], z\in [z_c-h/2, z_c+h/2], \mathbf{p\in M}\right\} Ωi={p∣x∈[xc−l/2,xc+l/2],y∈[yc−w/2,yc+w/2],z∈[zc−h/2,zc+h/2],p∈M},其中 p = [ x , y , z , r ] \mathbf{p}=[x,y,z,r] p=[x,y,z,r] 表示 M \mathbf{M} M 里面某个 LiDAR 点。
第一种数据增强就是对每个 3D 框及其里面的 LiDAR 点做扰动。以随机变量 Δ θ ∈ [ − π / 10 , + π / 10 ] \Delta{\theta} \in [-\pi/10, +\pi/10] Δθ∈[−π/10,+π/10],关于 ( x c , y c , z c ) (x_c,y_c,z_c) (xc,yc,zc) ,围绕 Z Z Z轴旋转 3D 框 b i \mathbf{b}_i bi,以及 Ω i \Omega_i Ωi。然后对 b i \mathbf{b}_i bi 和 Ω i \Omega_i Ωi 里的点都分别增加一个偏移量 Δ x , Δ y , Δ z \Delta{x}, \Delta{y}, \Delta{z} Δx,Δy,Δz。 Δ x , Δ y , Δ z \Delta{x}, \Delta{y}, \Delta{z} Δx,Δy,Δz 是从均值为 0 0 0,标准差为 1.0 1.0 1.0的高斯分布中随机选取的。如果两个边框在做了扰动后,发生了相互碰撞,则回退到原来的情形。因为扰动是独立地作用在每个 ground-truth 框和关联的 LiDAR 点上的,网络可以更有效地学习。
第二种方法就是全局缩放所有的 ground-truth 边框 b i \mathbf{b}_i bi 以及所有的点云 M \mathbf{M} M。将 X Y Z XYZ XYZ 坐标系、 b i \mathbf{b}_i bi 的三个维度以及所有点的坐标都乘以一个来自于 [ 0.95 , 1.05 ] [0.95, 1.05] [0.95,1.05] 均匀分布的随机数。这个增强方法提升了网络的鲁棒性,可以检测不同大小的目标。
最后一个方法就是对所有的 ground-truth 框 b i \mathbf{b}_i bi 和整体点云 M \mathbf{M} M 使用全局旋转。沿着 Z Z Z 轴在原点位置旋转。从均匀分布 [ − π / 4 , + π / 4 ] [-\pi/4, +\pi/4] [−π/4,+π/4] 随机选取全局旋转的偏移量。通过旋转点云,我们可以模拟车辆转弯的样子。