百度飞桨图像分割七日打卡营学习笔记

百度飞桨图像分割七日打卡营学习笔记

(来源:飞桨图像分割教程,课程链接https://aistudio.baidu.com/aistudio/course/introduce/1767)

1.语义分割概念:

图像分割是计算机视觉中除了分类和检测外的另一项基本任务,它意味着要将图片根据内容分割成不同的块。相比图像分类和检测,分割是一项更精细的工作,因为需要对每个像素点分类,如下图的街景分割,由于对每个像素点都分类,物体的轮廓是精准勾勒的,而不是像检测那样给出边界框。图像分割可以分为两类:语义分割(Semantic Segmentation)和实例分割(Instance Segmentation)。区别如下图所示:语义分割只是简单地对图像中各个像素点分类,但是实例分割更进一步,需要区分开不同物体,这更加困难,从一定意义上来说,实例分割更像是语义分割加检测。这里我们主要关注语义分割。
在这里插入图片描述

2.语义分割经典模型:
2.1 FCN

对于一般的分类CNN网络,如VGG和Resnet,都会在网络的最后加入一些全连接层,经过softmax后就可以获得类别概率信息。但是这个概率信息是1维的,即只能标识整个图片的类别,不能标识每个像素点的类别,所以这种全连接方法不适用于图像分割。而FCN提出可以把后面几个全连接都换成卷积,这样就可以获得一张2维的feature map,后接softmax获得每个像素点的分类信息,从而解决了分割问题,如下图,

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-o8F5DLHK-1603589300263)(C:\Users\fd\AppData\Roaming\Typora\typora-user-images\image-20201014100427980.png)]
对于特征融合的不同情况,作者在原文种给出3种网络结果对比,明显可以看出效果:FCN-32s < FCN-16s < FCN-8s,即使用多层feature融合有利于提高分割准确性
在这里插入图片描述

  1. 对于FCN-32s,直接对pool5 feature进行32倍上采样获得32x upsampled feature,再对32x upsampled feature每个点做softmax prediction获得32x upsampled feature prediction(即分割图)。
  2. 对于FCN-16s,首先对pool5 feature进行2倍上采样获得2x upsampled feature,再把pool4 feature和2x upsampled feature逐点相加,然后对相加的feature进行16倍上采样,并softmax prediction,获得16x upsampled feature prediction。
  3. 对于FCN-8s,首先进行pool4+2x upsampled feature逐点相加,然后又进行pool3+2x upsampled逐点相加,即进行更多次特征融合。具体过程与16s类似,不再赘述。

2.1.1 上采样

在这里插入图片描述

上采样有3种常见的方法:双线性插值(bilinear)反卷积(Transposed Convolution)反池化(Un-pooling)

1.双线性插值:是实践过程常用的上采样手段,计算简单,而且得到效果也不差。
在这里插入图片描述
在这里插入图片描述

2.反卷积:准确的说,应该叫做转置卷积(Transpose Convolution)

在这里插入图片描述

卷积操作(矩阵演示):

在这里插入图片描述

转置卷积(矩阵演示):
在这里插入图片描述

3.反池化:Un-Pooling,不太常用,比较老的方法

在这里插入图片描述

2.1.2 FCN实践过程中的巧妙之处:
def __init__(self,num_classes=59):
        super(FCN8s,self).__init__()
        backbone = VGG16BN(pretrained=False)

        self.layer1 = backbone.layer1
        self.layer1[0].conv._padding = [100,100]
        self.pool1 = Pool2D(pool_size=2,pool_stride=2,ceil_mode=True)
        self.layer2 = backbone.layer2
        self.pool2 = Pool2D(pool_size=2,pool_stride=2,ceil_mode=True)
        self.layer3 = backbone.layer3
        self.pool3 = Pool2D(pool_size=2,pool_stride=2,ceil_mode=True)
        self.layer4 = backbone.layer4
        self.pool4 = Pool2D(pool_size=2,pool_stride=2,ceil_mode=True)
        self.layer5 = backbone.layer5
        self.pool5 = Pool2D(pool_size=2,pool_stride=2,ceil_mode=True)

        self.fc6 = Conv2D(512,4096,7,act='relu')
        self.fc7 = Conv2D(4096,4096,1,act='relu')
        self.drop6 = Dropout()
        self.drop7 = Dropout()
        #1x1conv
        self.score = Conv2D(4096,num_classes,1)
        self.score_pool3 = Conv2D(256,num_classes,1)
        self.score_pool4 = Conv2D(512,num_classes,1)

        #up-smapling
        self.up_output = Conv2DTranspose(num_channels=num_classes,
                                            num_filters=num_classes,
                                            filter_size=4,
                                            stride=2,
                                            bias_attr=False)
        self.up_pool4 = Conv2DTranspose(num_channels=num_classes,
                                            num_filters=num_classes,
                                            filter_size=4,
                                            stride=2,
                                            bias_attr=False)
        self.up_final = Conv2DTranspose(num_channels=num_classes,
                                            num_filters=num_classes,
                                            filter_size=16,
                                            stride=8,
                                            bias_attr=False)

这里的FCN8s的编码backbone是VGG16,继续添加两个全连接层FC6,FC7(本质为conv),然后使用转置卷积进行上采样得到最后的mask。

卷积操作的输出尺寸计算,Houtput=(Hinput-K+2P)/S+1

根据卷积操作,那么转置卷积的输出尺寸计算,Houtput=(Hinput-1)XS+K-2P

思考:

1.为何在Conv1时加入padding = [100,100]?

一般来说,示例输入图像(HXW)尺寸为224x224->(conv1+pool1)->112x112->(conv2+pool2)->56x56->(conv3+pool3)->28x28->(conv4+pool4)->14x14->(conv5+pool5)->7x7 ->FC6(conv7x7)->1x1->FC7(conv1x1)->1x1->…

当图像尺寸小于224x224时,上面尺寸变化还会如此顺利吗?极端的考虑,把输入图像设为1x1,那么:

1x1->(conv1+pool1)->1x1->(conv2+pool2)->1x1->(conv3+pool3)->1x1->(conv4+pool4)->1x1->(conv5+pool5)->1x1 ->FC6(conv7x7)->Error->FC7(conv1x1)->…在经过FC6时就会报错。

所以,为了让网络可以接受任意大小的输入,就可以在conv1时加入100的padding,这样上面的过程就变为:

1x1->(conv1(padding100))->199x199->(pool1)->100x100->(conv2+pool2)->50x50->(conv3+pool3)->25x25->(conv4+pool4)->13x13->(conv5+pool5)->7x7 ->FC6(conv7x7)->1x1->FC7(conv1x1)->1x1->…

def forward(self,inputs):
        x = self.layer1(inputs)
        x = self.pool1(x)
        x = self.layer2(x)
        x = self.pool2(x)
        x = self.layer3(x)
        x = self.pool3(x)
        pool3 = x
        x = self.layer4(x)
        x = self.pool4(x)
        pool4 = x
        x = self.layer5(pool4)
        x = self.pool5(x)

        x = self.fc6(x)
        x = self.drop6(x)
        x = self.fc7(x)
        x = self.drop7(x)

        x = self.score(x)
        x = self.up_output(x)

        up_output = x  #1/16
        x = self.score_pool4(pool4)
		#crop操作
        x = x[:,:, 5:5+up_output.shape[2],5:5+up_output.shape[3]]

        up_pool4 = x
        x = up_pool4 + up_output
        x = self.up_pool4(x)
        up_pool4 = x

        x = self.score_pool3(pool3)
        #crop操作
        x = x[:,:, 9:9+up_pool4.shape[2],9:9+up_pool4.shape[3]]
        up_pool3 = x  #1/8

        x = up_pool3 + up_pool4

        x = self.up_final(x)
		#crop操作
        x = x[:,:, 31:31+inputs.shape[2],31:31+inputs.shape[3]] 

        return x

2.为什么要crop(5,9,31)?

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bhXmFETE-1603589300311)(C:\Users\fd\AppData\Roaming\Typora\typora-user-images\image-20201022162055686.png)]
优点:

任意尺寸输入、效率高、结合浅层信息

缺点:

分割结果不够精细、没有考虑上下文信息(“看看旁边有啥,左顾右盼”)

2.U-Net

(2015年MICCAI)

在这里插入图片描述

U-Net是原作者参加ISBI Challenge提出的一种分割网络,能够适应很小的训练集(大约30张图)。U-Net与FCN都是很小的分割网络,既没有使用空洞卷积,也没有后接CRF,结构简单。整个U-Net网络结构如上图,类似于一个大大的U字母:首先进行Conv+Pooling下采样,将特征抽象,获取丰富的高级语义信息,有助于分割目标物体的类别判断;然后Deconv反卷积进行上采样,将图像恢复到模板大小,但在直接恢复会导致分割出来的结果粗糙,所以crop之前的低层feature map,进行融合,获得更为精细的分割结果;然后再次上采样。重复这个过程,直到获得输出388x388x2的feature map,最后经过softmax获得output segment map。总体来说与FCN思路非常类似。

在这里插入图片描述
在这里插入图片描述

与FCN逐点相加不同,U-Net采用将特征在channel维度拼接在一起,形成更“厚”的特征。所以:

语义分割网络在特征融合时也有2种办法:

  1. FCN式的逐点相加,对应caffe的EltwiseLayer层,对应tensorflow的tf.add()
  2. U-Net式的channel维度拼接融合,对应caffe的ConcatLayer层,对应tensorflow的tf.concat()
    在这里插入图片描述
    相比其他大型网络,FCN/U-Net还是蛮简单的,就不多废话了。

总结一下,CNN图像语义分割也就基本上是这个套路:

  1. 下采样+上采样:Convlution + Deconvlution/Resize
  2. 多尺度特征融合:特征逐点相加/特征channel维度拼接
  3. 获得像素级别的segement map:对每一个像素点进行判断类别

即使是更复杂的DeepLab v3+依然也是这个基本套路

3.PSPNet(Pyramid Scene Parsing Network)

FCN缺点:没有考虑上下文信息

在这里插入图片描述
1.什么是上下文信息?
在这里插入图片描述

2.PSP网络如何获取上下文?

增大感受野(Receptive Field)。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nt4wAlIM-1603589300327)(C:\Users\fd\AppData\Roaming\Typora\typora-user-images\image-20201022202436541.png)]
感受野(RF)= 用于产生特征的输入图像中的区域大小

只针对于局部操作:例如conv,pooling

3.如何增大感受野?

不同scale的“feature pyramid”

4.PSP模块及特征图变化

在这里插入图片描述

5.Adaptive Pooling概念:

floor():向下取整

在这里插入图片描述

6.PSP完整结构

在这里插入图片描述

4.DeepLab系列

1.空洞卷积:

在这里插入图片描述

空洞卷积后的尺寸变化:

在这里插入图片描述
D=1,没有空洞

作用及优点:扩大感受野,计算量增加少

(dilated ResNet)
在这里插入图片描述

2.DeepLab 系列网络

在这里插入图片描述

如果觉得PSPNet,DeepLab等大模型在单卡上难以训练,可以考虑将后面的分割部分加到轻量级MobileNet V1等系列上去,训练可能会更快。

在这里插入图片描述

1)DeepLab V1

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-E2iqigwB-1603589300341)(C:\Users\fd\AppData\Roaming\Typora\typora-user-images\image-20201023140719961.png)]

2)DeepLab V2

在这里插入图片描述

3)DeepLab V3

在这里插入图片描述
Backbone:

![[]](https://img-blog.csdnimg.cn/20201025095937608.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2hhb2FoMzE2,size_16,color_FFFFFF,t_70#pic_center)
在这里插入图片描述
后续有相关内容会继续补充,欢迎各位有想法的小伙伴们积极指导和讨论。感谢观看~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值