Abstract
在这项工作中,我们消除了对 3D 点云进行手动特征工程的需要,并提出了 VoxelNet,这是一种通用的 3D 检测网络,它将特征提取和边界框预测统一到一个单一的阶段、端到端的可训练深度网络中。
Specifically,VoxelNet 将点云划分为等间距的 3D 体素,并通过新引入的体素特征编码(VFE)层将每个体素内的一组点转换为统一的特征表示。
Introduction
手动设计选择引入了信息瓶颈,阻碍了这些方法有效利用 3D 形状信息和检测任务所需的不变性。图像识别和检测 任务的重大突破是由于从手工制作的特征转向机器学习的特征。
RPN是一种高度优化的算法,用于有效的目标检测,但是这种方法要求数据稠密并以tensor结构组织,但LiDAR点云不是如此。本文缩小了用于3D检测任务的点集特征学习和RPN之间的差距。
VoxelNet以端到端的方式同时从点云中学习特征并预测准确的 3D 边界框。设计了VFE(voxel feature encoding)将逐点特征与局部聚合特征相结合,实现体素内的点间交互。堆叠多个 VFE 层允许学习用于表征局部 3D 形状信息的复杂特征。VoxelNet 将点云划分为等间距的 3D 体素,然后通过VFE对体素编码,然后3D卷积进一步聚合局部体素特征,将点云转换为高维体积表示。最后,RPN 使用体积表示并产生检测结果。
Related Work
当有丰富而详细的 3D 形状信息可用时,这些手工制作的特征会产生令人满意的结果。然而,它们无法适应更复杂的形状和场景,也无法从数据中学习所需的不变性,导致在自主导航等不受控制的场景中成功有限。
鉴于图像提供了详细的纹理信息,许多算法从 2D 图像中推断出 3D 边界框 [4, 3, 42, 43, 44, 36]。然而,基于图像的 3D 检测方法的准确性受限于深度估计的准确性。几种基于 LIDAR 的 3D 对象检测技术利用体素网格表示。 [41, 9] 用 6 个统计量对每个非空体素进行编码,这些统计量源自体素中包含的所有点。 [37]融合了多个局部统计数据来表示每个体素。 [38] 计算体素网格上截断的有符号距离。 [21] 对 3D 体素网格使用二进制编码。[5] 通过计算鸟瞰视图中的多通道特征图和正面视图中的圆柱坐标,引入了 LiDAR 点云的多视图表示。其他几项研究将点云投影到透视图上,然后使用基于图像的特征编码方案 [28、15、22]。还有几种多模态融合方法可以结合图像和激光雷达来提高检测精度[10,16,5]。与仅使用 LiDAR 的 3D 检测相比,这些方法提供了改进的性能,特别是对于小物体(行人、骑自行车的人)或当物体很远时,因为相机提供的测量值比 LiDAR 多一个数量级。然而,对与 LiDAR 时间同步和校准的附加相机的需求限制了它们的使用,并使解决方案对传感器故障模式更加敏感。在这项工作中,我们专注于仅 LiDAR 检测。
Contributions
- 端到端,直接使用点云,避免人工特征工程引入带来的信息瓶颈。(information bottlenecks introduced by manual feature)
- 可以高效并行处理
VoxelNet Architecture
VoxelNet 由三个功能块组成:(1)特征学习网络,(2)卷积中间层,(3)区域提议网络
Voxel Partition
(实际上不是这么弄的,而是遍历点云加入到对应的voxel中的)
假设点云包含 3D 空间,范围 D、H、W 分别沿 Z、Y、X 轴,我们相应地定义每个体素大小为vD、vH、vW。各个方向上生成的 3D 体素网格的大小为 D’ = D/vD,H’ = H/vH ,W’ = W/vW (The resulting 3D voxel grid is of size)。这里,为简单起见,我们假设 D、H、W 是 vD、vH、vW 的倍数。
Grouping
我们根据点所在的体素进行分组。由于距离、遮挡、对象的相对姿态和非均匀采样等因素,点云是稀疏的,并且在整个空间中具有高度可变的点密度。因此,分组后,一个体素将包含可变数量的点。
Random Sampling
在每个Voxel内随机选T个点,这样(1)节省计算量; (2) 减少体素之间的点不平衡,从而减少采样偏差,并为训练增加更多变化。
Stacked Voxel Feature Encoding
首先计算每个Voxel的均值(vx,vy,vz),然后计算每个点+到中心点距离作为输入特征:
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}={\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}_{i=1...t}
Vin=pi^=[xi,yi,zi,ri,xi−vx,yi−vy,zi−vz]T∈R7i=1...t
然后每个点的特征经过FCN特征变换来得到高维表示f_i,对体素中包含的表面形状进行编码。然后通过max函数对每个Voxel的特征点进行聚合。maxpooling all f_i to V,得到
f
^
作
为
这
个
V
o
x
e
l
的
特
征
\hat{f}作为这个Voxel的特征
f^作为这个Voxel的特征
然后concat每个f_i和\hat{f}得到f_{out}
f
o
u
t
=
[
f
i
T
,
f
T
^
]
f_{out}=[f_i^T,\hat{f^T}]
fout=[fiT,fT^]
因为输出特征结合了逐点特征和局部聚合特征,堆叠 VFE 层对体素内的点交互进行编码,并使最终特征表示能够学习形状信息(这种描述可能是不够的)。然后在做Voxel-wise Feature,通过一个FCN+maxpooling,将一个Voxel的特征聚合成一个向量。
Sparse Tensor Representation
通过上述流程处理非空体素格,我们可以得到一系列的体素特征(Voxel Feature)。这一系列的体素特征可以使用一个4维的稀疏张量来表示:C ×D′ ×H′ ×W′,其中后面的是提速格的数量。虽然一次lidar扫描包含接近10万个点,但是超过90%的体素格都是空的,使用稀疏张量来描述非空体素格在于能够降低反向传播时的内存和计算消耗。
Convolutional Middle Layers
3D卷积层
C
o
n
v
M
D
(
c
i
n
,
c
o
u
t
,
k
,
s
,
p
)
ConvMD(c_{in},c_{out},k,s,p)
ConvMD(cin,cout,k,s,p)
k是卷积核大小(3维的),s是stride,p是padding。
作用:聚合体素特征
Region Proposal Network
我们的 RPN 的输入是卷积中间层提供的特征图,该网络具有三个完全卷积层块。每个块的第一层通过步长为 2 的卷积将特征图下采样一半,然后是步长为 1 的卷积序列,在每个卷积层之后,应用 BN 和 ReLU 操作。然后我们将每个块的输出上采样到固定大小并连接以构建高分辨率特征图。最后,将该特征图映射到所需的学习目标:(1)概率分数和回归。(我觉得这个RPN就是一个U-net,拿ground truth做的)
Loss Function
首先定义正负样本
{
a
i
p
o
s
}
i
=
1...
N
p
o
s
\{a_{i}^{pos}\}_{i=1...N_{pos}}
{aipos}i=1...Npos
负样本
{
a
i
n
e
g
}
i
=
1...
N
n
e
g
\{a_{i}^{neg}\}_{i=1...N_{neg}}
{aineg}i=1...Nneg
3D ground truth box
(
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
是
长
宽
高
,
θ
g
是
偏
离
Z
轴
的
角
度
(x^g_c ,y^g_c ,z^g_c ,l_g,w_g,h_g,θ_g),其中x^g_c ,y^g_c,z^g_c代表中心点,l_g,w_g,h_g是长宽高,θ_g是偏离Z轴的角度
(xcg,ycg,zcg,lg,wg,hg,θg),其中xcg,ycg,zcg代表中心点,lg,wg,hg是长宽高,θg是偏离Z轴的角度
相应的正样本框:
(
x
c
a
,
y
c
a
,
z
c
a
,
l
a
,
w
a
,
h
a
,
θ
a
)
(x^a_c ,y^a_c ,z^a_c ,l_a,w_a,h_a,θ_a)
(xca,yca,zca,la,wa,ha,θa)
回归的目标为以下七个量:
其中
d
a
=
(
l
a
)
2
+
(
w
a
)
2
d^a = \sqrt{(l^a)^2 + (w^a)^2}
da=(la)2+(wa)2
是anchor底部的对角线,这里,我们的目标是直接估计定向的 3D 框,并使用对角线 da 均匀地归一化 Δx 和 Δy,定义损失函数如下:
p
i
p
o
s
是
S
o
f
t
m
a
x
(
a
i
p
o
s
)
,
p
i
n
e
g
是
S
o
f
t
m
a
x
(
a
i
n
e
g
)
,
u
i
和
u
∗
是
正
样
本
输
出
的
标
注
框
和
真
实
标
注
框
。
p_i^{pos}是Softmax(a_i^{pos}),p_i^{neg}是Softmax(a_i^{neg}),u_i和u^*是正样本输出的标注框和真实标注框。
pipos是Softmax(aipos),pineg是Softmax(aineg),ui和u∗是正样本输出的标注框和真实标注框。
损失函数的前两项表示对于正样本输出和负样本输出的分类损失(已经进行了正规化),其中L_cls表示交叉熵损失函数。α和β是两个常数,它们作为权重来平衡正负样本损失对于最后的损失函数的影响。L_reg表示回归损失,这里采用的是Smooth L1函数。
Efficient Implementation
在实际计算时,是通过遍历的方式读的点,创建的体素。并存储相应的坐标。去除点少的voxel。卷积中间层和 RPN 操作在密集体素网格上工作,可以在 GPU 上有效实现。
Training Details
Car Detection
Z轴:[−3,1]
Y轴:[−40,40]
X轴:[0,70.4]
超过范围的remove掉。
我们选择 vD = 0.4,vH = 0.2,vW = 0.2 米的体素大小,所以每个方向上的格子数量:D’ = 10, H’ = 400, W’ = 352。
每个Voxel内的点数量:T = 35
经过两层VFS后,张量大小: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))
这会产生一个大小为 64 ×2 ×400 ×352 的 4D 张量64 × 2 × 400 × 352,然后reshape下,
RPN 的输入是一个大小为 128×400×352 的特征图,其中尺寸对应于 3D 张量的通道、高度和宽度。
和【Multi-view 3d 2017】不同,我只使用一个anchor尺寸:l = 3.9 w = 1.6 h = 1.56 z_c = −1.0 rotations=0,90
在BEV视角下下,正样本:最高,或IoU>0.6;负样本:IoU<0.45,中间的不关心。正负样本的权重α = 1.5(正),β = 1(负)
Pedestrian and Cyclist Detection
Z: [−3,1]
Y:[−20,20]
X:[0,48]
我们使用与汽车检测相同的体素大小,得到 D = 10,H = 200,W = 240。
每个Voxel内的点数量:T = 45,以获得更多的 LiDAR 点以更好地捕获形状信息。特征学习网络和卷积中间层与汽车检测任务中使用的网络相同。
对于 RPN,我们通过将第一个 2D 卷积中的步幅大小从 2 更改为 1 对图 4 中的块 1 进行了修改。这允许更精细的锚匹配分辨率,这对于检测行人和骑自行车的人是必要的。
使用锚尺寸 l = 0.8 w = 0.6 h = 1.73 米,以 z = -0.6 米为中心,旋转 0 度和 90 度用于行人检测
使用锚尺寸 l = 1.76 w = 0.6 h = 1.73 米,以 z = -0.6 为中心,旋转 0 度和 90 度以检测骑车人
在BEV视角下下,正样本:最高,或IoU>0.5;负样本:IoU<0.35,中间的不关心。权重没说。
SGD
160epoch:150 个 epoch 的学习率为 0.01,最后 10 个 epoch 的学习率降低到 0.001
batch-size:16
Data Augmentation
引入了三种不同形式的数据增强。增强的训练数据是即时生成的,无需存储在磁盘上【引用了Imagenet
classification with deep convolutional neural networks】
-
将扰动独立地应用于每个地面实况 3D 边界框以及框内的那些 LiDAR 点。沿Z轴随机添加独立扰动。由于扰动独立地应用于每个地面实况框和相关的 LiDAR 点,因此网络能够从比原始训练数据更多的变化中学习。
-
我们将全局缩放应用于所有真实框 bi 和整个点云 M。具体来说,我们将 XYZ 坐标和每个 bi 的三个维度以及 M 中所有点的 XYZ 坐标与一个随机变量相乘从均匀分布 [0.95,1.05] 中提取。引入全局尺度增强提高了网络检测具有各种大小和距离的对象的鲁棒性。
-
我们将全局旋转应用于所有ground-truth框 bi 和整个点云 M。旋转沿 Z 轴和 (0,0,0) 周围应用。全局旋转偏移是通过从均匀分布 [−π/4,+π/4] 中采样确定的。通过旋转整个点云,我们模拟车辆转弯。
Experiments
用KITTI数据集,由于测试集得传服务器上测,他们就把训练集拆了。
这里还有些问题,尤其是RPN讲的不清。代码中RPN是在2D BEV视角下训练的。