digits tutorial 3 voc_segment 系列之1

参考链接:

https://github.com/NVIDIA/DIGITS/tree/master/examples/semantic-segmentation

https://blog.csdn.net/relar/article/details/53156033

https://devblogs.nvidia.com/image-segmentation-using-digits-5/

本文主要是基于 voc 2012 进行目标分割,提出了对于传统的alexnet进行微调,将原始的fc6改为卷积层,从而变成了FCN

一.传统的alexnet【图像分类模型,为每张图片做概率分布预测】与经过FCN修改过的alexnet【图像分割模型,为每个像素预测分布概率】的区别

传统的alexnet只能一次检测一个物体,但是不能多个物体

图像分割为这些短板解决了一些问题。不单独为整张图像预测一个概率分布,而是将图像分成多个区块,每个区块有自己的概率分布。在最常见的使用中,图像被分解到像素水平,每个像素都可被分类:对于图像中的每个像素来说,神经网络被训练用来预测每个像素的分类。图像分割通常都会生成一个与输入图像尺寸相同的标签图像,其像素会根据它们的颜色来编码。图 4 展示了一张图像中四个不同类别分割的例子:桌子、椅子、沙发和盆栽。

 

本文将向你展示仅仅是一些小小的调整也足够将一个分类神经网络转换成一个语义分割神经网络,并将用到在论文《Fully Convolutional Networks for Semantic Segmentation》中首次提到的技术(我称之为 FCN)。

二.FCN的alexnet的介绍

FCN(全卷积神经网络),仅仅由卷积层以及偶尔几个非参数层构成。

在一个卷积神经网络中,常见的做法是将网络分成两部分:在第一个部分特征提取器中,数据会经过若干卷基层来逐步提取更加复杂和抽象的特征。卷积层中通常会穿插非线性迁移函数(transfer function)和池化层(pooling layer)。每一个卷基层都可看作一组图像过滤器,可对特定模式触发高响应。

 

一个全连接层和一个卷积层之间有什么差别?这很简单:在一个全连接层中,每一个神经元的输出等于输入值中的加权求和。相比之下,在卷积层中,每一个过滤器都计算感受野的加权求和。等等,这说的同一个事情吗?是的,但是,只有当层的输入与感受野具有相同的大小时才成立【但是实际上输入都比感受野大,因此输入都是从左到右扫描感受野的,因此全连接仅仅做一次加权求和,但是卷积层做N次】。如果输入比感受野大,那么卷积层就会滑动它的输入 window 并计算另一个加权求和。这个过程会一直重复到输入的图像从左到右,从上到下都扫一遍为止。最后,每个过滤器都会生成一个激活矩阵;每个这样的矩阵叫做一个特征图(feature map)

 

这就提供了一个思路:为了用一个相等的卷积层替换一个全连接层,只要将过滤器的尺寸设置成层输入的尺寸,并使用数量与全连接层中的神经元数量相同的过滤器。我们会在 Alexnet(fc6)的第一个全连接层中展示这个过程:你能见到 fc6 从 pool5 中接收了它的输入,同时输入的形状是一个 256-channel 6×6 的图像。此外,fc6 上的激活是一个长度为 4096 的向量,这意味着 fc6 有 4096 个输出神经元。也就是说,如果我想用一个相等卷积层替换 fc6,我要做的就是将这个过滤器的大小设为 6×6,将输出特征图的数量设置为 4096。一个小小的题外话,你认为这一层有多少个可训练的参数?对于每个过滤器,感受野中每个数字都有一个偏项(bias term)加上一个权重。这个感受野的深度为 256,大小为 6×6,因此每一个过滤器都有 256×6×6+1=9217 个参数。因为有 4096 个过滤器,所以这一层的参数总数为9217*4096= 37752832。那正是 DIGITS 认为 fc6 会有的参数数量。

 

在实际中,取代该层很简单。如果你使用 Caffe,只需要用表 1 右边的定义取代左边的定义就行。

 

表 1:左:fc6 定义,右:对等的带有大小为 6 的核函数的 conv6,因为向 fc6 输入的是 6×6 的图像块。

 

「卷积化」基础 CNN 引进了大量的灵活性。模型不再被限制在一个固定的输入尺寸【FCN的贡献】(Alexnet 中是 224×224 个像素)上运行。它能像滑动 窗口 一样扫描整个输入来处理更大的图像,并且无需为整个输入单独输出一个概率分布,而是每 224×224 个 window 生成一个概率分布。网络输出的是一个带有 KxHxW 形状的张量,其中 K 是类别的数量,H 是垂直轴上滑动 window 的数量,W 是水平轴上滑动 window 的数量。

 

关于计算效率的一个提示:理论上你可以通过重复选择图像块并将它们馈送到 CNN 进行处理来实现 sliding window。但在实际中,计算效率会非常低:在你递增移动 window 时,只有一小部分新像素可被发现。如今,每个图像块都需要完全被 CNN 处理,即使在相邻图像块之间有很大的重叠。因此你可能要多次处理每个像素。在 FCN 中,因为这些计算都在网络内发生,只有小量的运算需要执行,因此处理速度有了量级增加。

对于这段话的理解:滑动窗口每进行一次滑动之后,仅仅更新一小部分像素,但是将整个感受野传入CNN的话就会效率很低,在FCN结构中,不需要将感受野传入到CNN了,直接在FCN内部进行计算,提高了效率。

 

三.图像分割FCN的介绍

当输入图像连续穿过「卷积的」Alexnet 的各个层时,输入中的像素数据被有效的压缩为一系列粗糙的、更高层次的特征表征。在图像分割中,这么做的目的是插入这些粗糙特征来为输入中的每个像素重建出好的分类。事实证明使用解卷积(deconvolutional)层能很好的做到这些。这些层进行与卷积相反的逆运算:给定卷积输出和 filter 定义的情况下,一个解卷积层能够发现会生成这种输出的输入数据【也就是卷积层的输出】。记住在处理输入时,卷积层(或池化层)中的 stride 决定了 window 滑动的距离,因此它也是输出如何下采样的一种测量。相反,在解卷积层中的 stride 是输出如何上采样的一种度量。把 stride 选择为 4,输出就更大了 4 倍!

下一个问题是:在模型中,我如何决定上采样多少最后卷积层的激活函数,从而获得与输入图像同样大小的输出?我需要检查每一层,并谨慎的记下它的换算系数(scaling factor)。一旦我检查了所有层,只需要把所有换算系数相乘就行。让我们看一下 Alexnet 中的第一个卷积层:

 

 

卷积层 1 的 stride s 是 4,因此换算系数是 1/4。在所有层上重复此过程,我测定该模型的所有换算系数是 1/32,就像表 2 总结的那样。因此,解卷积层所需的 stride 大小是 32。alexnet的卷积层一共有8层,因此上采样需要扩大4*8=32倍

 

 

四.训练模型

 

在 DIGITS 中开始训练模型所需要的只是对数据集和网络的描述。如果你认为卷积的 Alexnet 的流程有些复杂或者太耗时间:DIGITS 5.0 加上了一个模型库(model store),FCN-Alexnet 可从库中取回。

 

然而,如果你选择较难的方式,并创造自己的模型描述,你可能就想用到像 Kaiming(MSRA)方法这样合适的权重初始化 scheme,它如今是 Rectified Liner Units 的顶尖方法。通过在 Caffe 中向参数层加入一个 weight_filler { type: "msra" } 可轻松做到这一点。如果你在 DIGITS 中以这种方式训练模型,你可能会得到类似于图 11 的曲线。你可以看到表现有些不尽人意。验证准确率高峰在 35%(意味着验证集中只有 35% 的像素被准确标记了。)训练损失与验证损失一致,表明该网络在训练集上欠拟合。

 


图 11:在 Synthia 上使用 DIGITS 中的权重初始化训练 FCN-Alexnet 时的训练/验证损失和验证准确率。

 

你可以在样本图像上尝试一下,并用 DIGITS 对图像分割进行可视化。你会得到类似图 12 的图像,在此你能看到网络在建立时任意的分类每件事。结果证明这种建立是 SYNTHIA 中最具代表的目标分类,该网络通过在建立时标记所有东西也慢慢地学到了 35% 的准确率。处理网络欠拟合训练集的方法都有哪些呢?

 

  • 更长的训练:观察损失曲线,因为训练看起来已经达到了高点所以毫无办法。该网络已经进入了一个局部最小化,难以逃脱。

  • 增加学习率并减小 batch 大小:增大步幅,这可能激励陷入局部最小化的网络探索周围环境外的东西,但是同时这也增加了网络偏离的风险。

  • 增加模型的大小:这可能增加了模型的表达性。

 

我发现的另一个在计算机视觉上表现极好的方法是迁移学习。

 

图 12:在 SYNTHIA 数据集上使用随机权重初始化训练 FCN-Alexnet 时,DIGITS 中图像分割的样本可视化。该网络在建立的时候就分类了每件事。

 

你不必从随机初始化权重开始来训练模型。在很多情况下,它有助于重新使用网络在另一个数据集上训练时学习到的知识。这在使用 CNNs(卷积神经网络)的计算机视觉当中尤其如此,因为许多的低维特征(线、角、形状、纹理)直接适用于任何的数据集。因为图像分割是在像素的级别上进行分类,因此图像分类数据集中的迁移学习是有意义的,例如,ILSVRC2012。这在使用 Caffe 时显得相当简单—当然这会有一个或两个问题!记住,在 Alexnet 的 fc6 当中,权重的形状为 4096×9216。在 FCN-Alexnet 的 conv6 当中,权重的形状为 4096×256×6×6。这个数量与权重的数量完全相同,但是因为形状的不同,Caffe 无法自动携带权重给 FCN-Alexnet。该操作可以使用 net surgery script 来进行,其示例可以在 Github 上的 DIGITS 存储库中找到。net surgery script 的作用是将参数从完全连接层转移到它们对应的卷积层上。但是你可能会发现,直接从公共的 DIGITS 模型库上下载预训练模型会更加容易。图 13 显示了模型库的预览:单击「FCN-Alexnet」旁边的「导入」,DIGITS 将会下载预训练模型。

 

 

另一个相关的担心是如何初始化之前在文本上添加的上采样层,因为这一层并非是初始化的 Alexnet 模型:在 FCN 论文中,建议随机初始化相关权重并且使网络进行学习它们。论文的作者随后意识到,以这样的方式初始化这些权重也很简单,即通过进行双线性插值,该层仅充当放大镜。在 Caffe 中,这是通过向该层添加 weight_filler {type: "bilinear"} 指令来完成的。

 

使用预训练的 FCN-Alexnet 模型时,你会注意到精度会快速地超过 90%,并且当测试独立的图片的时候(如图 14 所示)结果将会是一个更令人信服的图像分割,拥有者 9 个不同的对象类的检测。然而,你可能会稍微有些失望地看到对象的轮廓都非常粗糙。阅读下一部分和最后一部分,了解如何进一步提升我们的分割模型的精度和准确度。

 

图 14:使用 ILSVRC2012 预训练的 Alexnet 在 SYNTHIA 数据集上训练 FCN-Alexnet 时 DIGITS 中图像分割的样本可视化。

 

精细分割

 

记住,添加到 FCN-Alexnet 的新的上采样层将 conv7 的输出放大了 32=4*8 倍。在实践当中,这意味着网络对每一个 32×32 的像素方块都会进行单独的预测,这解释了为什么对象的轮廓如此粗糙。FCN 论文中介绍了另一个解决这个限制的好方法:添加跳过链接,直接将 pool3 和 pool4 重定向到网络的输出。因为这些合并层在网络当中进一步回退,它们在低维特征上操作并且可以捕获到更加精细的细节。在被称为 FCN-8 的网络架构中,FCN 论文介绍了基于 VGG-16 的网络,其最终的输出是 pool3 上采样的总和的 8 倍,pool4 的上采样的 2 倍和 conv7 的 4 倍,如图 15 所示。这导致网络可以在更精细的颗粒上进行预测,下降到 8x8 的像素块。

 

图 15: FCN-8 跳过链接的图示—来源:FCN 论文

 

为了你的方便起见,可以从公共 DIGITS 模型商店下载预训练的 FCN-8。(你不会想要手动卷积 VGG-16 的!)如果你使用 DIGITS 训练 SYNTHIA 上的 FCN-8,你应该看到 只有几个时期,验证的准确率超过 95%。更重要的是,当你测试样例图片并且观察到 DIGITS 非常棒的图像分割可视化时,你会看到更加清晰地对象轮廓,如图 16 所示。

 

图 16:在 SYNTHIA 数据集上训练 FCN-8 时,DIGITS 中图像分割的样例可视化。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值