继上节介绍在Autoware平台中实现交通信号灯识别(traffic light recognition)项目,本节将继续针对自动驾驶的应用实例,解析如何利用ENet模型实现场景目标分割(segmentation),主要内容包括ENet模型原理简介和vision_segment_enet_detect代码解读。
ENet模型原理简介
ENet[1]是一种高效、准确的语义分割网络,旨在快速理解图像内容并查找场景目标。相比于其他主流的语义分割方法,其模型结构如下图1所示:
图1 ENet模型结构图
在initial部分只包含单个模块,分别对输入图片进行卷积和最大池化处理,并将结果进行融合(concat),如下图2(a)所示。随后模型结构采用ResNet[2]中的残差思想,共分为五个部分,其中前三部分为编码器结构,而后两部分为解码器结构。
1. 第一部分包含5个bottleneck模块,其中bottleneck的结构如下图2(b)所示:主路径通过MaxPooling进行下采样,同时在shortcut路径上两个1×1卷积进行通道降维,以降低模型参数量。而中间的conv采用步长为2的普通卷积;
2. 第二部分包含9个bottleneck模块,其中在shortcut路径中的conv分别采用步长为2的普通卷积、扩张卷积(dilaetd 2)、不对称卷积(asymmetric 5);
3. 第三部分与第二部分结构基本一致,只是少了bottleneck2.0模块;
4. 第四部分包含3个bottleneck模块,由于该部分属于解码器,因此在shortcut路径中conv采用反卷积结构(upsampling);
5. 第五部分包含2个bottleneck模块,其中模块结构与第四部分保持一致。
图2 ENet中残差结构模块
除了模型结构上的创新,ENet还针对现有语义分割所存在的精度不高、速度不快问题,提出了如下解决方法:
1. 特征图分辨率(feature map resolution)
语义分割过程对图像进行下采样会导致:(1) 特征图分辨率下降,导致部分特征空间信息丢失;(2) 由于语义分割任务需要输入与输出分辨率相同,因此过度下采样会影响目标分割的精度。因此,ENet通过扩张卷积(dilated convolution)来解决这个问题,不仅能够获得更大的感受野,还避免因下采样操作而导致的特征信息丢失问题。
2. 解码器大小(decoder size)
主流的语义分割方法所采用的编-解码器结构通常是对称的,即解码器是编码器的镜像。但这种方法存在一定结构上的冗余,导致模型推理速度变慢。在ENet中采用大编码器-小解码器的结构,通过复杂的编码器结构能够对小分辨率数据特征进行处理,而解码器的作用相当于上采样编码器,用于完善目标细节。如此,能够大大加快ENet模型的分割速度。
3. 分解卷积(factorizing filters)
已有的研究[3]表明:卷积权重有相当的冗余性。而将一个n×n卷积分解为两个串行卷积1×n和n×1,二者的感受野几乎不变,但后者的计算量大大降低。因此,在ENet中bottleneck模块大量采用这种不对称卷积结构,减少网络参数,加快模型推理速度。
此外,ENet模型还引入性能更好的激活函数PReLU[4]、采用Spatial Dropout[5]方法来防止过拟合等,具体方法细节可以参考原论文。总体来说,ENet是一个实时性好、准确度高的语义分割模型,在自动驾驶等领域得以广泛的应用。
vision_segment_enet_detect代码解读
该部分将介绍如何在Autoware中采用ENet模型实现目标分割示例,下面将对分割代码及所需的环境配置进行详细介绍。首先进入src/autoware/core_perception/vision_segment_enet_detect/launch,在vision_segment_enet_detect.launch文件中主要包含参数列表和节点vision_segment_enet_detect信息,如下图3所示。
图3 vision_segment_enet_detect.launch文件信息
ENet Caffe环境配置
在开始这部分代码解读前,首先需要配置ENet Caffe环境,主要包括以下几个步骤:
(1) 进入Caffe[6]官网,进行ubuntu系统的Caffe预编译过程。值得注意的是,ubuntu系统对Caffe框架支持较好,对CPU和GPU两个版本的Caffe都有很好的兼容性;
(2) 将ENet Caffe项目克隆到本地,并根据项目要求进行预编译;
cd ~
git clone --recursive https://github.com/TimoSaemann/ENet.git
cd ENet/caffe-enet
(3) 编译ENet Caffe环境
make && make distribute
(4) (可选) 从ENet Caffe项目中下载预训练模型(https://github.com/TimoSaemann/ENet/tree/master/Tutorial#kick-start),或也可以选择自己训练好的模型。
(5) 一旦编译完成,在终端(terminal)中运行
% roslaunch image_segmenter image_segmenter_enet.launch
值得注意的是,需要将这里network_definition_file和pretrained_model_file与src/autoware/core_perception/vision_segment_enet_detect/launch/vision_segment_enet_detect.launch中相应的地址保持一致。这样,就可以完成ENet Caffe的环境配置。
节点vision_segment_enet_detect
如下图4所示,在src/autoware/core_perception/vision_segment_enet_detect/nodes/vision_segment_enet_detect_node.cpp文件中找到main()函数,其中包括初始化ROS节点参数、调用类方法ROSENetSegmenterApp()并执行Run()方法等操作。
图4 vision_segment_enet_detetct.cpp文件中main()函数参数信息
类方法ROSENetSegmenterApp()
类方法ROSENetSegmenterApp()定义了ENet进行目标分割的具体操作。如下图5所示,首先声明ROS信息收发节点,定义image_callback()方法对图片进行处理,调用Predict()方法预测分割结果并发布。
图5 类方法ROSENetSegmenterApp()参数信息
然后,定义Run()方法,通过判断节点名来确定是否接收相应参数,并初始化ENetSegmenter()方法进行目标分割,最后将分割结果发布,如下图6所示。
图6 Run()方法参数信息
Predict()方法
转到src/autoware/core_perception/vision_segment_enet_detect/nodes/vision_segment_enet_detect.cpp文件,Predict()方法主要用于预测图片分割结果。如下图7所示,首先从caffe Blob文件获取网络输入并调用WrapInputLayer()和Preprocess()方法对输入图片进行处理;然后,将预测结果转换为相应标签信息并调用Visualization()方法对结果进行可视化。
图7 Predict()方法参数信息
WrapInputLayer()方法
WrapInputLayer()方法主要用于对输入通道进行处理,如下图8所示。
图8 WrapInputLayer()方法参数信息
Preprocess()方法
Preprocess()方法主要用于对输入图片的颜色空间、尺寸大小、编码格式进行处理,以适合网络输入的类型,如下图9所示。
图9 Preprocess()方法参数信息
Visualization()方法
Visualization()方法将预测结果进行转换,并结合标签信息可视化分割结果,如下图10所示。
图10 Visualization()方法参数信息
结束语
总的来说,本节内容主要介绍如何在Autoware平台使用ENet实现目标分割。在简单了解ENet模型原理后,配置ENet Caffe环境,并下载相应的网络配置文件和预训练模型。然后,在vision_segment_enet_detect项目中,通过节点vision_segment_enet_detect_node调用ENet模型,并对输入图片进行预处理。最后,可视化ENet模型的分割结果。
参考文献
[1] Paszke, A., Chaurasia, A., Kim, S., et al. ENet: A Deep Neural Network Architecture for Real-time Semantic Segmentation[C]. IEEE Computer Vision and Pattern Recognition, 2016.
[2] He, K. M., Zhang, X. Y., Ren, S. Q., et al. Deep Residual Learning for Image Recognition[C]. IEEE Computer Vision and Pattern Recognition, 2016.
[3] Szegedy, C., Liu, W., Jia, Y. Q., et al. Going Deeper with Convolutions[C]. IEEE Computer Vision and Pattern Recognition, 2015.
[4] He, K.M., Zhang, X.Y., Ren, S.Q., et al. Delving Deep Into Rectifiers: Surpassing Human-level Performance on ImageNet Classification[C]. International Conference on Computer Vision, 2015.
[5] Tompson, J., Goroshin, R., Jain, A., et al. Efficient Object Localization Using Convolutional Networks[C]. IEEE Computer Vision and Pattern Recognition, 2015.