理论-GAN1-对抗神经网络梳理(GAN,WGAN,WGAN-GP,Cycle-GAN)
1,WGAN
1.1,从GAN到WGAN,最核心的有这么几点:
-
GAN的损失函数如下:
\[\min_{G}\max_{D}V\{D,G\}=E_{x\sim{P_{data(x)}}}[logD(x)]+E_{x\sim{P_{z(z)}}}[log(1-D(G(z)))] \tag{0} \]判别器模型前向传播过程中最后需要加上sigmoid函数,结合nn.BCELoss()得到损失函数。
最优判别器为:
\[D(x)=\frac{P_{r}(x)}{P_r(x)+P_g(x)} \tag{1} \]这个结果从直观上很容易理解,就是看一个样本\(x\)来自真实分布和生成分布的可能性的相对比例。如果\(P_{r}(x)=0\)且\(P_{g}(x)\neq{0}\),最优判别器就应该非常自信地给出概率0;如果\(P_{r}(x)=P_{g}(x)\),说明该样本是真是假的可能性刚好一半一半,此时最优判别器也应该给出概率0.5。
-
判别器最优时,GAN的损失函数由:
\[E_{x\sim{P_{r}}}[logD(x)]+E_{x\sim{P_{g}}}[log(1-D(G(z)))] \tag{2} \]变为
\[E_{x\sim{P_{r}}}[log\frac{P_{r}(x)}{\frac{1}{2}[P_{r}(x)+P_{g}(x)]}]+E_{x\sim{P_{g}}}[log\frac{P_{g}(x)}{\frac{1}{2}[P_{r}(x)+P_{g}(x)]}]-2log2 \tag{3} \]已知KL散度以及JS散度:
\[KL(P_{1}||P_{2})=E_{x\sim{P_{1}}}log\frac{P_{1}}{P_{2}} \tag{4} \]\[JS(P_{1}||P_{2})=\frac{1}{2}KL(P_{1}||\frac{P_1+P_2}{2})+\frac{1}{2}KL(P_{2}||\frac{P_1+P_2}{2}) \tag{5} \]则3式可以写为
\[2JS(P_{r}||P_{g})-2log2 \tag{6} \]在最优判别器下,原始GAN定义的生成器loss等价变换为最小化真实分布\(P_{r}\)与生成分布\(P_{g}\)之间的JS散度。越训练判别器,它就越接近最优,最小化生成器的loss也就会越近似于最小化\(P_{r}\)和\(P_{g}\)之间的JS散度。
-
JS散度存在问题
-
我们希望如果两个分布之间越接近它们的JS散度越小,通过优化JS散度就能将\(P_{g}\)拉向\(P_{r}\),最终以假乱真。
-
这个希望在两个分布有所重叠的时候是成立的,但是如果两个分布完全没有重叠的部分,或者它们重叠的部分可忽略,JS散度固定为常数\(log2\),而这意味着梯度为0。
-
JS散度固定为常数\(log2\)证明如下:
对于任意一个x,只存在四种可能
\[P_1(x)=0~~~~~P_2(x)=0~~~~~就是说样本x不在P_1中也不在P_2中 \]\[P_1(x)\neq0~~~~~P_2(x)\neq0~~~~~就是说样本x即在P_1中也在P_2中(在GAN中就意味着生成的样本中存在样本与真实数据分不一致) \]\[P_1(x)=0~~~~~P_2(x)\neq0 \]\[P_1(x)\neq0~~~~~P_2(x)=0 \] 在这四种可能中,第一种对JS散度无贡献,第二种由于重叠部分可以忽略所以贡献为零,第三种和第四种情况带入式5可得
\[JS(P_{1}||P_{2})=\frac{1}{2}log\frac{P_{2}}{\frac{1}{2}(0+P_2)}+\frac{1}{2}log\frac{P_{1}}{\frac{1}{2}(P_1+0)}=log2 \] -
-
\(P_{g}\)与\(P_{r}\)不重叠或重叠部分可忽略的可能性非常大(当\(P_{r}\)与\(P_{g}\)的支撑集(support)是高维空间中的低维流形(manifold)时,\(P_{r}\)与\(P_{g}\)重叠部分测度(measure)为0的概率为1。而在数据生成时,\(P_{r}\)与\(P_{g}\)的支撑集是高维空间中的低维流形基本成立,因为生成器一般都是从某个低维(比如100维)的随机分布中采样出一个编码向量,再经过一个神经网络生成出一个高维样本(比如64x64的图片就有4096维)。当生成器的参数固定时,生成样本的概率分布虽然是定义在4096维的空间上,但它本身所有可能产生的变化已经被那个100维的随机分布限定了,其本质维度就是100,再考虑到神经网络带来的映射降维,最终可能比100还小,所以生成样本分布的支撑集就在4096维空间中构成一个最多100维的低维流形,“撑不满”整个高维空间。“撑不满”就会导致真实分布与生成分布难以“碰到面”,这很容易在二维空间中理解:一方面,二维平面中随机取两条曲线,它们之间刚好存在重叠线段的概率为0;另一方面,虽然它们很大可能会存在交叉点,但是相比于两条曲线而言,交叉点比曲线低一个维度,长度(测度)为0,可忽略。三维空间中也是类似的,随机取两个曲面,它们之间最多就是比较有可能存在交叉线,但是交叉线比曲面低一个维度,面积(测度)是0,可忽略。)
-
从其他角度论证梯度的消失:
- \(P_r\)与\(P_g\)之间几乎不可能有不可忽略的重叠,无论它们之间的“缝隙”多狭小,都肯定存在一个最优分割曲面把它们隔开,最多就是在那些可忽略的重叠处隔不开而已。
- 由于判别器作为一个神经网络可以无限拟合这个分隔曲面,所以存在一个最优判别器,对几乎所有真实样本给出概率1,对几乎所有生成样本给出概率0,而那些隔不开的部分就是难以被最优判别器分类的样本,但是它们的测度为0,可忽略。
- 最优判别器在真实分布和生成分布的支撑集上给出的概率都是常数(1和0),导致生成器的loss梯度为0,梯度消失。
也就是说,在(近似)最优判别器下,最小化生成器的loss等价于最小化\(P_r\)与\(P_g\)之间的JS散度,而由于\(P_r\)与\(P_g\)几乎不可能有不可忽略的重叠,所以无论它们相距多远JS散度都是常数\(log2\),最终导致生成器的梯度(近似)为0,梯度消失。
-
-
原始GAN问题的根源可以归结为两点
- 等价优化的距离度量(KL散度、JS散度)不合理
- 生成器随机初始化后的生成分布很难与真实分布有不可忽略的重叠
-
为了解决第二个问题,曾提出加噪声的方法以将原本的两个低维流形“弥散”到整个高维空间,强行让它们产生不可忽略的重叠。
-
WGAN则从第一个问题出发,提出了Wasserstein距离以替代JS散度
Wasserstein距离又叫Earth-Mover(EM)距离,定义如下:
\[W(P_{r},P_{g})=\inf_{\gamma{\sim{\prod(P_{r},P_{g})}}}E_{(x,y)\sim{\gamma}}[||x-y||] \]Wasserstein距离相比KL散度、JS散度的优越性在于,即便两个分布没有重叠,Wasserstein距离仍然能够反映它们的远近。(关键在于由散度/概率度量转变到了真正的距离)
在实际应用时由于Wasserstein距离定义中的\(\inf_{\gamma{\sim{\prod(P_{r},P_{g})}}}\)无法直接求解,将其变换为如下形式(转换原理可以看原文:Wasserstein generative adversarial networks.)
\[W(P_{r},P_{g})=\frac{1}{K}\sup_{||f||_{L}\leq{K}}E_{x\sim{P_{r}}}[f(x)]-E_{x\sim{P_{g}}}[f(x)] \]公式的含义是:在要求函数\(f\)的Lipschitz常数\(||f||_L\)(函数导数的最大值)不超过\(K\)的条件下,对所有可能满足条件的\(f\)取到\(E_{x\sim{P_{r}}}[f(x)]-E_{x\sim{P_{g}}}[f(x)]\)的上界,然后再除以\(K\)。特别的,可以用一组参数\(W\)定义一系列可能的函数\(f_{W}\)(神经网络),此时损失函数近似为:
\[K\cdot{W(P_{r},P_{g})} \approx \max_{w:|f_{W}|_{L}\leq{K}}E_{x\sim{P_{r}}}[f_{W}(x)]-E_{x\sim{P_{g}}}[f_{W}(x)] \]并且我们其实并不关心\(|f_{W}|_{L}\leq{K}\)这个限制中的\(K\)具体是多少,只要不是正无穷就行,因为它只是会使得梯度变大\(K\)倍,并不会影响梯度的方向,所以作者采取了一个非常简单的做法,就是限制神经网络的所有\(f_{W}\)参数\(W\)的不超过某个范围\([-c,c]\),比如\([-0.01,0.01]\),此时关于输入样本\(x\)的导数\(\frac{\partial{f_W}}{\partial{x}}\)也不会超过某个范围,所以一定存在某个不知道的常数\(K\)使得的局部变动幅度不会超\(f_{W}\)过它,约束条件得以满足。
-
总结:
-
到此为止,我们可以构造一个含参数\(W\)、最后一层不是非线性激活层的判别器网络\(f_{W}\),在限制\(W\)不超过某个范围的条件下,使得\(L=E_{x\sim{P_{r}}}[f_{W}(x)]-E_{x\sim{P_{g}}}[f_{W}(x)]\)尽可能取到最大,此时损失函数\(L\)就会近似真实分布与生成分布之间的Wasserstein距离(忽略常数倍数\(K\))。注意原始GAN的判别器做的是真假二分类任务,所以最后一层是sigmoid,但是现在WGAN中的判别器\(f_{W}\)做的是近似拟合Wasserstein距离,属于回归任务,所以要把最后一层的sigmoid拿掉。
-
接下来生成器要近似地最小化Wasserstein距离,即最小化\(L\),由于Wasserstein距离的优良性质,我们不需要担心生成器梯度消失的问题。再考虑到\(L\)的第一项与生成器无关,就得到了WGAN的两个loss。
\[-E_{x\sim{P_{g}}}[f_{W}(x)]~~~~~~~~~~~~~~~~生成器loss \]\[E_{x\sim{P_{g}}}[f_{W}(x)]-E_{x\sim{P_{r}}}[f_{W}(x)]~~~~~~~~~~~~~~~~判别器loss \]两个都是min
-
训练过程
-
1.2,相较于GAN,WGAN做了以下改进
-
判别器最后一层去掉sigmoid
-
生成器和判别器中的loss不取对数,损失函数如下:
\[W(P_{r},P_{g})=\frac{1}{K}\sup_{||f||_{L}\leq{K}}E_{x\sim{P_{r}}}[f(x)]-E_{x\sim{P_{g}}}[f(x)] \]实际应用时:
\[L(G)=-E_{x\sim{P_{g}}}[D(x)]~~~~~~~~~~~~~~~~生成器loss,相当于~~~~~~~~~~~~~~~~\min_{G}-E_{x\sim{P_{z(z)}}}[-D(G(z))] \]\[L(D)=E_{x\sim{P_{g}}}[D(x)]-E_{x\sim{P_{r}}}[D(x)]~~~~~~~~~~~~~~~~判别器loss,相当于~~~~~~~~~~~~~~~~\min_{D}-E_{x\sim{P_{data(x)}}}D(x)+E_{x\sim{P_{z(z)}}}D(G(z))) \]注意事项:
- 一般来说,Discrimnator比Genenrator训练的多,比如训练五次Discrimnator,再训练一次Genenrator(WGAN论文是这么干的)。
-
每次更新判别器的参数,将其绝对值截断到不超过一个固定常数c
for p in discriminator.parameters(): p.data.clamp_(clamp_lower, clamp_upper)
-
不要用基于动量的优化方法(momentum,Adam),推荐RMSProp,SGD也行(trick:作者发现如果使用Adam,判别器的loss有时候会崩掉,当它崩掉时,Adam给出的更新方向与梯度方向夹角的cos值就变成负数,更新方向与梯度方向南辕北辙,这意味着判别器的loss梯度是不稳定的,所以不适合用Adam这类基于动量的优化算法。作者改用RMSProp之后,问题就解决了,因为RMSProp适合梯度不稳定的情况。)
2,WGAN-GP
2.1,WGAN直接对权重的值进行约束的方式存在两个问题
-
Capacity undersure(网络容量不足)
体现训练后的网络只是对简单函数的近似(其实很容易理解,毕竟将w都限制死了,潜在的可学习到的函数肯定大大受限)
-
Exploding and vanishing gradients(梯度消失和爆炸)
若把clipping threshold设的较小,每经过一个网络,梯度就会变小,多级之后会成为指数衰减;反之,较大,则会使得指数爆炸.这个平衡区域可能很小。
2.2,改进
为了解决上述问题,WGAN-GP引入了gradient penalty,并将其与WGAN的判别器Loss函数相加构成新的判别器Loss函数:
-
\(\hat{x}\sim{P_{\hat{x}}}\)的获取方法:\(\tilde{x}\sim{P_g},x\sim{P_r},\epsilon\sim{[0,1]}\Rightarrow{\hat{x}}=\epsilon{\tilde{x}+(1-\epsilon)x}\)
epsilon = torch.rand(real.size(0), 1).expand(real.size()).cuda() realFake = epsilon * real + ((1-epsilon)) * fake
-
Our gradient penalty对梯度直接进行了限制
'''V1''' disResult = discriminator(realFake) gradients = autograd.grad(outputs=disResult, inputs=realFake, grad_outputs=torch.ones(disResult.size()).cuda(), create_graph=True, retain_graph=True, only_inputs=True)[0] gradient_penalty = ((gradients.norm(2, dim=1) - 1) ** 2).mean() '''V2''' disResult = discriminator(realFake) disResult.backward(torch.ones(disResult.size()).cuda()) gradients = realFake.grad gradient_penalty = ((gradients.norm(2, dim=1) - 1) ** 2).mean()
def compute_gradient_penalty(cuda, D, real_samples, fake_samples): Tensor = torch.cuda.FloatTensor if cuda else torch.FloatTensor alpha = Tensor(np.random.random((real_samples.size(0), 1, 1, 1))) interpolates = (alpha * real_samples + ((1 - alpha) * fake_samples)).requires_grad_(True) d_interpolates = D(interpolates) fake = autograd.Variable(Tensor(real_samples.shape[0], 1).fill_(1.0), requires_grad=False) gradients = autograd.grad( outputs=d_interpolates, inputs=interpolates, grad_outputs=fake, create_graph=True, retain_graph=True, only_inputs=True, )[0] gradients = gradients.view(gradients.size(0), -1) gradient_penalty = ((gradients.norm(2, dim=1) -1)**2).mean() return gradient_penalty
-
\(\lambda\)取10(原文中是这么取的)
-
优化算法用的Adam
参考博客:
https://blog.csdn.net/omnispace/article/details/54942668(深度好文,强烈推荐)
https://blog.csdn.net/junbaba_/article/details/106185743
https://www.cnblogs.com/kai-nutshell/p/12968454.html
https://www.cnblogs.com/kai-nutshell/p/12968484.html
3,Cycle-GAN
-
文献:Unpaired Image-to-Image Translation using Cycle-Consistent Adversarial Networks Jun-Yan
-
概念及定义:
- paired samples(成对样本)缺失导致的问题:
- 图像到图像转换问题的目标是使用一组对齐的图像对学习输入图像和输出图像之间的映射关系;但是在许多任务中,成对的训练数据是无法获取的;在没有配对示例的情况下需要学习的是源域X到目标域Y的转换方法:捕获一个域/样本集合的特殊特征并弄清楚如何将这些特征转换为另一个域/样本集合,一种不需要配对样本的风格转换方法。
- 使用经典方法优化后的\(G\)可以将域\(X\)转换为与\(Y\)分布相同的域\(\hat{Y}\),但是并不能确保单独的输入和输出样本\(x\)和\(y\)是以一种有意义的方式配对的——有无限多种映射\(G\)可以产生相同的分布\(\hat{Y}\),但这些映射针对单独的输入\(x\)却可能产生无限多种\(y\)。此外,模式崩溃问题导致很难孤立地优化对抗性目标,经常发生所有输入图像都映射到相同输出图像并且优化无法取得进展的现象。
- 循环一致性损失(cycle consistency loss):
- 学习的目标是映射关系:\(G:X\rightarrow{Y}\);而由于该映射是高度约束不足的(hightly under-constrained),将其与逆映射:\(F:Y\rightarrow{X}\)结合起来,引入循环一致性损失推动\(F(G(x))\approx{X}\)以及\(G(F(y))\approx{y}\)。
- paired samples(成对样本)缺失导致的问题:
-
解决方案
包含两个关联的对抗判别器\(D_X\)(用于区分\(x\)和\(F(y)\))和\(D_Y\)(用于区分\(y\)和\(G(x)\)),引入两个循环一致性损失:
-
前向循环一致性损失:\(x\rightarrow{G(x)}\rightarrow{F(G(x))}\approx{x}\)
-
反向循环一致性损失:\(y\rightarrow{F(y)}\rightarrow{G(F(y))}\approx{y}\)
-
损失函数:
-
判别器损失:
\[L_{GAN}(G,D_Y,X,Y)=E_{y\sim{p_{data}(y)}}[logD_Y(y)]+E_{x\sim{p_{data}(x)}}[log(1-D_Y(G(x)))] \]\[L_{GAN}(F,D_X,X,Y)=E_{x\sim{p_{data}(x)}}[logD_X(x)]+E_{y\sim{p_{data}(y)}}[log(1-D_X(F(y)))] \] -
循环一致性损失:
\[L_{cyc}(G,F)=E_{x\sim{p_{data}(x)}}[||F(G(x))-x||_1]+E_{y\sim{p_{data}(y)}}[||G(F(y))-y||_1] \]
-
-
该模型可以被视为训练两个自动编码器
-
在训练时,用到了两个技巧:
-
用最小二乘损失替换负对数似然目标以产生更高质量的结果:
\[L_{LSGAN}(G,D_Y,X,Y)=E_{y\sim{p_{data}(y)}}[(D_Y(y)-1)^2]+E_{x\sim{p_{data}(x)}}[D_Y(G(x))^2] \]\[L_{LSGAN}(F,D_X,X,Y)=E_{x\sim{p_{data}(x)}}[(D_X(x)-1)^2]+E_{y\sim{p_{data}(y)}}[D_X(F(y))^2] \] -
为了减少模型振荡,遵循Shrivastava等人的策略并使用生成图像的历史版本而不是最新生成网络生成的图像更新鉴别器 DX 和 DY。 为此保留一个图像缓冲区,用于存储 50 个先前生成的图像 。
-
-