首个端对端的针对像素级预测的全卷积网络
FCN是一个end-to-end
的网络,实现像素
级别(pixel-wise)的分类,即对每一个像素点都可以进行分类,在语义分割任务上取得了很不错的效果!
FCN论文地址:https://arxiv.org/abs/1411.4038
FCN原作代码:https://github.com/shelhamer/fcn.berkeleyvision.org
本文链接
论文共分为6个部分
本次讲解具体讲介绍
,全卷积网络
,分割网络
3个部分
首先介绍一下FCN的背景和工作成果
语义分割作为计算机视觉三大任务(图像分类、目标检测、图像分割)之一,图像分割已经在近些年里有了长足的发展。这项技术也被广泛地应用于无人驾驶领域中,比如用来识别可通行区域、车道线等。
全卷积网络(Fully Convolutional Networks,FCN)是UC Berkeley的Jonathan Long等人于2015年在Fully Convolutional Networks for Semantic Segmentation一文中提出的用于图像语义分割的一种框架。
看一下语义分割具体的效果
图像语义分割的意思就是机器自动分割并识别出图像中的内容,比如给出一个人骑摩托车的照片,机器判断后应当能够生成右侧图,红色标注为人,绿色是车(黑色表示back ground)。
接下来,我们直接看一下FCN的结果
FCN虽然是一个简单的框架,但是结果已经十分接近真实值。效果十分的不错
这个是在数据集上的一些成功。比当时的其他框架普遍高出10%,这是非常恐怖的事情
相关工作就不看,直接看第3章
首先讲一下之间传统CNN存在的问题
CNN做图像分类甚至做目标检测的效果已经被证明并广泛应用,图像语义分割本质上也可以认为是稠密的目标识别(需要预测每个像素点的类别)。
对于一般的分类CNN网络,如VGG和Resnet,都会在网络的最后加入一些全连接层,经过softmax后就可以获得类别概率信息。但是这个概率信息是1维的,即只能标识整个图片的类别,不能标识每个像素点的类别,所以这种全连接方法不适用于图像分割。
传统的基于CNN的语义分割方法是:将像素周围一个小区域(如25*25)作为CNN输入,做训练和预测。这样做有3个问题
这种方法有几个缺点:
总结一下就是以下几点
像素区域的大小如何确定
存储及计算量非常大
像素区域的大小限制了感受野的大小,从而只能提取一些局部特征
针对上面的问题,文章做出了3个方面的创新
第一步我们大致看一下 FCN的模型架构图
一张猫和狗的图片,经过普通的卷积网络进行下采样,然后通道转置卷积进行上采样。最后输出分割图片
首先看一下普通的CNN图像分类网络
在CNN中, 猫的图片输入到AlexNet, 得到一个长为1000的输出向量, 表示输入图像属于每一类的概率, 其中在“tabby cat”这一类统计概率最高, 用来做分类任务。
换句话讲为什么需要FCN?
我们分类使用的网络通常会在最后连接几层全连接层,它会将原来二维的矩阵(图片)压扁成一维的,从而丢失了空间信息,最后训练输出一个标量,这就是我们的分类标签。
而图像语义分割的输出需要是个分割图,且不论尺寸大小,但是至少是二维的。所以,我们需要丢弃全连接层,换上全卷积层,而这就是全卷积网络了。
总结以下,全连接层丢失了空间信息,所以得使用卷积层代替了全连接层
总结以下就是以下这幅图
让我们来看一下怎么替换。上面是为 7 ∗ 7 ∗ 512 7*7*512 7∗7∗512的feature map 。通过平铺成25088的一维向量。然后和全连接进行运算。
卷积是如何替换的呢?我们可以通过卷积核为 7 ∗ 7 7*7 7∗7,步长为1,卷积核数目为 4096 4096 4096,实现全连接层的效果。
我们可以看到参数量是一样的。卷积完成后的数据也是一样的
什么叫做上采样
看一下效果
我们可以看到第一章图片的宽高为200*200
。通过上采样图片的宽高变成25*250
。通过上采样。图片维度变大,但是呢。图片还是差不多
现在我们知道上采样操作,有几种
转置卷积
feature maps补0,然后做卷积操作
线性差值
插值法不需要学习任何的参数,只是根据已知的像素点对未知的点进行预测估计,从而可以扩大图像的尺寸,达到上采样的效果
反池化unpooling
在空隙中填充 0
unsampling
在空隙中填充同样的值
这里解释一下转置卷积的内容,它是如何对图片进行上采样的.两张图解释一下
nn.ConvTranspose2d
nn.ConvTranspose2d(in_channels,
out_channels,
kernel_size,
stride=1,
padding=0,
output_padding=0,
groups=1,
bias=True,
dilation=1)
参数详解
padding
(int or tuple, optional) - 输入的每一条边补充0的层数,高宽都增加2*paddingoutput_padding
(int or tuple, optional) - 输出边补充0的层数,高宽都增加paddingstrides
:步长。每次窗口滑动距离
VGG,GoogleNet,LeNet
采用的是VGG16的架构
作用:连接底层信息到高层信息,从而提升精度。
看完VGG16这个模型,才能理解这个跳跃链接的效果。因为VGG16中对应的池化
对于FCN-32s,直接对pool5 feature进行32倍上采样获得32x upsampled feature,再对32x upsampled feature每个点做softmax prediction获得32x upsampled feature prediction(即分割图)。
对于FCN-16s,首先对pool5 feature进行2倍上采样获得2x upsampled feature,再把pool4 feature和2x upsampled feature逐点相加,然后对相加的feature进行16倍上采样,并softmax prediction,获得16x upsampled feature prediction。
对于FCN-8s,首先进行pool4+2x upsampled feature逐点相加,然后又进行pool3+2x upsampled逐点相加,即进行更多次特征融合。具体过程与16s类似,不再赘述。
作者在原文种给出3种网络结果对比,明显可以看出效果:FCN-32s < FCN-16s < FCN-8s,即使用多层feature融合有利于提高分割准确性。
下面这个为模型的全部架构图
训练过程分为四个阶段,也体现了作者的设计思路,值得研究。
第1阶段
以经典的分类网络为初始化。最后两级是全连接(红色),参数弃去不用
第2阶段
从特征小图( 16 ∗ 16 ∗ 4096 16*16*4096 16∗16∗4096)预测分割小图( 16 ∗ 16 ∗ 21 16*16*21 16∗16∗21),之后直接升采样为大图。
反卷积(橙色)的步长为32,这个网络称为FCN-32s。
这一阶段使用单GPU训练约需3天。
1/32的图进行上采样->1/16 +maxpool4 (1/16) -> 上采样
第3阶段
升采样分为两次完成(橙色×2)。
在第二次升采样前,把第4个pooling层(绿色)的预测结果(蓝色)融合进来。使用跳级结构提升精确性。
第二次反卷积步长为16,这个网络称为FCN-16s。
这一阶段使用单GPU训练约需1天。
第4阶段
升采样分为三次完成(橙色×3)。
进一步融合了第3个pooling层的预测结果。
第三次反卷积步长为8,记为FCN-8s。
这一阶段使用单GPU训练约需1天。
fcn网络的输入batchsize是1,因为分割loss的计算在每一个像素点都一个真值(标签),相当于每一个像素点的都是一个分类任务,一个图像就有对应像素点个样本。所以分割任务的batch是一个图片,将一个图片最后在所有像素点上的分类loss加起来计算一次梯度的更新。
评价指标使用了miou
作者还做了很多实验来尝试提升网络性能,很多都没有效果。这部分挺有意思的。
作者尝试了减少最后一层的池化层的步长到1,可是这导致池化层后面的卷积层卷积核感受野很大。这样增大了计算量,这么大感受野的卷积核很难学习。作者也试过了用更小的过滤器来调整池化层上面的层,可是效果也不好。
作者也尝试了 shift and stitch trick,但是代价太大,性价比还不如层融合。得不偿失。
添加了一些训练数据,提升了mIOU
尝试了patch sampling,块抽样,发现相比于全图训练并没有带来更快地收敛。
尝试通过修改损失值的权重或者采样loss来实现平衡训练集(class balance),发现虽然数据集的类很不平衡,其中四分之三都是背景,但是类平衡并不能带来性能的提升。
作者还尝试了数据增强,也并没有带来显著地提升。
传统 CNN 有几个缺点:
为了解决上面的部分问题,FCN 将传统 CNN 中的全连接层转化成卷积层,对应 CNN 网络 FCN 把最后三层全连接层转换成为三层卷积层(4096,4096,1000)。
FCN 的缺点:
FCN实现VOC数据集训练 | Kaggle
说了半天,到底什么是上采样?
实际上,上采样(upsampling)一般包括2种方式:
什么是Resize就不多说了,这里解释一下Deconvolution。
对于一般卷积,输入蓝色4x4矩阵,卷积核大小3x3。当设置卷积参数pad=0,stride=1时,卷积输出绿色2x2矩阵,如图6。
而对于反卷积,相当于把普通卷积反过来,输入蓝色2x2矩阵(周围填0变成6x6),卷积核大小还是3x3。当设置反卷积参数pad=0,stride=1时输出绿色4x4矩阵,如图7,这相当于完全将图4倒过来(其他更多卷积示意图点这里)。
图7 Deconvolution forward示意图
传统的网络是subsampling的,对应的输出尺寸会降低;upsampling的意义在于将小尺寸的高维度feature map恢复回去,以便做pixelwise prediction,获得每个点的分类信息。
上采样在FCN网络中的作用如图8,明显可以看到经过上采样后恢复了较大的pixelwise feature map(其中最后一个层21-dim是因为PACSAL数据集有20个类别+Background)。这其实相当于一个Encode-Decode的过程。
具体的FCN网络结构,可以在fcn caffe prototext中查到,建议使用[Netscope](Netscope (ethereon.github.io))查看网络结构。这里解释里面的难点:
为了解决图像过小后 1/32 下采样后输出feature map太小情况,FCN原作者在第一个卷积层conv1_1加入pad=100。
layer {
name: "conv1_1"
type: "Convolution"
bottom: "data"
top: "conv1_1"
param {
lr_mult: 1
decay_mult: 1
}
param {
lr_mult: 2
decay_mult: 0
}
convolution_param {
num_output: 64
pad: 100 # pad=100
kernel_size: 3
stride: 1
}
}
考虑如果不在conv1_1加入pad=100,会发生什么?
假设输入图像高度为h。由于VGG中缩小输出feature map只在pooling层,经过每个pooling后输出高度变为:
简单翻译:由于一副需要语义分割的图片中有很多我们不关注的区域,因此直接输入全卷积网络会有很多的多余计算,避免冗余的一个标准方法是只输入给网络图像中的随机小块(围绕感兴趣目标的小图像区域)而不是整图像,这样的“patchwise sampling”保证输入有足够的方差和训练集的有效表示。 可以从训练集中进行小块采样,或者直接对整图的损失进行采样,所以有这个说法“Patchwise training is loss sampling”,本文[fcn]后来实验发现patchwise training 比起直接训练整幅图 并没有大的提升,但是训练花费的时间更多了,因此本文是整幅图训练。
参考链接Shift and stitch理解 - 知乎 (zhihu.com)
在Semantic Segmentation中,由于CNN网络的下采样,使得输出是coarse的,要想得到 pixel级别的dense prediction,其中一种方法是shift and stitch,介绍如下。
网上的关于shift-and-stitch的解释:
设原图与FCN所得输出图之间的降采样因子是f,那么对于原图的每个fxf 的区域(不重叠),“
shift the input x pixels to the right and y pixels down for every (x,y) ,0 < x,y < f."
把这个f x f区域对应的output作为此时区域中心点像素对应的output,
这样就对每个 fxf 的区域得到了 f2 个output,也就是每个像素都能对应一个output,所以成为了dense prediction
假设降采样因子为s
,那么output map(这里为了简单起见,仅考虑二维)的spatial size则是 input的 1/s
, 平移 input map, 向左或向上(向右向下情况一样),偏移量为(x,y)
, 其中,
参考链接
图像语义分割入门+FCN/U-Net网络解析 - 知乎 (zhihu.com)
https://blog.csdn.net/m0_37935211/article/details/83098997
FCN的学习及理解(Fully Convolutional Networks for Semantic Segmentation)_moonuke的博客-CSDN博客_fcn
深度学习语义分割(一)FCN论文解读_su扬帆启航的博客-CSDN博客_fcn论文解读