转自 https://blog.csdn.net/isMarvellous/article/details/80087705ide
什么是转置卷积(反卷积)?
转置卷积(Transposed Convolution)又称为反卷积(Deconvolution)。在PyTorch中可使用torch.nn.ConvTranspose2d()来调用,在Caffe中也有对应的层deconv_layer。.net
转置卷积经常用于CNN中对特征图进行上采样,好比语义分割和超分辨率任务中。之因此叫转置卷积是由于,它实际上是把咱们平时所用普通卷积操做中的卷积核作一个转置,而后把普通卷积的输出做为转置卷积的输入,而转置卷积的输出,就是普通卷积的输入。这样说可能有点绕,咱们能够参照CNN中的反向传播过程来理解,转置卷积形式上就和一个卷积层的反向梯度计算相同。既然是输入输出对调,那么就有两个很重要的特性:blog
转置的卷积核变为了普通卷积核的转置;
若是把由输入特征图到输出特征图的计算过程画成一个计算图,那么输入输出元素的链接关系是不变的
关于第二点,也就是说,在普通卷积中,若元素a和元素1有链接(元素1由a计算获得),那么在相应的转置卷积中,元素1和元素a依然是有链接的(元素a由元素1计算获得)。token
下面就基于此讨论一下我对转置卷积计算过程的一个理解。这并非一个严格的推导,只是为了形象地帮助理解为何要这样计算,或者说这个计算过程是怎么来的。而后再总结一下转置卷积输出特征图大小的计算。因为是本身的我的看法,不免有疏漏或理解不许确的地方,这里总结出来,但愿你们一块儿来讨论。get
普通卷积的计算过程
以下图:io
这是一个卷积核大小为3x3,步长为2,padding为1的普通卷积。卷积核在红框位置时输出元素1,在绿色位置时输出元素2。咱们能够发现,输入元素a仅和一个输出元素有运算关系,也就是元素1,而输入元素b和输出元素1, 2均有关系。同理c只和一个元素2有关,而d和1,2,3,4四个元素都有关。那么在进行转置卷积时,依然应该保持这个链接关系不变。sed
转置卷积(反卷积)的计算过程
根据前面的分析,咱们须要将上图中绿色的特征图做为输入,蓝色的特征图做为输出,而且保证链接关系不变。也就是说,a只和1有关,b和1,2两个元素有关,其它类推。怎么才能达到这个效果呢?咱们能够先用0给绿色特征图作插值,插值的个数就是使相邻两个绿色元素的间隔为卷积的步长,同时边缘也须要进行与插值数量相等的补0。以下图:im
注意,这时候卷积核的滑动步长就不是2了,而是1,步长体如今了插值补0的过程当中。总结
通常在CNN中,转置卷积用于对特征图进行上采样,好比咱们想要将特征图扩大2倍,那么就可使用步长为2的转置卷积。可是且慢!为何咱们这里2x2的输入,只获得了3x3的输出呢?说好的扩大2倍呢?不该该是4x4么?
别急,咱们来算一算为何是3x3。
咱们将2x2的特征图插空并在边缘补0后,边长变成了2x2+1=5,使用3x3的卷积核作滑动步长为1的卷积,获得的特征图边长为(5-3+1)/1=3。因此咱们只获得了3x3而非4x4的输出。那么在通常状况下,输出特征图的大小要怎么计算呢?下面咱们来总结一下。img
输出特征图的尺寸计算假设咱们作转置卷积的输入特征图大小为 n×nn×n,卷积核大小为 k×kk×k,后面为了表示方便,咱们直接使用边长来表示大小。步长stride为ss,那么转置卷积须要在四周每一个边缘补0的数量为s−1s−1,边缘和内部插空补0后输入特征图大小变为s×n+s−1s×n+s−1;使用大小为kk的卷积核进行卷积(滑动步长为1),获得的输出特征图大小为:(s×n+s−1−k+1)/1=s×n+(s−k)(s×n+s−1−k+1)/1=s×n+(s−k)。能够看到,转置卷积并非严格将输入特征图变为了s倍,而是还相差了个s−ks−k。这和PyTorch中的torch.nn.ConvTranspose2d()获得的结果是一致的。