Pyramid Scene Parsing Network

Pyramid Scene Parsing Network
Keras实现代码链接:https://github.com/BBuf/Keras-Semantic-Segmentation

Contribution

  • 提出了金字塔场景解析网络,以将困难的场景上下文特征嵌入基于FCN的像素预测框架中。
  • 基于深度监督的损失为深度ResNet开发了有效的优化策略。
  • 构建了一个用于最新场景解析和语义分割的实用系统,其中包括了所有关键的实现细节。

Related Work

大多数语义分割模型的工作基于两个方面:

  • 一方面:具有多尺度的特征融合。高层特征包含更多的语义信息和较少的位置信息。 组合多尺度特征可以提高性能。
  • 另一个方面:是基于结构预测。例如使用CRF(条件随机场)做处理细化分割结果。

Pyramid Pooling Module

Pyramid Scene Parsing Network_第1张图片
为了进一步减少不同子区域之间的上下文信息丢失,本文提出了一个分层的全局先验,其中包含具有不同规模和不同子区域之间变化的信息,称其为金字塔池模块,用于在深度神经网络的最终层特征图上进行全局场景提前构造,如图3(c)所示。
该模块融合了4种不同金字塔尺度的特征,第一行红色是最粗糙的特征–全局池化生成单个bin输出,后面三行是不同尺度的池化特征。为了保证全局特征的权重,如果金字塔共有N个级别,则在每个级别后使用1×1的卷积将对于级别通道降为原本的1/N。再通过双线性插值进行up-sample获得未池化前的大小,最终将它们concat到一起。

金字塔等级的池化核大小是可以设定的,这与送到金字塔的输入有关。论文中使用的4个等级,核大小分别为1×1,2×2,3×3,6×6。

Network Architecture

Pyramid Scene Parsing Network_第2张图片

  • 基础层经过预训练的模型(ResNet101)和空洞卷积策略(dilated network strategy)提取feature map,提取后的feature map是输入大小的1/8
  • feature map经过Pyramid Pooling Module得到融合的带有整体信息的feature,在上采样之后与池化前的feature map相concat
  • 最后过一个卷积层得到最终输出
    PSPNet本身提供了一个全局上下文的先验(即指代Pyramid Pooling Module这个结构),后面的实验会验证这一结构的有效性。

Deep Supervision for ResNet-Based FCN

Pyramid Scene Parsing Network_第3张图片
图4展示了本文受深度监督的ResNet101模型的示例。除了使用softmax损失来训练最终分类器的主分支外,在第四阶段之后使用了另一个分类器,即res4b22残基块。 与将反向辅助损耗阻止到几个浅层的中继反向传播不同,本文让两个损耗函数通过所有先前的层。 辅助损失有助于优化学习过程,而主分支损失承担最大责任,增加权重以平衡辅助损失。

Implementation Details

  • 1、学习率:采用“poly”策略,即 l r = l r b a s e ∗ ( 1 − i t e r m a x i t e r ) p o w e r lr = lr_base * (1 - iter \over max_iter)^power maxiter)powerlr=lrbase(1iter,设置 l r b a s e = 0.01 , p o w e r = 0.9 , m o m e n t u m = 0.9 , w e i g h t d e c a y = 0.0001 lr_base = 0.01,power = 0.9,momentum = 0.9,weight decay = 0.0001 lrbase=0.01power=0.9momentum=0.9weightdecay=0.0001
  • 2、迭代次数:ImageNet数据集:150k,PASCAL VOC:30k,Cityscapes:90k
  • 3、数据增强:随机翻转、尺度在0.5-2之间随机缩放、角度在-10-10度之间随机旋转、随机高斯滤波
  • 4、batchsize = 16
  • 5、辅助loss的权重为0.4
  • 6、语言:Caffe

Keras实现的模型代码:

#coding=utf-8
from keras.models import *
from keras.layers import *
import keras.backend as K
import tensorflow as tf

#池化块(POOL)
def pool_block(inp, pool_factor):
    h = K.int_shape(inp)[1]
    w = K.int_shape(inp)[2]
    pool_size = strides = [int(np.round( float(h) / pool_factor)), int(np.round( float(w)/ pool_factor))]
    x = AveragePooling2D(pool_size, strides=strides, padding='same')(inp)
    x = Conv2D(256, (1, 1), padding='same', activation='relu')(x)
    x = BatchNormalization()(x)
    x = Lambda(lambda x: tf.image.resize_bilinear(x, size=(int(x.shape[1])*strides[0], int(x.shape[2])*strides[1])))(x)	# 上采样up-sample
    x = Conv2D(256, (1, 1), padding='same', activation='relu')(x)
    return x

def PSPNet(nClasses, input_width=384, input_height=384):
    assert input_height % 192 == 0
    assert input_width % 192 == 0
    inputs = Input(shape=(input_height, input_width, 3))

    x = (Conv2D(64, (3, 3), activation='relu', padding='same'))(inputs)
    x = (BatchNormalization())(x)
    x = (MaxPooling2D((2, 2)))(x)
    f1 = x
    # 192 x 192

    x = (Conv2D(128, (3, 3), activation='relu', padding='same'))(x)
    x = (BatchNormalization())(x)
    x = (MaxPooling2D((2, 2)))(x)
    f2 = x
    # 96 x 96
    
    x = (Conv2D(256, (3, 3), activation='relu', padding='same'))(x)
    x = (BatchNormalization())(x)
    x = (MaxPooling2D((2, 2)))(x)
    f3 = x
    # 48 x 48
    
    x = (Conv2D(256, (3, 3), activation='relu', padding='same'))(x)
    x = (BatchNormalization())(x)
    x = (MaxPooling2D((2, 2)))(x)
    f4 = x
    # 24 x 24
    
    o = f4
    pool_factors = [1, 2, 3, 6]	# 不同尺度的池化因子(4个)
    pool_outs = [o]
    for p in pool_factors:
        pooled = pool_block(o, p)
        pool_outs.append(pooled)

    o = Concatenate(axis=3)(pool_outs)	# 将上采样后的特征图拼接在一起
    o = Conv2D(256, (3, 3), activation='relu', padding='same')(o)
    o = BatchNormalization()(o)

    o = Lambda(lambda x: tf.image.resize_bilinear(x, size=(int(x.shape[1])*8, int(x.shape[2])*8)))(x)

    o = Conv2D(nClasses, (1, 1), padding='same')(o)
    o_shape = Model(inputs, o).output_shape
    outputHeight = o_shape[1]
    outputWidth = o_shape[2]
    print(outputHeight)
    print(outputWidth)
    o = (Reshape((outputHeight*outputWidth, nClasses)))(o)
    o = (Activation('softmax'))(o)
    model = Model(inputs, o)
    model.outputWidth = outputWidth
    model.outputHeight = outputHeight

    return model

参考:https://zhuanlan.zhihu.com/p/36670958
Pyramid Scene Parsing Network_第4张图片

你可能感兴趣的:(图像分割,python,深度学习)