深度学习图像语义分割网络总结:FCN与SegNet的Pytorch实现

图像语义分割网络系列博文索引

FCN与SegNet U-Net与V-Net DeepLab系列 DenseNet、PSPNet、与DenseASPP Mask R-CNN

(后四个在计划中,敬请期待)

全卷积网络FCN

FCN为深度学习在图像语义分割领域里程碑的一篇,实现了对任意大小输入图像进行像素级别的端到端的语义分割。原文链接:Fully Convolutional Networks for Semantic Segmentation
全卷积网络FCN示意图

图1 全卷积网络FCN示意图

我们的关键观点是构建“全卷积”网络,它接受任意大小的输入,并通过有效的推理和学习产生相应大小的输出。我们定义并详述全卷积网络的空间,解释它们在空间密集预测任务中的应用,并与之前的模型建立联系。我们将当前的分类网络(AlexNet [19], VGG网[31],和GoogLeNet[32])改造为完全卷积网络,并通过微调来将其学习到的表示迁移到分割任务。然后,我们定义了一种新的架构,该架构结合了来自深、粗层的语义信息和来自浅、细层的表征信息,从而产生精确和详细的分割。我们的全卷积网络实现了最先进的NYUDv2,SIFT流和PASCAL VOC分割(相对2012年的结果提升了20%,达到了62.2%的平均IU),而对一个典型图像的推断只需要不到五分之一秒。

FCN主要贡献

  1. 使用迁移学习的方法对已有的分类网络(AlexNet,VGG,GoogLeNet)进行结构改造和参数微调(fine-tuning)用于图像的语义分割。
  2. 使用全卷积的方法替代分类网络中的全连接层,因为作者认为全连接层破坏了图像像素中的空间关系。图2中展示了使用全连接层与卷积层的对比图,全连接层输出的是一维概率分布,卷积层输出为二维热力图(heat map),较好的保留了像素之间的空间关系,为之后像素级别的图像分割提供了便利。同时采用全卷积相对全连接也大大提升了计算效率。全连接与全卷积对比图
    图2 全连接与全卷积对比图
  3. 为了稀疏的输出(卷积得到的heat map)与密集的像素建立联系,作者采用了反卷积的方式进行上采样,采用反卷积进行上采样是需要学习的,也可以直接采用双线性插值的方式进行上采样。这个密集和稀疏建立联系是由分多个阶段的跃迁实现的,一定程度上可以理解为多尺度图像融合,目的是实现精细的预测。

FCN网络结构

FCN网络结构

图3 FCN网络结构图

如图3所示FCN-32s是由pool5得到的特征图直接采用上采样得到的结果,FCN-16s是pool5经过二倍上采样与pool4求和之后再进行上采样,FCN-8s与此过程类似。可视化的FCN网络机构可以参考这里(http://ethereon.github.io/netscope/#/preset/fcn-8s-pascal)

Pytorch框架下FCN实现

这里使用的代码是在Github中guanfuchen/semseg原代码的基础上做了一些顺序上的调整及更多的标注帮助理解。

# -*- coding: utf-8 -*-
import time

import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.autograd import Variable
from torchvision import models

# fcn32s模型
def fcn_32s(n_classes=21, pretrained=True):
    model = fcn(module_type='32s', n_classes=n_classes, pretrained=pretrained)
    return model

def fcn_16s(n_classes=21, pretrained=True):
    model = fcn(module_type='16s', n_classes=n_classes, pretrained=pretrained)
    return model

def fcn_8s(n_classes=21, pretrained=True):
    model = fcn(module_type='8s', n_classes=n_classes, pretrained=pretrained)
    return model
    
def cross_entropy2d(input, target, weight=None, size_average=True):
    n, c, h, w = input.size()
    nt, ht, wt = target.size()

    # Handle inconsistent size between input and target
    if h > ht and w > wt:  # upsample labels
        target = target.unsequeeze(1)
        target = F.upsample(target, size=(h, w), mode="nearest")
        target = target.sequeeze(1)
    elif h < ht and w < wt:  # upsample images
        input = F.upsample(input, size=(ht, wt), mode="bilinear")
    elif h != ht and w != wt:
        raise Exception("Only support upsampling")

    input = input.transpose(1, 2).transpose(2, 3).contiguous().view(-1, c)
    target = target.view(-1)
    loss = F.cross_entropy(input, target, weight=weight, size_average=size_average, ignore_index=250)
    return loss

class fcn(nn.Module):
    def __init__(self, module_type='32s', n_classes=21, pretrained=True):
        super(fcn, self).__init__()
        self.n_classes = n_classes
        self.module_type = module_type

        # VGG16=2+2+3+3+3+3
        # VGG16网络的第一个模块是两个out_channel=64的卷积块
        self.conv1_block = nn.Sequential(
            nn.Conv2d(3, 64, 3, padding=100),        #输入3通道,输出64通道,卷积核大小为3,用100填充
            nn.ReLU(inplace=True),                   #inplace=True,节省内存
            nn.Conv2d(64, 64, 3, padding=1),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(2, stride=2, ceil_mode=True), #核的大小为2,步长为2,向上取整
        )

        # VGG16网络的第二个模块是两个out_channel=128的卷积块
        self.conv2_block = nn.Sequential(
            nn.Conv2d(64, 128, 3, padding=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(128, 128, 3, padding=1),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(2, stride=2, ceil_mode=True),
        )

        # VGG16网络的第三个模块是三个out_channel=256的卷积块
        self.conv3_block = nn.Sequential(
            nn.Conv2d(128, 256, 3, padding=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(256, 256, 3, padding=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(256, 256, 3, padding=1),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(2, stride=2, ceil_mode=True),
        )

        # VGG16网络的第四个模块是三个out_channel=512的卷积块
        self.conv4_block = nn.Sequential(
            nn.Conv2d(256, 512, 3, padding=1),
            nn.ReLU(inplace=True),
            nn.Conv2d(512
  • 4
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值