一.资源
DeelLab系列:DeepLabv1、DeepLabv2及运行、DeepLabv3、DeepLabv3+及运行。
二.模型结构
三.编码器
编码器是Deeplabv3模型的logits前的部分。
四.解码器
让空洞卷积提取更稠密的特征有助于恢复边界细节,但计算量会剧增,所以需要解码器。
单纯使用上采样的解码器不一定能恢复物体边界细节,所以重新设计了解码器。
v3+的表1说明解码器中1×1的卷积通道应为48,表2说明上采样前应该使用两个[3×3×256]的卷积。
五.空洞卷积
定义:感受野内像素不连续的卷积。一个感受野内相邻像素间的距离(单位是像素个数)称为空洞率。图5-1的空洞率为2,普通卷积是空洞率为1的空洞卷积。
作用:随意控制特征的分辨率、调整感受野的尺度。
空洞卷积可以在加深网络的同时保持较好的性能,如图5-2所示。ResNet有4个block,把block4复制3份作为block5、block6、block7串联在block4后面。
不带空洞卷积的串联模型,如图5-2(a):复制的3个block各包含3个卷积,其中block5和block6的第三个卷积步长为2(模仿resNet的做法)。从图中可以看出,因为步长为2,block5和block6后图像分辨率变小了,而block7后没变。这样连续的跨步(步长大于1)丢失了细节信息所以效果不好,如表5-1,output_stride(特征图与原图的边长比)为256时mIOU明显降低。
带空洞卷积的串联模型,如图5-2(b):同样每个block中有3个卷积,参数没有增加,可以把output_stride保持为16。不采用output_stride=8是为了避免较大的内存占用。
六.深度可分离卷积、空洞可分离卷积
1.普通卷积的操作如图6-1所示,左图是卷积操作的输入,[宽, 高, 通道]=[6, 12, 7]。右图是3×3的卷积核,[宽, 高, 通道]=[3, 3, 7]。因为输入有7个通道,所以卷积核也有7个通道,一个卷积核的权重个数为3×3×7=63。
2.深度可分离卷积:图6-2中(a)和(b)的组合。深度可分离卷积的卷积核是平面的。对图6-1中的卷积,一个深度可分离卷积的卷积核的权重参数个数是3×3+1=10(1是点卷积的权重)。所以可以减少参数、降低计算量。
3.空洞可分离卷积:图6-2中(c)和(b)的组合。具备深度可分离卷积参数少、计算量少的特点和空洞卷积能随意控制特征分辨率、调整感受野尺度的特点。
七.ASPP
1.DeepLabv2提出ASPP。
2.DeepLabv3在ASPP中加入了BN。ASPP使用不同的空洞率提取不同尺度的信息,但当滤波器采样率(空洞率)变大时卷积核有效权重(非填充0区域对应的权重)的个数会变少,如图7-1。
为了解决这个问题,去掉了空洞率为24的卷积添加了1×1的卷积和图像级特征,如图7-2所示:
具体来说就是:
#步骤一
1×1的普通卷积:conv_1×1=conv2d(inputs, depth, [1, 1], stride=1)
#步骤二
3×3的空洞卷积:conv_3×3_1=conv2d(inputs, depth, [3, 3], stride=1, rate=6)
#步骤三
3×3的空洞卷积:conv_3×3_2=conv2d(inputs, depth, [3, 3], stride=1, rate=12)
#步骤四
3×3的空洞卷积:conv_3×3_3=conv2d(inputs, depth, [3, 3], stride=1, rate=18)
#步骤五
全局平均池化:image_level_features = tf.reduce_mean(inputs, [1, 2], name='global_average_pooling', keepdims=True)
1x1×256的卷积加BN:image_level_features = layers_lib.conv2d(image_level_features, depth, [1, 1], stride=1, scope='conv_1x1')
双线性上采样:image_level_features = tf.image.resize_bilinear(image_level_features, inputs_size, name='upsample')
步骤五利用全局平均池化获取图像级特征,上面的depth=256。上面5个操作就是图7-2黄色大括号中的具体实现。然后对5个操作的结果进行合并、卷积,就是编码器的输出:
net = tf.concat([conv_1x1, conv_3x3_1, conv_3x3_2, conv_3x3_3, image_level_features], axis=3, name='concat')
net = layers_lib.conv2d(net, depth, [1, 1], stride=1, scope='conv_1x1_concat')