DeepLab系列:
DeepLabV1
贡献:首次把空洞卷积引入图形分割领域。
基本内容:
- 基于VGG16
- 去掉最后两个池化层改为卷积层(控制分辨率不要太小)
- 去掉全连接层(保留最后一个用于softmax分类)
- 后三个卷积改为空洞卷积(保证感受野与去掉池化层前接近)
- 对结果上采样后用CRF细化分割效果。
DeepLabv2
贡献:引入带空洞卷积的空间金字塔池化(ASPP)
基本内容:
- 基础网络由VGG16->ResNet
- 多尺度空洞卷积并行
- 采用多项式lr衰减
- 与v1一样,对结果上采样后用CRF细化分割效果。
DeepLabV3
贡献:优化ASPP
基本内容:
- 提出了多尺度信息的并行与串行结构
- ASPP中应用了BN层
- 考虑了dilation rate的意义,重新设置了rate不能过大(rate过大,filter中有效权重减少,更难捕获远距离信息)
- ASPP中加入全局平均池化,获取全局尺度信息
- 去掉了CRF后处理
DeepLabV3+
贡献:引入了编码-解码结构
基本内容:
- v3作为编码部分,添加了解码部分
- 尝试了用Xception作为基础网络
后续改进方法
改进网络结构:
- 尝试范围空间卷积
- ASPP全局平均池化如果是要传递全局尺度信息,直接传原feature map会不会有更好的效果
- 解码部分尝试U-Net结构,结合不同分辨率下提取到的信息进行分割
用集成学习提高模型效果(模型融合)
- 同轴为下,相同模型不同参数做平均
- 同轴位下,不同模型之间做集成
- 三个轴位,各自训练 模型,然后集成
ASPP卷积那块是不是可以尝试多个卷积,以及加原feature map用上来;以及外加一个senet模块
以及双目结构
DeepLabv1:SEMANTIC IMAGE SEGMENTATION WITH DEEP CONVOLUTIONAL NETS AND FULLY CONNECTED CRFS
贡献:首次把空洞卷积引入图形分割领域。
基本内容:
- 基于VGG16
- 去掉最后两个池化层改为卷积层(控制分辨率不要太小)
- 去掉全连接层(保留最后一个用于softmax分类)
- 后三个卷积改为空洞卷积(保证感受野与去掉池化层前接近)
- 对结果上采样后用CRF细化分割效果。
DCNN在像素标记存在两个问题:信号下采样和空间不变性。
第一个问题是由于DCNN重复的最大池化核下采样造成分辨率下降,DeepLabv1通过带孔(atrous)算法解决。
第二个问题是分类器获得以对象为中心的决策需要空间不变性,从而限制了DCNN的空间精度,DeepLabv1通过条件随机场(CRF)提高模型捕获精细细节的能力。
- 多次池化、下采样使输出信号分辨率变小:使用空洞卷积
- 池化对于输入变换具有内在空间不变性:使用CRF
DeepLabv1是结合力深度卷积神经网络(DCNNs)和概率图(DenseCRFs)的方法。DeepLab创造性的结合了DCNN和CRF产生一种新的语义分割模型,模型有准确的预测结果同时计算效率高。在PASCAL VOC 2012上展现了先进的水平。DeepLab是卷积神经网络和概率图模型的交集,后续可考虑将CNN和CRF结合到一起做end-to-end训练。
方法
空洞卷积

条件随机场CRF


- VGG16的全连接层(FC层)转为卷积层(步幅32,步幅=输入尺寸/输出特征吃尺寸)
- 最后的两个池化层去掉了下采样(目标步幅8)
- 后续卷积层的卷积核改为了空洞卷积(扩大感受野,缩小步幅)
- 在ImageNet预训练的VGG16的权重上做fine-tune(迁移学习)
DeepLabv2: Semantic Image Segmentation with Deep Convolutional Nets, Atrous Convolution, and Fully Connected CRFs
贡献:引入带空洞卷积的空间金字塔池化(ASPP)
基本内容:
- 基础网络由VGG16->ResNet
- 多尺度空洞卷积并行
- 采用多项式lr衰减
- 与v1一样,对结果上采样后用CRF细化分割效果。
在V1的基础上,做了以下改进:
-
在多尺度获得了更好的分割效果(使用ASPP)
-
基础层由VGG16转为ResNet
-
使用不同的学习策略(poly)
-
首先,
强调使用空洞卷积,作为密集预测任务的强大工具。空洞卷积能够明确的控制DCNN内计算特征响应的分辨率,即可有效的扩大感受野,在不增加参数量和计算量的同时获取更多的上下文。 -
其次,
提出了空洞空间卷积池化金字塔(atrous spatial pyramid pooling(ASPP)),以多尺度的信息得到更强健的分割效果。ASPP并行的采用多个采样率的空洞卷积来探测,以多个比例捕捉对象以及图像上下文。 -
最后,
通过组合DCNN和概率图模型,改进分割边界结果。在DCNN中最大池化和下采样组合实现可平移不变性,但这对精度是由影响的。通过将最终的DCNN层响应和全连接的CRF组合来克服这个问题。


总体步骤如下:
- 输入经过改进的DCNN(带空洞卷积和ASPP模型)得到粗略预测结果,即
Aeroplane Coarse Score map; - 通过双线性插值扩大到原本大小,即
Bi-linear Interpolation - 再通过全连接的CRF细化预测结果,得到最终输出
Final Output
空洞卷积能在保持计算量和参数量的同时扩大感受野,配合使用金字塔池化方案可以聚合多尺度的上下文信息,可通过空洞卷积控制特征分辨率,配合更先进的DCNN模型、多尺度联合技术,并在DCNN之上集成全连接的CRF可以获得更好的分割效果。
- 空洞卷积用于密集特征提取和扩大感受野
- 使用ASPP模块表示多尺度图像
- 使用全连接CRF做结构预测用于恢复边界精度。
DeepLabV3:Rethinking Atrous Convolution for Semantic Image Segmentation
贡献:优化ASPP
基本内容:
-
提出了多尺度信息的并行与串行结构
-
ASPP中应用了BN层
-
考虑了dilation rate的意义,重新设置了rate不能过大(rate过大,filter中有效权重减少,更难捕获远距离信息)
-
ASPP中加入全局平均池化,获取全局尺度信息
-
去掉了CRF后处理
-
在本文中重新讨论了空洞卷积的使用,在级联模块和空间金字塔池化的框架下,能够获取更大的感受野从而获取多尺度的信息。
-
改进了ASPP模块:由不同采样率的空洞卷积核BN层组成,我们尝试以级联或并行的方式布局模块。
-
讨论了一个重要问题:使用大采样率的3 * 3 的空洞卷积,因为图像边界响应无法捕捉远距离信息,会退化为1 x 1的卷积,我们建议将图像级特征融合到ASPP模块中。
4种不同的类型利用上下文信息做语义分割的全卷积网络
- 图像金字塔(Image pyramid):通常使用共享权重的模型,适用于多尺度的输入。
小尺度的输入响应控制语义,大尺寸的输入响应控制细节。通过拉布拉斯金字塔对输入变换成多尺度,传入DCNN,融合输出。这类的缺点是:因为GPU存储器的限制,对于更大/更深的模型不方便扩展。通常应用于推断阶段。 - 编码器-解码器(Encoder-decoder):
编码器的高层次的特征容易捕获更长的距离信息,在解码器阶段使用编码器阶段的信息帮助恢复目标的细节和空间维度。例如SegNet利用下采样的池化索引作为上采样的指导;U-Net增加了编码器部分的特征跳跃连接到解码器;RefineNet等证明了Encoder-Decoder结构的有效性。 - 上下文模块(Context module):包含了额外的模块用于级联编码长距离的上下文。一种有效的方法是DenseCRF并入DCNN中,共同训练DCNN和CRF.
- 空间金字塔池化(Spatial pyramid pooling):
采用空间金字塔池化可以捕获多个层次的上下文。在ParseNet中从不同图像等级的特征中获取上下文信息;DeepLabV2提出ASPP,以不同采样率的并行空洞卷积捕捉多尺度信息。最近PSPNet在不同网格尺度上执行空间池化,并在多个数据集上获得优异的表现。

串联

纵式

DeepLabv3+:Encoder-Decoder with Atrous Separable Convolution for Semantic Image Segmentation
贡献:引入了编码-解码结构
基本内容:
- v3作为编码部分,添加了解码部分
- 尝试了用Xception作为基础网络
v3+的创新点:
- 设计基于v3的decode的module
- 用modify xception作为backbone


代码

class BilinearUpsampling(Layer):
def __init__(self, upsampling=(2, 2), data_format=None, **kwargs):
super(BilinearUpsampling, self).__init__(**kwargs)
self.data_format = normalize_data_format(data_format)
self.upsampling = normalize_tuple(upsampling, 2, 'size')
self.input_spec = InputSpec(ndim=4)
def compute_output_shape(self, input_shape):
height = self.upsampling[0] * \
input_shape[1] if input_shape[1] is not None else None
width = self.upsampling[1] * \
input_shape[2] if input_shape[2] is not None else None
return (input_shape[0],
height,
width,
input_shape[3])
def call(self, inputs):
return K.tf.image.resize_bilinear(inputs, (int(inputs.shape[1]*self.upsampling[0]),
int(inputs.shape[2]*self.upsampling[1])))
def get_config(self):
config = {'size': self.upsampling,
'data_format': self.data_format}
base_config = super(BilinearUpsampling, self).get_config()
return dict(list(base_config.items()) + list(config.items()))
# 定义xception的下采样模块
def xception_downsample_block(x, channels, top_relu=False):
##separable conv1
if top_relu:
x = Activation("relu")(x)
x = DepthwiseConv2D((3, 3), padding="same", use_bias=False)(x)
x = BatchNormalization()(x)
x = Conv2D(channels, (1, 1), padding="same", use_bias=False)(x)
x = BatchNormalization()(x)
x = Activation("relu")(x)
##separable conv2
x = DepthwiseConv2D((3, 3), padding="same", use_bias=False)(x)
x = BatchNormalization()(x)
x = Conv2D(channels, (1, 1), padding="same", use_bias=False)(x)
x = BatchNormalization()(x)
x = Activation("relu")(x)
##separable conv3
x = DepthwiseConv2D((3, 3), strides=(2, 2), padding="same", use_bias=False)(x)
x = BatchNormalization()(x)
x = Conv2D(channels, (1, 1), padding="same", use_bias=False)(x)
x = BatchNormalization()(x)
return x
# 定义一个res的xception的下采样模块
def res_xception_downsample_block(x,channels):
res=Conv2D(channels,(1,1),strides=(2,2),padding="same",use_bias=False)(x)
res=BatchNormalization()(res)
x=xception_downsample_block(x,channels)
x=add([x,res])
return x
# 定义一个xception的卷积模块
def xception_block(x, channels):
##separable conv1
x = Activation("relu")(x)
x = DepthwiseConv2D((3, 3), padding="same", use_bias=False)(x)
x = BatchNormalization()(x)
x = Conv2D(channels, (1, 1), padding="same", use_bias=False)(x)
x = BatchNormalization()(x)
##separable conv2
x = Activation("relu")(x)
x = DepthwiseConv2D((3, 3), padding="same", use_bias=False)(x)
x = BatchNormalization()(x)
x = Conv2D(channels, (1, 1), padding="same", use_bias=False)(x)
x = BatchNormalization()(x)
##separable conv3
x = Activation("relu")(x)
x = DepthwiseConv2D((3, 3), padding="same", use_bias=False)(x)
x = BatchNormalization()(x)
x = Conv2D(channels, (1, 1), padding="same", use_bias=False)(x)
x = BatchNormalization()(x)
return x
# 定义一个res_xception模块
def res_xception_block(x,channels):
res=x
x=xception_block(x,channels)
x=add([x,res])
return x
# 定义一个aspp模块
def aspp(x, input_shape, out_stride):
b0 = Conv2D(256, (1, 1), padding="same", use_bias=False)(x)
b0 = BatchNormalization()(b0)
b0 = Activation("relu")(b0)
b1 = DepthwiseConv2D((3, 3), dilation_rate=(6, 6), padding="same", use_bias=False)(x)
b1 = BatchNormalization()(b1)
b1 = Activation("relu")(b1)
b1 = Conv2D(256, (1, 1), padding="same", use_bias=False)(b1)
b1 = BatchNormalization()(b1)
b1 = Activation("relu")(b1)
b2 = DepthwiseConv2D((3, 3), dilation_rate=(12, 12), padding="same", use_bias=False)(x)
b2 = BatchNormalization()(b2)
b2 = Activation("relu")(b2)
b2 = Conv2D(256, (1, 1), padding="same", use_bias=False)(b2)
b2 = BatchNormalization()(b2)
b2 = Activation("relu")(b2)
b3 = DepthwiseConv2D((3, 3), dilation_rate=(12, 12), padding="same", use_bias=False)(x)
b3 = BatchNormalization()(b3)
b3 = Activation("relu")(b3)
b3 = Conv2D(256, (1, 1), padding="same", use_bias=False)(b3)
b3 = BatchNormalization()(b3)
b3 = Activation("relu")(b3)
out_shape = int(input_shape[0] / out_stride)
b4 = AveragePooling2D(pool_size=(out_shape, out_shape))(x)
b4 = Conv2D(256, (1, 1), padding="same", use_bias=False)(b4)
b4 = BatchNormalization()(b4)
b4 = Activation("relu")(b4)
b4 = BilinearUpsampling((out_shape, out_shape))(b4)
x = Concatenate()([b4, b0, b1, b2, b3])
return x
def deeplabv3_plus(input_shape=(512, 512, 3), out_stride=16, num_classes=21):
img_input = Input(shape=input_shape)
x = Conv2D(32, (3, 3), strides=(2, 2), padding="same", use_bias=False)(img_input)
x = BatchNormalization()(x)
x = Activation("relu")(x)
x = Conv2D(64, (3, 3), padding="same", use_bias=False)(x)
x = BatchNormalization()(x)
x = Activation("relu")(x)
x = res_xception_downsample_block(x, 128)
res = Conv2D(256, (1, 1), strides=(2, 2), padding="same", use_bias=False)(x)
res = BatchNormalization()(res)
x = Activation("relu")(x)
x = DepthwiseConv2D((3, 3), padding="same", use_bias=False)(x)
x = BatchNormalization()(x)
x = Conv2D(256, (1, 1), padding="same", use_bias=False)(x)
x = BatchNormalization()(x)
x = Activation("relu")(x)
x = DepthwiseConv2D((3, 3), padding="same", use_bias=False)(x)
x = BatchNormalization()(x)
x = Conv2D(256, (1, 1), padding="same", use_bias=False)(x)
skip = BatchNormalization()(x)
x = Activation("relu")(skip)
x = DepthwiseConv2D((3, 3), strides=(2, 2), padding="same", use_bias=False)(x)
x = BatchNormalization()(x)
x = Conv2D(256, (1, 1), padding="same", use_bias=False)(x)
x = BatchNormalization()(x)
x = add([x, res])
x = xception_downsample_block(x, 512, top_relu=True)
for i in range(8):
x = res_xception_block(x, 512)
res = Conv2D(1024, (1, 1), padding="same", use_bias=False)(x)
res = BatchNormalization()(res)
x = Activation("relu")(x)
x = DepthwiseConv2D((3, 3), padding="same", use_bias=False)(x)
x = BatchNormalization()(x)
x = Conv2D(512, (1, 1), padding="same", use_bias=False)(x)
x = BatchNormalization()(x)
x = Activation("relu")(x)
x = DepthwiseConv2D((3, 3), padding="same", use_bias=False)(x)
x = BatchNormalization()(x)
x = Conv2D(1024, (1, 1), padding="same", use_bias=False)(x)
x = BatchNormalization()(x)
x = Activation("relu")(x)
x = DepthwiseConv2D((3, 3), padding="same", use_bias=False)(x)
x = BatchNormalization()(x)
x = Conv2D(1024, (1, 1), padding="same", use_bias=False)(x)
x = BatchNormalization()(x)
x = add([x, res])
x = DepthwiseConv2D((3, 3), padding="same", use_bias=False)(x)
x = BatchNormalization()(x)
x = Conv2D(1024, (1, 1), padding="same", use_bias=False)(x)
x = BatchNormalization()(x)
x = Activation("relu")(x)
x = DepthwiseConv2D((3, 3), padding="same", use_bias=False)(x)
x = BatchNormalization()(x)
x = Conv2D(1024, (1, 1), padding="same", use_bias=False)(x)
x = BatchNormalization()(x)
x = Activation("relu")(x)
x = DepthwiseConv2D((3, 3), padding="same", use_bias=False)(x)
x = BatchNormalization()(x)
x = Conv2D(2048, (1, 1), padding="same", use_bias=False)(x)
x = BatchNormalization()(x)
x = Activation("relu")(x)
# aspp
x = aspp(x, input_shape, out_stride)
x = Conv2D(256, (1, 1), padding="same", use_bias=False)(x)
x = BatchNormalization()(x)
x = Activation("relu")(x)
x = Dropout(0.9)(x)
##decoder
x = BilinearUpsampling((4, 4))(x)
dec_skip = Conv2D(48, (1, 1), padding="same", use_bias=False)(skip)
dec_skip = BatchNormalization()(dec_skip)
dec_skip = Activation("relu")(dec_skip)
x = Concatenate()([x, dec_skip])
x = DepthwiseConv2D((3, 3), padding="same", use_bias=False)(x)
x = BatchNormalization()(x)
x = Activation("relu")(x)
x = Conv2D(256, (1, 1), padding="same", use_bias=False)(x)
x = BatchNormalization()(x)
x = Activation("relu")(x)
x = DepthwiseConv2D((3, 3), padding="same", use_bias=False)(x)
x = BatchNormalization()(x)
x = Activation("relu")(x)
x = Conv2D(256, (1, 1), padding="same", use_bias=False)(x)
x = BatchNormalization()(x)
x = Activation("relu")(x)
x = Conv2D(num_classes, (1, 1), padding="same")(x)
x = BilinearUpsampling((4, 4))(x)
# 添加softmax层
x = Reshape((-1,num_classes))(x)
output = Softmax()(x)
model = Model(img_input, output)
return model
1万+



被折叠的 条评论
为什么被折叠?



