语义分割—FCN网络 学习笔记 (附代码)

论文地址:https://arxiv.org/abs/1411.4038
代码地址:https://gitcode.com/mirrors/wzmiaomiao/deep-learning-for-image-processing/overview?utm_source=csdn_github_accelerator

1.是什么?

全卷积网络(Fully Convolutional Networks,FCN)是Jonathan Long等人于2015年在Fully Convolutional Networks for Semantic Segmentation一文中提出的用于图像语义分割的一种框架,是首个端对端的针对像素级预测的全卷积网络。
与传统的卷积神经网络(CNN)只能输出一个固定大小的标量值或向量不同,FCN可以输出与输入图像相同大小的像素级别的预测结果,即对每个像素进行分类。
FCN的核心思想是将传统的全连接层替换为卷积层,从而使得网络可以接受任意尺寸的输入图像,并输出相应尺寸的预测结果。FCN的网络结构主要分为两个部分:全卷积部分和反卷积部分。其中全卷积部分为一些经典的CNN网络(如VGG,ResNet等),用于提取特征;反卷积部分则是通过上采样得到原尺寸的语义分割图像。FCN的输入可以为任意尺寸的彩色图像,输出与输入尺寸相同,通道数为n(目标类别数)+1(背景)。

2.怎么样

2.1网络结构

FCN网络结构主要分为两个部分:全卷积部分和反卷积部分。其中全卷积部分为一些经典的CNN网络(如VGG,ResNet等),用于提取特征;反卷积部分则是通过上采样得到原尺寸的语义分割图像。FCN的输入可以为任意尺寸的彩色图像,输出与输入尺寸相同,通道数为n(目标类别数)+1(背景),(原始FCN是在PASCAL数据集上训练的所以一共有20+1类)。FCN-8s网络结构如下:

21张概率图中每个像素处是一个概率,表明当前像素属于哪一种类别

 这里为什么会产生568*568大小的图片呢,是因为原论文的源码中在第一个卷积层处将padding设置为100,这样做的目的是防止图片下采样32倍后尺寸小于7x7(因为下采样32倍后会经过7x7大小的卷积层),之后上采样32倍后会产生与原图不一样大小的图片,需要进行裁剪才能得到原图大小的输出。
 

2.2 官方模型

官方模型是采用了VGG16作为backbone,VGG16网络结果如下图所示:

其中最大池化层为2x2 步长为2,论文中提出了三个模型分别是FCN-32s、FCN-16s、FCN-8s。

2.2.1 FCN-32s

pool5的输出直接上采样32倍恢复到原图大小,将损失了原图很多细节信息的特征图直接上采样,效果较差

现在的FCN的源码中FC6的卷积层的padding为3,这样可以使输出的图片高宽不变,防止输入图片过小导致该卷积层报错,例如若没有该padding,那么输入192x192的图片FC6的输入会是6x6大小的图片,FC6就报错了。
论文源码中的转置卷积的参数是冻结的,因为作者发现冻结和不冻结的结果相差不大,为了提高效率,所以就冻结了。此时转置卷积层相当于是双线性插值。这里效果不明显的原因是上采样倍数太大了

2.2.2 FCN-16s

pool5的输出上采样2倍(采样后大小与pool4的输出相同)然后与pool4输出相加然后再直接上采样16倍恢复到原图大小 

2.2.3  FCN-8s

pool5的输出上采样2倍(采样后大小与pool4的输出相同)然后与pool4输出相加然后再上采样2倍(采样后大小与pool3的输出相同),然后与pool3输出相加然后再直接上采样8倍恢复到原图大小。

 实现FCN-8s时的参数如下

参数名称 参数值
f6.stride 1
f6.padding 3
f7.stride 1
f7.padding 1
转置卷积1.padding 1
转置卷积1.stride 2
转置卷积2.padding 1
转置卷积2.stride 2
转置卷积3.padding 4
转置卷积3.stride 8

规律:设倍率为x,当转置卷积的2*padding -x = k.size、 s为上采样倍率x时恰好可以上采样  

转置卷积计算公式:

o'为卷积输出大小,i‘为卷积输入大小,s为卷积核stride,k为卷积核大小,p为填充

2.3 代码实现

 FCN-32s

pre_model = models.vgg16_bn(weights=True)

class FCN32(nn.Module):
    def __init__(self, num_classes = 1):
        super(FCN32, self).__init__()

        self.stage1 = pre_model.features[:7]
        self.stage2 = pre_model.features[7:14]
        self.stage3 = pre_model.features[14:24]
        self.stage4 = pre_model.features[24:34]
        self.stage5 = pre_model.features[34:]


        self.stage6 = nn.Sequential(
                    nn.Conv2d(512, 4096, kernel_size=(7,7), stride=1, padding=3),
                    nn.ReLU(inplace=True),
                    nn.Dropout())
        self.stage7 = nn.Sequential(
                    nn.Conv2d(4096, 4096, kernel_size=(1,1), stride=1),
                    nn.ReLU(inplace=True),
                    nn.Dropout())

        self.conv1 = nn.Sequential(
                    nn.Conv2d(4096, num_classes, kernel_size=(1,1), stride=1))

        self.invers_conv1 = nn.ConvTranspose2d(num_classes,num_classes,kernel_size=(64,64), stride=32, padding=16)


    def forward(self, x):
        x_size = x.size()
        out = self.stage1(x)
        out = self.stage2(out)
        out = self.stage3(out)
        out = self.stage4(out)
        out = self.stage5(out)


        out = self.stage6(out)
        out = self.stage7(out)
        out = self.conv1(out)

        out = self.invers_conv1(out)
        return out 

 FCN-16s

class FCN16(nn.Module):
    def __init__(self, num_classes = 1):
        super(FCN16, self).__init__()

        self.stage1 = pre_model.features[:7]
        self.stage2 = pre_model.features[7:14]
        self.stage3 = pre_model.features[14:24]
        self.stage4 = pre_model.features[24:34]
        self.stage5 = pre_model.features[34:]

        self.score_pool4 = nn.Conv2d(512, num_classes, kernel_size=1)

        self.stage6 = nn.Sequential(
                    nn.Conv2d(512, 4096, 7, padding=3),
                    nn.ReLU(inplace=True),
                    nn.Dropout())
        self.stage7 = nn.Sequential(
                    nn.Conv2d(4096, 4096, 1),
                    nn.ReLU(inplace=True),
                    nn.Dropout())

        self.conv1 = nn.Sequential(
                    nn.Conv2d(4096, num_classes, 1))
        self.invers_conv1 = nn.ConvTranspose2d(num_classes,num_classes,4, stride=2, padding=1)
        self.invers_conv2 = nn.ConvTranspose2d(num_classes,num_classes,kernel_size=(32,32), stride=16, padding=8)


    def forward(self, x):
        x_size = x.size()
        out = self.stage1(x)
        out = self.stage2(out)
        out = self.stage3(out)
        out_4 = self.stage4(out)
        out = self.stage5(out_4)

        out = self.stage6(out)
        out = self.stage7(out)
        mid1 = self.conv1(out)
        upscore2 = self.invers_conv1(mid1)
        score_pool4 = self.score_pool4(out_4)
        upscore16 = self.invers_conv2(score_pool4 + upscore2)
        return upscore16

FCN-8s 

class FCN8(nn.Module):
    def __init__(self, num_classes = 1):
        super(FCN8, self).__init__()

        self.stage1 = pre_model.features[:7]
        self.stage2 = pre_model.features[7:14]
        self.stage3 = pre_model.features[14:24]
        self.stage4 = pre_model.features[24:34]
        self.stage5 = pre_model.features[34:]

        self.score_pool4 = nn.Conv2d(512, num_classes, kernel_size=1)
        self.score_pool3 = nn.Conv2d(256, num_classes, kernel_size=1)

        self.stage6 = nn.Sequential(
                    nn.Conv2d(512, 4096, 7, padding=3),
                    nn.ReLU(inplace=True),
                    nn.Dropout())
        self.stage7 = nn.Sequential(
                    nn.Conv2d(4096, 4096, 1),
                    nn.ReLU(inplace=True),
                    nn.Dropout())
        self.conv1 = nn.Sequential(
                    nn.Conv2d(4096, num_classes, 1))

        self.invers_conv0 = nn.ConvTranspose2d(num_classes,num_classes,4, stride=2, padding=1)
        self.invers_conv1 = nn.ConvTranspose2d(num_classes,num_classes,4, stride=2, padding=1)
        self.invers_conv2 = nn.ConvTranspose2d(num_classes,num_classes,kernel_size=(16,16), stride=8, padding=4)


    def forward(self, x):
        x_size = x.size()
        out = self.stage1(x)
        out = self.stage2(out)
        out_3 = self.stage3(out)
        out_4 = self.stage4(out_3)
        out = self.stage5(out_4)

        out = self.stage6(out)
        out = self.stage7(out)
        mid1 = self.conv1(out)

        upscore2 = self.invers_conv0(mid1)
        score_pool4 = self.score_pool4(out_4)
        fc16 = self.invers_conv1(score_pool4 + upscore2)
        score_pool3 = self.score_pool3(out_3)
        upscore16 = self.invers_conv2(fc16+score_pool3)
        return upscore16

参考: 

FCN(全卷积神经网络)详解 

语义分割——FCN模型pytorch实现

B站霹雳吧啦

全卷积网络 FCN 详解

你可能感兴趣的:(网络,学习,笔记,人工智能,深度学习)