- Authors

- Name
- Youngju Kim
- @fjvbn20031
- 1. 论文概述与历史意义
- 2. GAN 的核心思想
- 3. 数学基础
- 4. 训练算法
- 5. GAN 的核心问题
- 6. GAN 谱系总览
- 7. 用 PyTorch 实现 GAN
- 8. GAN vs Diffusion Model 比较
- 9. GAN 的现状与未来
- 10. 结论
- 参考资料
1. 论文概述与历史意义
1.1 论文基本信息
"Generative Adversarial Nets" 是 2014 年在 NeurIPS(当时称为 NIPS)上发表的论文,由 Ian J. Goodfellow、Jean Pouget-Abadie、Mehdi Mirza、Bing Xu、David Warde-Farley、Sherjil Ozair、Aaron Courville、Yoshua Bengio 共同撰写。据传,Goodfellow 是在蒙特利尔的一家酒吧与同事讨论生成模型时想到这个点子的,当晚回家写代码,第一个原型就直接跑通了。
这篇论文的核心思路出奇地直观:假币制造者(Generator)与警察(Discriminator)相互竞争 —— 假币制造者不断做出更精巧的假币,警察则不断提升鉴别能力。这场对抗过程一旦收敛,假币制造者做出的钞票就会变得与真钞无法区分。
1.2 历史背景:2014 年的生成模型格局
GAN 出现之前,生成模型的主流方法如下。
变分自编码器(VAE,2013):由 Kingma 与 Welling 提出的 VAE,在 Encoder-Decoder 结构中引入概率潜变量来学习数据分布。但在优化 ELBO(Evidence Lower Bound,证据下界)的过程中,生成的图像往往会变得模糊。
玻尔兹曼机(Boltzmann Machine)系列:Deep Boltzmann Machine、Restricted Boltzmann Machine 等基于能量的模型,理论上很优雅,但依赖 MCMC(Markov Chain Monte Carlo,马尔可夫链蒙特卡洛)采样,训练缓慢,扩展性也受限。
自回归(Autoregressive)模型:PixelRNN(2016)等模型逐像素地顺序生成,能产出高质量样本,但生成速度极慢。
GAN 一举突破了这些局限。它不需要定义显式的概率分布就能生成高质量样本,也不依赖 Markov chain 或顺序生成过程,只需一次前向传播(Forward pass)就能即时生成样本。这在生成模型领域是一次范式转变。
1.3 影响力
截至 2024 年,GAN 论文的被引用次数已超过约 65,000 次,此后十年间涌现出数百种 GAN 变体。Yann LeCun 曾盛赞 GAN 是"过去 20 年机器学习领域中最有趣的想法"。GAN 被应用于图像生成、超分辨率、风格迁移、数据增强、药物发现等无数领域,在 Diffusion Model 出现之前,一直是生成模型领域绝对的主流。
2. GAN 的核心思想
2.1 双人博弈:Generator vs Discriminator
GAN 的框架由两个相互竞争的神经网络构成。
生成器(Generator,G):接收随机噪声向量 作为输入,生成伪造数据 。生成器的目标是产出足以骗过判别器的、与真实数据足够相似的样本。
判别器(Discriminator,D):判断输入数据是来自真实数据分布(),还是生成器制造的假数据()。输出是一个 0 到 1 之间的概率值,越接近 1 表示越倾向于判定为真。
这两个网络的目标彼此相反:
- 生成器:试图最大化 (让判别器把假的判断成真的)
- 判别器:试图给真实数据分配高概率,给假数据分配低概率
2.2 直观类比
把 GAN 的训练过程类比成艺术品市场,会更容易理解。
| 构成要素 | 类比 | 角色 |
|---|---|---|
| Generator | 造假画家 | 目标是制作出与真品无法区分的赝品 |
| Discriminator | 美术鉴定师 | 目标是区分真品与赝品 |
| Training Data | 真品美术作品 | 来自真实数据分布的样本 |
| Noise Vector | 画家的灵感/素材 | 潜在空间中的一个随机点 |
一开始,造假画家的功力很差,鉴定师很容易识破赝品。但造假画家通过鉴定师的反馈(gradient)不断改进技艺,鉴定师也为了应对越来越精巧的赝品而不断提升鉴别能力。这场竞争如果充分进行下去,造假画家最终会做出与真品无法区分的作品。
2.3 Minimax 博弈的公式化
GAN 的训练目标被形式化为如下的 minimax 博弈:
让我们逐项分析这个价值函数 。
第一项:
这是判别器对真实数据 的判断。判别器试图最大化这个值,因此以 (把真的判断成真的)为目标。生成器对这一项没有影响。
第二项:
这是判别器对生成器制造的假数据的判断。
- 判别器试图最大化这个值:当 (把假的判断成假的)时,,达到最大
- 生成器试图最小化这个值:当 (把假的判断成真的)时,,达到最小
这正是"对抗(Adversarial)"这个名字的由来。两个玩家围绕同一个价值函数,朝相反的方向优化。
3. 数学基础
3.1 最优判别器(Optimal Discriminator)
针对固定的生成器 ,来推导最优判别器 。根据期望的定义,把价值函数转换为积分形式:
其中 是生成器所生成数据的分布。把它们合并为一个积分:
对被积函数关于 求导并令其为 0:
解出 ,最优判别器为:
这个结果直观上也是合理的。如果某个数据点 为真实数据的概率是 ,为假数据的概率是 ,那么最优判别恰好等于 Bayes 法则给出的后验概率。
关键观察:当 ,也就是生成器完美学到了真实数据分布时,对所有 都有 。判别器彻底无法区分真假。
3.2 与 Jensen-Shannon 散度的关系
把最优判别器 代入价值函数:
整理后得到:
其中 是 Jensen-Shannon 散度,定义为:
JSD 是 KL 散度的对称化版本,且总是落在 的范围内。 当且仅当 ,也就是两个分布完全相同时。
3.3 全局最优性的证明
定理(Goodfellow et al., 2014): 的全局最小值当且仅当 时取得,此时 。
证明:
(1)
(2) (JSD 的非负性)
(3)
(4) 因此 ,等号成立的条件是
这为 GAN 的训练提供了理论保证:只要生成器与判别器拥有足够的容量,在 minimax 博弈的 Nash 均衡点上,生成器就能完美还原真实数据分布。
3.4 Nash 均衡
从博弈论的视角看,GAN 的训练是在两个玩家之间寻找 Nash 均衡 的问题。Nash 均衡指的是,在对方策略固定的前提下,任何一方单独改变自己的策略都不再能获得更多收益的状态。
GAN 中的 Nash 均衡是:
- :达成 的生成器
- :对所有 都输出 的判别器
理论上这个均衡点存在且唯一,但在实际训练中找到它却非常困难,因为这是一个必须同时优化两个网络的非凸博弈(non-convex game)。这是 GAN 训练的核心难点,也成了此后大量后续研究的出发点。
3.5 KL 散度 vs JS 散度
为什么偏偏是 JSD?让我们和 KL 散度做个比较。
KL 散度的问题:
KL 散度是非对称的,且在 而 的区域会发散到无穷大。这在训练初期、生成器分布尚未充分覆盖真实分布时会成为问题。
JS 散度的优点:
- 对称:
- 恒有限:
- 以两个分布的混合分布 为基准计算 KL,因此即便某一侧分布为 0 也不会发散
但 JSD 也并非完美。当两个分布的 support 不重叠时,JSD 会变成常数 ,导致 gradient 为 0。这正是 GAN 训练中梯度消失(vanishing gradient)问题的根本原因,也是此后 WGAN 引入 Wasserstein distance 的核心动机。
4. 训练算法
4.1 训练流程
原论文提出的训练算法如下:
Algorithm 1: GAN Training (Goodfellow et al., 2014)
for number of training iterations do
# --- 第一步:更新判别器(k 步)---
for k steps do
- 从噪声先验 p_z(z) 中抽取 m 个噪声样本 {z^(1), ..., z^(m)}
- 从数据分布 p_data(x) 中抽取 m 个真实样本 {x^(1), ..., x^(m)}
- 用随机梯度上升(stochastic gradient ascending)更新判别器参数:
nabla_{theta_d} (1/m) sum_{i=1}^{m} [log D(x^(i)) + log(1 - D(G(z^(i))))]
end for
# --- 第二步:更新生成器(1 步)---
- 从噪声先验 p_z(z) 中抽取 m 个噪声样本 {z^(1), ..., z^(m)}
- 用随机梯度下降(stochastic gradient descending)更新生成器参数:
nabla_{theta_g} (1/m) sum_{i=1}^{m} log(1 - D(G(z^(i))))
end for
4.2 交替优化(Alternating Optimization)
核心在于交替优化:判别器与生成器轮流更新。
为什么要先更新判别器 k 次,再更新生成器 1 次:
理论上,只有先求出最优判别器 ,再更新生成器,才能得到正确的梯度方向。但实际上完全优化 是不可能的,因此用 步 gradient step 来近似。原论文默认使用 。
保持平衡的重要性:
- 判别器过强时:生成器的梯度会消失,训练停滞
- 判别器过弱时:无法为生成器提供有用的学习信号
- 理想情况下,判别器与生成器应当以相近的水平共同进步
4.3 Non-Saturating Loss(实战修正)
在理论上的 minimax 目标函数中,生成器的目标是最小化 。但训练初期生成器很弱时,,于是 ,梯度几乎为 0。
Goodfellow 为了解决这个问题,把生成器的目标函数修改如下:
原始(Minimax):
修正后(Non-Saturating):
两个目标函数拥有相同的不动点(Nash 均衡),但训练初期的梯度大小差异很大。Non-saturating loss 即使在 很小时也能提供较强的梯度,让生成器能够更快学习。
4.4 原论文的实验结果
原论文在 MNIST、Toronto Face Database(TFD)、CIFAR-10 数据集上进行了实验,使用基于 Parzen window 的 log-likelihood 估计来评估,结果显示 GAN 相较于已有的 Deep Boltzmann Machine 或 Stacked Denoising Autoencoder 具有竞争力。
但以今天的标准来看,原论文的结果相当朴素。生成器与判别器都只使用了简单的 MLP(Multi-Layer Perceptron,多层感知机),生成图像的分辨率与质量都很有限。真正的突破是此后通过架构改进与训练技巧的发展才实现的。
5. GAN 的核心问题
5.1 模式崩溃(Mode Collapse)
GAN 最臭名昭著的问题是模式崩溃(Mode Collapse)。这是指生成器未能学到数据分布的全部模式(多样的模式),只专注于极少数模式,反复生成相似输出的现象。
发生机制:
当生成器发现少数几种特别擅长骗过判别器的模式后,就不再去探索其他多样的模式,而是反复生成那几种模式。举例来说,在 MNIST 上训练时,生成器可能只能完美生成数字"1",而完全无法生成其他数字。
数学解读:
模式崩溃与从 minimax 转变为 maximin 博弈有关:
在理论上的 minimax 中,生成器必须应对所有可能的判别器,因此必须覆盖整个分布。但在实际训练中,生成器只需要骗过当前这一个判别器即可,因此专注于特定模式反而可能成为一种"合理"的策略。
5.2 训练不稳定性
GAN 的训练本质上是在寻找非协作博弈(non-cooperative game)的 Nash 均衡,这远比单纯的优化问题困难。
震荡(Oscillation)问题:生成器与判别器经常不收敛,而是围绕彼此震荡(oscillate)。在一般的 loss landscape 中,gradient descent 会走向 local minimum,但在 minimax 博弈中,gradient descent 可能在鞍点(saddle point)附近打转。
训练平衡的困难:判别器收敛得太快,生成器就学不动;反之判别器太弱,又无法向生成器传达有意义的学习信号。维持这种微妙的平衡,是实务中 GAN 训练最大的挑战。
5.3 梯度消失(Vanishing Gradients)
正如前文 3.5 节所述,当两个分布的 support 不重叠时,JS 散度会变成常数 ,梯度为 0。
在高维数据(例如图像)中,真实数据分布与生成器分布都存在于高维空间中的低维流形(manifold)上。这两个流形重叠的概率非常低,因此训练初期两个分布的 support 几乎不重叠是常态。在这种情况下,基于 JSD 的 GAN 完全无法提供有用的梯度。
5.4 评估的困难
客观评估 GAN 的性能本身也是一个非常困难的问题。主要的评估指标如下:
Inception Score(IS):衡量生成图像的质量(sharpness,清晰度)与多样性。使用预训练的 Inception 网络,若单张图像的类别预测足够确定(质量),同时整体又分布在多样的类别上(多样性),则得分较高。
Frechet Inception Distance(FID):衡量真实数据与生成数据在 Inception 特征分布之间的 Frechet distance,数值越低越好,是比 IS 更受信赖、也更常用的指标。
其中 与 分别是真实图像与生成图像在 Inception feature 上的均值和协方差。
6. GAN 谱系总览
6.1 DCGAN(2015):CNN 驱动的稳定训练之始
Radford, Metz, Chintala. "Unsupervised Representation Learning with Deep Convolutional Generative Adversarial Networks" (2015)
原始 GAN 只由 MLP(全连接层)构成,未能利用 CNN 强大的空间特征提取能力来做图像生成。DCGAN(Deep Convolutional GAN) 是第一个成功把 CNN 融入 GAN 的架构,提出了多条实现稳定训练的架构准则。
DCGAN 的核心架构规则:
- 去掉 Pooling 层:用 strided convolution(判别器)与 fractional-strided convolution / transposed convolution(生成器)取代 max pooling
- 应用 Batch Normalization:生成器与判别器都使用 Batch Normalization,但生成器的输出层与判别器的输入层除外
- 去掉全连接层:使用 global average pooling 或直接的卷积连接
- 激活函数:生成器在输出层用 Tanh,其余层用 ReLU;判别器所有层都用 LeakyReLU
DCGAN 生成器结构(概念示意):
z (100-dim) -> FC -> Reshape (4x4x1024) -> ConvT -> BN -> ReLU (8x8x512)
-> ConvT -> BN -> ReLU (16x16x256) -> ConvT -> BN -> ReLU (32x32x128)
-> ConvT -> Tanh (64x64x3)
DCGAN 不仅生成了不错的图像,更展示了学到的潜在空间(latent space)具有有意义的结构。一个著名的例子是,潜在空间中的向量运算对应着语义层面的变换:
6.2 WGAN(2017):引入 Wasserstein 距离
Arjovsky, Chintala, Bottou. "Wasserstein GAN" (2017)
WGAN 是 GAN 理论最重要的进展之一,它引入 Wasserstein distance(Earth Mover's distance,推土机距离) 来解决 JS 散度的根本局限。
Wasserstein 距离(EM Distance):
其中 是以 和 为边缘分布(marginal)的所有联合分布的集合。直观地说,它就是把一个分布转换成另一个分布时"搬运土堆"所需的最小成本。
Wasserstein 距离的核心优点:
与 JSD 不同,即便两个分布的 support 不重叠,它也能提供连续且可微的距离。举例来说,考虑两个点分布 和 ():
Kantorovich-Rubinstein 对偶性:
直接计算 Wasserstein 距离是不可行的(intractable),因此借助 Kantorovich-Rubinstein 对偶性:
其中 supremum 取遍所有 1-Lipschitz 函数。WGAN 训练判别器(这里改称为 Critic)去逼近这个 1-Lipschitz 函数。
权重裁剪(Weight Clipping):最初的 WGAN 为了强制满足 Lipschitz 约束,把 critic 的权重裁剪到 范围内。但这严重限制了 critic 的表达能力,也可能引发训练不稳定。
6.3 WGAN-GP(2017):梯度惩罚(Gradient Penalty)
Gulrajani, Ahmed, Arjovsky, Dumoulin, Courville. "Improved Training of Wasserstein GANs" (2017)
为解决 weight clipping 的问题,有人提出了 梯度惩罚(Gradient Penalty,GP) 方法。它不直接强制 Lipschitz 约束,而是让 critic 的 gradient norm 正则化到接近 1。
其中 是真实数据与生成数据之间的随机插值(interpolation):
WGAN-GP 默认使用 、critic 更新次数 ,几乎不需要调参,就能在各种架构上稳定训练。
6.4 Progressive GAN(2017):分辨率的渐进式提升
Karras, Aila, Laine, Lehtinen. "Progressive Growing of GANs for Improved Quality, Stability, and Variation" (2017)
Progressive GAN(ProGAN) 是 NVIDIA 研究团队提出的架构,为高分辨率图像生成开辟了新天地。核心思路是让生成器与判别器从低分辨率开始训练,再逐步添加层来提升分辨率。
训练过程:
Phase 1: 在 4x4 分辨率下训练 G 与 D
Phase 2: 添加 8x8 层,通过 fade-in 渐进过渡
Phase 3: 添加 16x16 层
...
Phase N: 达到 1024x1024 的最终分辨率
Fade-in 机制:添加新层时,把已有层的输出与新层的输出按加权平均结合。权重 从 0 缓慢增加到 1,新层随之逐步被激活。
核心贡献:
- 训练稳定性大幅提升:先在低分辨率下学到大致结构,再逐渐加入精细细节,训练过程稳定得多
- 达成 1024x1024 分辨率:在 CelebA-HQ 数据集上首次成功生成 1024x1024 分辨率的逼真人脸图像
- Minibatch standard deviation:引入利用 minibatch 内统计量来提升多样性的技巧
6.5 StyleGAN 系列(2019-2021):风格化生成的巅峰
StyleGAN(2019)
Karras, Laine, Aila. "A Style-Based Generator Architecture for Generative Adversarial Networks" (2019)
StyleGAN 是把 Progressive GAN 的渐进式训练与 Neural Style Transfer 的风格分离概念结合在一起的革命性架构。
核心结构变化:
-
Mapping Network:把输入潜在向量 经由非线性映射网络 转换到中间潜在空间(intermediate latent space)。由 8 层 FC 构成。
-
自适应实例归一化(Adaptive Instance Normalization,AdaIN):把 空间中的风格向量 注入到每一个卷积层。
其中 与 是由风格向量 经过学习到的仿射变换(affine transformation)得到的 scale 和 bias。
-
Constant Input:生成器的输入使用一个可学习的常数张量(4x4x512)。风格只通过 AdaIN 注入。
-
Noise Injection:在每个卷积层之后加入逐像素(per-pixel)噪声,用来控制随机性变化(stochastic variation,例如头发位置、毛孔等)。
风格层级结构:
| 分辨率层 | 控制的特征 |
|---|---|
| (粗粒度) | 姿态、脸型、是否戴眼镜 |
| (中等) | 面部特征、发型、眼睛开合 |
| (精细) | 色彩、精细结构、背景细节 |
StyleGAN2(2020)
Karras, Laine, Aittala, Hellsten, Lehtinen, Aila. "Analyzing and Improving the Image Quality of StyleGAN" (2020)
StyleGAN2 解决了 StyleGAN 的多种伪影问题,大幅提升了图像质量。
主要改进:
- Weight Demodulation:取代 AdaIN,消除水滴状的伪影(blob artifact),解决了 AdaIN 的 instance normalization 会破坏 feature map 内相对量级信息的问题
- 去掉 Progressive Growing:借助 skip connection 与 residual connection,即使不做 progressive growing 也能实现稳定的高分辨率训练
- Path Length Regularization:改善潜在空间的平滑度(smoothness),让潜在向量的微小变化在图像上产生成比例的变化
- Lazy Regularization:每 16 步才做一次正则化,而不是每步都做,以提升效率
StyleGAN2-ADA:引入了自适应判别器增强(Adaptive Discriminator Augmentation),即使数据有限也能在不过拟合的情况下训练,在只有数千张图像规模的小数据集上也能实现高质量生成。
StyleGAN3(2021)
Karras, Aittala, Laine, et al. "Alias-Free Generative Adversarial Networks" (2021)
StyleGAN3 解决了一个更根本的信号处理问题。
问题:在 StyleGAN2 中,生成图像的细微细节看起来像是"粘"在图像坐标上。当画面本该移动时,纹理却没有跟随物体一起移动,而是停留在原地,这是一种 aliasing(混叠)问题。
解决方案:把网络中所有信号都重新设计为在连续域中处理,从根源上阻断因离散采样而产生的混叠。
核心变化:
- 用基于 Fourier feature 的输入替代原有方式
- 保证连续的等变(equivariant)运算
- 实现了对平移(translation)和旋转(rotation)的完全等变性
- FID 与 StyleGAN2 相当,但内部表示从根本上不同
StyleGAN3 为视频生成和动画打下了更合适的基础。
6.6 Conditional GAN、Pix2Pix、CycleGAN
Conditional GAN(cGAN,2014)
Mirza, Osindero. "Conditional Generative Adversarial Nets" (2014)
原始 GAN 无法控制所生成的数据。Conditional GAN 给生成器和判别器都额外提供条件信息 (例如类别标签)作为输入,从而能够有条件地生成具有指定属性的数据。
Pix2Pix(2017)
Isola, Zhu, Zhou, Efros. "Image-to-Image Translation with Conditional Adversarial Networks" (2017)
Pix2Pix 是使用成对(paired)图像数据的 Image-to-Image Translation 框架。它用统一的框架解决了把黑白照片转成彩色、把卫星图像转成地图、把素描转成照片等多种任务。
核心组成:
- U-Net Generator:在 Encoder-Decoder 结构上加入 skip connection
- PatchGAN Discriminator:不对整张图像判真伪,而是以 的 patch 为单位判断
- L1 重建损失 + 对抗损失:同时追求结构相似性与真实感
CycleGAN(2017)
Zhu, Park, Isola, Efros. "Unpaired Image-to-Image Translation using Cycle-Consistent Adversarial Networks" (2017)
Pix2Pix 有一个很大的限制,就是需要成对(paired)数据。CycleGAN 只用非成对(unpaired)数据,就能学到两个域之间的转换。
核心思路:循环一致性损失(Cycle Consistency Loss)
训练两个生成器 和 ,以及两个判别器 、。
即,把域 的图像转到 之后再转回 ,应当能还原出原始图像。这个约束使得即便没有成对数据,也能学到有意义的映射。
应用领域:把马变成斑马、把夏日风景变成冬日风景、把照片转成莫奈风格的画作等。
6.7 BigGAN(2018):规模的力量
Brock, Donahue, Simonyan. "Large Scale GAN Training for High Fidelity Natural Image Synthesis" (2018)
BigGAN 用戏剧性的方式证明了"GAN 训练中规模至关重要"这件事。它使用了比以往多 2~4 倍的参数量和 8 倍的 batch size 来训练。
核心技巧:
- Class-Conditional Batch Normalization:共享类别嵌入(class embedding),来调节每个 Batch Normalization 层的 scale 和 bias
- Truncation Trick:在推理阶段对潜在向量 的分布做截断(truncation),以控制质量与多样性之间的权衡
- Orthogonal Regularization:对生成器的权重施加正交正则化,以确保训练稳定性
成果:在 ImageNet 128x128 上达到了 IS 166.5、FID 7.4,大幅超越了此前的最佳纪录(IS 52.52、FID 18.6)。
6.8 GigaGAN(2023):GAN 的复兴?
Kang, Zhu, et al. "Scaling up GANs for Text-to-Image Synthesis" (2023)
在 Diffusion Model 主导图像生成的时期,GigaGAN 以一个十亿(1B)参数规模的 Text-to-Image GAN 再次证明了 GAN 的潜力。
核心创新:
- Adaptive Kernel Selection:为每张图像生成不同的卷积滤波器,由风格向量对滤波器库(filter bank)做凸组合(convex combination)来决定
- Stable Attention:基于 L2 distance 计算 attention score 来保证 Lipschitz 连续性,并把 attention weight matrix 正则化为单位方差(unit variance)
- Query-Key Tying:共享 Query 与 Key 矩阵以确保稳定性
- CLIP Text Encoder:用预训练的 CLIP 模型提取文本嵌入
成果与意义:
- 在 FID 上超越了 Stable Diffusion v1.5、DALL-E 2、Parti-750M
- 生成 512px 图像仅需 0.13 秒:推理速度比 Diffusion model 快几十到几百倍
- 证明了 GAN 在大规模 text-to-image 合成中依然具备竞争力
7. 用 PyTorch 实现 GAN
7.1 基础 GAN 实现(MNIST)
下面是用 PyTorch 在 MNIST 数据集上实现的最基础的 GAN 代码。
import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, transforms
from torch.utils.data import DataLoader
# ============================================================
# 超参数设置
# ============================================================
LATENT_DIM = 100 # 潜在向量维度(z 的维度)
IMG_DIM = 28 * 28 # 展平后的 MNIST 图像维度
HIDDEN_DIM = 256 # 隐藏层维度
BATCH_SIZE = 64
EPOCHS = 200
LR = 0.0002
BETAS = (0.5, 0.999) # Adam optimizer 的 beta 参数
DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")
# ============================================================
# Generator 定义
# ============================================================
class Generator(nn.Module):
"""
接收潜在向量 z 作为输入,生成假图像。
结构:z(100) -> 256 -> 512 -> 1024 -> 784(28x28)
"""
def __init__(self, latent_dim: int, img_dim: int, hidden_dim: int):
super().__init__()
self.net = nn.Sequential(
nn.Linear(latent_dim, hidden_dim),
nn.LeakyReLU(0.2),
nn.Linear(hidden_dim, hidden_dim * 2),
nn.LeakyReLU(0.2),
nn.Linear(hidden_dim * 2, hidden_dim * 4),
nn.LeakyReLU(0.2),
nn.Linear(hidden_dim * 4, img_dim),
nn.Tanh(), # 把输出归一化到 [-1, 1] 范围
)
def forward(self, z: torch.Tensor) -> torch.Tensor:
return self.net(z)
# ============================================================
# Discriminator 定义
# ============================================================
class Discriminator(nn.Module):
"""
接收图像作为输入,输出真/假的概率。
结构:784(28x28) -> 1024 -> 512 -> 256 -> 1
"""
def __init__(self, img_dim: int, hidden_dim: int):
super().__init__()
self.net = nn.Sequential(
nn.Linear(img_dim, hidden_dim * 4),
nn.LeakyReLU(0.2),
nn.Dropout(0.3),
nn.Linear(hidden_dim * 4, hidden_dim * 2),
nn.LeakyReLU(0.2),
nn.Dropout(0.3),
nn.Linear(hidden_dim * 2, hidden_dim),
nn.LeakyReLU(0.2),
nn.Dropout(0.3),
nn.Linear(hidden_dim, 1),
nn.Sigmoid(), # 把输出转换为 [0, 1] 的概率
)
def forward(self, x: torch.Tensor) -> torch.Tensor:
return self.net(x)
# ============================================================
# 数据加载器设置
# ============================================================
transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.5,), (0.5,)), # [0,1] -> [-1,1]
])
dataset = datasets.MNIST(root="./data", train=True, transform=transform, download=True)
dataloader = DataLoader(dataset, batch_size=BATCH_SIZE, shuffle=True, drop_last=True)
# ============================================================
# 模型、优化器、损失函数初始化
# ============================================================
G = Generator(LATENT_DIM, IMG_DIM, HIDDEN_DIM).to(DEVICE)
D = Discriminator(IMG_DIM, HIDDEN_DIM).to(DEVICE)
opt_G = optim.Adam(G.parameters(), lr=LR, betas=BETAS)
opt_D = optim.Adam(D.parameters(), lr=LR, betas=BETAS)
criterion = nn.BCELoss() # 二元交叉熵(Binary Cross Entropy)
# ============================================================
# 训练循环
# ============================================================
for epoch in range(EPOCHS):
d_loss_total, g_loss_total = 0.0, 0.0
for batch_idx, (real_imgs, _) in enumerate(dataloader):
real_imgs = real_imgs.view(-1, IMG_DIM).to(DEVICE)
batch_size = real_imgs.size(0)
# 真/假标签
real_labels = torch.ones(batch_size, 1, device=DEVICE)
fake_labels = torch.zeros(batch_size, 1, device=DEVICE)
# -----------------------------------------
# Step 1: 训练 Discriminator
# -----------------------------------------
# 对真实图像判别
d_real = D(real_imgs)
d_loss_real = criterion(d_real, real_labels)
# 生成假图像并判别
z = torch.randn(batch_size, LATENT_DIM, device=DEVICE)
fake_imgs = G(z).detach() # 阻断 Generator 的梯度
d_fake = D(fake_imgs)
d_loss_fake = criterion(d_fake, fake_labels)
# Discriminator 总损失并更新
d_loss = d_loss_real + d_loss_fake
opt_D.zero_grad()
d_loss.backward()
opt_D.step()
# -----------------------------------------
# Step 2: 训练 Generator
# -----------------------------------------
z = torch.randn(batch_size, LATENT_DIM, device=DEVICE)
fake_imgs = G(z)
d_fake = D(fake_imgs)
# Non-saturating loss:Generator 试图提高 D(G(z))
g_loss = criterion(d_fake, real_labels)
opt_G.zero_grad()
g_loss.backward()
opt_G.step()
d_loss_total += d_loss.item()
g_loss_total += g_loss.item()
# 每个 epoch 输出一次日志
num_batches = len(dataloader)
print(
f"Epoch [{epoch+1}/{EPOCHS}] "
f"D Loss: {d_loss_total/num_batches:.4f} | "
f"G Loss: {g_loss_total/num_batches:.4f}"
)
7.2 DCGAN 实现(核心部分)
把 DCGAN 的生成器和判别器改为卷积结构后的版本。
class DCGANGenerator(nn.Module):
"""
DCGAN Generator:用 Transposed Convolution 生成图像。
z(100) -> 4x4x512 -> 8x8x256 -> 16x16x128 -> 32x32x64 -> 64x64x3
"""
def __init__(self, latent_dim: int = 100, feature_map_size: int = 64, channels: int = 3):
super().__init__()
self.net = nn.Sequential(
# 输入:z (latent_dim x 1 x 1) -> (feature_map_size*8 x 4 x 4)
nn.ConvTranspose2d(latent_dim, feature_map_size * 8, 4, 1, 0, bias=False),
nn.BatchNorm2d(feature_map_size * 8),
nn.ReLU(inplace=True),
# (feature_map_size*8 x 4 x 4) -> (feature_map_size*4 x 8 x 8)
nn.ConvTranspose2d(feature_map_size * 8, feature_map_size * 4, 4, 2, 1, bias=False),
nn.BatchNorm2d(feature_map_size * 4),
nn.ReLU(inplace=True),
# (feature_map_size*4 x 8 x 8) -> (feature_map_size*2 x 16 x 16)
nn.ConvTranspose2d(feature_map_size * 4, feature_map_size * 2, 4, 2, 1, bias=False),
nn.BatchNorm2d(feature_map_size * 2),
nn.ReLU(inplace=True),
# (feature_map_size*2 x 16 x 16) -> (feature_map_size x 32 x 32)
nn.ConvTranspose2d(feature_map_size * 2, feature_map_size, 4, 2, 1, bias=False),
nn.BatchNorm2d(feature_map_size),
nn.ReLU(inplace=True),
# (feature_map_size x 32 x 32) -> (channels x 64 x 64)
nn.ConvTranspose2d(feature_map_size, channels, 4, 2, 1, bias=False),
nn.Tanh(),
)
def forward(self, z: torch.Tensor) -> torch.Tensor:
return self.net(z)
class DCGANDiscriminator(nn.Module):
"""
DCGAN Discriminator:用 Strided Convolution 判别真伪。
(3 x 64 x 64) -> (64 x 32 x 32) -> (128 x 16 x 16) ->
(256 x 8 x 8) -> (512 x 4 x 4) -> 1
"""
def __init__(self, feature_map_size: int = 64, channels: int = 3):
super().__init__()
self.net = nn.Sequential(
# (channels x 64 x 64) -> (feature_map_size x 32 x 32)
nn.Conv2d(channels, feature_map_size, 4, 2, 1, bias=False),
nn.LeakyReLU(0.2, inplace=True),
# (feature_map_size x 32 x 32) -> (feature_map_size*2 x 16 x 16)
nn.Conv2d(feature_map_size, feature_map_size * 2, 4, 2, 1, bias=False),
nn.BatchNorm2d(feature_map_size * 2),
nn.LeakyReLU(0.2, inplace=True),
# (feature_map_size*2 x 16 x 16) -> (feature_map_size*4 x 8 x 8)
nn.Conv2d(feature_map_size * 2, feature_map_size * 4, 4, 2, 1, bias=False),
nn.BatchNorm2d(feature_map_size * 4),
nn.LeakyReLU(0.2, inplace=True),
# (feature_map_size*4 x 8 x 8) -> (feature_map_size*8 x 4 x 4)
nn.Conv2d(feature_map_size * 4, feature_map_size * 8, 4, 2, 1, bias=False),
nn.BatchNorm2d(feature_map_size * 8),
nn.LeakyReLU(0.2, inplace=True),
# (feature_map_size*8 x 4 x 4) -> (1 x 1 x 1)
nn.Conv2d(feature_map_size * 8, 1, 4, 1, 0, bias=False),
nn.Sigmoid(),
)
def forward(self, x: torch.Tensor) -> torch.Tensor:
return self.net(x).view(-1, 1)
7.3 WGAN-GP 核心 Loss 实现
def compute_gradient_penalty(
discriminator: nn.Module,
real_samples: torch.Tensor,
fake_samples: torch.Tensor,
device: torch.device,
lambda_gp: float = 10.0,
) -> torch.Tensor:
"""
计算 WGAN-GP 的 Gradient Penalty。
在真实数据与生成数据之间的随机插值点上,
对 Discriminator(Critic)梯度的 L2 norm 施加接近 1 的惩罚。
"""
batch_size = real_samples.size(0)
# 随机插值系数
epsilon = torch.rand(batch_size, 1, 1, 1, device=device)
# 真实与假数据之间的插值点
interpolated = (epsilon * real_samples + (1 - epsilon) * fake_samples).requires_grad_(True)
# Critic 的输出
d_interpolated = discriminator(interpolated)
# 计算梯度
gradients = torch.autograd.grad(
outputs=d_interpolated,
inputs=interpolated,
grad_outputs=torch.ones_like(d_interpolated),
create_graph=True,
retain_graph=True,
)[0]
# 梯度的 L2 norm
gradients = gradients.view(batch_size, -1)
gradient_norm = gradients.norm(2, dim=1)
# Gradient Penalty:(||grad|| - 1)^2 的期望
gradient_penalty = lambda_gp * ((gradient_norm - 1) ** 2).mean()
return gradient_penalty
# WGAN-GP 训练循环(核心部分)
def train_wgan_gp_step(
G: nn.Module,
D: nn.Module,
opt_G: optim.Optimizer,
opt_D: optim.Optimizer,
real_imgs: torch.Tensor,
latent_dim: int,
device: torch.device,
n_critic: int = 5,
):
"""WGAN-GP 的一次 iteration 训练。"""
batch_size = real_imgs.size(0)
# --- Critic(Discriminator)训练:n_critic 次 ---
for _ in range(n_critic):
z = torch.randn(batch_size, latent_dim, 1, 1, device=device)
fake_imgs = G(z).detach()
# Wasserstein Loss:最大化 E[D(real)] - E[D(fake)]
d_real = D(real_imgs).mean()
d_fake = D(fake_imgs).mean()
gp = compute_gradient_penalty(D, real_imgs, fake_imgs, device)
d_loss = d_fake - d_real + gp # Critic 要最小化这个值
opt_D.zero_grad()
d_loss.backward()
opt_D.step()
# --- Generator 训练:1 次 ---
z = torch.randn(batch_size, latent_dim, 1, 1, device=device)
fake_imgs = G(z)
g_loss = -D(fake_imgs).mean() # Generator 要最大化 D(G(z))
opt_G.zero_grad()
g_loss.backward()
opt_G.step()
return d_loss.item(), g_loss.item()
8. GAN vs Diffusion Model 比较
进入 2020 年代后,Diffusion Model(DDPM、Score-based model)作为图像生成的新范式崛起。2021 年 Dhariwal 与 Nichol 发表论文《Diffusion Models Beat GANs on Image Synthesis》之后,Diffusion Model 通过 DALL-E 2、Stable Diffusion、Midjourney 等产品,确立了生成模型主流地位。下面系统比较一下 GAN 与 Diffusion Model。
8.1 基本原理比较
| 方面 | GAN | Diffusion Model |
|---|---|---|
| 训练方式 | 对抗训练(Adversarial Training,minimax 博弈) | 去噪分数匹配(Denoising Score Matching) |
| 生成过程 | 单次前向传播 | 迭代去噪(数十到数百步) |
| 概率模型 | 隐式(implicit) | 显式(explicit) |
| 损失函数 | 对抗损失(+ 辅助 loss) | 简单的 MSE/L1(噪声预测) |
| 理论分布 | via JSD/Wasserstein | via ELBO |
8.2 优缺点比较
GAN 的优点:
- 推理速度:只需一次前向传播即可生成图像,适合实时应用
- 样本清晰度:通过对抗训练,倾向于生成锐利、逼真的图像
- 潜在空间控制:可以通过结构良好的潜在空间做语义层面的操控
- 轻量:即便参数相对较少,也能实现高质量生成
GAN 的缺点:
- 训练不稳定:模式崩溃、训练震荡等
- 多样性不足:模式崩溃可能限制生成的多样性
- 扩展性有限:在文本条件生成等方面,不如 Diffusion model 扩展得自然
- 评估困难:难以用可靠的指标来监控训练进展
Diffusion Model 的优点:
- 训练稳定:用简单的 MSE loss 就能稳定训练
- 样本多样性:几乎不存在模式崩溃问题
- 文本条件生成:通过 classifier-free guidance 等手段实现自然的条件生成
- 理论严谨性:作为显式概率模型,可以计算 likelihood
Diffusion Model 的缺点:
- 推理速度:需要数十到数百次迭代去噪,速度较慢(近来通过 distillation 等方法在改善)
- 计算成本:训练和推理都需要较高的计算资源
- 内存占用:高分辨率生成时,U-Net 需要大规模参数
8.3 收敛特性比较
| 特性 | GAN | Diffusion Model |
|---|---|---|
| 收敛保证 | 仅在理论上保证 Nash 均衡 | 通过 ELBO 优化实现稳定收敛 |
| Mode Coverage | 存在模式崩溃风险 | 出色的模式覆盖 |
| 训练曲线 | 不稳定,难以解读 | 稳定,损失可直接解读 |
| 超参数敏感度 | 高 | 相对较低 |
8.4 2025 年的现状
截至 2025 年,Diffusion Model 已成为图像生成的主流。Stable Diffusion、DALL-E 3、Midjourney 等商业上最成功的图像生成模型,全部基于 Diffusion。
但 GAN 并没有被完全取代,在以下领域依然表现出强势:
- 需要实时生成的领域:电子游戏、VR/AR 等
- 图像编辑/操控:基于 StyleGAN 的精细人脸编辑、属性操控
- 超分辨率(Super-Resolution):实时超分辨率处理
- GAN-Diffusion 混合方案:把 GAN loss 结合进 Diffusion process,或把 GAN 的快速推理用于 Diffusion model 的 distillation
GigaGAN(2023)的出现证明了 GAN 在大规模 text-to-image 合成中依然具备竞争力,融合两种范式优点的研究也在积极进行中。
9. GAN 的现状与未来
9.1 GAN 的当前地位
自 2014 年发表以来,GAN 在约十年间一直处于生成模型的中心,但 2021 年后把主流地位让给了 Diffusion Model。不过,GAN 留下的遗产与它当前的角色依然重要。
目前 GAN 仍被广泛使用的领域:
- 医学影像:在保护患者隐私的同时增强训练数据,GAN 被广泛使用
- 数据增强:扩充小规模数据集的训练数据,以提升模型性能
- 图像编辑与修复:人脸修复、去噪、超分辨率等
- 时尚与设计:虚拟试穿(virtual try-on)、设计原型制作
- 游戏与仿真:实时内容生成、纹理合成
9.2 GAN 留下的理论遗产
GAN 最大的贡献并不止于图像生成技术本身。
对抗训练(Adversarial Training)范式:GAN 引入的对抗训练,其影响远超出生成模型本身。
- 对抗样本(Adversarial Examples):深度学习模型鲁棒性(robustness)研究
- 域自适应(Domain Adaptation):利用对抗训练实现跨域知识迁移
- 自监督学习(Self-supervised Learning):利用对抗信号做自监督学习
- 逆强化学习(Inverse Reinforcement Learning):以对抗方式学习奖励函数
隐式生成模型(Implicit Generative Models):GAN 的核心洞见——不必定义显式的概率分布也能学到复杂分布——也影响了此后 Energy-based Model、Score-based Model 等的发展。
9.3 未来展望
GAN-Diffusion 融合:最有前景的方向之一,是结合 GAN 与 Diffusion Model 各自的优点。目前有研究正在用 GAN 替代 Diffusion 过程中的去噪步骤,以提升推理速度。
3D 生成:把 GAN 与 3D 表示(Neural Radiance Fields、3D Gaussian Splatting 等)结合来生成 3D 内容的研究相当活跃,EG3D、GET3D 是其中的代表。
视频生成:StyleGAN3 的等变特性可以自然地应用于视频生成,具有时间一致性的视频生成研究正在进行中。
高效训练:通过 Few-shot GAN、GAN 的迁移学习(Transfer Learning)等手段,用少量数据训练出高质量生成模型的研究仍在持续。
9.4 GAN 论文谱系时间线总览
| 年份 | 模型 | 核心贡献 | 分辨率 |
|---|---|---|---|
| 2014 | GAN | 对抗训练框架 | Low |
| 2014 | cGAN | 条件生成 | Low |
| 2015 | DCGAN | 基于 CNN 的架构指南 | 64x64 |
| 2017 | WGAN | Wasserstein distance | 64x64 |
| 2017 | WGAN-GP | 梯度惩罚 | 64x64 |
| 2017 | Pix2Pix | 成对 image-to-image translation | 256x256 |
| 2017 | CycleGAN | 非成对 image-to-image translation | 256x256 |
| 2017 | ProGAN | 渐进式增长 | 1024x1024 |
| 2018 | BigGAN | 大规模训练、truncation trick | 512x512 |
| 2019 | StyleGAN | Mapping network、AdaIN、风格分离 | 1024x1024 |
| 2020 | StyleGAN2 | Weight demodulation、path regularization | 1024x1024 |
| 2021 | StyleGAN3 | Alias-free、等变生成 | 1024x1024 |
| 2023 | GigaGAN | 十亿参数规模的 text-to-image GAN | 512x512+ |
10. 结论
Ian Goodfellow 在 2014 年提出的 GAN,用一个简单却强大的想法 --- "两个网络的竞争会产生更好的生成模型" --- 为 AI 领域带来了一场革命。minimax 博弈这一数学框架既优雅又实用,此后十年间衍生出数百种变体,把图像生成的质量推向了一个又一个新高度。
DCGAN 通过与 CNN 的结合,为实用化的发展打下了基础;WGAN 用 Wasserstein distance 这一理论创新,解决了训练稳定性问题。Progressive GAN 与 StyleGAN 系列让 1024x1024 分辨率的照片级真实感图像生成成为可能,CycleGAN 与 Pix2Pix 则开拓了图像转换这一全新的应用领域。
尽管 2021 年后 Diffusion Model 已成为生成模型的主流,GAN 留下的遗产依然巨大。对抗训练这一范式仍在众多领域被广泛使用,融合 GAN 与 Diffusion 优点的混合研究也在积极推进。正如 GigaGAN 的出现所展示的那样,GAN 的故事还远未结束。
在生成模型的历史上,GAN 将作为第一个证明了"人工智能真的可以进行创作"这一可能性的里程碑,被人们铭记。
参考资料
-
Goodfellow, I. J. et al. (2014). "Generative Adversarial Nets." NeurIPS 2014. arXiv:1406.2661
-
Mirza, M. & Osindero, S. (2014). "Conditional Generative Adversarial Nets." arXiv:1411.1784
-
Radford, A., Metz, L. & Chintala, S. (2015). "Unsupervised Representation Learning with Deep Convolutional Generative Adversarial Networks." arXiv:1511.06434
-
Arjovsky, M., Chintala, S. & Bottou, L. (2017). "Wasserstein GAN." arXiv:1701.07875
-
Gulrajani, I. et al. (2017). "Improved Training of Wasserstein GANs." arXiv:1704.00028
-
Isola, P. et al. (2017). "Image-to-Image Translation with Conditional Adversarial Networks." CVPR 2017. arXiv:1611.07004
-
Zhu, J.-Y. et al. (2017). "Unpaired Image-to-Image Translation using Cycle-Consistent Adversarial Networks." ICCV 2017. arXiv:1703.10593
-
Karras, T. et al. (2017). "Progressive Growing of GANs for Improved Quality, Stability, and Variation." ICLR 2018. arXiv:1710.10196
-
Brock, A., Donahue, J. & Simonyan, K. (2018). "Large Scale GAN Training for High Fidelity Natural Image Synthesis." ICLR 2019. arXiv:1809.11096
-
Karras, T., Laine, S. & Aila, T. (2019). "A Style-Based Generator Architecture for Generative Adversarial Networks." CVPR 2019. arXiv:1812.04948
-
Karras, T. et al. (2020). "Analyzing and Improving the Image Quality of StyleGAN." CVPR 2020. arXiv:1912.04958
-
Karras, T. et al. (2021). "Alias-Free Generative Adversarial Networks." NeurIPS 2021. arXiv:2106.12423
-
Kang, M. et al. (2023). "Scaling up GANs for Text-to-Image Synthesis." CVPR 2023. arXiv:2303.05511
-
Dhariwal, P. & Nichol, A. (2021). "Diffusion Models Beat GANs on Image Synthesis." NeurIPS 2021. arXiv:2105.05233