直接上图片比较清晰直观。我们可以看到,7x7的feature map经过3x3kernel (dilation = 2),我们可以代入计算公式:Hout = (7 - 2 x (3-1) -1 + 1) = 3。当然stride = 2的话可以自己另外计算。
虽然空洞卷积能够增加感受野,增加在下采样过程中空间信息的保留。但是它也存在一些缺点:
空洞卷积和转置卷积的区别是,空洞卷积是卷积核裂开,转置卷积是feature map裂开,加padding。这个原来已经整理过,在FCN大总结中。
为了防止出现栅格化的现象,一般在使用block的第一个卷积层的dilation rate是1,就像图a所示,这样能够让经过空洞卷积的feature map的感受野有连续性。否则,从第一个卷积层是2的话,感受野就会不连续,出现栅格化效应也就不奇怪了。
这个网络是从VGG-16网络改变而来的。其实主要做了以下的一些改变:
在这里再总结一下V1的流程:
至于CRF,觉得不知道它为什么能够提高分辨的精确率
Multi-scale 就是把相同图片,变成不懂大小一起输入,之后把结果平均一下。
E ( x ) = ∑ i θ i ( x i ) + ∑ i j θ i j ( x i , x j ) E(\boldsymbol{x})=\sum_{i} \theta_{i}\left(x_{i}\right)+\sum_{i j} \theta_{i j}\left(x_{i}, x_{j}\right) E(x)=∑iθi(xi)+∑ijθij(xi,xj) x表示每一个像素的类别, x i x_i xi 表示第i个像素的类别。每一个点有21个取值情况。
θ i ( x i ) = − log P ( x i ) \theta_{i}\left(x_{i}\right)=-\log P\left(x_{i}\right) θi(xi)=−logP(xi)
θ i j ( x i , x j ) = μ ( x i , x j ) ∑ m = 1 K w m ⋅ k m ( f i , f i ) \theta_{i j}\left(x_{i}, x_{j}\right)=\mu\left(x_{i}, x_{j}\right) \sum_{m=1}^{K} w_{m} \cdot k^{m}\left(\boldsymbol{f}_{i}, \boldsymbol{f}_{i}\right) θij(xi,xj)=μ(xi,xj)∑m=1Kwm⋅km(fi,fi)
= μ ( x i , x j ) [ w 1 exp ( − ∥ p i − p j ∥ 2 2 σ α 2 − ∥ I i − I j ∥ 2 2 σ β 2 ) + w 2 exp ( − ∥ p i − p j ∥ 2 2 σ γ 2 ) ] μ ( x i , x j ) = 0 \quad=\mu\left(x_{i}, x_{j}\right)\left[w_{1} \exp \left(-\frac{\left\|p_{i}-p_{j}\right\|^{2}}{2 \sigma_{\alpha}^{2}}-\frac{\left\|I_{i}-I_{j}\right\|^{2}}{2 \sigma_{\beta}^{2}}\right)+w_{2} \exp \left(-\frac{\left\|p_{i}-p_{j}\right\|^{2}}{2 \sigma_{\gamma}^{2}}\right)\right] \quad \mu\left(x_{i}, x_{j}\right)=0 =μ(xi,xj)[w1exp(−2σα2∥pi−pj∥2−2σβ2∥Ii−Ij∥2)+w2exp(−2σγ2∥pi−pj∥2)]μ(xi,xj)=0 if x i = x j x_{i}=x_{j} xi=xj
μ ( x i , x j ) = 1 \mu\left(x_{i}, x_{j}\right)=1 μ(xi,xj)=1 if x i ≠ x j x_{i}≠x_{j} xi=xj,让这个θ变小一些。不过这一部分在DeepLabV3里面就被干掉了。
更多的是求解,和梯度下降。
large-FOV就是把3x3的空洞卷积stride变成12.让感受野变得更大,甚至是比原图的更大。
这个rate的意思就是dilation rate,其实现在看来还是写得比较清楚的。经过这4个卷积块之后,能够实现对不同尺度(感受野)的特征进行融合,提取到更加丰富的信息。
论文里面对ASPP还进行了一些说明和实验,在这里就把图片先贴出来。这个r就是rate,里面的列表表示的是每一个卷积层对应的dilation rate。实验中,数据占优的是ASPP-L,它的rate是比较大的,都是6的倍数。有些事情就是人肉搜索出来的,强硬解释为什么这个效果好的方法就只能说,这个卷积的感受野更大,融合的特征感受野也更大,有利于分割任务的完成。
在这里加一下ASPP的代码实现,这个还是比较重要的,因为自己对于代码实现还是比较薄弱的。需要增强一下这方面的知识。
import torch
import torch.nn as nn
import torch.nn.functional as F
class ASPP(nn.Module):
def __init__(self, in_chans, out_chans, rate=1):
super(ASPP, self).__init__()
# 1 x 1 无孔洞卷积
# conv2d 参数先是输入输出通道,然后是kernel size,stride padding dilation默认一般是1,
# bias看看能不能要
self.conv_part1 = nn.Sequential(
nn.Conv2d(in_chans,out_chans,1,1,padding=0,dilation=rate,bias=True),
nn.BatchNorm2d(out_chans),
nn.ReLU(inplace=True)
)
# 3 x 3 空洞6卷积
self.conv_part2 = nn.Sequential(
nn.Conv2d(in_chans, out_chans, 3, 1, padding = 6*rate, dilation= 6*rate,bias = True),
nn.BatchNorm2d(out_chans),
nn.ReLU(inplace= True)
)
self.conv_part3 = nn.Sequential(
nn.Conv2d(in_chans,out_chans,3,1,padding=12 * rate,dilation=12 * rate, bias = True),
nn.BatchNorm2d(out_chans),
nn.ReLU(inplace=True)
)
# 为什么没有24的dilation,因为在deeplabV3+中24的dilation被去除了
self.conv_part4 = nn.Sequential(
nn.Conv2d(in_chans,out_chans,3,1,padding=18*rate, dilation=18*rate,bias = True),
nn.BatchNorm2d(out_chans),
nn.ReLU(inplace=True)
)
# 全局池化:里面的参数output size,这部分代码,就是对合并之后的feature map处理的代码作者
# 在论文里面并没有写。
self.conv_part5_avg = nn.AdaptiveAvgPool2d(1)
# 1 x 1的cbr用来处理平均池化所得到的特征图
self.conv_part5_conv = nn.Conv2d(in_chans,out_chans,1,1,bias = True)
self.conv_part5_bn = nn.BatchNorm2d(out_chans)
self.conv_part5_relu = nn.ReLU(inplace=True)
self.conv_cat = nn.Sequential(
nn.Conv2d(out_chans * 5,out_chans, 1,1,padding=0,bias=True),
nn.BatchNorm2d(out_chans),
nn.ReLU(inplace=True)
)
def forward(self, x):
b, c, h, w = x.size()
conv1x1 = self.conv_part1(x)
conv3x3_1 = self.conv_part2(x)
conv3x3_2 = self.conv_part3(x)
conv3x3_3 = self.conv_part4(x)
global_feature = self.conv_part5_avg(x)
# 对全局池化的特征要进行处理
global_feature = self.conv_part5_relu(self.conv_part5_bn(self.conv_part5_conv(global_feature)))
# 上采样到原图的大小,一直到deeplabV3+作者才用了了转置卷积
global_feature = F.interpolate(global_feature,(h,w),None,'bilinear',True)
# 在bchw上contact,所以dim必须是1
feature_cat = torch.cat([conv1x1,conv3x3_1,conv3x3_2,conv3x3_3,global_feature],dim = 1)
result = self.conv_cat(feature_cat)
return result
KaTeX parse error: Expected '}', got '_' at position 42: … }}{\text { max_̲iter }}\right)^… 这个是作者在训练的时候对学习率的调整策略,和原来百度的三角调整策略很相似。
在论文中,作者实验的power值是0.9.iter是每一次迭代(不是epoch的意思,max_iter = epoch * iter_per_epoch)。当然这个应该只是一个权重,前面应该还需要乘上一个系数,也就是lr。
作者在计算的时候发现,batch_size减小的时候mean_IOU也不会降低,于是就减小了它,加快训练速度。
论文的剩下部分就是实验结果部分了。我们可以大踏步来到V3
作者一直在想方设法把CRF给去掉,终于在这一个版本,作者成功去掉了CRF这个模块。在这一个版本,作者的改动其实并不太多。用的block都是resnet_block。只不过在使用的时候,作者把block4重复了好几次,做了一个Cascade。在block内部,作者对每一个conv的dilation rate进行了调整。当然作者也不会忘记对ASPP进行调整,作者也做了一个parallel网络,最终选择的网络还是parallel,说明特征融合的强大。
我们首先来看看Cascade模块:
其中image Pooling的代码如下:
global_feature = self.conv_part5_avg(x)
# 对全局池化的特征要进行处理
global_feature = self.conv_part5_relu(self.conv_part5_bn(self.conv_part5_conv(global_feature)))
global_feature = F.interpolate(global_feature,(h,w),None,'bilinear',True)
经过作者不断地人肉搜索结构之后,得到的结果还是比较好的。在之后也成功地删除了CRF,终于不用搞这个麻烦的公式了。