生成对抗网络GAN
论文:https://arxiv.org/abs/1406.2661
参考:https://www.bilibili.com/video/BV1rb4y187vD
https://zhuanlan.zhihu.com/p/266677860
前言
GAN(Generative Adversarial Networks,生成对抗网络)是一种生成模型,更确切地说,GAN是一种框架,它为生成模型提供了一种新的全局架构。生成模型究竟在做什么?很简单:它想产生一个分布,使得这个分布尽可能接近数据的真实分布。那么真实的数据分布是什么意思?举个例子,在所有真实图像的集合中,一个物体拥有清晰可变的边缘是大概率事件,但一个物体呈现出模糊难辨的马赛克则是小概率事件,一个人拥有黄皮肤是大概率事件,而一个人拥有绿皮肤则是小概率事件,如此看来,真实世界中的图像是服从某种概率分布的,我们只需要从这个分布中采样,就能得到一张“真实”的图像,因此,生成模型的目标就是使得模型产生的图像分布尽可能接近真实图像的分布。
在开始前,我们先回顾一下最大似然估计MLE,我们的目标是在真实分布中采样若干个样本,使得这些样本在模型分布中的似然最大。也就是说,假如我们从$P_{data}(x)$中采样了m个样本${x_1, x_2, …, x_m}$,我们希望最大化这些样本在模型分布$P_{G}(x)$中的似然,即找到一个分布参数$\theta^*$,使得$\theta^* = \arg \max_{\theta} L=\arg \max_{\theta} \prod_{i=1}^m P_G(x_i;\theta)$
从$\theta^* = \arg \max_{\theta} L$出发,我们可以通过一系列计算,得到$\theta^* = \arg \max_{\theta} \int_{x} P_{data}(x) \log P_{G}(x; \theta) dx - \int_{x} P_{data}(x) \log P_{data}(x) dx$,即$\theta^*= \arg \min_{\theta} KL(P_{data}(x) || P_{G}(x; \theta))$。也就是说MLE等价于找到 $\theta$ 使得 $P_{G}(x; \theta)$ 与目标分布 $P_{data}(x)$ 的 KL 散度尽可能低,也就是使得两者的分布尽可能接近。
那么,现在的问题变为了,我该如何找到这个分布$P_{G}(x; \theta)$,使得KL散度最小,Likelihood最大呢?在GAN之前,有些模型尝试不构建先验分布$P_{G}$,而是直接通过数据来寻找真实分布$P_{data}$的类型和参数,但这类方法在高维空间中表现不佳,因为它们需要对数据分布进行显式建模,这在复杂数据(如图像、文本等)中是非常困难的。而像GAN这样的模型则不直接寻找数据的真实分布,而是先假定一个先验分布(如高斯分布),然后通过一个生成器网络将这个先验分布进行调整变形,映射到数据空间中,生成器的目标就是使得生成的数据分布尽可能接近真实数据分布。当然,我们可以直接最大化Likelihood的那个连乘,但这样计算过于复杂,没有可行性。有的模型(如VAE,DDPM)则通过数学变换(如ELBO)来简化计算,得到一个更简单的目标函数。而GAN提出了一种全新的思路:对于生成器,它不再优化某个具体的目标函数,而是接入一个判别器,通过判别器的输出来衡量生成器的好坏,生成器的目标就是让判别器无法区分生成的数据和真实的数据。这个判别器可以很强大,很灵活,由此也能训练出更好的生成器。
GAN的基本架构
GAN的基本架构由两个主要组件组成:生成器(Generator)和判别器(Discriminator)。生成器的目标是从一个简单的先验分布(如高斯分布)中采样,并通过一个神经网络将这些样本映射到数据空间中,生成看起来像真实数据的样本。判别器是一个二分类器,它的任务是区分输入的数据是真实的还是生成的,将真实图像作为正样本(输出1),将生成图像作为负样本(输出0)。在训练过程中,生成器和判别器相互竞争:生成器试图欺骗判别器,使其认为生成的图像是真实的,而判别器则试图正确区分真实和生成的图像。G和D的训练过程交替进行,这个对抗的过程使得G生成的图像越来越逼真,D“打假”的能力也越来越强。
那么,我们就可以自然得到GAN整体的目标函数:
V(G,D)简单来讲就是一个价值/评分函数,用于衡量判别器的准确度。判别器D的目标就是最大化自己的准确度,而生成器G的目标就是在判别器D的性能已经达到最优的情况下,最小化它的准确度,我们的目标就是得到使$max_D V(G,D)$最小的生成器$G^*$。V(G,D)的具体形式如下:
也可以写成
V(G,D)由两项构成:第一项衡量了从真实数据采样,判别器将其判定为真实图片的可能性,概率越大,说明判别器越能识别出真实图片;第二项衡量了从生成器采样,判别器将其判定为生成图片的可能性,概率越大,说明判别器越能识别出生成图片。
现在我们先来关注内层,即$\max_D V(G,D)$。对于固定的G:
D(x)是判别器的输出,可以将其看做一个函数。那么对于每一个x,我们都可以单独优化D(x),使得$P_{data}(x)\log D(x)+P_G(x)\log(1-D(x))$最大化。也就是$f(D)=a\log D+b\log (1-D)$,通过求导解得$D^*=\frac{a}{a+b}$,也就是$D^*(x)=\frac{P_{data}(x)}{P_{data}(x)+P_G(x)}$。
将$D^*(x)$代入$V(G,D)$中,则:
第三步在分母上除以2是为了将其转化为一个概率分布,积分值为1。

观察这个式子,我们发现:1,在最优的判别器$D^*$下,V(G,D)仍然不是其数学上的最优值(0),而是一个关于生成器G的函数,这是因为即使是最强的判别器,除非生成器G的分布与真实数据分布完全不同,否则判别器也没法做到完全准确(考虑一种极端情况,即生成器G的分布与真实数据分布完全重合,那么判别器无论如何都无法区分真假图像,输出都是0.5,此时V(G,D)的值为$-2\log2$)。2,$V(G,D^*)$是一个关于G的函数,准确来讲是生成器分布与真实数据分布的JSD(Jensen-Shannon Divergence,JS散度)的函数,这说明 $\max_{D} V(G, D)$ 确实是衡量了 $P_{data}(x)$ 和 $P_{G}(x)$ 之间的差异,因此我们需要的使得差异最小的$G^*$:
当JSD=0时,表示两个分布完全相同。此时我们可以将$V(G,D^*)$看做模型关于G的损失,通过梯度下降来实现对G的优化:
- 工程实践上的差异:值得注意的是,虽然上面的推导认为在得到了一个理论最优的判别器D之后,V(G,D)就变为了生成器G的JS散度,于是我们通过最小化这个JS散度来优化G,但实际上,我们并不会让判别器训练至理论最优,而是仅仅训练k轮判别器,然后就开始优化生成器,此时,由于D不是最优,那么V(G,D)就不完全等于JS散度了,而是它本来的样子$V(G,D) = E_{x\sim P_{data}}[\log D(x)] + E_{z\sim P_{prior}}[log(1-D(G(z)))]$,现在我们要通过优化G来使得这个V(G,D)最小化,注意,此时D已经是确定不变的了,那么V(G,D)的第一项就是一个常数,和G无关(因为D已经固定了),因此我们只需要最小化第二项$\frac{1}{m} \sum_{i=1}^{m} \log(1 - D(G(z^i)))$即可(这里用均值近似期望),而由于一些训练有效性上的考量,我们实际上会用最大化$\frac{1}{m} \sum_{i=1}^{m} \log(D(G(z^i)))$来替代最小化$\frac{1}{m} \sum_{i=1}^{m} \log(1 - D(G(z^i)))$(原因见“补充”部分)。
GAN算法实现

为什么每个iteration都要更新一次$D^*$呢?因为$D^*$是一个关于G的函数,随着G的更新,$D^*$也会发生变化,因此我们需要在每次更新G之前都重新计算$D^*$,以确保我们使用的是当前生成器G对应的最优判别器$D^*$,这很像两个人之间的博弈过程。
那么如何确定 $D^*$ 使得 $V(G, D)$ 最大,也就是:给定 $G$,如何计算 $\arg \max_{D} V(G, D)$呢?方法如下:
从 $P_{data}(x)$ 采样 ${x^1, x^2, \dots, x^m}$
从 $P_{G}(x)$ 采样 ${\tilde{x}^1, \tilde{x}^2, \dots, \tilde{x}^m}$
因此我们可以将 $\max_{D} V(G, D)$ 从期望值计算改写为对样本计算(近似估计):
这实际上是一个负的交叉熵,我们只需要通过梯度下降来最大化 $\tilde{V}$ ,就能得到D的最终参数了。也就是说,D的负交叉熵的最大值,就等于G的JSD(不考虑系数和常数项)。
那么GAN的最终算法流程就很清晰了:
初始化参数 $\theta_{D}$ (for D) 和 $\theta_{G}$ (for G)
对于训练的每一轮:
第一部分 学习优化判别器 D:
- 从 $P_{data}(x)$ 采样 ${x^1, x^2, \dots, x^m}$
- 从 $P_{prior}(z)$ 采样 ${z^1, z^2, \dots, z^m}$
- 通过生成器 $\tilde{x}^i = G(z^i)$ 获得生成样本 ${\tilde{x}^1, \tilde{x}^2, \dots, \tilde{x}^m}$
- 梯度下降更新 $\theta_{D}$ 来最大化 $\tilde{V} = \frac{1}{m} \sum_{i=1}^{m} \log D(x^i) + \frac{1}{m} \sum_{i=1}^{m} \log(1 - D(\tilde{x}^i))$:$\theta_{D} \leftarrow \theta_{D} - \eta \nabla \tilde{V}(\theta_{D})$
注:以上第一部分可以重复多次(论文中为k次,这是一个重要的超参数,下面会说);此过程本质上是在通过D不断最大化V(G,D),从而使其逼近两分布之间的 JS 散度
第二部分 学习优化生成器 G:
- 再从 $P_{prior}(z)$ 采样另一组 ${z^1, z^2, \dots, z^m}$
- 梯度下降更新 $\theta_{G}$ 来最小化 $\tilde{V} = \frac{1}{m} \sum_{i=1}^{m} \log D(x^i) + \frac{1}{m} \sum_{i=1}^{m} \log(1 - D(G(z^i)))$:$\theta_{G} \leftarrow \theta_{G} - \eta \nabla \tilde{V}(\theta_{G})$。实际上 $\tilde{V}$ 第一项与 $G$ 无关,梯度下降只需最小化 $\frac{1}{m} \sum_{i=1}^{m} \log(1 - D(G(z^i)))$ 即可。
注:以上过程仅一次

补充
- 超参数k的选择:
- k过大:判别器D的训练过于充分,导致其过于强大,能 100% 区分真假图片,生成器G很难欺骗它。此时,真实分布和生成分布在 D 看来毫无重叠,JS 散度变成了一个常数($\log 2$)。常数的导数是 0,导致梯度消失。此外k过大会导致训练时间过久,资源浪费。
- k过小:判别器D的训练不足,无法正确区分真假图片,生成器G很容易欺骗它。D 还没有学到真假数据的真正特征边界,就开始指导 G,它传给 G 的梯度将是极其嘈杂和不准确的,导致G生成毫无意义,但能骗过D的废图。
- 后来的 WGAN 通过引入 Wasserstein 距离,从根本上解决了“D 太强导致梯度消失”的问题,所以在 WGAN 中,可以放心地把 $k$ 设得很大(比如 $k=5$ 甚至更大),让 $D$ 越强越好。
- 为什么要将 $\min \log(1 - D(G(z)))$ 改为 $\max \log(D(G(z)))$?


总结
GAN的最大的创新就是在于非常精妙地引入了判别器,从样本的维度解决了衡量两个分布差异的问题。这种对抗学习的模式极具启发性与借鉴意义,同时合乎人的自然逻辑,为后续的模型提供了一种全新的范式,并被用于各种类型的任务,包括生成,修复,翻译,增强等。
再次感谢知乎文章https://zhuanlan.zhihu.com/p/266677860的作者,提供了非常清晰的讲解和数学推导,极大地帮助了我理解GAN的原理和算法实现。