0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

一种基于点云的Voxel(三维体素)特征的深度学习方法

电子工程师 来源:lq 2018-12-07 09:32 次阅读

兰州大学在读硕士研究生,主要研究方向无人驾驶深度学习;兰大未来计算研究院无人车团队负责人,自动驾驶全栈工程师

之前我们提到使用SqueezeSeg进行了三维点云的分割,由于采用的是SqueezeNet作为特征提取网络,该方法的处理速度相当迅速(在单GPU加速的情况下可达到100FPS以上的效率),然而,该方法存在如下的问题:

第一,虽然采用了CRF改进边界模糊的问题,但是从实践结果来看,其分割的精度仍然偏低;

第二,该模型需要大量的训练集,而语义分割数据集标注困难,很难获得大规模的数据集。当然,作者在其后的文章:SqueezeSegV2: Improved Model Structure and Unsupervised Domain Adaptation for Road-Object Segmentation from a LiDAR Point Cloud 中给出了改进的方案,我将在后面的文章中继续解读。需要注意的是,在无人车环境感知问题中,很多情况下并不需要对目标进行精确的语义分割,只需将目标以一个三维的Bounding Box准确框出即可(即Detection)。

本文介绍一种基于点云的Voxel(三维体素)特征的深度学习方法,实现对点云中目标的准确检测,并提供一个简单的ROS实现,供大家参考。

VoxelNet结构

VoxelNet是一个端到端的点云目标检测网络,和图像视觉中的深度学习方法一样,其不需要人为设计的目标特征,通过大量的训练数据集,即可学习到对应的目标的特征,从而检测出点云中的目标,如下:

VoxelNet的网络结构主要包含三个功能模块:

(1)特征学习层;

(2)卷积中间层;

(3) 区域提出网络( Region Proposal Network,RPN)。

特征学习网络

特征学习网络的结构如下图所示,包括体素分块(Voxel Partition),点云分组(Grouping),随机采样(Random Sampling),多层的体素特征编码(Stacked Voxel Feature Encoding),稀疏张量表示(Sparse Tensor Representation)等步骤,具体来说:

体素分块

这是点云操作里最常见的处理,对于输入点云,使用相同尺寸的立方体对其进行划分,我们使用一个深度、高度和宽度分别为(D,H,W)的大立方体表示输入点云,每个体素的深高宽为(vD,vH,vW) ,则整个数据的三维体素化的结果在各个坐标上生成的体素格(voxel grid)的个数为:

点云分组

将点云按照上一步分出来的体素格进行分组,如上图所示。

随机采样

很显然,按照这种方法分组出来的单元会存在有些体素格点很多,有些格子点很少的情况,64线的激光雷达一次扫描包含差不多10万个点,全部处理需要的计算力和内存都很高,而且高密度的点势必会给神经网络的计算结果带来偏差。所以,该方法在这里插入了一层随机采样,对于每一个体素格,随机采样固定数目的点,T 。

多个体素特征编码(Voxel Feature Encoding,VFE)层

之后是多个体素特征编码层,简称为VFE层,这是特征学习的主要网络结构,以第一个VFE层为例说明:

对于输入:

是一个体素格内随机采样的点集,分别点的XYZ坐标以及激光束的反射强度(即intensity),我们首先计算体素内所有点的平均值 (vx,vy,vz) 作为体素格的形心(类似于Voxel Grid Filter),那么我们就可以将体素格内所有点的特征数量扩充为如下形式:

接着,每一个都会通过一个全连接网络(Fully Connected,FC,论文中用的是FCN来简称,实际上FCN更多的被用于表示全卷积网络,所以原文此处用FCN简称实际上不妥)被映射到一个特征空间,输入的特征维度为7,输出的特征维数变成m mm,全连接层包含了一个线性映射层,一个批标准化(Batch Normalization),以及一个非线性运算(ReLU),得到逐点的(point-wise)的特征表示。

接着我们采用最大池化(MaxPooling)对上一步得到的特征表示进行逐元素的聚合,这一池化操作是对元素和元素之间进行的,得到局部聚合特征(Locally Aggregated Feature),即 ,最后,将逐点特征和逐元素特征进行连接(concatenate),得到输出的特征集合:

对于所有的非空的体素格我们都进行上述操作,并且它们都共享全连接层(FC)的参数。我们使用符号来描述经过VFE以后特征的维数变化,那么显然全连接层的参数矩阵大小为:

由于VFE层中包含了逐点特征和逐元素特征的连接,经过多层VFE以后,我们希望网络可以自动学习到每个体素内的特征表示(比如说体素格内的形状信),那么如何学习体素内的特征表示呢?原论文的方法下图所示:

通过对体素格内所有点进行最大池化,得到一个体素格内特征表示 C 。

稀疏张量表示

通过上述流程处理非空体素格,我们可以得到一系列的体素特征(Voxel Feature)。这一系列的体素特征可以使用一个4维的稀疏张量来表示:

虽然一次lidar扫描包含接近10万个点,但是超过90%的体素格都是空的,使用稀疏张量来描述非空体素格在于能够降低反向传播时的内存和计算消耗。

对于具体的车辆检测问题,我们取沿着Lidar坐标系的(Z,Y,X) (Z,Y,X)(Z,Y,X)方向取[−3,1]×[−40,40]×[0,70.4] [−3, 1] × [−40, 40] × [0, 70.4][−3,1]×[−40,40]×[0,70.4]立方体(单位为米)作为输入点云,取体素格的大小为:

那么有

我们设置随机采样的T=35 T = 35T=35,并且采用两个VFE层:VFE-1(7, 32) 和 VFE-2(32, 128),最后的全连接层将VFE-2的输出映射到 。最后,特征学习网络的输出即为一个尺寸为 (128×10×400×352) 的稀疏张量。整个特征网络的TensorFlow实现代码如下:

classVFELayer(object):def__init__(self,out_channels,name):super(VFELayer,self).__init__()self.units=int(out_channels/2)withtf.variable_scope(name,reuse=tf.AUTO_REUSE)asscope:self.dense=tf.layers.Dense(self.units,tf.nn.relu,name='dense',_reuse=tf.AUTO_REUSE,_scope=scope)self.batch_norm=tf.layers.BatchNormalization(name='batch_norm',fused=True,_reuse=tf.AUTO_REUSE,_scope=scope)defapply(self,inputs,mask,training):#[K,T,7]tensordot[7,units]=[K,T,units]pointwise=self.batch_norm.apply(self.dense.apply(inputs),training)#n[K,1,units]aggregated=tf.reduce_max(pointwise,axis=1,keep_dims=True)#[K,T,units]repeated=tf.tile(aggregated,[1,cfg.VOXEL_POINT_COUNT,1])#[K,T,2*units]concatenated=tf.concat([pointwise,repeated],axis=2)mask=tf.tile(mask,[1,1,2*self.units])concatenated=tf.multiply(concatenated,tf.cast(mask,tf.float32))returnconcatenatedclassFeatureNet(object):def__init__(self,training,batch_size,name=''):super(FeatureNet,self).__init__()self.training=training#scalarself.batch_size=batch_size#[ΣK,35/45,7]self.feature=tf.placeholder(tf.float32,[None,cfg.VOXEL_POINT_COUNT,7],name='feature')#[ΣK]self.number=tf.placeholder(tf.int64,[None],name='number')#[ΣK,4],eachrowstores(batch,d,h,w)self.coordinate=tf.placeholder(tf.int64,[None,4],name='coordinate')withtf.variable_scope(name,reuse=tf.AUTO_REUSE)asscope:self.vfe1=VFELayer(32,'VFE-1')self.vfe2=VFELayer(128,'VFE-2')#booleanmask[K,T,2*units]mask=tf.not_equal(tf.reduce_max(self.feature,axis=2,keep_dims=True),0)x=self.vfe1.apply(self.feature,mask,self.training)x=self.vfe2.apply(x,mask,self.training)#[ΣK,128]voxelwise=tf.reduce_max(x,axis=1)#car:[N*10*400*352*128]#pedestrian/cyclist:[N*10*200*240*128]self.outputs=tf.scatter_nd(self.coordinate,voxelwise,[self.batch_size,10,cfg.INPUT_HEIGHT,cfg.INPUT_WIDTH,128])

卷积中间层

每一个卷积中间层包含一个3维卷积,一个BN层(批标准化),一个非线性层(ReLU),我们用:

来描述一个卷积中间层,Conv3D表示是三维卷积,cin,cout分别表示输入和输出的通道数,k是卷积核的大小,它是一个向量,对于三维卷积而言,卷积核的大小为(k,k,k);s即stride,卷积操作的步长;p即padding,填充的尺寸。

对于车辆检测而言,设计的卷积中间层如下:

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))

卷积中间层的TensorFlow代码如下:

defConvMD(M,Cin,Cout,k,s,p,input,training=True,activation=True,bn=True,name='conv'):temp_p=np.array(p)temp_p=np.lib.pad(temp_p,(1,1),'constant',constant_values=(0,0))withtf.variable_scope(name)asscope:if(M==2):paddings=(np.array(temp_p)).repeat(2).reshape(4,2)pad=tf.pad(input,paddings,"CONSTANT")temp_conv=tf.layers.conv2d(pad,Cout,k,strides=s,padding="valid",reuse=tf.AUTO_REUSE,name=scope)if(M==3):paddings=(np.array(temp_p)).repeat(2).reshape(5,2)pad=tf.pad(input,paddings,"CONSTANT")temp_conv=tf.layers.conv3d(pad,Cout,k,strides=s,padding="valid",reuse=tf.AUTO_REUSE,name=scope)ifbn:temp_conv=tf.layers.batch_normalization(temp_conv,axis=-1,fused=True,training=training,reuse=tf.AUTO_REUSE,name=scope)ifactivation:returntf.nn.relu(temp_conv)else:returntemp_conv#convolutinalmiddlelayerstemp_conv=ConvMD(3,128,64,3,(2,1,1),(1,1,1),self.input,name='conv1')temp_conv=ConvMD(3,64,64,3,(1,1,1),(0,1,1),temp_conv,name='conv2')temp_conv=ConvMD(3,64,64,3,(2,1,1),(1,1,1),temp_conv,name='conv3')temp_conv=tf.transpose(temp_conv,perm=[0,2,3,4,1])temp_conv=tf.reshape(temp_conv,[-1,cfg.INPUT_HEIGHT,cfg.INPUT_WIDTH,128])

区域提出网络(RPN)

RPN实际上是目标检测网络中常用的一种网络,下图是VoxelNet中使用的RPN:

如图所示,该网络包含三个全卷积层块(Block),每个块的第一层通过步长为2的卷积将特征图采样为一半,之后是三个步长为1的卷积层,每个卷积层都包含BN层和ReLU操作。将每一个块的输出都上采样到一个固定的尺寸并串联构造高分辨率的特征图。最后,该特征图通过两种二维卷积被输出到期望的学习目标:

概率评分图(Probability Score Map )

回归图(Regression Map)

使用TensorFlow实现该RPN如下(非完整代码,完整代码请见文末链接)):

defDeconv2D(Cin,Cout,k,s,p,input,training=True,bn=True,name='deconv'):temp_p=np.array(p)temp_p=np.lib.pad(temp_p,(1,1),'constant',constant_values=(0,0))paddings=(np.array(temp_p)).repeat(2).reshape(4,2)pad=tf.pad(input,paddings,"CONSTANT")withtf.variable_scope(name)asscope:temp_conv=tf.layers.conv2d_transpose(pad,Cout,k,strides=s,padding="SAME",reuse=tf.AUTO_REUSE,name=scope)ifbn:temp_conv=tf.layers.batch_normalization(temp_conv,axis=-1,fused=True,training=training,reuse=tf.AUTO_REUSE,name=scope)returntf.nn.relu(temp_conv)#rpn#block1:temp_conv=ConvMD(2,128,128,3,(2,2),(1,1),temp_conv,training=self.training,name='conv4')temp_conv=ConvMD(2,128,128,3,(1,1),(1,1),temp_conv,training=self.training,name='conv5')temp_conv=ConvMD(2,128,128,3,(1,1),(1,1),temp_conv,training=self.training,name='conv6')temp_conv=ConvMD(2,128,128,3,(1,1),(1,1),temp_conv,training=self.training,name='conv7')deconv1=Deconv2D(128,256,3,(1,1),(0,0),temp_conv,training=self.training,name='deconv1')#block2:temp_conv=ConvMD(2,128,128,3,(2,2),(1,1),temp_conv,training=self.training,name='conv8')temp_conv=ConvMD(2,128,128,3,(1,1),(1,1),temp_conv,training=self.training,name='conv9')temp_conv=ConvMD(2,128,128,3,(1,1),(1,1),temp_conv,training=self.training,name='conv10')temp_conv=ConvMD(2,128,128,3,(1,1),(1,1),temp_conv,training=self.training,name='conv11')temp_conv=ConvMD(2,128,128,3,(1,1),(1,1),temp_conv,training=self.training,name='conv12')temp_conv=ConvMD(2,128,128,3,(1,1),(1,1),temp_conv,training=self.training,name='conv13')deconv2=Deconv2D(128,256,2,(2,2),(0,0),temp_conv,training=self.training,name='deconv2')#block3:temp_conv=ConvMD(2,128,256,3,(2,2),(1,1),temp_conv,training=self.training,name='conv14')temp_conv=ConvMD(2,256,256,3,(1,1),(1,1),temp_conv,training=self.training,name='conv15')temp_conv=ConvMD(2,256,256,3,(1,1),(1,1),temp_conv,training=self.training,name='conv16')temp_conv=ConvMD(2,256,256,3,(1,1),(1,1),temp_conv,training=self.training,name='conv17')temp_conv=ConvMD(2,256,256,3,(1,1),(1,1),temp_conv,training=self.training,name='conv18')temp_conv=ConvMD(2,256,256,3,(1,1),(1,1),temp_conv,training=self.training,name='conv19')deconv3=Deconv2D(256,256,4,(4,4),(0,0),temp_conv,training=self.training,name='deconv3')#final:temp_conv=tf.concat([deconv3,deconv2,deconv1],-1)#Probabilityscoremap,scale=[None,200/100,176/120,2]p_map=ConvMD(2,768,2,1,(1,1),(0,0),temp_conv,training=self.training,activation=False,bn=False,name='conv20')#Regression(residual)map,scale=[None,200/100,176/120,14]r_map=ConvMD(2,768,14,1,(1,1),(0,0),temp_conv,training=self.training,activation=False,bn=False,name='conv21')

损失函数

我们首先定义为正样本集合,为负样本集合,使用来表示一个真实的3D标注框,其中

表示标注框中心的坐标,表示标注框的长宽高,表示偏航角(Yaw)。相应的,表示正样本框。那么回归的目标为一下七个量:

其中

是正样本框的对角线。我们定义损失函数为:

其中分别表示正样本和负样本的Softmax输出,分别表示神经网络的正样本输出的标注框和真实标注框。损失函数的前两项表示对于正样本输出和负样本输出的分类损失(已经进行了正规化),其中表示交叉熵,是两个常数,它们作为权重来平衡正负样本损失对于最后的损失函数的影响。表示回归损失,这里采用的是Smooth L1函数。

ROS实践

我们仍然使用第二十六篇博客的数据(截取自KITTI),下载地址:https://pan.baidu.com/s/1kxZxrjGHDmTt-9QRMd_kOA

我们直接采用qianguih提供的训练好的模型(参考:https://github.com/qianguih/voxelnet ,大家也可以基于该项目自己训练模型)。

安装项目依赖环境:

python3.5+

TensorFlow (tested on 1.4)

opencv

shapely

numba

easydict

ROS

jsk package

准备数据

下载上面的数据集,解压到项目(源码地址见文末)的data文件夹下,目录结构为:

data----lidar_2d--------0000...1.npy--------0000...2.npy--------.......

运行

catkin_make

roscd voxelnet/script/

python3 voxelnet_ros.py & python3 pub_kitti_point_cloud.py

注意不能使用rosrun,因为VoxelNet代码为Python 3.x

rqt节点图

使用Rviz可视化

存在的问题

实例的模型的性能不佳,由于论文作者没有开源其代码,许多参数仍然有待调整

调整速度慢,没有实现作者提出的高效策略

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 数据集
    +关注

    关注

    4

    文章

    1179

    浏览量

    24356
  • 深度学习
    +关注

    关注

    73

    文章

    5239

    浏览量

    119922

原文标题:无人驾驶汽车系统入门:基于VoxelNet的激光雷达点云车辆检测及ROS实现

文章出处:【微信号:rgznai100,微信公众号:rgznai100】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    基于深度学习三维点云配准方法

    基于深度学习三维点云配准方法成为研究的主流,并随之诞生了DeepVCP、DGR、Predator等著名的方法
    发表于 11-29 11:41 1403次阅读

    [原创]GOCAD 2009 完整版功能强大的三维地质建模软件

    性质的单位。GOCAD技术研究联合体经过十多年的共同攻关,于1997年正式推出了采用独特专利技术的勘探开发一体三维综合地质建模及虚拟现实技术软件---GOCAD!3、GOCAD软件综合建模技术特色要
    发表于 10-30 16:54

    如何运用LabVIEW中的三维控件

    如何运用LabVIEW中的三维控件?我想将excel中的数据在LabVIEW中显示出来,显现出三维定点的效果
    发表于 05-15 16:28

    基于安芯号SLH89F5162的真三维立体图形显示

    Display,也称为显示),其中全息三维显示和显示属于真三维显示技术。全息三维显示在动态显示方面需要高分辨的、高速的空间光调制器,目
    发表于 10-19 15:16

    精密铸造+三维扫描=机械制造完美解决方案

    再加工的工作量。铸件和模具偏差比较是精密铸造的重点和难点所在,传统的检测方法很难精确地测量复杂精密的铸件和模具的偏差值,因此,一种高效精确的三维检测方式对机械制造业的意义非常重大。激光三维
    发表于 08-09 11:17

    三维快速建模技术与三维扫描建模的应用

    的HANDYSCAN三维激光扫描仪采集它的三维信息,然后利用Vxelements软件对多站式
    发表于 08-07 11:14

    基于stm32f4的三维旋转显示平台设计资料(原理图、代码)

    现实的世界是个拥有宽度、高度和深度三维立体世界。在平面二显示技术已经成熟的今天,三维立体显示技术首当其冲的成为了当今显示技术领域的研究
    发表于 08-30 14:42

    AI工程师 10 个深度学习方法

    Machines) 针对波兹曼机提出了一种新的学习算法,其中包含许多隐藏层。Stanford 和 Google 2012年联合发表的文章《使用大规模非监督学习构建高层特征》(Buil
    发表于 03-07 20:17

    三维设计应用案例

    CAD是目前工业制造产品设计的重要软件之,广泛应用于机械、建筑等领域。而常用的CAD软件,也就是所谓的三维制图软件,较二的图纸和二的绘图软件,
    发表于 07-03 07:06

    广西北海三维动画制作在虚拟校园中的应用

    广西钦州三维动画制作,在虚拟校园中的相关研究。虚拟现实技术又称灵境技术,简称VR技术。是20世纪发展起来的项全新的实用技术,虚拟现实技术囊括计算机、电子信息、仿真技术于一体,其基本实现方式是在
    发表于 03-15 09:24

    如何去开发一种基于LabVIEW的三维显示系统?

    如何去开发一种基于LabVIEW的三维显示系统?
    发表于 06-01 06:50

    怎样去设计一种基于RGB-D相机的三维重建无序抓取系统?

    为什么要开发一种三维重建无序抓取系统?三维重建无序抓取系统是由哪些部分组成的?三维重建无序抓取系统有哪些关键技术和创新
    发表于 07-02 06:29

    如何去实现一种基于STM32的三维旋转显示平台设计呢

    如何去实现一种基于STM32的三维旋转显示平台设计呢?怎样去设计一种基于STM32F4的四轴航拍飞行器呢?
    发表于 11-11 07:54

    深度学习技术的开发与应用

    :OpenAI Gym实践1.Gym安装2.Gym使用3.强化学习高频问题:1.如何基于Gym实现强化学习训练与测试关键:1.掌握马尔可夫决策过程 2.低输入的强化
    发表于 04-21 14:57

    模型驱动深度学习的标准流程与学习方法解析

    模型驱动的深度学习方法近年来,深度学习在人工智能领域一系列困难问题上取得了突破性成功应用。
    的头像 发表于 01-24 11:30 4650次阅读
    模型驱动<b class='flag-5'>深度</b><b class='flag-5'>学习</b>的标准流程与<b class='flag-5'>学习方法</b>解析