反卷积原理 + pytorch反卷积层参数output_padding

一般我们会认为2维卷积的计算分为了以下3类:

1.full   2.same   3. valid

参考:https://cn.mathworks.com/help/matlab/ref/conv2.html?

same和valid相信各位同学都不陌生。Valid指不进行padding操作,而same则是通过padding使得卷积之后输出的feature map尺寸保持不变(相对于输入图片)。当然,same模式不代表完全输入输出尺寸一样,也跟卷积核的步长有关系。比如图片尺寸6*6,步长为2,那么same后输出的图片尺寸应为6/2 = 3。那么,问题来了,如果输入图片是5*5,步长为2呢?如果选择padding=(kernel_size-1)/2,那么输出也是3*3。

valid
same

 

(图片来源:卷积的三种模式:full, same, valid)

这个就是我们今天要重点讨论的问题:当步长大于1时,不同尺寸的feature map在选择同一padding = (kernel_size-1)/2时,可以得到相同尺寸的输出。

这一点和标题的“反卷积”有什么关系呢?还有我们是不是忘了full模式?那好我们慢慢讲来。

full即反卷积

先让我说出一个不严谨但方便理解的想法:

Valid就是“纯净”的卷积,full是“纯净”的反卷积

所谓“纯净”是指没有进行padding的操作。而在“不纯净”的操作中有一种特例使得输入输出尺寸符合以步长为比例的预期,称之为same。

参考:深度学习 | 反卷积/转置卷积 的理解 transposed conv/deconv

反卷积原理 + pytorch反卷积层参数output_padding_第1张图片 资料

 

反卷积原理 + pytorch反卷积层参数output_padding_第2张图片

full

stride>1的反卷积

步长大于1的反卷积在计算时,在其输入特征单元之间插入strider-1个0,插入0后把其看出是新的特征输入。反卷积有时候也被叫做Fractionally Strided Convolution,翻译过来大概意思就是小数步长的卷积。参考资料:Transposed Convolution, Fractionally Strided Convolution or Deconvolution

结合动图查看是不是比较形象呢?打个比方就像是原本的卷积操作一步一步把数据从输入映射到输出,步长为二时嘛就跨越着映射从输入那边少拿了东西,输出自然也就少了。而反卷积则是半步半步(小数步长)映射,从输入拿到一个东西居然要映射到输出两次,输出自然就多了嘛。(不严谨的理解哈)

pytorch中的output_padding参数

说了半天终于要引出我写这篇博文的起因啦,那就是:pytorch中的

nn.ConvTranspose2d()

在传入参数时除了常见的输入输出通道数、卷积核尺寸等,还会有一个稍微令人费解的参数:output_padding

反卷积原理 + pytorch反卷积层参数output_padding_第3张图片

这个参数在做步长为1的反卷积时是不用在意的。然而当步长大于1了,就需要手动设置以免网络出错。那么这个参数究竟是干嘛的呢?其实源代码中有说明:

反卷积原理 + pytorch反卷积层参数output_padding_第4张图片

有没有一种恍然大悟的感觉(好吧也许没有),现在是不是有点明白我前面为什么要讲

  1. 步长大于1卷积尺寸有多种对应的情况;
  2. 反卷积是卷积的逆向运算(在尺寸计算方面)。

问题就是,不同尺寸的图片经过卷积运算能得到相同尺寸的输出,那么作为逆运算,同样的一张输入图像经过反卷积是否会有不同尺寸的合法输出?这样的话就存在争议了呀。我们来验证一下是否的确会出现这种情况:

借用参考博文中的例子:

反卷积原理 + pytorch反卷积层参数output_padding_第5张图片

可以看到,在卷积过程中,7*7的输入尺寸+步长为2+卷积核3*3 = 3*3输出尺寸。这是一个完美的卷积核滑动过程。但是观察图中用蓝笔画×的区域我们知道,那块地方是不进行卷积的也就是说如果那里有数据,也就是假设输入8*8,那么输出仍然是3*3.至于原因原文作者如此解释:

如果商不是一个整数,就需要我们向下取整。用符号⌊⌋⌊⌋表示,也叫做进行进行地板除(floor)这个原则实现的方式是,你只在蓝框完全包括在图像或填充完的图像内部时,才对它进行运算。如果有任意一个蓝框移动到了外面,那你就不要进行相乘操作,这是一个惯例。你的 3×3 的过滤器必须完全处于图像中或者填充之后的图像区域内才输出相应结果,这就是惯例。

那么反卷积呢?我们很自然可以想到,3*3的输入进行步长为2的反卷积,7*7的输出与8*8的输出都将会是合法的。但哪个是我们需要的呢?

仍然是这副图,我们注意到它实际上是使用了same填充的反卷积(蓝色的输入图像外层有p=(s-1)/2的填充),因此我们实际上是期待其输入输出是按照以步长为比例的(2)(PS:上面说的3*3输入步长为2,则7与8是合法输出那并不是same,是“纯净”的反卷积)但是我们看到的是:输入蓝色3*3,输出绿色5*5. 这就不是我们的预期了呀,然而人家5*5确实也是合法输出。可是基于前面的讨论我们知道6*6在这里也是合法输出,那么选择哪个合适呢?

output_padding参数作用

看到了确实有争议情况的存在。那么pytorch就机智地提出了解决办法,使用output_padding参数消除争议,那么它是怎么样发挥作用的呢?

首先我们要认同一个前提:大多数情况下我们都希望经过卷积/反卷积处理后的图像尺寸比例与步长相等,也就是same模式。因此pytorch将参数padding(注意与output_padding区别)建议设置为(kernel_size - 1)/2 ,在源代码注释中可以看到:

接下来我们再给出反卷积尺寸变化计算公式

反卷积原理 + pytorch反卷积层参数output_padding_第6张图片

 

稍微一运算就能够知道(此处先无视output_padding),要满足输入输出尺寸满足预期,

需要:padding = (kernel_size - stride)/2

对比一下pytorch的建议:padding = (kernel_size - 1)/2

现在再把output_padding考虑进来,也就是说,最好的output_padding应该取stride-1.这样输入输出才能够成比例。那取别的值运算可以吗?可以,不会妨碍到这一个反卷积的计算,但是在网络的后面进行与尺寸有关的操作时就要注意了,此时的输出不是输入尺寸* stride了。

总结

由于卷积核滑动过程中,边界情况的不确定,使得在运算步长大于1的反卷积时会出现多种合法输出尺寸,pytorch的反卷积层提供了output_padding供使用者选择输出,一般情况下我们希望输入输出尺寸以步长为比例,因此output_padding一般取stride-1,同时padding取 (kernel_size - 1)/2 。

 

参考资料:卷积神经网络CNN(1)——图像卷积与反卷积(后卷积,转置卷积)

你可能感兴趣的:(反卷积原理 + pytorch反卷积层参数output_padding)