Segnet: 一种用于图像分割的深度卷积编码-解码架构

摘要

我们展示了一种新奇的有实践意义的深度全卷积神经网络结构,用于逐个像素的语义分割,并命名为SegNet.核心的可训练的分割引擎包含一个编码网络,和一个对应的解码网络,并跟随着一个像素级别的分类层.编码器网络的架构在拓扑上与VGG16网络中的13个卷积层相同.解码网络的角色是映射低分辨率的编码后的特征图到输入分辨率的特征图.具体地,解码器使用在相应编码器的最大合并步骤中计算的池化索引来执行非线性上采样.这消除了上采样的学习需要.上采样后的图是稀疏的,然后与可训练的滤波器卷积以产生密集的特征图.我们把我们提出的架构和广泛采用的FCN架构和众所周知的DeepLab-LargeFOV、DeconvNet架构做了比较,这种比较揭示了实现良好分割性能的内存与准确性的权衡。

SegNet的主要动机是场景理解应用.因此,它在设计的时候保证在预测期间,内存和计算时间上保证效率.在可训练参数的数量上和其他计算架构相比也显得更小,并且可以使用随机梯度下降进行端到端的训练.我们还在道路场景和SUN RGB-D室内场景分割任务中执行了SegNet和其他架构的受控基准测试.这些定量的评估表明,SegNet在和其他架构的比较上,提供了有竞争力的推断时间和最高效的推理内存。

1 介绍

语义分割具有广泛的应用范围,从场景理解,推断对象之间的支持关系到自主驾驶.依靠低级别视觉线索的早期方法已经被流行的机器学习算法所取代.特别的,深度学习后来在手写数字识别、语音、整图分类以及图片中的检测上都取得了成功[VGG][GoogLeNet].现在图像分割领域也对这个方法很感兴趣[crfasrnn][parsent]等.然而,近来的很多方法的都尽力直接采用设计来图像分类的方法进行语义分割.结果虽然令人鼓舞,但是比较粗糙[deeplab].这主要是因为max-pooling和sub-sampling减少了特征图的分辨率.我们设计SegNet的动机就是来自于对于为了语义分割而从低分辨率的特征图到输入分辨率映射的需要.这种映射也必须产生一些特征用于精确地边界定位.
我们的架构,SegNet,设计的目的是作为一种高效的语义分割架构.它主要是由道路现场理解应用的动机,需要建模外观(道路,建筑物),形状(汽车,行人)的能力,并了解不同类别(如道路和侧面行走)之间的空间关系(上下文).在典型的道路场景中,大多数像素属于大型类,如道路,建筑物,因此网络必须产生平滑的分段.引擎还必须具有根据其形状来描绘对象的能力,尽管它们的尺寸很小.因此,在提取的图像表示中保留边界信息是重要的.从计算的角度来看,在推理过程中,网络需要保证在内存和计算时间两方面都是高效的.进行端到端的训练为了使用诸如随机梯度下降(SGD)之类的有效的权重更新技术来联合优化网络中所有权重的能力是一个额外的好处,因为它更容易重复.SegNet的设计源于需要符合这些标准.

SegNet中的编码网络和VGG16的卷积层是拓扑上相同的.我们移除了全连接层,这样可以使SegNet比其他许多近来的结构[FCN][DeconvNet][ParseNet][Decoupled]显著的小并且训练起来更容易.SegNet的关键部件是解码器网络,由一个对应于每个编码器的解码器层次组成.其中,解码器使用从相应的编码器接受的max-pooling indices来进行输入特征图的非线性upsampling.这个想法来自设计用于无监督功能学习的架构.在解码网络中重用max-pooling indics有多个实践好处:(1)它改进了边界划分(2)减少了实现端到端训练的参数数量(3)这种upsampling的形式可以仅需要少量的修改而合并到任何编码-解码形式的架构[FCN][crfasrnn].

这篇论文的一个主要贡献是,我们对Segnet解码技术和广泛使用的FCN的分析.这是为了传达在设计分割架构中的实际权衡.近来许多分割的深度架构使用相同的编码网络,例如VGG16,但是在解码网络的形式、训练和推理上是不同的.另一个常见的特点是,这些网络通常有亿级别的训练参数,从而导致端到端的训练很困难[DeconvNet].训练困难导致了多阶段的训练[FCN],或者添加一个与训练的网络结构如FCN[crfasrnn],或者用辅助支持,例如在推理阶段使用区域proposals[DeconvNet],或者使用分类和分割网络的不相交训练[Decoupled],或者用额外的数据进行与训练[Parsenet]或者全训练[crfasrnn].另外,性能提升后处理技术也受到欢迎.尽管这些因素都很好的提高了在voc上的性能,但是他们的定量结果难以解决实现良好性能所必需的关键设计因素.因此我们分析了被用在这些方法[FCN][DeconvNet]中的解码过程,并揭示了他们的优点和缺陷.

我们评估了SegNet在两种场景分割任务中的性能,分别是CamVid道路场景分割和SUN RGB-D室内场景分割.VOC12在过去很多年都有分割的居基准挑战.但是,这个任务的大部分都有一个或两个由高度多样的背景包围的前景类.这隐含地有利于用于检测的技术,如最近关于解耦分类分割网络的工作所示[Decoupled],其中分类网络可以用大量弱标签数据进行训练,并且独立分割网络性能得到改善.[deeplab]的方法还使用分类网络的特征图和独立的CRF后处理技术来执行分割.性能也可以通过额外的推理辅助来增强,例如区域proposals[DeconvNet][Edge Boxes].因此,因此,它与场景理解不同之处在于,其目的是利用对象的共同出现以及其他空间上下文来执行可靠的分割.为了证明SegNet的高效性,我们展示了一个实时的道路场景分割的在线demo,来分割11类的自主驾驶兴趣类(如图1所示).图1中展示了从Google中找的一些随机道路图片和SUNRGB-D中产生的一些随机室内测试场景图片的分割结果.。

逐像素的semantic segmentation是目前比较活跃的一个研究热点。在深度网络出现之前,效果比较好的方法有随机数,boosting等。而目前比较热门的语义分割结构有:U-Net、SegNet、DeepLab、FCN、ENet、LinkNet等等。这篇文章主要介绍SegNet的结构和tensorflow实现以及对应的CamVid数据集的使用方法。

SetNet是由Vijay、Alex等人发表在IEEE上的一种deep convolutional encoder-decoder 结构的图像分割方法。该分割的核心训练部分包含一个encoder network,一个相对应的decoder network,最后是一个逐像素的分类层。其中encoder network使用的是VGG16中的前13层卷积网络结构,只是添加了少许改动。decoder network的作用在于将原图像经由encoder network计算出的feature maps从低分辨率映射到和原图尺寸一致的分辨率以便于做逐像素的分类处理。而SegNet的创新就在于其decoder net对低分辨率的feature map(s)做上采样(upsample)的一个设计。其方法是,在encoder的每一个max-pooling过程中保存其池化索引(最大值的index),在decoder层使用这些得到的索引来做非线性上采样。这些经过上采样的特征图是稀疏的,再对其做可训练的卷积操作产生密集feature maps,最后将其送入multi-class softmax分类器中进行分类。 原文中作者将其与FCN、Deeplab、DeconvNet做了一个比较,有兴趣的可以看看论文。

下图为SegNet的结构图,从图来看,我们可以将其做成end-to-end的结构。

编码-译码架构

这样的对称结构有种自编码器的感觉在里面,先编码再解码。这样的结构主要使用了反卷积和上池化。即:

Encoder network

其encoder部分使用了VGG16的前13层卷积结构。即conv1_1-conv1_2-pool-conv2_1-conv2_2-pool-conv3_1-conv3_2-conv3_3-pool-conv4_1-conv4_2-conv4_3-pool的结构。每个conv层包含convolution+Batch normalization+ReLU操作。pool层采用2X2的窗口,以及stride 2的步长。每次pool层相当于对图像做一个分辨率减少一半的降采样。并在每次maxpool的过程中,将feature maps中的每个池化窗口中的最大值的位置记录下来。简而言之,你可以认为这就是一个VGG net,不过多了一步记录maxpool 索引的操作。事实上,大部分分割结构都使用相同的encoder 结构,其主要变化在于decoder network。

Decoder network

在经过卷积池化得到输入图像的feature maps之后,使用记录下来的最大池化的索引来对其做上采样处理。如下图所示,左图为SegNet的上采样过程,右图为FCN的上采用过程。

话句话说:SegNet和FCN最大的不同就在于decoder的upsampling方法,上图结构中,注意,前面encoder每一个pooling层都把pooling indices保存,并且传递到后面对称的upsampling层. 进行upsampling的过程具体如下:

左边是SegNet的upsampling过程,就是把feature map的值 abcd, 通过之前保存的max-pooling的坐标映射到新的feature map中,其他的位置置零.

右边是FCN的upsampling过程,就是把feature map, abcd进行一个反卷积,得到的新的feature map和之前对应的encoder feature map 相加.

SegNet的分割精度略好于FCN

这么做会产生稀疏的feature maps。再对执行卷积操作产生密集feature maps。值得注意的是,在与encoder中第一层对应的decoder层中(即decoder的最后一层卷积),与原图像为RGB的3通道不同,该层产生的是一个通道为K(类别数)的multi-channel feature maps,然后将其送入softmax分类器,做逐像素的分类处理。

CamVid Road Scenes Dataset

CamVid road scenes dataset 是一个小型数据集,其中包含有367训练样本,233涨测试样本,均为360X480分辨率的RGB图像。其标签中包含有11个类别。在对数据集进行训练之前,先对其做local contrast normalization 处理,其方法可以参考这篇博文https://blog.csdn.net/mao_xiao_feng/article/details/53488271

训练过程

encoder和decoder的权值初始化均采用

Delving Deep into Rectifiers: Surpassing Human-Level Performance on ImageNet Classification中介绍的方法。采用SGD方法进行训练,learing rate 为0.1 以及0.9的momentum。并对训练集做shuffle处理,使用softmax cross-entropy loss,loss 计算一个mini-batch中的所有像素的单个loss之和。并添加了 median frequency balancing方法优化训练过程, 该方法即是对每一个类别添加一个权值,对于物体较大的类别(车,路,天空)设置一个较小的权值,对于物体较小的类别,设置一个较大的权值。

结果及代码使用

先上结果图,第一张图为测试集中的最后一张图的分割图(别人训练好的),后两张为我自己迭代6000次(GTX1066,约1个小时),再用来测试的测试集的第一张图。




代码中实现的是论文SegNet-base, 即4个encode和4个deencode

def inference(images, labels, batch_size, phase_train):# norm1norm1 = tf.nn.lrn(images, depth_radius=5, bias=1.0, alpha=0.0001, beta=0.75,        #local response normalization.name='norm1')# conv1conv1 = conv_layer_with_bn(norm1, [7, 7, images.get_shape().as_list()[3], 64], phase_train, name="conv1")# pool1pool1, pool1_indices = tf.nn.max_pool_with_argmax(conv1, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1],padding='SAME', name='pool1')# conv2conv2 = conv_layer_with_bn(pool1, [7, 7, 64, 64], phase_train, name="conv2")# pool2pool2, pool2_indices = tf.nn.max_pool_with_argmax(conv2, ksize=[1, 2, 2, 1],strides=[1, 2, 2, 1], padding='SAME', name='pool2')# conv3conv3 = conv_layer_with_bn(pool2, [7, 7, 64, 64], phase_train, name="conv3")# pool3pool3, pool3_indices = tf.nn.max_pool_with_argmax(conv3, ksize=[1, 2, 2, 1],strides=[1, 2, 2, 1], padding='SAME', name='pool3')# conv4conv4 = conv_layer_with_bn(pool3, [7, 7, 64, 64], phase_train, name="conv4")# pool4pool4, pool4_indices = tf.nn.max_pool_with_argmax(conv4, ksize=[1, 2, 2, 1],strides=[1, 2, 2, 1], padding='SAME', name='pool4')""" End of encoder """""" start upsample """# upsample4# Need to change when using different dataset out_w, out_h# upsample4 = upsample_with_pool_indices(pool4, pool4_indices, pool4.get_shape(), out_w=45, out_h=60, scale=2, name='upsample4')upsample4 = deconv_layer(pool4, [2, 2, 64, 64], [batch_size, 45, 60, 64], 2, "up4")# decode 4conv_decode4 = conv_layer_with_bn(upsample4, [7, 7, 64, 64], phase_train, False, name="conv_decode4")# upsample 3# upsample3 = upsample_with_pool_indices(conv_decode4, pool3_indices, conv_decode4.get_shape(), scale=2, name='upsample3')upsample3= deconv_layer(conv_decode4, [2, 2, 64, 64], [batch_size, 90, 120, 64], 2, "up3")# decode 3conv_decode3 = conv_layer_with_bn(upsample3, [7, 7, 64, 64], phase_train, False, name="conv_decode3")# upsample2# upsample2 = upsample_with_pool_indices(conv_decode3, pool2_indices, conv_decode3.get_shape(), scale=2, name='upsample2')upsample2= deconv_layer(conv_decode3, [2, 2, 64, 64], [batch_size, 180, 240, 64], 2, "up2")# decode 2conv_decode2 = conv_layer_with_bn(upsample2, [7, 7, 64, 64], phase_train, False, name="conv_decode2")# upsample1# upsample1 = upsample_with_pool_indices(conv_decode2, pool1_indices, conv_decode2.get_shape(), scale=2, name='upsample1')upsample1= deconv_layer(conv_decode2, [2, 2, 64, 64], [batch_size, 360, 480, 64], 2, "up1")# decode4conv_decode1 = conv_layer_with_bn(upsample1, [7, 7, 64, 64], phase_train, False, name="conv_decode1")""" end of Decode """""" Start Classify """# output predicted class number (6)with tf.variable_scope('conv_classifier') as scope:kernel = _variable_with_weight_decay('weights',shape=[1, 1, 64, NUM_CLASSES],initializer=msra_initializer(1, 64),wd=0.0005)conv = tf.nn.conv2d(conv_decode1, kernel, [1, 1, 1, 1], padding='SAME')biases = _variable_on_cpu('biases', [NUM_CLASSES], tf.constant_initializer(0.0))conv_classifier = tf.nn.bias_add(conv, biases, name=scope.name)logit = conv_classifierloss = cal_loss(conv_classifier, labels)return loss, logit

这是SegNet-base的网络结构,其为自定义函数,详情可以自己阅读代码。

该代码使用前现在main.py文件中修改运行参数,如image_dir,test_dir,_val_dir,以及log_dir和max_steps。然后开始训练,训练完后可以使用tensorboard查看训练记录。再之后可以修改tesing或finetune的参数(该参数为载入训练好的模型,可以是你的log_dir,也可以将Log_dir里的模型复制到指定文件目录下),进行测试或微调。

自己制作国内高速公路label,使用SegNet训练高速公路模型,测试效果


SegNet是Cambridge提出旨在解决自动驾驶或者智能机器人的图像语义分割深度网络,开放源码,基于caffe框架。SegNet基于FCN,修改VGG-16网络得到的语义分割网络,有两种SegNet,分别为正常版与贝叶斯版,同时SegNet作者根据网络的深度提供了一个basic版(浅网络)。

在传统的CNN网络中,ReLU通常在全连接之后,结合偏置bias用于计算权值的输出,但是,在Seg
Net作者的研究中发现,激活层越多越有利于图像语义分割。图3为论文中,不同深度的卷积层增加与不增加激活函数的对比图。

主要贡献:

将池化层结果应用到译码过程
说明:

引入了更多的编码信息。使用的是pooling indices而不是直接复制特征。

SegNet-论文笔记-理解相关推荐

  1. SegNet——论文笔记

    1.什么是语义分割(semantic segmentation)? 图像语义分割,简而言之就是对一张图片上的所有像素点进行分类,将所有属于同一类的物体标记为同一像素点. SegNet基于FCN,修改V ...

  2. Deep Learning论文笔记之(五)CNN卷积神经网络代码理解

    Deep Learning论文笔记之(五)CNN卷积神经网络代码理解 zouxy09@qq.com http://blog.csdn.net/zouxy09          自己平时看了一些论文,但 ...

  3. 【ACL19 论文笔记】EPAr:探索+提议+组装:多跳阅读理解的可解释模型

    Yichen Jiang, Nitish Joshi, Yen-Chun Chen Mohit Bansal ; UNC Chapel Hill Explore, Propose, and Assem ...

  4. unet论文_图像分割之RefineNet 论文笔记

    RefineNet: Multi-Path Refinement Networks forHigh-Resolution Semantic Segmentation (2017) 论文笔记 文章的创新 ...

  5. LinkNet论文笔记

    LinkNet论文笔记 LinkNet: Exploiting Encoder Representations for Efficient Semantic Segmentation Abstract ...

  6. ORB-SLAM3 论文笔记

    ORB-SLAM3 论文笔记 这篇博客 ORB-SLAM3系统 相机模型的抽象(Camera Model) 重定位的问题 图片矫正的问题 视觉惯性SLAM的工作原理 相关公式 IMU初始化 跟踪和建图 ...

  7. 论文笔记 《Maxout Networks》 《Network In Network》

    原文出处:http://zhangliliang.com/2014/09/22/paper-note-maxout-and-nin/ 论文笔记 <Maxout Networks> & ...

  8. 论文笔记:Autoregressive Tensor Factorizationfor Spatio-temporal Predictions

    0 摘要 张量因子tensor factorization分解方法在时空数据分析领域很受欢迎,因为它们能够处理多种类型的时空数据,处理缺失值,并提供计算效率高的参数估计程序. 然而,现有的张量因子分解 ...

  9. Deep Learning论文笔记之(八)Deep Learning最新综述

    Deep Learning论文笔记之(八)Deep Learning最新综述 zouxy09@qq.com http://blog.csdn.net/zouxy09 自己平时看了一些论文,但老感觉看完 ...

  10. Deep Learning论文笔记之(七)深度网络高层特征可视化

    Deep Learning论文笔记之(七)深度网络高层特征可视化 zouxy09@qq.com http://blog.csdn.net/zouxy09          自己平时看了一些论文,但老感 ...

最新文章

  1. php智能客服,智能客服系统
  2. mysql 查询商品列表 显示tag_javascript - MYSQL——怎么一个sql语句查询出用户和用户商品的列表啊...
  3. boost::log模块记录多个线程的示例
  4. [蓝桥杯2015决赛]分机号-枚举(水题)
  5. 2019蓝桥杯省赛---java---B---2(不同子串)
  6. 微软符号服务器 2020年_微软介绍了2020年后它将如何淘汰Edge中的Flash支持
  7. gdb 调试 入手 实例讲解-转
  8. 【写作技巧】科研思维与论文写作之“5C”法则
  9. Shell脚本学习(一)Shell命令基础
  10. 简单的遗传算法实例(MATLAB版)
  11. 迈达斯GTS-NX网格模型(FPN)导入Flac3D 6.0
  12. 微信小程序的支付流程 —— 总结
  13. 数据湖、物联网等--南水北调中线工程的“智慧大脑”,是如何工作的?
  14. windows7旗舰版序列号[经测试,第一枚即可完成升级!]
  15. 万能ghost 更改电源
  16. py-01-LINUX
  17. mysql int 时间戳转换_MySQL时间戳相互转换
  18. httpd离线安装(含依赖包下载地址)
  19. Guava 系列 - Guava基础
  20. 史上最全DDoS攻击与防御教程

热门文章

  1. 信号与系统公式笔记(1)
  2. 软考高项——第七章质量管理
  3. 写给充满浮躁与抱怨的程序员
  4. html标签引入css样式的四种方式
  5. USB 协议整理 四:USB概述及协议基础(三)
  6. Git安装包(window64版本,附有下载教程)
  7. LaSOT: A High-quality Benchmark for Large-scale Single Object Tracking(论文翻译)
  8. form表单属性集合
  9. C#封装,继承,多态
  10. 干货分享 基于MATLAB的带噪图像的高斯滤波论文