ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

生成对抗网络原始论文精读:目标函数、理论证明与稳定训练实战

生成对抗网络原始论文精读:目标函数、理论证明与稳定训练实战

生成对抗网络这个方向,我在第一次读到《Generative Adversarial Nets》的时候并没有立刻觉得它“惊艳”。当时最直观的感觉是:原来生成模型还能这样定义——不直接去逼近数据分布,而是让两个网络互相“逼”着对方提高。这篇论文我前后读了三遍,第一遍只记住了min max公式,第二遍才真正看懂判别器最优解那条推导,第三遍是在自己动手训练某个图像生成Demo时踩了一堆坑之后回过头来重读的。这篇文章就按我自己的学习路径来写:先讲论文的动机和核心设计,再拆目标函数和理论证明,然后结合模拟项目X的训练复盘聊实操中的问题,最后说说后续模型在哪些方向上补了原论文的漏洞。

1. 为什么我认为这篇论文是自学生成模型的“第一课”

1.1 GAN之前,生成模型的主流思路

在读这篇论文之前,我接触过的生成模型大致可以分为两类。一类是显式密度模型,典型代表是最大似然估计框架下的模型。它们的目标很直接:给数据分布假设一个带参数的概率密度函数,然后通过调整参数让训练样本的似然尽量大。这类方法理论上很漂亮,但一旦数据维度变高,比如图像这种动辄几万维的样本空间,密度函数的归一化常数计算会变得极其困难。另一类是自回归模型,把联合分布拆成条件分布的乘积,逐像素或逐token生成,在语音和文本上效果很好,但在图像这种高维连续空间里生成速度慢、长期依赖也不好处理。

这两类模型有一个共同特点:都是在“显式地建模数据分布”。而《Generative Adversarial Nets》走了一条完全不同的路,它不显式地写分布,不计算似然,而是通过一个对抗博弈来隐式地逼近真实分布。这正是这篇论文让我印象最深刻的地方——它在方法论上做出了一个很根本的转向:与其辛辛苦苦定义并计算一个复杂的密度函数,不如让一个神经网络直接去“生成”,再由另一个神经网络去评估生成得好不好。

我当时读完引言后的反应是:这个思路虽然简洁,但蕴含了一个很反直觉的前提——两个网络互相博弈,真的能收敛到我们要的那个最优解吗?带着这个疑问往下读,才慢慢体会到论文里那句“用判别器提供学习信号”到底有多关键。

1.2 对抗思路的直觉:生成器像伪造者,判别器像鉴定师

论文里最直觉化的描述,就是把生成器比作伪造假币的团队,判别器比作鉴定假币的警察。生成器努力让造假结果足够逼真,判别器则努力分辨真伪。两者不断对抗,最终生成器产出的样本会逼真到“以假乱真”。这个比喻对新手极其友好,但它也容易让人忽略一个重点:这个博弈里两个角色的目的并不对称。

判别器的目标是最大化分类正确率,本质上是做一个二分类:真实样本标为真,生成样本标为假。生成器的目标则恰恰相反,它希望最小化判别器对生成样本的判断正确率,也就是让判别器把生成样本误判为真。两个网络的目标函数大致上是同一个式子的一正一反,这正是原文目标函数的由来。这里有一个很有意思的点:生成器并不是直接去模仿训练样本的像素细节,它只通过判别器给出的梯度来间接学习。因此整个系统的性能上限,其实很大程度上取决于判别器能否提供准确且有信息量的梯度信号。

在实际训练前,我觉得这个对抗思路有点“太完美”。后来亲手训练后才意识到,博弈双方的平衡极其脆弱,但这个“脆弱”本身又是另一个值得深挖的问题——我会在后面的实操章节详细展开。

2. 原始论文的公式拆解:min max目标函数到底在做什么

2.1 目标函数里每一项的含义

原论文的目标函数是一个极小极大博弈:

$$\min_{G} \max_{D} V(D,G) = \mathbb{E}{x \sim p{data}(x)}[\log D(x)] + \mathbb{E}_{z \sim p_z(z)}[\log(1 - D(G(z)))]$$

初学者第一次看这个式子容易懵。我在模拟项目X里也遇到过同事问:这里面怎么又是min又是max,训练的时候参数到底往哪调?拆开看就清楚了。

先看判别器D这部分。D是一个二分类网络,输入一张图片,输出一个介于0到1之间的标量,表示“这张图片来自真实数据的概率”。对真实样本x,我们希望D(x)尽量接近1,所以 $\log D(x)$ 要尽量大;对生成样本 $G(z)$,我们希望D的输出尽量接近0,也就是 $\log(1 - D(G(z)))$ 尽量大。所以判别器的目标就是最大化整个式子,这对应外层max。

再看生成器G。它的参数只影响第二项 $\log(1 - D(G(z)))$。生成器希望自己生成的图片被判别器判定为“真”,也就是 $D(G(z))$ 尽量接近1,那么 $\log(1 - D(G(z)))$ 就尽量小。因此生成器要最小化整个式子,这对应外层min。

这样理解以后,公式就不再可怕了:它本质上是一个二元零和博弈的损失函数,两边共享同一个目标,但一方的增益就是另一方的损失。不过我在实际中慢慢发现,纸上这样写很对称,训练时完全不对称——判别器收敛得太快,几乎是GAN训练里最常见的病。

2.2 “训练D到最优”与“梯度消失”的两个极端

论文在推导最优解时,先假设生成器G固定,然后去求最优判别器D。这个假设在理论上很方便,但在实操中就埋下了一个隐患:如果每次都把D训练到接近最优,生成器的梯度会不会变得非常糟?答案是肯定的。

我已经记不清在模拟项目X里踩过多少次这种坑了。D太弱,G得不到有效梯度,生成图像一直是噪声;D太强,梯度又会迅速消失,G更新后几乎没有变化。论文原文在实验部分用一个三层全连接网络加tanh激活跑通了MNIST和CIFAR-10,这部分描述得比较简略,很多人跳过。但真正动过手的人都知道,训练GAN在早期更像是在“抢救”一个随时可能崩溃的训练过程。

我会在后面的训练章节详细说,这里只强调一个核心原因:原始GAN用二元交叉熵损失,当D对生成样本的判断已经非常自信且正确时, $\log(1 - D(G(z)))$ 的梯度会趋近于0,生成器几乎学不到东西。后来很多研究都试图解决这个梯度消失的问题,比如换用最小二乘损失、改用Wasserstein距离,本质都是为了让生成器始终能拿到有意义的梯度。

2.3 为什么理论推导最后会指向JS散度

论文里有个非常漂亮的推导环节:在最优判别器确定以后,目标函数可以被改写为真实分布与生成分布之间某个距离度量。推导并非“突然出现”,而是顺着定义一步步推下来的。我先说结论:当D优化到最优时,目标函数的值与真实分布 $p_{data}$ 和生成分布 $p_g$ 之间的JS散度(Jensen-Shannon散度)相差一个常数。也就是说,对抗训练本质上是在最小化两个分布之间的JS散度。

这里有个初读时很容易忽略的细节:JS散度是两个分布之间的对称度量,理论上它比不对称的KL散度更适合做生成模型的训练目标。但它有一个致命的边界行为——如果两个分布的重叠非常少,JS散度会变成一个常数 $\log 2$,梯度信号彻底消失。这个特性从数学上解释了为什么原始GAN在训练初期或分布覆盖不佳时容易遇到梯度消失的问题。

当年读到这一段只觉得“数学很优美”,后来对照WGAN的论文才明白,优美和实用之间的鸿沟恰好就是由JS散度自身的缺陷造成的。理解这一点对阅读后续几乎所有GAN改进论文都有帮助,因为它们大多是在换“分布之间距离度量”这件事。

3. 全局最优与收敛性证明的阅读方法

3.1 命题1:固定G时最优D的表达式

论文中在讲博奕最优解时给出了一个核心结论:当G固定时,最优判别器是

$$D^*G(x) = \frac{p{data}(x)}{p_{data}(x) + p_g(x)}$$

这个公式的实际含义非常明显。如果某点x在真实分布里概率很高、在生成分布里概率为0,那么最优判别器输出接近1,也就是判为真实样本;反过来,如果生成分布概率很高、真实分布很低,最优判别器输出接近0。当两个分布概率相等时,最优判别器恰好输出0.5,这时它已经无法区分真伪了。

我建议读者把这一步当作推导重点。大部分GAN变种的数学分析,都会从“固定一方、求另一方最优”入手,这个“坐标下降式”的思路是理解整个对抗框架的基础。但这里要提醒一句:推导中的“最优判别器”是理论上的极限,实践中网络容量有限、训练步数有限,D几乎不可能真正做到全局最优。所以理论中的收敛保证,在实际中只是一种近似倾向。

3.2 全局最小值和对称性说明

论文还证明了,如果我们把最优判别器表达式代回目标函数,并且用JS散度表达,那么整个博弈的全局最小值在 $p_g = p_{data}$ 时取得,此时目标函数值等于 $-\log 4$。换句话说,生成分布等于真实分布时,判别器彻底失效,生成器也达到了最理想状态。

不过这个证明有一个隐含的对等关系:博弈在示意图中出现“生成分布越过真实分布继续偏移”的情况时,论文从对称性角度指出,生成器最终还是会回到真实分布。理论上的对称性很优雅,但是在实际训练里,如果生成器过度拟合了训练数据里的某一部分子分布,它不但不会自动回到全局最优,反而会陷入我下面要讲的模式崩塌。

3.3 理论证明的边界:凸性要求与现实差距

原论文的收敛性分析部分,假定了博弈双方都在一个凸函数空间里更新。对这种无限维凸空间的设定,作者承认它过于局限,无法直接推广到神经网络这种高度非凸的环境。也就是说,原始论文从理论上给出的收敛保证,更多是“理想化版本的说明”,而不是对实际深度网络训练过程的严格保证。

这一点很容易被初学者忽略,很多人看到“收敛到全局最优”就以为训练GAN是稳的,结果自己一跑就发现问题重重。我建议在读论文时把理论部分当成“指向标”:它告诉我们如果一切顺利,系统的目标是什么;但现实中深度网络的非凸性、有限容量和有限步数,决定了通往这个目标的路上必然有大量工程陷阱。我在后面结合训练经验展开的很多内容,其实都是围绕这个理论假设与现实的落差展开的。

4. 实践复现中的真实体验:模拟图像生成Demo的复盘

4.1 网络结构与训练参数设定

我在模拟项目X里搭了一个最接近原论文实验设置的图像生成Demo:生成器从100维正态噪声出发,通过全连接层映射到784维的像素空间,激活函数用ReLU和tanh;判别器是结构对称的全连接网络,输出用sigmoid二分类概率。训练数据用的是标准的灰度手写数字数据集,我刻意没有做任何数据增强,想先看看最原始的GAN能做到什么效果。

训练参数的初始设定是这样的:batch size 128,判别器用学习率0.0002的Adam,生成器用学习率0.0002的Adam,每轮先更新K次判别器再更新1次生成器。这里的K我一开始设成了5,结果很快就出问题了:判别器的loss稳定下降到接近0,生成器梯度迅速消失,输出的图像像一张灰蒙蒙的噪声图。

这个经历让我明白,原论文里那些看起来平平无奇的实验说明,其实隐藏了太多没有写出来的调参细节。后来我把K从5改成1,也就是让判别器和生成器交替各更新一次,训练才勉强稳定下来。但即便这样,生成的图像仍然有很多重复模式,这就是下面要说的模式崩塌的前兆。

4.2 D收敛过快导致的生成退化

D收敛过快是最早出现、也最普遍的问题。原因很直接:真实样本是固定的,判别器只需要把“这批真实样本”和“生成器当前产物”区分开,而生成器又很弱,所以判别器很容易学到一个能短暂碾压生成器的决策边界。一旦D的loss降到接近0,生成器收到的梯度信号就几乎消失,看起来就像两个人在下棋,对手每步都把你将死,你想了一整晚也发现自己一步都走不出去。

我试过几种补救办法,最简单的就是把判别器训练得更少,比如每轮先训练一次D,再训练一次G。还有一个很有效的做法是把真实样本和生成样本的标签做soft化,就是所谓的标签平滑:不把真实样本的标签设为1,而是设为0.9;不把生成样本的标签设为0,而是设为0.1。标签平滑实际上相当于告诉判别器不要把置信度推得太满,这在一定程度上保住了生成器沿loss曲面的梯度。

另外我把优化器从SGD换成了Adam。SGD在普通分类任务上表现稳定,但在GAN这种两个网络争抢的环境中,SGD的梯度方向震荡很大,很容易把其中一个网络推入饱和区。Adam对每个参数维度做了自适应缩放,对梯度的尺度变化更宽容,是更稳妥的选择。

4.3 模式崩塌的两种典型表现

模式崩塌是我在模拟项目X里遭遇的最直观也最让人头疼的问题。第一种表现是类别级崩塌:训练好之后,生成器只会产出某一类数字或有限的几种数字,整批生成的图像“同质化”严重。这是因为生成器找到了一个相对容易被判别器误判的“捷径”类别,于是它不必继续拓展覆盖整个数据分布的多样性,只需把这个类别做得足够好就能骗过D。

第二种表现是样本级重复:生成不同的随机编码z,结果输出的图像几乎一模一样。这种通常发生在后期,判别器对某些样本的判别已经饱和,生成器在这些局部点上的梯度几乎为零,无法把z映射到更多不同的输出区域。无论是哪种表现,本质上都是生成器在绕开覆盖整个真实分布这个难题,转而优化一个局部目标。

模式崩塌的出现让我重新去理解论文里的理论证明:全局最优只有在 $p_g = p_{data}$ 时才成立,而实际优化的过程并不保证朝向它。要缓解崩塌,我试了两种比较有效的手段。第一种是给生成器的输入z加上很小的高斯噪声级别,增加一定扰动后,生成器被迫学习不同z之间的连续性;第二种是频繁把生成的batch拿出来人工目检,一旦发现同质率上升,立刻降低判别器学习率,给生成器喘息的余地。

5. 一些让原始GAN能稳定训练的实用补丁

5.1 从“二元交叉熵”到“标签平滑”

如果要我给第一次复现原始GAN的人一个建议,我会把标签平滑列在最前面。设计标签平滑的理念很简单:原来判别器看到真实样本要输出1,看到生成样本要输出0,这是两个硬目标。但用软目标之后,判别器不需要把真实样本的logit推到极大值,也不需要把生成样本的logit压到极小值,相当于给它留了一个缓冲区间。

具体做法并不复杂。训练时真样本标签设为0.9左右,生成样本标签设为0.1左右,或者只在真样本上做平滑,生成样本标签仍然是0。这个做过之后,我观测到的变化是:判别器的loss不会掉到极低,生成器每轮的梯度幅度更稳定,生成的图像也会更早出现肉眼可辨的结构。虽然标签平滑并不能根治模式崩塌,但它能把训练过程从一个“随时会断”的状态拉到一个“还可以慢慢修”的状态。

5.2 用RMSprop、Adam代替SGD的实战理由

原始GAN论文实验部分虽然用的是自定义网络,但并没有特别强调优化器选择。我实际跑下来,SGD在GAN上的表现非常糟糕,主要原因是梯度的scale变化剧烈。生成器在不同迭代阶段面临的loss表面差异很大,SGD对梯度尺度敏感,因此更新步长不稳定,容易出现振荡或发散。

Adam则不然,它用梯度的一阶矩估计和二阶矩估计对每个参数做了自适应归一化,相当于自动帮我们调整学习率。实践中我常用的参数是学习率0.0002、$\beta_1=0.5$、$\beta_2=0.999$。需要注意,$\beta_1$ 设成0.5而不是常见的0.9,是为了让梯度更新不那么“惯性化”。在普通监督任务里0.9带来平滑,但GAN里这种做法容易让优化过程出现慢性的偏移累积。

后来我也用到了RMSprop。在某些明显出现判别器loss震荡的场景下,RMSprop的更新通常比Adam更温和,尤其是当梯度的二阶矩变化比较剧烈时。不过RMSprop对学习率更敏感,通常我会把学习率降到1e-4再试。

5.3 简单可靠的生成质量评估方法

训练GAN时最常被问的问题就是:怎么看生成模型练得好不好?原始论文里主要靠人工目检和最大似然估计的近似计算。我自己现在常用的组合是“三类指标交叉验证”。

第一是人工目检,虽然主观,但最直接。我通常会固定若干个随机种子z,每隔一定轮数把对应样本拼成一张大图保存下来。通过这些固定种子的演化,可以直观看到生成器从噪声到结构的过程,也能快速发现是否出现了重复模式。

第二是FID,全称Fréchet Inception Distance。做法是拿生成的图像和真实图像分别输入一个预训练的分类网络,取其中一层的特征向量,假设这些特征服从高斯分布,然后计算两个分布之间的Fréchet距离。FID值越低表示生成分布与真实分布在特征空间里越接近。它比单纯看loss更可信,缺点是必须依赖一个与任务不一定完全匹配的预训练模型。

第三是最近邻分析。随机选几张生成的图像,去训练集里找它们的最近邻真实样本,如果生成样本都能找到非常相似的真实样本,说明生成器可能只是记住了训练数据,而不是学会了分布。这种方法无需额外模型,直接在像素空间算欧氏距离,虽然粗糙,但判断“是否记忆过头”很有效。

这三种方法组合使用,比单纯盯着训练loss靠谱得多。我在模拟项目X上就是靠固定种子目检+FID及时发现了生成质量的波动,才及时调整了超参,没有让训练白跑几个小时。

6. 从这篇论文出发:后续改进与我觉得值得保留的思维习惯

6.1 DCGAN、WGAN、条件GAN分别补了什么

这篇论文以后,生成对抗网络的相关工作迎来了爆发。我自己读后续工作的时候有一个基本框架:看它究竟动了原始GAN的哪个环节。

DCGAN解决的环节是网络结构。把原始的全连接网络换成卷积层和转置卷积层,配合批量归一化以及去掉全连接隐藏层,收敛稳定性和生成图像质量都有了很明显的提升。它给我的启示是,生成器和判别器的表达能力直接决定了对抗博弈能否在有限容量里逼近最优。

WGAN解决的环节是分布距离度量。原始GAN用JS散度作为隐式目标,但JS散度在分布重叠小的情况下梯度消失。WGAN改用Wasserstein距离,并取消了判别器最后一层的sigmoid,改成输出一个任意实数,用梯度惩罚或权重裁剪来约束判别器的Lipschitz性质。我跑过WGAN训练,一个很直观的感受是:训练过程比原始GAN稳定太多,判别器的loss不再是一个迅速熄灭的信号,而是可以长期作为训练进展的指示器。

条件GAN解决的环节是控制生成方向。它在生成器的输入里额外拼接一个class标签,让生成过程变为“给定类别,生成对应图像”。原始GAN里生成器完全不知道自己要生成什么类别的内容,条件GAN则让“对抗式分布逼近”引入外部信息,这种方法后来在图像翻译、超分辨率重建中都发挥了巨大作用。

6.2 论文思维方式的迁移价值

回看这篇论文,我最想保留的并不是那些已经被后续工作升级或修正的细节,而是它背后的思维方式:当显式建模难以推进时,能不能引入一个“竞争性的代理任务”来隐式逼近目标?

这个思路并不局限在图像生成。我在其他方向上也试着用这种博弈思想做迁移:让一个预测模型和一个评判模型相互对抗,以激励预测模型探索更难、更不明确的部分。事实证明,这种方式在为模型提供学习信号方面往往比手工设计复杂损失函数更简洁,也更接近人类“在竞争中学习”的经验。

另一层启发是对理论边界的敏感。原始论文其实清楚写明了收敛保证只存在于凸情形,但很多人只看结论不看假设。动手做工程的人,更要养成“先看假设和边界,再谈结论”的习惯,有了这个习惯,读任何一篇论文都不容易被人牵着走。

我在模拟项目X里跑完原始GAN后,最大的收获不是“我会写GAN代码了”,而是深刻地理解了“优化目标设计”比“网络结构设计”更容易决定一个模型的上限。今天很多新的生成模型层出不穷,但回头来看,《Generative Adversarial Nets》这篇论文的价值从来不只是给出了一个能用的模型,而是给整个领域示范了一种用博弈眼光看待生成问题的方式。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进