训练GANs,你应该知道的二三事
作者:追一科技AI Lab 研究员 Miracle
写在前面的话
笔者接触GANs也有一段时间了,从一开始的小白,到现在被GANs虐了千百遍但依然深爱着GANs的小白,被GANs的对抗思维所折服,被GANs能够生成万物的能力所惊叹。我觉得GANs在某种程度上有点类似于中国太极,‘太极生两仪,两仪生四象’,太极阐明了宇宙从无极而太极,以至万物化生的过程,太极也是讲究阴阳调和。(哈哈,这么说来GANs其实在中国古代就已经有了发展雏形了。)
众所周知,GANs的训练尤其困难,笔者自从跳入了GANs这个领域(坑),就一直在跟如何训练GANs做对抗训练,受启发于ganhacks,并结合自己的经验记录总结了一些常用的训练GANs的方法,以备后用。
(⚠️本篇不是GANs的入门扫盲篇,初学者慎入。)
什么是GANs?
GANs,Generative Adversarial Networks,可以说是一种强大的"万能"数据分布拟合器,主要由一个生成器(generator)和判别器(discriminator)组成。生成器主要从一个低维度的数据分布中不断拟合真实的高维数据分布,而判别器主要是为了区分数据是来源于真实数据还是生成器生成的数据,他们之间相互对抗,不断学习,最终达到Nash均衡,即任何一方的改进都不会导致总体的收益增加,这个时候判别器再也无法区分是生成器生成的数据还是真实数据。
图1 GANs architecture
GANs最初由Ian Goodfellow1于2014年提出,目前已经在图像、语音、文字等方面得到广泛研究和应用;特别是在图像生成方面,可谓是遍地开花,例如图像风格迁移(style transfer)、图像修复(image inpainting)、超分辨率(super resolution)等。
##GANs出了什么问题?
GANs通常被定义为一个minimax的过程:
min
G
max
D
V
(
D
,
G
)
=
E
x
∼
P
r
(
x
)
[
log
D
(
x
)
]
+
E
z
∼
P
z
(
z
)
[
log
(
1
−
D
(
G
(
z
)
)
)
]
\min _{G} \max _{D} V(D, G)=\mathbb{E}_{\boldsymbol{x} \sim P_{r}(\boldsymbol{x})}[\log D(\boldsymbol{x})]+\mathbb{E}_{\boldsymbol{z} \sim P_{\boldsymbol{z}}(\boldsymbol{z})}[\log (1-D(G(\boldsymbol{z})))]
GminDmaxV(D,G)=Ex∼Pr(x)[logD(x)]+Ez∼Pz(z)[log(1−D(G(z)))]
其中
P
r
P_{r}
Pr是真实数据分布,
P
z
P_{\boldsymbol{z}}
Pz是随机噪声分布。乍一看这个目标函数,感觉有点相互矛盾,其实这就是GANs的精髓所在—— 对抗训练。
在原始的GANs中,判别器要不断的提高判别是非的能力,尽可能的将真实样本分类为正例,将生成样本分类为负例,判别器需要优化如下损失函数:
−
E
x
∼
P
r
[
log
D
(
x
)
]
−
E
x
∼
P
g
[
log
(
1
−
D
(
x
)
)
]
-\mathbb{E}_{x \sim P_{r}}[\log D(x)]-\mathbb{E}_{x \sim P_{g}}[\log (1-D(x))]
−Ex∼Pr[logD(x)]−Ex∼Pg[log(1−D(x))]
作为对抗训练,生成器需要不断将生成数据分布拉到真实数据分布,Ian Goodfellow首先提出了如下式子的生成器损失函数:
E
x
∼
P
g
[
log
(
1
−
D
(
x
)
)
]
\mathbb{E}_{x \sim P_{g}}[\log (1-D(x))]
Ex∼Pg[log(1−D(x))]
由于在训练初期阶段,生成器的能力比较弱,而判别器可以很精准的区分生成样本和真实样本,这样
D
(
x
)
D(x)
D(x)就非常接近1,导致
log
(
1
−
D
(
x
)
)
\log (1-D(x))
log(1−D(x))达到饱和,后续就很难再调整过来。为了解决饱和问题,作者提出了另外一个损失函数,即:
E
x
∼
P
g
[
−
log
D
(
x
)
]
\mathbb{E}_{x \sim P_{g}}[-\log D(x)]
Ex∼Pg[−logD(x)]
以上面这个两个目标函数为例,简单地分析一下GAN模型存在的几个问题:
Ian Goodfellow论文里面已经给出,固定
G
G
G的参数,我们得到最优的
D
∗
D^*
D∗:
D
G
∗
(
x
)
=
P
r
(
x
)
P
r
(
x
)
+
P
g
(
x
)
D_{G}^{*}(\boldsymbol{x})=\frac{P_{r}(\boldsymbol{x})}{P_{r}(\boldsymbol{x})+P_{g}(\boldsymbol{x})}
DG∗(x)=Pr(x)+Pg(x)Pr(x)
也就是说,只有当
P
r
=
P
g
P_{r }= P_{g}
Pr=Pg 时候,不管是真实样本和生成样本,判别器给出的概率都是0.5,这个时候就无法区分样本到底是来自于真实样本还是来自于生成样本。
-
对于第一种目标函数
在最优判别器下 D ∗ D^* D∗下,我们给损失函数加上一个与 G G G无关的项,(3)式即变成:
E x ∼ P r [ log D ( x ) ] + E x ∼ P g [ log ( 1 − D ( x ) ) ] \mathbb{E}_{x \sim P_{r}}[\log D(x)]+\mathbb{E}_{x \sim P_{g}}[\log (1-D(x))] Ex∼Pr[logD(x)]+Ex∼Pg[log(1−D(x))]
注意,该式子其实就是判别式的损失函数的反。把最优判别器 D ∗ D^* D∗带入,计算可以得到:
2 J S ( P r ∥ P g ) − 2 log 2 2 J S\left(P_{r} \| P_{g}\right)-2 \log 2 2JS(Pr∥Pg)−2log2
(推导:
E x ∼ P r [ log D G ∗ ( x ) ] + E z ∼ P z [ log ( 1 − D G ∗ ( G ( z ) ) ) ] = E x ∼ P x [ log D G ∗ ( x ) ] + E x ∼ P g [ log ( 1 − D G ∗ ( x ) ) ] = E x ∼ P r [ log P r ( x ) P r ( x ) + P g ( x ) ] + E x ∼ P g [ log P g ( x ) P r ( x ) + p g ( x ) ] = E x ∼ P r [ log 1 2 ∗ P r ( x ) 1 2 ∗ ( P r ( x ) + P g ( x ) ) ] + E x ∼ P g [ log 1 2 ∗ P g ( x ) 1 2 ∗ ( P r ( x ) + p g ( x ) ) ] = E x ∼ P r [ log P r ( x ) 1 2 ∗ ( P r ( x ) + P g ( x ) ) − log 2 ] + E x ∼ P g [ log P g ( x ) 1 2 ∗ ( P r ( x ) + p g ( x ) ) − log 2 ] = 2 J S ( P r ∥ P g ) − 2 log 2 \begin{aligned} &\mathbb{E}_{x \sim P_r}\left[\log D_{G}^{*}(x)\right]+\mathbb{E}_{z \sim P_{z}}\left[\log \left(1-D_{G}^{*}(G(z))\right)\right] \\ &=\mathbb{E}_{x \sim P_{x}}\left[\log D_{G}^{*}(x)\right]+\mathbb{E}_{x \sim P_{g}}\left[\log \left(1-D_{G}^{*}(x)\right)\right] \\ &=\mathbb{E}_{x \sim P_{r}}\left[\log \frac{P_{r}(x)}{P_{r}(x)+P_{g}(x)}\right]+\mathbb{E}_{x \sim P_{g}}\left[\log \frac{P_{g}(x)}{P_{r}(x)+p_{g}(x)}\right] \\ &= \mathbb{E}_{x \sim P_{r}}\left[\log \frac{\frac {1}{2} *P_{r}(x)}{\frac {1}{2} * (P_{r}(x)+P_{g}(x))}\right]+\mathbb{E}_{x \sim P_{g}}\left[\log \frac{\frac {1}{2} * P_{g}(x)}{\frac {1}{2} * (P_{r}(x)+p_{g}(x))}\right] \\ &= \mathbb{E}_{x \sim P_{r}}\left[\log \frac{P_{r}(x)}{\frac {1}{2} * (P_{r}(x)+P_{g}(x))} - \log 2\right]+\mathbb{E}_{x \sim P_{g}}\left[\log \frac{P_{g}(x)}{\frac {1}{2} * (P_{r}(x)+p_{g}(x))}-\log 2\right] \\ &= 2 JS\left(P_{r} \| P_{g}\right)-2 \log 2 \end{aligned} Ex∼Pr[logDG∗(x)]+Ez∼Pz[log(1−DG∗(G(z)))]=Ex∼Px[logDG∗(x)]+Ex∼Pg[log(1−DG∗(x))]=Ex∼Pr[logPr(x)+Pg(x)Pr(x)]+Ex∼Pg[logPr(x)+pg(x)Pg(x)]=Ex∼Pr[log21∗(Pr(x)+Pg(x))21∗Pr(x)]+Ex∼Pg[log21∗(Pr(x)+pg(x))21∗Pg(x)]=Ex∼Pr[log21∗(Pr(x)+Pg(x))Pr(x)−log2]+Ex∼Pg[log21∗(Pr(x)+pg(x))Pg(x)−log2]=2JS(Pr∥Pg)−2log2
)到这里,我们就可以看清楚我们到底在优化什么东西了,在最优判别器的情况下,其实我们在优化两个分布的 J S JS JS散度。当然在训练过程中,判别器一开始不是最优的,但是随着训练的进行,我们也在优化的目标也逐渐接近 J S JS JS散度,而问题恰恰就出现在这个 J S JS JS散度上面。一个直观的解释就是只要两个分布之间的没有重叠或者重叠部分可以忽略不计,那么大概率上我们优化的目标就变成了一个常数 − 2 l o g 2 -2log2 −2log2,这种情况通过判别器传递给生成器的梯度就是零,也就是说,生成器不可能从判别器那里学到任何有用的东西,这也就导致了无法继续学习。
Arjovsky2以其精湛的数学技巧提供一个更严谨的一个数学推导(?手动截图原论文了)。
所以,在 Theorm 2.4 \boldsymbol{\text{Theorm} 2.4} Theorm2.4成立的情况下:
lim ∥ D − D ∗ ∥ → 0 ∇ θ E z ∼ p ( z ) [ log ( 1 − D ( g θ ( z ) ) ) ] = 0 \lim _{\left\|D-D^{*}\right\| \rightarrow 0} \nabla_{\theta} \mathbb{E}_{z \sim p(z)}\left[\log \left(1-D\left(g_{\theta}(z)\right)\right)\right]=0 ∥D−D∗∥→0lim∇θEz∼p(z)[log(1−D(gθ(z)))]=0
抛开上面这些文邹邹的数学表述,其实上面讲的核心内容就是当两个分布的支撑集是没有交集的或者说是支撑集是低维的流形空间,随着训练的进行,判别器不断接近最优判别器,会导致生成器的梯度处处都是为0。 -
对于第二种目标函数
同样在最优判别器下,优化4式等价优化如下
K L ( P g ∥ P r ) − 2 J S ( P r ∥ P g ) K L\left(P_{g} \| P_{r}\right)-2 J S\left(P_{r} \| P_{g}\right) KL(Pg∥Pr)−2JS(Pr∥Pg)
(推导:
K L ( P g ∥ P r ) = E x ∼ P g [ log P g ( x ) P r ( x ) ] = E x ∼ P g [ log P g ( x ) / ( P r ( x ) + P g ( x ) ) P r ( x ) / ( P r ( x ) + P g ( x ) ) ] = E x ∼ P g [ log 1 − D ∗ ( x ) D ∗ ( x ) ] = E x ∼ P g log [ 1 − D ∗ ( x ) ] − E x ∼ P g log D ∗ ( x ) \begin{aligned} K L\left(P_{g} \| P_{r}\right) &=\mathbb{E}_{x \sim P_{g}}\left[\log \frac{P_{g}(x)}{P_{r}(x)}\right] \\ &=\mathbb{E}_{x \sim P_{g}}\left[\log \frac{P_{g}(x) /\left(P_{r}(x)+P_{g}(x)\right)}{P_{r}(x) /\left(P_{r}(x)+P_{g}(x)\right)}\right] \\ &=\mathbb{E}_{x \sim P_{g}}\left[\log \frac{1-D^{*}(x)}{D^{*}(x)}\right] \\ &=\mathbb{E}_{x \sim P_{g}} \log \left[1-D^{*}(x)\right]-\mathbb{E}_{x \sim P_{g}} \log D^{*}(x) \end{aligned} KL(Pg∥Pr)=Ex∼Pg[logPr(x)Pg(x)]=Ex∼Pg[logPr(x)/(Pr(x)+Pg(x))Pg(x)/(Pr(x)+Pg(x))]=Ex∼Pg[logD∗(x)1−D∗(x)]=Ex∼Pglog[1−D∗(x)]−Ex∼PglogD∗(x)由上式可得:
E x ∼ P g [ − log D ∗ ( x ) ] = K L ( P g ∥ P r ) − E x ∼ P g log [ 1 − D ∗ ( x ) ] = K L ( P g ∥ P r ) − 2 J S ( P r ∥ P g ) + 2 log 2 + E x ∼ P r [ log D ∗ ( x ) ] \begin{aligned} \mathbb{E}_{x \sim P_{g}}\left[-\log D^{*}(x)\right] &=K L\left(P_{g} \| P_{r}\right)-\mathbb{E}_{x \sim P_{g}} \log \left[1-D^{*}(x)\right] \\ &=K L\left(P_{g} \| P_{r}\right)-2 J S\left(P_{r} \| P_{g}\right)+2 \log 2+\mathbb{E}_{x \sim P_{r}}\left[\log D^{*}(x)\right] \end{aligned} Ex∼Pg[−logD∗(x)]=KL(Pg∥Pr)−Ex∼Pglog[1−D∗(x)]=KL(Pg∥Pr)−2JS(Pr∥Pg)+2log2+Ex∼Pr[logD∗(x)]
由于上式第三项和第四项与优化G无关,所以舍去不管。)
仔细盯着上面式子几秒钟,不难发现我们优化的目标是相互悖论的,因为 K L KL KL散度和 J S JS JS散度的符号相反,优化 K L KL KL是把两个分布拉近,但是优化 − J S -JS −JS是把两个分布推远,这"一推一拉"就会导致梯度更新非常不稳定。此外,我们知道 K L KL KL不是对称的,对于生成器无法生成真实样本的情况, K L KL KL对loss的贡献非常大,而对于生成器生成的样本多样性不足的时候, K L KL KL对loss的贡献非常小。
而 J S JS JS是对称的,不会改变 K L KL KL的这种不公平的行为。这就解释了我们经常在训练阶段经常看见两种情况,一个是训练loss抖动非常大,训练不稳定;另外一个是即使达到了稳定训练,生成器也大概率上只生成一些安全保险的样本,这样就会导致模型缺乏多样性。
此外,在有监督的机器学习里面,经常会出现一些过拟合的情况,然而GANs也不例外。当生成器训练得越来越好时候,生成的数据越接近于有限样本集合里面的数据。特别是当训练集里面包含有错误数据时候,判别器会过拟合到这些错误的数据,对于那些未见的数据,判别器就不能很好的指导生成器去生成可信的数据。这样就会导致GANs的泛化能力比较差。
综上所述,原始的GANs在训练稳定性、模式多样性以及模型泛化性能方面存在着或多或少的问题,后续学术上的工作大多也是基于此进行改进(填坑)。
训练GAN的常用策略
上一节都是基于一些简单的数学或者经验的分析,但是根本原因目前没有一个很好的理论来解释;尽管理论上的缺陷,我们仍然可以从一些经验中发现一些实用的tricks,让你的GANs不再难训。这里列举的一些tricks可能跟ganhacks里面的有些重复,更多的是补充,但是为了完整起见,部分也添加在这里。
-
model
-
input layer
假如你的输入是一张图片,将图片数值归一化到[-1, 1];假如你的输入是一个随机噪声的向量,最好是从N(0, 1)的正太分布里面采样,不要从U(0,1)的均匀分布里采样。
-
output layer
使用输出通道为3的卷积作为最后一层,可以采用1x1或者3x3的filters,有的论文也使用9x9的filters。(注:ganhacks 推荐使用tanh)
-
transposed convolution layer
在做decode的时候,尽量使用upsample+conv2d组合代替transposed_conv2d,可以减少checkerboard的产生5;
在做超分辨率等任务上,可以采用pixelshuffle6。在tensorflow里,可以用tf.depth_to_sapce 来实现pixelshuffle 操作。
-
convolution layer
由于笔者经常做图像修复方向相关的工作,推荐使用gated-conv2d7。
-
normalization
虽然在resnet里的标配是BN,在分类任务上表现很好,但是图像生成方面,推荐使用其他normlization方法,例如parameterized 方法有instance normalization8、layer normalization9等,non-parameterized 方法推荐使用pixel normalization10。假如你有选择困难症,那就选择大杂烩的normalization 方法——switchable normalization11。
-
discriminator
要生成高清的图像,推荐multi-stage discriminator10。简单的做法就是对于输入图片,把它下采样(maxpooling)到不同scale的大小,输入三个不同参数但结构相同的discriminator。
-
minibatch discriminator
由于判别器是单独处理每张图片,没有一个机制能告诉discriminator每张图片之间要尽可能的不相似,这样就会导致判别器会将所有图片都push到一个看起来真实的点,缺乏多样性。minibatch discriminator 就是这样这个机制,显式的告诉discriminator每张图片应该要不相似。在tensorflow中,一种实现minibatch discriminator方式如下:
def minibatch_discriminator_layer(x, output_dim, hidden_dim): """ Improved Techniques for Training GANs (https://arxiv.org/pdf/1606.03498.pdf) """ if x.ndim > 2: x = tf.layers.flatten(x) in_dim = shape_list(x)[-1] w = tf.get_variable("kernel", [in_dim, hidden_dim, output_dim], tf.float32, initializer=weight_initializer, regularizer=weight_regularizer ) xw = tf.einsum('ij, jkl->ikl', x, w) diff = tf.abs(tf.expand_dims(xw, axis=1), tf.expand_dims(xw, axis=0)) o = tf.exp(-tf.reduce_sum(diff, axis=1)) o = tf.reduce_sum(o, axis=1) # [batch, output_dim] return o
上面是通过一个可学习的网络来显示度量每个样本之间的相似度,PGGAN里提出了一个更廉价的不需要学习的版本,即通过统计每个样本特征每个像素点的标准差,然后取他们的平均,把这个平均值复制到与当前feature map一样空间大小单通道,作为一个额外的feature maps 拼接到原来的feature maps里,一个简单的tensorflow 实现如下:
def minibatch_discriminator_layer(x): """ Progressive Growing of GANs for Improved Quality, Stability, and Variation (https://arxiv.org/pdf/1710.10196.pdf) """ s = shape_list(x) adjusted_std = lambda x, **kwargs: tf.sqrt( tf.reduce_mean((x - tf.reduce_mean(x, **kwargs)) ** 2, **kwargs) + 1e-8) vals = adjusted_std(input, axis=0, keep_dims=True) vals = tf.reduce_mean(vals, keep_dims=True) vals = tf.tile(vals, multiples=[s[0], s[1], s[2], 1]) o = tf.concat([x, vals], axis=3) return o
-
GAN loss
除了第二节提到的原始GANs中提出的两种loss,还可以选择wgan loss 12、hinge loss、lsgan loss13等。wgan loss 使用Wasserstein 距离(推土机距离)来度量两个分布之间的差异,lsgan 采用类似最小二乘法的思路设计损失函数,最后演变成用皮尔森卡方散度代替了原始GAN中的 J S JS JS散度,hinge loss 是迁移了SVM里面的思想,在SAGAN14和BigGAN15等都是采用该函数。
type formula GAN1 L D G A N = E [ log ( D ( x ) ) ] + E [ log ( 1 − D ( G ( z ) ) ) ] L G G N = E [ log ( D ( G ( z ) ) ) ] \begin{aligned} L_{D}^{G A N} &=E[\log (D(x))]+E[\log (1-D(G(z)))] \\ L_{G}^{G N} &=E[\log (D(G(z)))] \end{aligned} LDGANLGGN=E[log(D(x))]+E[log(1−D(G(z)))]=E[log(D(G(z)))] LSGAN13 L D L S G A N = E [ ( D ( x ) − 1 ) 2 ] + E [ D ( G ( z ) ) 2 ] L G L S G A N = E [ ( D ( G ( z ) ) − 1 ) 2 ] \begin{aligned} L_{D}^{L S G A N} &=E\left[(D(x)-1)^{2}\right]+E\left[D(G(z))^{2}\right] \\ L_{G}^{L S G A N} &=E\left[(D(G(z))-1)^{2}\right] \end{aligned} LDLSGANLGLSGAN=E[(D(x)−1)2]+E[D(G(z))2]=E[(D(G(z))−1)2] WGAN12 L D W G A N = E [ D ( x ) ] − E [ D ( G ( z ) ) ] L G W G A N = E [ D ( G ( z ) ) ] W D ← c l i p − b y − v a l u e ( W D , − 0.01 , 0.01 ) \begin{aligned} L_{D}^{W G A N} &=E[D(x)]-E[D(G(z))] \\ L_{G}^{W G A N} &=E[D(G(z))] \\ W_{D} \leftarrow & c l i p_{-} b y_{-} v a l u e\left(W_{D},-0.01,0.01\right) \end{aligned} LDWGANLGWGANWD←=E[D(x)]−E[D(G(z))]=E[D(G(z))]clip−by−value(WD,−0.01,0.01) WGAN-GP16 L D W G A N − G P = L D W G A N + λ E [ ( ∥ ∇ D ( α x + ( 1 − α ) G ( z ) ) ) ∥ − 1 ) 2 ] L G W G A N − G P = L G W G A N \begin{aligned} L_{D}^{W G A N_{-} G P} &=L_{D}^{W G A N}+\lambda E\left[(\|\nabla D(\alpha x+(1-\alpha )G(z)))\|-1)^{2}\right] \\ L_{G}^{W G A N_{-} G P} &=L_{G}^{W G A N} \end{aligned} LDWGAN−GPLGWGAN−GP=LDWGAN+λE[(∥∇D(αx+(1−α)G(z)))∥−1)2]=LGWGAN Hinge Loss L D = E [ r e l u ( 1 − D ( x ) ) ] + E [ r e l u ( 1 + D ( G ( z ) ) ) ] L G = − E [ D ( G ( z ) ) ] \begin{array}{l}{L_{D}=E[relu (1-D(x))]+E[relu (1+D(G(z)))]} \\ {L_{G}=-E[D(G(z))]}\end{array} LD=E[relu(1−D(x))]+E[relu(1+D(G(z)))]LG=−E[D(G(z))] ps: 我自己经常使用没有relu的hinge loss 版本。
-
other loss
-
gradient penalty
Gradient penalty 首次在wgan-gp 里面提出来的,记为1-gp,目的是为了让discriminator满足1-lipchitchz 连续,后续Mescheder, Lars M. et al19又提出了只针对正样本或者负样本进行梯度惩罚,记为0-gp-sample。Thanh-Tung, Hoang et al20提出了0-gp,具有更好的训练稳定性。三者的对比如下:
12. Spectral normalization21
谱归一化是另外一个让判别器满足1-lipchitchz 连续的利器,建议在判别器和生成器里同时使用。
ps:在个人实践中,它比梯度惩罚更有效。
13. one-size label smoothing22
平滑正样本的label,例如1变成0.9-1.1之间的随机数,保持负样本label仍然为0。个人经验表明这个tricks能够有效缓解训练不稳定的现象,但是不能根本解决问题,假如模型不够好的话,随着训练的进行,后期loss会飞。
-
add supervised labels
- add labels
- conditional batch normalization
-
instance noise(decay over time)
在原始GAN中,我们其实在优化两个分布的 J S JS JS散度,前面的推理表明在两个分布的支撑集没有交集或者支撑集是低维的流形空间,他们之间的JS散度大概率上是0;而加入instance noise 就是强行让两个分布的支撑集之间产生交集,这样 J S JS JS散度就不会为0。新的JS散度变为:
d σ , J S ( P r ∣ P g ) = J S [ P σ ∗ P r ∣ P σ ∗ P g ] d_{\sigma, J S\left(P_{r} | P_{g}\right)}=J S\left[P_{\sigma} * P_{r} | P_{\sigma} * P_{g}\right] dσ,JS(Pr∣Pg)=JS[Pσ∗Pr∣Pσ∗Pg] -
TTUR23
在优化G时候,我们默认是假定我们的D的判别能力是比当前的G的生成能力要好的,这样D才能指导G朝更好的方向学习。通常的做法是先更新D的参数一次或者多次,然后在更新G的参数,TTUR提出了一个更简单的更新策略,即分别为D和G设置不同的学习率,让D收敛速度更快。
-
training strategy
-
PGGAN10
PGGAN是一个渐进式的训练技巧,因为要生成高清(eg, 1024x1024)的图片,直接从一个随机噪声生成这么高维度的数据是比较难的;既然没法一蹴而就,那就循序渐进,首先从简单的低纬度的开始生成,例如4x4,然后16x16,直至我们所需要的图片大小。在PGGAN里,首次实现了高清图片的生成,并且可以做到以假乱真,可见其威力。此外,由于我们大部分的操作都是在比较低的维度上进行的,训练速度也不比其他模型逊色多少。
-
coarse-to-refine
coarse-to-refine 可以说是PGGAN的一个特例,它的做法就是先用一个简单的模型,加上一个l1 loss,训练一个模糊的效果,然后再把这个模糊的照片送到后面的refine模型里,辅助对抗loss等其他loss,训练一个更加清晰的效果。这个在图片生成里面广泛应用。
-
-
Exponential Moving Average24
EMA主要是对历史的参数进行一个指数平滑,可以有效减少训练的抖动。强烈推荐!!!
总结
训练GAN是一个精(折)细(磨)的活,一不小心你的GAN可能就是一部惊悚大片。笔者结合自己的经验以及一些文献资料,列出了常用的tricks,在此抛砖引玉,由于笔者能力和视野有限,有些不正确之处或者没补全的tricks,还望斧正。
最后,祝大家炼丹愉快,不服就GAN。: )
参考文献
Goodfellow, Ian, et al. “Generative adversarial nets.” Advances in neural information processing systems. 2014. ↩︎ ↩︎
Arjovsky, Martín and Léon Bottou. “Towards Principled Methods for Training Generative Adversarial Networks.” CoRR abs/1701.04862 (2017): n. pag. ↩︎
Radford, Alec et al. “Unsupervised Representation Learning with Deep Convolutional Generative Adversarial Networks.” CoRR abs/1511.06434 (2016): n. pag. ↩︎
He, Kaiming et al. “Deep Residual Learning for Image Recognition.” 2016 IEEE Conference on Computer Vision and Pattern Recognition (CVPR) (2016): 770-778. ↩︎
Shi, Wenzhe et al. “Real-Time Single Image and Video Super-Resolution Using an Efficient Sub-Pixel Convolutional Neural Network.” 2016 IEEE Conference on Computer Vision and Pattern Recognition (CVPR) (2016): 1874-1883. ↩︎
Yu, Jiahui et al. “Free-Form Image Inpainting with Gated Convolution.” CoRRabs/1806.03589 (2018): n. pag. ↩︎
Ulyanov, Dmitry et al. “Instance Normalization: The Missing Ingredient for Fast Stylization.” CoRR abs/1607.08022 (2016): n. pag. ↩︎
Ba, Jimmy et al. “Layer Normalization.” CoRR abs/1607.06450 (2016): n. pag. ↩︎
Karras, Tero et al. “Progressive Growing of GANs for Improved Quality, Stability, and Variation.” CoRR abs/1710.10196 (2018): n. pag. ↩︎ ↩︎ ↩︎
Luo, Ping et al. “Differentiable Learning-to-Normalize via Switchable Normalization.” CoRRabs/1806.10779 (2018): n. pag. ↩︎
Arjovsky, Martín et al. “Wasserstein GAN.” CoRR abs/1701.07875 (2017): n. pag. ↩︎ ↩︎
Mao, Xudong, et al. “Least squares generative adversarial networks.” Proceedings of the IEEE International Conference on Computer Vision. 2017. ↩︎ ↩︎
Zhang, Han, et al. “Self-attention generative adversarial networks.” arXiv preprint arXiv:1805.08318 (2018). ↩︎
Brock, Andrew, Jeff Donahue, and Karen Simonyan. “Large scale gan training for high fidelity natural image synthesis.” arXiv preprint arXiv:1809.11096 (2018). ↩︎
Gulrajani, Ishaan et al. “Improved Training of Wasserstein GANs.” NIPS (2017). ↩︎
Johnson, Justin et al. “Perceptual Losses for Real-Time Style Transfer and Super-Resolution.” ECCV (2016). ↩︎ ↩︎
Liu, Guilin et al. “Image Inpainting for Irregular Holes Using Partial Convolutions.” ECCV(2018). ↩︎
Mescheder, Lars M. et al. “Which Training Methods for GANs do actually Converge?” ICML(2018). ↩︎
Thanh-Tung, Hoang et al. “Improving Generalization and Stability of Generative Adversarial Networks.” CoRR abs/1902.03984 (2018): n. pag. ↩︎
Yoshida, Yuichi and Takeru Miyato. “Spectral Norm Regularization for Improving the Generalizability of Deep Learning.” CoRR abs/1705.10941 (2017): n. pag. ↩︎
Salimans, Tim et al. “Improved Techniques for Training GANs.” NIPS (2016). ↩︎
Heusel, Martin et al. “GANs Trained by a Two Time-Scale Update Rule Converge to a Local Nash Equilibrium.” NIPS (2017). ↩︎
Yazici, Yasin et al. “The Unusual Effectiveness of Averaging in GAN Training.” CoRRabs/1806.04498 (2018): n. pag. ↩︎