21 / 28
5.1 初识生成对抗网络
在本节中我们将会介绍GAN,即生成对抗网络的基本原理,并在下一节5.2中利用这些介绍的概念进行手写数字生成的实战。
具体地,本节的内容大致分为以下几个部分:
- 什么是GAN?
- GAN的损失函数
- 训练流程
5.1.1 什么是GAN?
GAN: 是通过对抗训练的方式来使得生成网络产生的样本服从真实数据分布。而其网络的关键在于生成网络和判别网络的对抗学习。
- 判别网络 ,目标是尽量准确地判断一个样本是来自于真实数据还是由生成网络产生;
- 生成网络 ,目标是尽量生成判别网络无法区分来源的样本。
这两个目标相反的网络不断地进行交替训练。 当最后收敛时,如果判别网络再也无法判断出一个样本的来源,那么也就等价于生成网络可以生成符合真实数据分布的样本。生成对抗网络的流程图如下所示。

1. GAN的思路
如果读者没有看懂上述较为正式的说法,以下的解读将从更为直观的角度为读者展示GAN网络的训练过程。
直观的来讲可以把生成网络想象为一位莫奈风格的名画伪造者,把判别网络当作一位莫奈风格的艺术鉴定师。 整个训练的过程可以理解为伪造者和鉴定师不断学习成长的过程,主要流程如下:
- 一开始,伪造者是个刚入门的小白,网络中的参数都是随机初始化的,因此只会在画布上画出混乱的颜色;
- 之后他将自己的一些作品和莫奈风格的真品混在一起,请艺术鉴定师进行真实性评估;
- 艺术鉴定师通过真实的数据集学习,一开始很容易鉴别出了赝品,并向伪造者反馈告诉他哪些看起来像真迹、哪些看起来不想真迹。
- 伪造者根据这些反馈,改进自己的赝品。

随着时间的推移,伪造者技能越来越高,艺术商人也变得越来越擅长找出赝品。最后,他们手上就拥有了一些非常逼真的赝品。而这就是生成对抗网络核心的理念!!
如果你看懂了,那么恭喜你,你就大致了解了什么是生成对抗网络,而之后GAN网络的衍生也是基于这个理念进行拓展的。
下面我们从一个更加形象的图完整走一遍GAN网络的流程。
2. GAN网络的结构
GAN从网络的角度来看,它由两部分组成。
- 生成器网络:它一个潜在空间的随机向量作为输入,并将其解码为一张合成图像。
- 判别器网络:以一张图像(真实的或合成的均可)作为输入,并预测该图像来自训练集还是来自生成器网络。

而整个模型训练的过程就是两个网络不断交互,不断提升的过程,也是整个网络设计中最重要的一环,网络如何提升呢,损失函数又是怎么样的呢?
下一小节,我们将从数学角度详细介绍GAN网络的损失函数,如果觉得困难的同学只需要知道,生成网络优化的目标就是让生成的图片尽可能的骗过判别网络,即使得判别网络将生成的图片判别为真实的图片。而判别网络优化的目标就是类似于图像的二分类问题,在这里只有两类,真实图片or生成图片。
5.1.2 损失函数
从GAN的架构图可知,控制生成器或判别器的关键是损失函数,而如何定义损失函数就成为整个GAN的关键!!
我们的目标很明确,既要不断提升判断器辨别是非或真假的能力,又要不断提升生成器不断提升图像质量,使判别器越来越难判别。那这些目标如何用程序体现?
本小节将从生成网络和判别网络两方的损失函数进行具体的介绍,首先我们先来定义一下一些数学符号。
1. 符号定义
| 符号 | 说明 |
|---|---|
| 输入到某个网络的样本(可以理解为一张图画) | |
| 样本的标签,真实样本为1,生成样本为0 | |
| 生成网络的参数 | |
| 判别网络的参数 | |
| 低维空间 𝒵 中的一个样本(可以理解为一个低纬张量) | |
| 来自于真实分布的概率 | |
| 来自于生成模型的概率 | |
| 低维空间 𝒵 中的一个简单容易采样的分布,通常为标准多元正态分布 $\mathcal{N}(\mathbf{0}, \mathbf{1}) $ | |
| 将低纬张量 输入到参数为 的生成网络中,得到一个虚假的生成样本(可以理解为一张图画) | |
| 将样本 输入到参数为 的判别网络中,得到一个是否为真样本的概率 |
2. 判别网络的损失函数
判别网络(Discriminator Network) 的目标是区分出一个样本 是来自于真实分布 还是来自于生成模型 ,因此判别网络实际上是一个二分类的分类器。简单而言,就是图像分类的问题。

判别网络的输出为:𝒙属于真实数据分布的概率,即
则样本来自生成模型的概率为
给定一个样本,𝑦 = {1, 0}表示其来自于真实样本还是生成样本,判别网络的目标函数为最小化交叉熵,即
假设分布 𝑝(𝒙) 是由分布 和分布 等比例混合而成,即 $p(𝒙) =
\frac{1}{2}\left(p_{r}(\boldsymbol{x})+p_{\theta}(\boldsymbol{x})\right) $,则上式等价于
为了能够更加清晰的理解公式,以下为判别网络损失函数的部分代码
# D表示判别器、G为生成器、real_labels、fake_labels分别表示真图像标签、假图像标签。
# images是真图像,z是从潜在空间随机采样的向量,通过生成器得到假图像。
# 定义判断器对真图像的损失函数
outputs = D(images)
# 二分类交叉熵损失函数
d_loss_real = criterion(outputs, real_labels)
real_score = outputs
# 定义判别器对假图像(即由潜在空间点生成的图像)的损失函数
# 由随机向量通过生成器网络生成假图像
z = torch.randn(batch_size, latent_size).to(device)
fake_images = G(z)
# 定义判断器对假图像的损失函数
outputs = D(fake_images)
d_loss_fake = criterion(outputs, fake_labels)
fake_score = outputs
# 得到判别器总的损失函数
d_loss = d_loss_real + d_loss_fake
3. 生成网络的损失函数
生成网络(Generator Network)的目标刚好和判别网络相反,即让判别网络将自己生成的样本判别为真实样本。
上面的这两个目标函数的优化目标是等价的,理论上都能求出模型最优的参数 。但是在实际训练时,一般使用前者,因为其梯度性质更好。

我们知道,函数, 𝑥 ∈ (0, 1)在𝑥 接近1时的梯度要比接近0时的梯度小很多,接近“饱和”区间。 这样,当判别网络𝐷以很高的概率认为生成网络产生的样本是“假”样本,即,这时目标函数关于𝜃 的梯度反而很小,从而不利于优化。
而一开始判别器是很容易鉴别仿造数据的,因此的初始值是在靠近 0 的左端。而对于刚开始训练的模型,我们希望在初期能够快速地更新,但不幸的是,目标函数左端刚好是平缓的区域,依据梯度下降原理这会阻碍的快速更新。
生成器的损失函数如何定义,才能使其越来越向真图像靠近?以真图像为标杆或标签即可。具体代码如下:
# 定义p(Z)是一个高斯分布
z = torch.randn(batch_size, latent_size).to(device)
# 由随机向量通过生成器网络生成假图像
fake_images = G(z)
# 定义判断器对假图像的损失函数
outputs = D(fake_images)
# 注意此处和判别器不同,判别器为fake_labels,而生成器为real_labels.即其优化目标是使得生成图片能尽可能判定为真.
g_loss = criterion(outputs, real_labels)
4. 最小化最大化游戏
将判别网络和生成网络合并,整个生成对抗网络的目标函数看作是最小化最大化游戏(Minimax Game)。
但是如果判断器的能力过于好,趋近于0时,会导致max的值趋近一个常数。这时即使采取目标函数关于𝜃 的梯度变化较大的的损失函数,由于最优的判别器对所有生成的数据的输出都为0。因此生成网络的梯度消失。
5.1.3 训练流程
在本节的最后,我们来介绍下GAN网络的训练流程
和单目标的优化任务相比,生成对抗网络的两个网络的优化目标刚好相反。因此生成对抗网络的训练比较难,往往不太稳定。
一般情况下,需要平衡两个网络的能力。
对于判别网络来说,一开始的判别能力不能太强,否则难以提升生成网络的能力。但是,判别网络的判别能力也不能太弱,否则针对它训练的生成网络也不会太好。在训练时需要使用一些技巧,使得在每次迭代中,判别网络比生成网络的能力强一些,但又不能强太多。
而生成网络更新一次生成对抗网络的训练流程如下算法所示。每次迭代时,判别网络更新 𝐾 次 ,即首先要保证判别网络足够强才能开始训练生成网络。在实践中𝐾 是一个超参数,其取值一般取决于具体任务。(在下一小节手写数字生成的案例中,我们使得 )
