动手学gluon系列之--上采样的实现方法:Conv2DTranspose,转置卷积的实现与原理

说道上采样,就不得不提一篇非常经典的论文FCN,其在使用卷积缩放尺度后,利用上采样将特征图放大,实现图像分割,并且论文中多次提到的利用双线性插值实现上采样,那么在gluon中,如何实现呢?

这里需要使用函数nn.Conv2DTranspose,本质就是下面这两行(备注中包含参数介绍


### 利用反卷积实现上采样,初始化方式采用Bilinear便实现了双线性插值上采样
upsample=nn.Conv2DTranspose(channels=1024, kernel_size=4, padding=1, strides=2, groups=1024, weight_initializer=init.Bilinear())

### 如果将上采样的学习率设置为0,则始终是双线性插值,参数不会变化
upsample.collect_params()/setattr("lr_mult", 0.0)

## 函数参数介绍
## channels: 这个通卷积的channel
## kernel_size: 这个不用多说,就是卷积核
## padding: 这个要多说一些,这个padding并不是conv2Dtranspose时候在特征图两侧添加的padding的数目,而是与它互逆的conv2D对应的padding数目,conv2Dtranspose两侧添加的数据是 kernel_size -1 - padding
## strides: 这里也对应的是与之对应的conv2D所对应的strides
## groups: 不多说,好理解
## weight_initializer: 不多说,好理解

## 输出尺度的计算方法
## out_height = (height-1)*strides[0]-2*padding[0]+kernel_size[0]+output_padding[0]
## out_width = (width-1)*strides[1]-2*padding[1]+kernel_size[1]+output_padding[1]

如果想实现的放大倍数为f(偶数)通常的设置为:

  • kernel_size = 2f
  • strides = f
  • padding = f/2

-------- 介绍完了函数,就好好介绍一下转置卷积是怎么回事吧—

转置卷积,顾名思义,肯定是把卷积转置了,没错,在进行转置卷积的时候,的确是将卷积转置了,不过为什么将卷积转置呢?实际是根据公式计算出来的,这就要从转置卷积的目的说起了,其实转置卷积的目的就是来进行卷积相反的计算,假如我们有特征图X,卷积核W,可以得到Y = WX,那么我们已知Y和W如何得到X呢?利用公式就是WTY=XW^{T}Y=X,转置就是这么出来的,想要详细了解的小伙伴可以参考链接https://zhuanlan.zhihu.com/p/48501100,以及一篇非常经典的paper:https://arxiv.org/pdf/1603.07285.pdf

那么从实现层面具体是怎么做的呢?

其实也比较简单,主要就是先padding后conv。

这里可以根据是不是存在strides,而分成两种情况:

  • 情况一:没有strides:
    这就比较好理解了,下图的第一张就是最典型的转置卷积,其输入图像为2x2大小,两边增加padding后,然后利用3x3的卷积核进行卷积操作,最终得到的是4x4的结果。

两侧增加的padding怎么计算呢?这里注意一下,再次强调一下,这里padding的多少并不是函数中padding参数的值,而是kernel_size-1-padding的值,为什么是这个意思呢?主要是因为函数要保证conv与convtranspose的参数一样的情况下,可以互逆

  • 情况二:strides不等于1:
    这就是下面第二行的图了,首先会在输入特征图中间插入0点,然后再进行反卷积操作。

动手学gluon系列之--上采样的实现方法:Conv2DTranspose,转置卷积的实现与原理
其实上面的图是动图,动图可以访问链接:https://github.com/vdumoulin/conv_arithmetic/blob/master/README.md

https://github.com/vdumoulin/conv_arithmetic#convolution-arithmetic