赞
踩
卷积-池化-再上采样
会出现的问题在图像分割领域,图像输入到CNN(典型的网络比如FCN[3])中,FCN先像传统的CNN那样对图像做卷积再pooling,降低图像尺寸的同时增大感受野,但是由于图像分割预测是pixel-wise的输出,所以要将pooling后较小的图像尺寸upsampling到原始的图像尺寸进行预测(upsampling一般采用deconv反卷积操作,deconv可参见知乎答案如何理解深度学习中的deconvolution networks?),之前的pooling操作使得每个pixel预测都能看到较大感受野信息。
因此图像分割FCN中有两个关键,一个是pooling减小图像尺寸增大感受野,另一个是upsampling扩大图像尺寸。
在先减小再增大尺寸的过程中,肯定有一些信息损失掉了,那么能不能设计一种新的操作,不通过pooling也能有较大的感受野看到更多的信息呢?答案就是dilated conv。
空洞卷积最初的提出是为了解决图像分割的问题而提出的,常见的图像分割算法通常使用池化层和卷积层来增加感受野(Receptive Filed),同时也缩小了特征图尺寸(resolution),然后再利用上采样还原图像尺寸,特征图缩小再放大的过程造成了精度上的损失,因此需要一种操作可以在增加感受野的同时保持特征图的尺寸不变,从而代替下采样和上采样操作
,在这种需求下,空洞卷积就诞生了
空洞卷积为什么能够保持特征图尺寸不变的同时增加感受野,详细原因可以参考这一篇博客:吃透空洞卷积(Dilated Convolutions)
扩大感受野
:在deep net中为了增加感受野且降低计算量,总要进行降采样(pooling或s2/conv),这样虽然可以增加感受野,但空间分辨率降低了。为了能不丢失分辨率(持怀疑态度),且仍然扩大感受野,可以使用空洞卷积。这在检测,分割任务中十分有用。一方面感受野大了可以检测分割大目标,另一方面分辨率高了可以精确定位目标。捕获多尺度上下文信息
:空洞卷积有一个参数可以设置dilation rate,具体含义就是在卷积核中填充dilation rate-1个0【n-1】
,因此,当设置不同dilation rate时,感受野就会不一样,也即获取了多尺度信息。多尺度信息在视觉任务中相当重要。其实说白了,就是池化可以扩大感受野,可以降低数据维度,可以减少计算量,但是会损失信息,而对于语义分割来说,这造成了发展瓶颈。而空洞卷积可以在扩大感受野的情况下不损失信息,但其实,空洞卷积的确没有损失信息,但是却没有用到所有的信息.
在二维图像上直观地感受一下扩张卷积的过程:
上图是一个扩张率为2的3×3卷积核,感受野与5×5的卷积核相同,而且仅需要9个参数。你可以把它想象成一个5×5的卷积核,每隔一行或一列删除一行或一列。
在相同的计算条件下,空洞卷积提供了更大的感受野。空洞卷积经常用在实时图像分割中。当网络层需要较大的感受野,但计算资源有限而无法提高卷积核数量或大小时,可以考虑空洞卷积
。
但是空洞卷积也有其缺点,比如连续使用的时候可能丢失局部信息等,具体可以参考空洞卷积的超详细解释
空洞卷积模型定义
#pytorch封装卷积层 class ConvModule(nn.Module): def __init__(self): super(ConvModule,self).__init__() #定义六层卷积层 #两层HDC(1,2,5,1,2,5) self.conv = nn.Sequential( #第一层 (3-1)*1+1=3 (64-3)/1 + 1 =62 nn.Conv2d(in_channels = 3,out_channels = 32,kernel_size = 3 , stride = 1,padding=0,dilation=1), nn.BatchNorm2d(32), # inplace-选择是否进行覆盖运算 nn.ReLU(inplace=True), #第二层 (3-1)*2+1=5 (62-5)/1 + 1 =58 nn.Conv2d(in_channels = 32,out_channels = 32,kernel_size = 3 , stride = 1,padding=0,dilation=2), nn.BatchNorm2d(32), # inplace-选择是否进行覆盖运算 nn.ReLU(inplace=True), #第三层 (3-1)*5+1=11 (58-11)/1 +1=48 nn.Conv2d(in_channels = 32,out_channels = 64,kernel_size = 3 , stride = 1,padding=0,dilation=5), nn.BatchNorm2d(64), # inplace-选择是否进行覆盖运算 nn.ReLU(inplace=True), #第四层(3-1)*1+1=3 (48-3)/1 + 1 =46 nn.Conv2d(in_channels = 64,out_channels = 64,kernel_size = 3 , stride = 1,padding=0,dilation=1), nn.BatchNorm2d(64), # inplace-选择是否进行覆盖运算 nn.ReLU(inplace=True), #第五层 (3-1)*2+1=5 (46-5)/1 + 1 =42 nn.Conv2d(in_channels = 64,out_channels = 64,kernel_size = 3 , stride = 1,padding=0,dilation=2), nn.BatchNorm2d(64), # inplace-选择是否进行覆盖运算 nn.ReLU(inplace=True), #第六层 (3-1)*5+1=11 (42-11)/1 +1=32 nn.Conv2d(in_channels = 64,out_channels = 128,kernel_size = 3 , stride = 1,padding=0,dilation=5), nn.BatchNorm2d(128), # inplace-选择是否进行覆盖运算 nn.ReLU(inplace=True) ) #输出层,将通道数变为分类数量 self.fc = nn.Linear(128,num_classes) def forward(self,x): #图片经过三层卷积,输出维度变为(batch_size,C_out,H,W) out = self.conv(x) #使用平均池化层将图片的大小变为1x1,第二个参数为最后输出的长和宽(这里默认相等了) out = F.avg_pool2d(out,32) #将张量out从shape batchx128x1x1 变为 batch x128 out = out.squeeze() #输入到全连接层将输出的维度变为3 out = self.fc(out) return out
注:可以从上面可以看出一共有6个空洞卷积层,其空洞率
分别是1、2、5、1、2、5;1、2、5不包含大于1的公约数,所以其是包含2个的HDC,然后其每一层的输入和输出的算法见注释。
“3x3的kernel设置dialted-rate=2时,理应变为5x5”的kernel,多出来的空洞用0填充,这也是变相的增加了感受野。也就是说,设置dialted-rate>1时,会使得卷积的kernel变大。”
参考文章:简书:空洞卷积(dilated convolution)理解
pytorch实现空洞卷积+残差网络实验(torch实现)
pytorch代码验证空洞卷积
【深度学习】空洞卷积(Atrous Convolution)
总结-空洞卷积(Dilated/Atrous Convolution)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。