在生成图像中,我们需要不断的扩大图像的尺寸。
目前在深度学习中,ConvTranspose2d是其中一个方法。
在DCGAN(Unsupervised Representation Learning with Deep Convolutional Generative Adversarial Networks)(原文地址)中就是用这个来实现的。
别名:
convTranspose2d 是pytorch里的函数名字,代码文档地址(英文版)
论文中,可以称为fractionally-strided convolutions, 也有的称为deconvolutions,但是我不建议大家用后一个,因为这个实际操作并不是去卷积。大家只要知道就可以了。
最后,做个总结,以下本文将会使用两个名字,分别对应代码版和学术论文版,分别是ConvTranspose2d和fractionally-strided convolutions
看到这里,为了简化说明,我后面把这个名字翻译成逆卷积
1.逆卷积ConvTranspose2d(fractionally-strided convolutions)是什么?
解释什么是逆卷积,先得明白什么是卷积。
先说卷积:对于一个图片A,设定它的高度和宽度分别为Height,Width,通道数为Channels。 然后我们用卷积核(kernel * kernel)去做卷积,(这里设定卷积核为正方形,实际长方形也可以类推,相信我,不会很难),步长为stride(同样的,不区分高宽方向),做padding。卷积后得到B。
重复上面的话就是利用一个卷积操作将A变成B。
那么,在这个前提下,逆卷积就是将B变成A。
那么怎么规定卷积核这些参数呢,这些又是什么意思?
对于卷积操作,我不多说了,这里不做解释。而且我们应该比较清楚如何从输入的图片大小格式等得到新的图片大小,或许有的人熟悉用特征图来代替图片。
对于逆卷积操作,卷积核的设置就是和卷积操作相同。如:给定一个特征图x,并输入卷积核设置。我们就是想得到一个特征图y经过输入的卷积核进行卷积,然后得到特征图x,这里我们要求的就是特征图y。
写到这里大家应该比较理解我为什么把它翻译成逆卷积了吧。
如果不懂,也没事,可以看下面的例子。
举个例子:
上面这个是一个卷积操作。
我们输入的特征图为:x: 44channels_in,channels_in表示通道数
卷积核设置:无padding, kernel size为3*3, 步长stride 为1,
输出的特征图为y,2 * 2 * channels_out,channels_out也是通道数。
逆卷积操作的输入就是特征图y, 卷积核设置同上。要求上面的特征图x。
这里先给出这个对应逆卷积的说明图。后面给出泛化的说明。
2.怎么求逆卷积ConvTranspose2d(fractionally-strided convolutions)?
这里我并不想解释理论的推导,我直接说算法怎么实现的。也就是代码中如何实现。
当给一个特征图a, 以及给定的卷积核设置,我们分为三步进行逆卷积操作:
第一步:对输入的特征图a进行一些变换,得到新的特征图a’
第二步:求新的卷积核设置,得到新的卷积核设置,后面都会用右上角加撇点的方式区分
第三步:用新的卷积核在新的特征图上做常规的卷积,得到的结果就是逆卷积的结果,就是我们要求的结果。
以下当然就要解释怎么做了。
在说怎么做之前,我们下规定一下符号,右上角加撇点的为修改之后的:
特征图a:
H
e
i
g
h
t
Height
Height,
W
i
d
t
h
Width
Width
输入的卷积核: kernel 的size =
S
i
z
e
Size
Size, 步长为
S
t
r
i
d
e
Stride
Stride,padding 就是
p
a
d
d
i
n
g
padding
padding。
新的特征图:
H
e
i
g
h
t
′
=
H
e
i
g
h
t
+
(
S
t
r
i
d
e
−
1
)
∗
(
H
e
i
g
h
t
−
1
)
Height'=Height+(Stride-1)*(Height-1)
Height′=Height+(Stride−1)∗(Height−1),
W
i
d
t
h
Width
Width同样的。这里说一下这个新的特征图是怎么得到的:我们在输入的特征图基础加上一些东西,专业名词叫做interpolation,也就是插值。
这就涉及到两个问题,插在哪里,插什么。
插什么?插得就是0。
插在哪里?在原先高度方向的每两个相邻中间插上"
S
t
r
i
d
e
−
1
Stride-1
Stride−1"列0。我们知道对于输入为
H
e
i
g
h
t
Height
Height的特征图来说有
H
e
i
g
h
t
−
1
Height-1
Height−1个位置,所以,最终我们的特征图在原先的基础上加上
(
S
t
r
i
d
e
−
1
)
∗
(
H
e
i
g
h
t
−
1
)
(Stride-1)*(Height-1)
(Stride−1)∗(Height−1)
新的卷积核: S t r i d e ′ = 1 Stride'=1 Stride′=1,这个数不变,无论你输入是什么。kernel的 s i z e ′ size' size′也不变,= S i z e Size Size, p a d d i n g ′ padding' padding′为 S i z e − p a d d i n g − 1 Size-padding-1 Size−padding−1.
然后,我利用新的卷积核和新的特征图,得到最终的逆卷积结果。
根据公式可以知道输出的特征图(用输入的符号表示)的大小是多少了,下面我给出简单的推导。
先给出公式:
H
e
i
g
h
t
o
u
t
=
(
H
e
i
g
h
t
i
n
+
2
∗
p
a
d
d
i
n
g
−
k
e
r
n
e
l
s
i
z
e
)
/
s
t
r
i
d
e
s
+
1
Height_{out}=(Height_{in}+2*padding-kernel_{size})/strides+1
Heightout=(Heightin+2∗padding−kernelsize)/strides+1
这里补充一句,padding的size只是针对一边的,所以要乘以2.
带上上面新的卷积核和新的特征图设置情况,可以得到
(
H
e
i
g
h
t
+
(
S
t
r
i
d
e
−
1
)
∗
(
H
e
i
g
h
t
−
1
)
+
2
∗
(
S
i
z
e
−
p
a
d
d
i
n
g
−
1
)
−
S
i
z
e
)
/
1
+
1
(Height+(Stride-1)*(Height-1) +2*(Size-padding-1) - Size)/1+1
(Height+(Stride−1)∗(Height−1)+2∗(Size−padding−1)−Size)/1+1
化简可得:
(
H
e
i
g
h
t
−
1
)
∗
S
t
r
i
d
e
−
2
∗
p
a
d
d
i
n
g
+
S
i
z
e
(Height-1)*Stride-2*padding+Size
(Height−1)∗Stride−2∗padding+Size
上面这幅图就是pytorch官网给出的计算方法,和这里给出是一样的。当然这里先忽略output_padding是什么。
有兴趣可以算一下从这个是否满足反向计算的一致性。
最后,这里给一个例子参考,特别是怎么计算到新的特征图的,尤其是怎么插值(interpolation)。
对图的说明:
输入特征图A:
3
∗
3
3*3
3∗3
输入卷积核K:kernel为
3
∗
3
3*3
3∗3, stride为2, padding为1
新的特征图A’:
3
+
(
3
−
1
)
∗
(
2
−
1
)
=
3
+
2
=
5
3 + (3-1)*(2-1) = 3+2 = 5
3+(3−1)∗(2−1)=3+2=5 注意加上padding之后才是7。
新的卷积核设置K’: kernel不变,stride为1,padding=
3
−
1
−
1
=
1
3-1-1=1
3−1−1=1
最终结果:
(
5
+
2
−
3
)
/
1
+
1
=
5
(5+2-3)/1+1=5
(5+2−3)/1+1=5
使用逆卷积的注意事项
从以上来看,我们要特别注意使用逆卷积时的参数设置。
上图为DCGAN的generator的生成模型中的结构图。
对应于DCGAN,我们的设置如下:
除了从噪声z到第一个特征图(441024)的kernel设置不一样,为(4, 1, 0),其他都一样(4,2, 1),括号中依次表示:核大小,步长stride,padding大小
再给一个实际的代码例子:(使用pytorch,记住在实行前import必要的模块)
逆卷积和卷积的关系
为什么可以这样操作来得到逆卷积的结果,我不解释,我也解释不了。
给出两个条件:
1.特征图大小要适合。(这一点不解释)
2.保证同样的连接性。
什么是同样的连接性?这是指从A到B(AB分别表示卷积前和卷积后的特征图),如果A中一个位置与B中一个位置通过kernel有关系,那么在卷积核逆卷积中有相同的连通。
卷积和逆卷积是什么关系?(这节内容为新增)
时间:2020-10-06 18:13:06
可以参考台湾大学李宏毅老师的视频中关于这一部分的讲解(machine learning 第16课,无监督学习):Youtube地址
从32:19开始。这里给出一个图。
后记
看完这些,希望你已经没有想看源码的冲动了。
如果是这样的话,不妨点个赞吧。
为何要点赞?
如果本文解决了你的困惑,不妨点个赞鼓励一下。
不管你信不信,也不管你同不同意,实际上,你的每一次点赞都标志着你自身的进步。而打赏乃是点赞的高级形式
曾经有无数个点赞的机会,但是我都没有好好珍惜,假如时光可以倒流,我一定为他们也为自己点赞。