反卷积学习笔记
最近在学习InversionNet的过程中,对于反卷积有部分疑问,因此查阅资料详细学习,形成这一篇学习笔记。
卷积
要想了解反卷积的原理,我们首先要明白卷积的原理。要进行卷积操作,我们首先要定义卷积的输入和参数:
- 输入特征图尺寸 H i n H_{in} Hin、 W i n W_{in} Win
- 输入特征图的通道数 C i n C_{in} Cin
- 输出特征图的通道数 C o u t C_{out} Cout
- 卷积核尺寸 H k H_{k} Hk、 W k W_{k} Wk
- 步长 s t r i d e stride stride
- 填充 p a d d i n g padding padding
单次卷积
单次卷积的过程,可以视作在完成输入特征图进行填充后,将卷积核放在输入图上,按照步长进行移动,在每次移动后卷积核与特征图对应的部分求数量积,放在输出特征图的对应位置。下图是卷积的一种可视化计算过程:
如图所示,蓝色部分是输入,深蓝部分是卷积核,绿色部分是输出。在训练过程中,可学习的卷积核用来提取图像的特征。通俗来说,卷积核内保存着特征图像,如果对应的输入图片具有相同的特征,数量积的算法会输出一个较大的值,表示“输入图像的该位置有此特征”;如果输入图像没有类似的特征,数量积的结果将会是一个较小的值。同时,卷积操作在输入图上移动的操作也保证了特征间位置的一致性,保证了“眼睛应该和鼻子长在一起”。
卷积核越大,卷积核记载的特征就会有更大的尺度,这被称为卷积的感受野。但卷积核并非越大越好,卷积核的增大会导致计算量显著提示。据研究,一个7*7的卷积核可以使用3层3*3的卷积核进行替代,降低计算量的同时有相近的效果。
除了输入尺寸和和卷积核尺寸,卷积还有其他参数。
步长
步长是指卷积核在输入图上移动的距离,如下图展示的是步长为2的卷积操作。
填充
填充是指在卷积操作中对原图进行的扩充操作,使卷积核能学习到边缘的特征,放大卷积核的输出。下图展示的是对原图填充了两像素后进行的卷积,也被称为任意填充:
如果填充后使输出图像与输入图像尺寸一致或成比例进行的填充称为半填充(Half padding)或者相同填充(Same padding)。如下图所示:
全填充(Full padding)则是保证了输入图像每个像素在同方向上卷积的次数相同,或者说卷积时从输入图像最边缘的一个像素开始进行。如下图所示:
输入通道
输入通道取决于图像的类型或者上一层的通道数。比如一张彩色RGB图片拥有三个通道。在计算时,每个通道都与自己对应的不同卷积核进行卷积操作。如图展示的是对RGB三个通道分别进行卷积操作。
输出通道
输出通道来源于人为设定,有多少个输出通道,就会有多少组不同的卷积核进行特征提取工作,因此输出通道数越多,提取的特征也越多。而每组卷积核都由输入通道淑个卷积核组成。因此一张输出4通道特征图的RGB3通道图像共有12个卷积核。如图所示:
卷积输出
了解完卷积的参数,我们就可以求得卷积的输出了。这里需要指出的是,不仅输入图片、卷积核的长宽可以不同,步长和填充的长宽也可以不同,因此我们可以实现长宽的异步变化。
H
o
u
t
=
⌊
H
i
n
+
2
p
a
d
d
i
n
g
−
H
k
s
t
r
i
d
e
⌋
+
1
H_{out}=\lfloor\frac{H_{in}+2padding-H_k}{stride}\rfloor+1
Hout=⌊strideHin+2padding−Hk⌋+1
反卷积
了解完卷积,反卷积的理解就较为简单了。反卷积进行的是卷积的逆运算,但使用的工具类似于转置,因此反卷积(Deconvolution)在代码中被称为卷积转置(Transposed Convolution)。我们依然是分参数进行讨论。
- 输入特征图尺寸 H i n H_{in} Hin、 W i n W_{in} Win
- 输入特征图的通道数 C i n C_{in} Cin
- 输出特征图的通道数 C o u t C_{out} Cout
- 卷积核尺寸 H k H_{k} Hk、 W k W_{k} Wk
- 步长 s t r i d e stride stride
- 填充 p a d d i n g padding padding
- 输出填充 o u t p u t _ p a d d i n g output\_padding output_padding
其中,反卷积的通道数与卷积的通道数含义完全相同,不再重复解释,除此外,反卷积多了一个输出填充的参数。
单次反卷积
下图展示的是一个步长与填充均为0的经典反卷积过程,蓝色像素是输入,深蓝色像素是卷积核,绿色像素是输出。反卷积的过程一般是由少量特征生成更多特征的过程。通俗来说,如果前一个特征图认为图片上某位置应该有一张脸,记录脸部特征的反卷积核就会在脸的位置画上五官。
可以看到虽然参数设定上填充为0,但实际上输入图片仍然进行了填充,这是怎么回事?实际上反卷积的填充为0指的是该反卷积对应的卷积运算填充为0。反卷积的过程在本图中是自下而上的,而卷积的过程是自上而下的,我们可以把卷积核放到绿色部分进行移动,卷积的结果就如蓝色所示,该过程如章节"单次卷积"中的图片。
也就是说,虽然反卷积依然有步长,填充等参数,但这些参数控制的是反卷积对应卷积操作的过程。因此这两者在反卷积中的含义需要特殊理解。
步长
我们首先观察步长为2的反卷积过程图片,并用卷积的方式思考步长为1时输入应当是什么样子。
很明显,以卷积的角度看,如果步长为1,输入的蓝色像素应该是3*3的九宫格。但是反卷积对应的卷积操作步长为2,意味着九宫格内白色部分的输出实际上被跳过了。反之,对于反卷积来说,进行步长为2的操作就是把输入拆到九宫格的四个角上,再进行相应操作。当步长大于1时,需要在输入像素之间填充(stride-1)个空白像素。
步长
步长的含义已经在单次反卷积中阐明,这里不再赘述。与卷积相同,反卷积依然有半填充和全填充等的相关概念。值得一提的是,如下图所示,反卷积的全填充实际上没有在输入图外侧添加像素,使得这个过程与卷积相似。此时回头看看卷积的全填充操作,可以发现这也是一个反卷积的过程。
输出填充
输出填充操作应用的前提条件是步长大于1时进行半填充的反卷积操作。在解释参数之前,我们需要思考一个问题。一般而言,函数的1个输出可能由多个输入得来,但1个输入却至多只有1个输出,卷积操作符合函数的定义:
- 情况A:输入为(6, 6),stride=2, kernel_size=3,进行half padding填充一个像素后得到的输出尺寸为(3, 3)
- 情况B:输入为(5, 5),stride=2, kernel_size=3,进行half padding填充一个像素后得到的输出尺寸为(3, 3)
但这两种情况对于反卷积来说就不太友好了。输入为(3, 3),输出到底是(5, 5)还是(6, 6)呢?因此pytorch引入了output_padding参数。我们将output_padding加入到尺寸的计算公式里。同时为了方便理解,我们在这里将公式改写为卷积的样子,注意左式是输入尺寸,右式含有输出尺寸:
H
i
n
=
H
o
u
t
+
2
p
a
d
d
i
n
g
−
H
k
−
o
u
t
p
u
t
_
p
a
d
d
i
n
g
s
t
r
i
d
e
+
1
H_{in}=\frac{H_{out}+2padding-H_k-output\_padding}{stride}+1
Hin=strideHout+2padding−Hk−output_padding+1
引入这个参数后,如果要得到(5, 5)的输出,output_padding可以设置为0。要得到(6, 6)的输出,output_padding应该设置为1。
参考
在学习过程中,我参考了以下资料: