Part V · 第 19 章 生成模型 · 19.2

生成对抗网络 (GAN)

GAN 不写下概率密度,也不最大化似然:它让两个网络对弈。生成器把随机噪声变成样本,判别器判断样本是真是假,生成器再顺着判别器的梯度改进自己。本节推导最优判别器和它背后的 Jensen-Shannon 散度,在浏览器里实时训练一个二维 GAN,再逐个拆解 GAN 出名难训的原因:梯度饱和、模式坍缩、博弈不收敛,以及非饱和损失、Wasserstein 评论家和 R1 正则这些对策;最后看条件 GAN 怎样给机器人生成多模态动作,以及判别器怎样在 GAIL 和 AMP 里变成奖励。

约 40 分钟 前置:16.3 反向传播 · 4.11 信息论(KL) · 6.3 梯度下降 · 对照 19.1 VAE 6 个交互

    1为什么机器人需要它

    机器人学习里有大量“一对多”的问题。同一个杯子可以从左边抓,也可以从右边抓;同一个障碍物可以从左绕,也可以从右绕;仿真里的同一张图像,换到真实相机下可以有无数种光照和纹理。用均方误差去回归这类目标,网络会学到各个答案的平均:两种抓法的平均是抓在杯把和杯身之间的空气里,两条绕行路线的平均正好撞上障碍物。我们需要的不是平均值,而是一个能采样的模型:每次给出一个合理的、属于某一种模式的答案。这就是第 19 章的生成模型要做的事。

    19.1 节的 VAE 走的是似然路线:写出一个潜变量模型,最大化对数似然的下界 ELBO。生成对抗网络(GAN,Goodfellow 等,2014)换了一条完全不同的路:不写密度,只要求“骗得过一个裁判”。生成器 \(G\) 把噪声 \(\mathbf z\) 映射成样本 \(G(\mathbf z)\);判别器 \(D\) 是一个二分类器,输出“这个样本来自真实数据”的概率;两者对着同一个目标一个最大化、一个最小化。训练好的生成器只需一次前向传播就能出一个样本,样本往往很清晰(VAE 的样本常常偏模糊),代价是训练很不稳定。理解它为什么不稳定,以及每一个“训练技巧”背后的数学,是本节的主线。

    它和机器人的关系不止于生成图片。判别器“区分专家与非专家”的能力本身就很有用:GAIL 把它当作奖励来做模仿学习(20.6 节),AMP 用它让腿式机器人和仿真角色学出自然的动作风格;在 sim-to-real 里,GAN 被用来把仿真图像“翻译”成看起来像真实相机拍的图像。

    2直觉:伪造者与鉴定师

    想象一个伪造者(生成器)和一个鉴定师(判别器)。鉴定师看一堆真品和一堆伪造品,学会给每件东西打一个“是真品”的概率 \(D(x)\)。伪造者看不到真品,只能看到鉴定师的打分,并朝着“让分数变高”的方向改进伪造手法。如果鉴定师已经做到最好,他在 \(x\) 处给出的分数应该是多少?在 \(x\) 附近,真品出现的密度是 \(\hl{pdata}{p_{\text{data}}(x)}\),伪造品出现的密度是 \(\hl{pg}{p_g(x)}\),那么一件落在 \(x\) 的东西是真品的概率就是两者之比:

    $$ \hl{dstar}{D^*(x)}=\frac{p_{\text{data}}(x)}{p_{\text{data}}(x)+p_g(x)} $$

    (两堆一样多时;第 6 节会从损失函数严格推出它。)这一个式子已经说明了 GAN 的很多性质。伪造品与真品完全一样时,\(D^*\equiv\tfrac12\),鉴定师只能瞎猜,这正是训练的终点。伪造品离真品很远、两堆不重叠时,\(D^*\) 在真品上是 1、在伪造品上是 0,鉴定师“完美”,可伪造品附近的 \(D^*\) 是一片平坦的 0:伪造者顺着分数往上爬,却没有坡可爬。下图让你亲手摆放生成器的分布 \(p_g\),看最优判别器怎样随之变化,并读出两者之间的 Jensen-Shannon 散度(JS):它就是“最优鉴定师能把真假分得多开”的度量,定义和性质见第 6 节。

    FIG 1最优判别器 D* 与 JS 散度
    横轴是一个一维量,例如示教中抓取器接近杯子的角度:人类示教有两种习惯(两个峰)。紫色是数据密度 \(p_{\text{data}}\)(两个宽 0.35 的高斯,各占一半),琥珀色是生成器密度 \(p_g\),拖动底部的琥珀色圆圈移动它的均值,滑块改宽度 σ;右上角可切换为两个等权高斯。绿色曲线是最优判别器 \(D^*(x)\),纵轴 0 到 1,虚线是 ½。密度和 \(D^*\) 共用纵轴;太窄的 \(p_g\) 峰会超出画面。读数里的 JS 以 nat 为单位,上限是 \(\log 2\approx0.693\)。
    试一试
    • 用一个高斯,把 \(p_g\) 拖到远离数据的一侧(均值 \(|m|>3\))并调窄(σ < 0.3):JS 超过 \(\log 2\) 的 99%,\(D^*\) 在数据上几乎是 1、在 \(p_g\) 上几乎是 0,而且这时再左右拖动,JS 几乎不变。
    • 切换到“两个高斯”,把两个均值和宽度对准数据,使 JS < 0.01:\(D^*\) 在每一处都接近 ½,\(V(D^*,G)\) 接近 \(-\log4\approx-1.386\)。
    核心洞见

    最优判别器把“两个分布差多少”变成了一个可以用分类器学出来的量。GAN 的生成器其实是在最小化 JS 散度,只不过这个散度从来没被显式算过,而是由一个正在学习的判别器近似。也请留意单个高斯的情形:要盖住两个峰,最小的 JS 是 0.162(均值 0、σ ≈ 1.24,把两个峰都罩住),而只贴住一个峰(均值 ±1.2、σ = 0.35)是 JS = 0.215 的一个局部极小。两个解都是稳定点,梯度下降落在哪个取决于起点。

    3动手:在浏览器里训练一个 GAN

    FIG 1 里的 \(D^*\) 是用真实密度算出来的;真实的 GAN 两边都不知道密度,只有样本。下图是一个真正在训练的 GAN:生成器 \(G\) 是一个 2→24→24→2 的 MLP(leaky ReLU),把二维高斯噪声 \(\mathbf z\) 变成平面上的一个点;判别器 \(D\) 是 2→24→24→1 的 MLP,输出一个 logit \(l(x)\),\(D(x)=\sigma(l(x))\)。每次迭代:

    1. 判别器一步:取 32 个真样本和 32 个 \(G(\mathbf z)\),用二分类交叉熵(16.1 节)把真样本推向 1、假样本推向 0,Adam 走一步。
    2. 生成器一步:再取 32 个 \(\mathbf z\),把 \(G(\mathbf z)\) 送进判别器,判别器参数不动,只把损失对判别器输入的梯度 \(\partial L/\partial x\) 反向传回生成器(16.3 节的反向传播:一路穿过 \(D\),再穿过 \(G\)),更新 \(G\) 的参数。

    默认用“非饱和”生成器损失 \(-\log D(G(\mathbf z))\),第 4 节解释为什么不用原始的那个。背景颜色是当前判别器的判断:越绿越像“真”,越红越像“假”;青色箭头是判别器给每个生成样本的“推力”\(-\partial L_G/\partial x\),也就是 \(\hl{gradx}{\nabla_x\log D(x)}\) 的方向。

    FIG 2二维 GAN 实时训练
    紫点是 300 个固定的真实样本,琥珀点是 300 个固定噪声 \(\mathbf z\) 经当前生成器得到的样本(所以动画是连续的)。背景是 \(D(x)\):绿表示 \(D>\tfrac12\),红表示 \(D<\tfrac12\),颜色越浓离 ½ 越远。青色箭头画在 40 个生成样本上,长度与该样本在所选损失下得到的梯度大小 \(|\partial L_G/\partial x|\) 成正比(有上限)。右侧曲线是 \(D\)(真样本)和 \(D\)(假样本)的滑动平均:紫与琥珀,虚线是 ½。精确率 = 生成样本中离某个真样本不到 0.15 的比例(“像不像”),召回率 = 真样本中离某个生成样本不到 0.15 的比例(“全不全”);“8 峰”数据另给出被覆盖的峰数(一个峰至少有 2% 的样本落在其 0.3 之内才算)。每帧按时间预算跑若干次迭代(最多约 7 ms),所以速度因电脑而异,但迭代次数相同时结果完全一样(随机种子固定)。
    试一试
    • 选“8 峰”,按“训练”:先是一团琥珀点被红色背景推开,几百次迭代后它们分裂成几股、各自爬向绿色区域。训练到 8 个峰都被覆盖且精确率 ≥ 0.8(默认种子约 1500 次迭代)。
    • 把损失切到“minimax(饱和)”,选“2 簇”数据(或按“重置”),按“D 先练 500 步”(只训练判别器、不动生成器),再单步一次:读数里 minimax 梯度不到非饱和梯度的 0.2 倍。箭头也明显变短了:判别器越有把握,原始损失给生成器的信号越弱。
    值得注意的现象

    (1) 损失不是进度条:判别器损失停在 \(2\log2\approx1.39\) 附近(这里大约在 1.2 到 1.4 之间)来回摆,既不单调下降,也不说明样本好坏;样本要看图或看精确率/召回率。(2) 生成器从来没见过真数据:它的全部信息都来自判别器的输入梯度(青色箭头)。判别器把“真数据在哪”编码进自己的梯度场,生成器只是顺着这个场往前走。(3) 在“8 峰”上,琥珀点在峰与峰之间常留下细细的“桥”:生成器是一个连续函数,把连通的高斯噪声映射到 8 个分开的峰时,必然有少量样本落在中间。(4) 换成“圆环”(一个连续的环,例如绕圆柱一周的抓取位置):默认种子下约 850 次迭代后精确率和召回率都超过 0.9,右侧两条曲线都收拢到 ½,判别器沦为瞎猜,正如 \(D^*=\tfrac12\) 所预言。

    4两种失败:梯度饱和与模式坍缩

    原始损失为什么会“饱和”

    Goodfellow 等的原始目标里,生成器最小化 \(\hl{mm}{\log(1-D(G(\mathbf z)))}\)。问题出在训练初期:生成样本很差,判别器很容易认出它们,\(D(G(\mathbf z))\approx0\)。此时 \(\log(1-D)\) 对 logit 的导数是 \(-D\approx0\):判别器越有把握,生成器的梯度越小,就在它最需要学习的时候。原论文已经给出了补救:改成最小化 \(\hl{ns}{-\log D(G(\mathbf z))}\),对 logit 的导数是 \(-(1-D)\approx-1\)。两个损失的不动点相同(都希望 \(D(G(\mathbf z))\) 变大),但信号的强弱正好颠倒:原始损失按 \(D\) 加权每个样本,非饱和损失按 \(1-D\) 加权。第三种做法是 WGAN(Arjovsky 等,2017):判别器不再输出概率,而是一个受 1-Lipschitz 约束的“评论家”\(f\),生成器最小化 \(\hl{wgan}{-f(G(\mathbf z))}\)。

    下图把三者放在一个能精确求解的例子里比较:真数据是 \(\mathcal N(1.5,\,0.3^2)\),生成器是 \(\mathcal N(\theta,\,0.3^2)\),只有一个参数 \(\theta\)。两个等宽高斯之间的最优判别器 logit 恰好是 \(x\) 的线性函数,所以可以把“判别器强度”\(\beta\) 写成 logit 的倍数:\(\beta=1\) 是最优判别器,\(\beta\) 小一些是“没练好、拿不准”的判别器。对每个 \(\theta\),图中给出生成器损失对 \(\theta\) 的梯度大小(判别器固定)。

    FIG 3饱和:判别器越有把握,原始损失的梯度越小
    左:紫色是真数据密度,琥珀色是生成器密度(拖动底部琥珀圆圈或用滑块改 \(\theta\)),绿色是强度为 \(\beta\) 的判别器 \(D(x)\)(0 到 1)。右:横轴是 \(\theta\),纵轴是梯度大小的以 10 为底的对数,三条曲线分别是 原始 minimax 损失(红)、非饱和损失(青)和 WGAN(蓝,最优 1-Lipschitz 评论家,梯度恒为 1);竖虚线标出当前 \(\theta\),横轴上的紫点是数据均值 1.5,低于 \(10^{-12}\) 的部分贴在底边。期望对生成器噪声用 481 点求积精确计算,没有随机采样。
    • 保持 \(\beta=1\)(最优判别器),把 \(\theta\) 拖到 \(-2\) 或更左(与数据相距 ≥ 3.5):原始损失的梯度跌到 \(10^{-6}\) 以下,而非饱和损失的梯度超过 10。
    • \(\theta\) 留在 \(-2\) 或更左,把判别器强度 \(\beta\) 降到 0.1 或以下:原始损失的梯度比同一 \(\theta\) 下 \(\beta=1\) 时大 1000 倍以上(读数给出这个倍数)。一个“拿不准”的判别器反而给出了有用的梯度。

    读数里还给出 JS 和 Wasserstein 距离 \(W=|1.5-\theta|\)。随着 \(\theta\) 远离,JS 趋于 \(\log2\) 后就几乎不再变化,它对 \(\theta\) 的导数趋于 0;\(W\) 却始终以斜率 1 增长。这就是 WGAN 的出发点:在两个分布几乎不重叠时(高维里的常态,真实图像只占像素空间里极薄的一层),JS 失去了“还差多远”的信息,而 Wasserstein 距离保留了它。注意非饱和损失的梯度也不是“越大越好”:它随距离线性增长,判别器很尖锐时会给出很大、很吵的梯度,这是 FIG 2 里有时需要较小学习率的原因之一。

    模式坍缩:对一个固定判别器的最优回应

    GAN 最出名的失败是模式坍缩:生成器只产出数据里的一种或几种模式,例如只会从一个方向去抓杯子。原因藏在目标的顺序里。理论上我们解的是 \(\min_G\max_D V\):对每个 \(G\),判别器先做到最好,生成器再选最好的 \(G\)。可是交替梯度下降里,生成器每一步面对的是一个固定的判别器。而对一个固定的 \(D\),生成器的最优回应是什么?它的损失 \(-\mathbb E_{x\sim p_g}[\log D(x)]\) 对 \(p_g\) 是线性的,线性函数在概率单纯形上的最小值落在顶点:把所有质量放在 \(D\) 最大的那一点。判别器随后发现“这一点全是假货”,把那里的 \(D\) 压低,生成器又整体跳到下一个 \(D\) 最高的地方……这就是模式跳跃。

    下图把这个机制剥离出来,用一个可以精确计算的离散版本:抓取器有 8 个接近方向,示教数据 \(p\) 均匀分布在这 8 个方向上;生成器是 8 个方向上的分布 \(q=\operatorname{softmax}(\boldsymbol\theta)\);判别器每隔 \(m\) 步重新算成当前 \(q\) 下的最优判别器 \(D_k=p_k/(p_k+q_k)\),其余时间保持不动;生成器在两次刷新之间用学习率 \(\eta\) 对非饱和损失做梯度下降。

    FIG 4模式坍缩与模式跳跃:对过时判别器的最优回应
    左:俯视的杯子和 8 个接近方向。琥珀色箭头的粗细和长度与生成器概率 \(q_k\) 成正比,紫色刻度标出数据概率 \(p_k=\tfrac18\) 对应的长度;外圈 8 个绿点的大小是当前(可能已过时的)判别器 \(D_k\)。右上:每个方向的 \(q_k\)(琥珀柱)、\(p_k\)(紫线)和 \(D_k\)(绿色方块,0 到 1)。右下:最近 600 步的历史,每一行是一个方向,越琥珀表示 \(q_k\) 越大。“跳跃次数”统计占多数(\(q_k\ge0.5\))的方向换了几次。
    • 先按“重置”,“判别器刷新”选“冻结”,按“运行”:生成器把 95% 以上的概率堆到一个方向上(η = 3 时约 130 步后是方向 3)。继续运行,约 1000 步时它又整体搬到方向 5,冻结的判别器在那里打分最高(\(D_5\approx0.87\)):对固定判别器的最优回应就是它最大值处的一个点质量。这两个方向在数据里都不比别的方向更常见(数据是均匀的)。
    • 选“每 30 步”,保持 η = 3,重置后运行:占多数的方向至少换 3 次,生成器在方向之间来回跳,始终没有覆盖全部 8 个方向。
    • 选“每步”(判别器始终最优),重置后运行:\(q\) 收敛到均匀分布,JS < 0.001 且每个方向都超过 10%。同样的学习率,只是判别器不再过时。

    真实的 GAN 介于这几种情形之间:判别器只走几步、永远“半过时”,生成器每一步又会同时移动所有样本(它是一个共享参数的函数,FIG 4 里的 softmax 也一样)。所以坍缩是否发生取决于 \(\eta\) 与 \(m\) 的乘积这类“生成器在判别器跟上之前能走多远”的量:试试把 η 调到 1,再选“每 30 步”,它会收敛。对策都围绕这个机制:让判别器“看见”一整批样本的多样性(minibatch discrimination,Salimans 等,2016)、让生成器预判判别器的回应(unrolled GAN,Metz 等,2017)、给判别器加梯度惩罚或谱归一化让它的回应更平滑,或者干脆换一个按似然训练、天然要覆盖所有数据的模型(VAE、flow、扩散模型)。

    5另一个视角:训练是一场博弈,不是下山

    6.3 节的梯度下降有一个总是在下降的目标函数,学习率够小就能收敛。GAN 不是这样:两个玩家沿着同一个函数的相反方向走,联合的“梯度场”可以绕圈,而不是指向一个谷底。Mescheder、Geiger 与 Nowozin(2018)用一个最小的例子把这一点说清楚了,称为 Dirac GAN:真数据是 \(x=0\) 处的一个点,生成器是 \(x=\theta\) 处的一个点,判别器是 \(D(x)=\sigma(\psi x)\),只有一个参数 \(\psi\)。唯一的平衡点是 \(\theta=0,\ \psi=0\)。在平衡点附近,两人的更新近似为

    $$ \dot\psi\approx-\tfrac12\,\theta-\hl{r1}{\gamma\,\psi},\qquad \dot\theta\approx\tfrac12\,\psi $$

    (先看 \(\gamma=0\))。这是一个纯旋转:判别器看到生成器在右边(\(\theta>0\)),就让 \(\psi\) 变负,把右边判成“假”;生成器于是往左走;走过头之后判别器又反过来……线性化矩阵的特征值是 \(\pm\tfrac i2\),纯虚数,没有任何衰减。下图在 \((\theta,\psi)\) 平面上运行真实(非线性)的离散更新,用的是原始的零和损失(非饱和损失在平衡点处的线性化完全相同)。

    FIG 5Dirac GAN:同时更新螺旋发散,交替更新绕圈,R1 让它收敛
    左:横轴 \(\theta\)(生成器),纵轴 \(\psi\)(判别器)。青色箭头是连续时间下的更新方向场,绿圈是平衡点,琥珀色是从起点(可拖动的圆圈)出发的离散轨迹。右:同一时刻的一维图景,紫色竖线是真数据点 \(x=0\),琥珀色竖线是生成器的点 \(x=\theta\),绿色曲线是 \(D(x)=\sigma(\psi x)\);短的红色线段是 \(D\) 在真数据处的切线,斜率 \(\psi/4\),与 R1 惩罚的 logit 斜率 \(\psi\) 成正比。读数里的 ρ 是线性化后每步更新矩阵的谱半径:ρ > 1 向外螺旋,ρ = 1 绕圈,ρ < 1 收敛。
    • 选“同时更新”,γ = 0,从默认起点 \((\theta,\psi)=(1,0)\) 运行:轨迹向外螺旋,离平衡点的距离超过起点的 2 倍(η = 0.1 时约 660 步)。
    • 把 R1 系数 γ 调到 0.1 以上(两种更新方式都行),重置后运行:轨迹盘旋着收进平衡点,距离降到起点的 2% 以下。

    “交替更新”(判别器先走一步,生成器用更新后的判别器再走一步)也不收敛,只是不再发散:在 η = 0.1 下跑 6000 步,距离始终在起点的 0.99 到 1.02 倍之间,永远绕圈。\(\hl{r1}{\gamma\psi}\) 这一项来自 R1 正则:给判别器加惩罚 \(\tfrac\gamma2\,\mathbb E_{x\sim p_{\text{data}}}\|\nabla_x l(x)\|^2\),即判别器 logit 在真数据上的梯度平方。在 Dirac GAN 里 \(\nabla_xl=\psi\),惩罚就是 \(\tfrac\gamma2\psi^2\),它给旋转加上了阻尼。直觉上,R1 告诉判别器:“在真数据附近别太陡”,到了平衡点,判别器就没有理由偏离 \(\psi=0\)。γ 也不是越大越好:γ = 1 时约 140 步收敛到 2% 以内,γ = 2 反而要约 310 步(过阻尼)。WGAN-GP 的梯度惩罚、谱归一化都属于同一类“约束判别器斜率”的方法。

    一个想法,几种看法

    散度:判别器最优时,生成器在最小化 JS 散度(第 6 节);换一种判别器损失就换一种散度(f-GAN 给出整个 f-散度家族,WGAN 给出 Wasserstein 距离)。 分类:判别器是一个“真 vs 假”的二分类器,\(D^*\) 是贝叶斯最优分类器,它的 logit 正是密度比 \(\log(p_{\text{data}}/p_g)\):这一招(用分类器估计密度比)在 GAIL、AMP 和对比学习(18.3 节)里反复出现。 博弈:训练是寻找两人零和博弈的纳什均衡,梯度方法在这里会绕圈(FIG 5)。 学到的损失:判别器是一个随训练变化的、可微的“感知损失”,替代了逐像素 MSE,这也是它能让图像变清晰的原因。

    6再看数学

    提示:把鼠标悬停在公式中带底色的符号上,图中对应的元素会被高亮(FIG 1 的三条曲线,FIG 2 的点和箭头,FIG 3 的三条梯度曲线,FIG 5 的切线,FIG 6 的条件切片)。

    价值函数

    噪声 \(\mathbf z\sim p_z\)(这里是标准高斯),生成器 \(G_\theta\) 把它映射为样本,诱导出分布 \(p_g\);判别器 \(D_\phi(x)\in(0,1)\)。GAN 的目标是一个极小极大问题:

    $$ \min_\theta\max_\phi\ V(D_\phi,G_\theta)=\mathbb E_{x\sim \hl{pdata}{p_{\text{data}}}}\big[\log D_\phi(x)\big]+\mathbb E_{\mathbf z\sim p_z}\big[\hl{mm}{\log\big(1-D_\phi(G_\theta(\mathbf z))\big)}\big] $$

    对 \(\phi\) 而言这就是二分类交叉熵取负(真样本标签 1,假样本标签 0,16.1 节),所以“最大化 \(V\)”就是训练一个分类器。生成器只出现在第二项里。

    最优判别器与 JS 散度

    固定 \(G\),把第二项改写成对 \(p_g\) 的期望:\(V=\int\big[p_{\text{data}}(x)\log D(x)+p_g(x)\log(1-D(x))\big]dx\)。假设 \(D\) 可以是任意函数,就能逐点最大化:对 \(a\log y+b\log(1-y)\) 求导,\(a/y-b/(1-y)=0\) 得 \(y=a/(a+b)\),这就是第 2 节的 \(\hl{dstar}{D^*}\)。代回去:

    $$ V(D^*,G)=\mathbb E_{p_{\text{data}}}\Big[\log\frac{p_{\text{data}}}{p_{\text{data}}+p_g}\Big]+\mathbb E_{p_g}\Big[\log\frac{p_g}{p_{\text{data}}+p_g}\Big]=-\log4+2\,\mathrm{JS}(p_{\text{data}}\,\|\,p_g) $$ $$ \mathrm{JS}(p\,\|\,q)=\tfrac12\,D_{\mathrm{KL}}\big(p\,\|\,m\big)+\tfrac12\,D_{\mathrm{KL}}\big(q\,\|\,m\big),\qquad m=\tfrac12(p+q),\qquad 0\le\mathrm{JS}\le\log2 $$

    (在每个对数里乘上再除以 2,得到 \(-\log2\) 两次和两个对 \(m\) 的 KL。)KL 非负且只在两分布相同时为 0(4.11 节),所以 \(\mathrm{JS}\ge0\),等号当且仅当 \(p_g=p_{\text{data}}\):全局最优解唯一,就是生成器完美复制数据分布,此时 \(D^*=\tfrac12\)、\(V=-\log4\)(FIG 1 的第二个任务)。JS 对称、有界;两分布支撑不相交时它恒等于 \(\log2\),对参数的导数为零(FIG 1 的第一个任务、FIG 3)。这一切都假设判别器是“任意函数”且训练到了最优:真实的判别器是一个有限的网络,只走了几步,它近似的是一个被平滑过的 JS。

    生成器的梯度:穿过判别器的反向传播

    写 \(l_\phi(x)\) 为判别器的 logit,\(D=\sigma(l)\)。生成器损失 \(L_G=\mathbb E_{\mathbf z}[\ell(l_\phi(G_\theta(\mathbf z)))]\),由链式法则(2.2、16.3 节):

    $$ \nabla_\theta L_G=\mathbb E_{\mathbf z}\Big[\ell'(l)\,\Big(\frac{\partial G_\theta(\mathbf z)}{\partial\theta}\Big)^{\!\top}\hl{gradx}{\nabla_x l_\phi(x)}\Big|_{x=G_\theta(\mathbf z)}\Big] $$ $$ \ell=\log(1-\sigma(l)):\ \ \hl{mm}{\ell'(l)=-\sigma(l)=-D},\qquad \ell=-\log\sigma(l):\ \ \hl{ns}{\ell'(l)=-(1-D)} $$

    \(\ell'(l)\) 是每个样本的一个标量权重;转置的雅可比 \((\partial G/\partial\theta)^\top\) 乘一个向量,就是穿过 \(G\) 的向量-雅可比积(VJP,16.3 节)。实现上就是:判别器做一次前向、一次反向,但只要它对输入的梯度(R101.NN 的 backward 正好返回 \(\partial L/\partial x\)),把判别器自己累积的参数梯度丢掉;再把这个向量当作生成器输出的上游梯度做一次反向传播。两种损失的区别只在标量权重:原始损失乘 \(D\),非饱和损失乘 \(1-D\),FIG 2 的读数同时给出两者。Arjovsky 与 Bottou(2017)进一步指出,判别器最优时非饱和损失的梯度等于 \(\nabla_\theta\big[D_{\mathrm{KL}}(p_g\|p_{\text{data}})-2\,\mathrm{JS}\big]\):其中反向 KL 惩罚“在没有数据的地方放样本”,却几乎不惩罚“漏掉一个模式”(4.11 节的“抓峰”),这是模式坍缩的另一个来源。

    训练算法

    每次迭代:(1) 判别器做 \(k\) 步:采样一批真样本 \(\{x_i\}\) 和噪声 \(\{\mathbf z_i\}\),沿 \(\nabla_\phi\frac1n\sum_i\big[\log D(x_i)+\log(1-D(G(\mathbf z_i)))\big]\) 上升;(2) 生成器做 1 步:采样新的 \(\{\mathbf z_i\}\),沿 \(-\nabla_\theta\frac1n\sum_i\ell(l(G(\mathbf z_i)))\) 下降。原论文的实验取 \(k=1\),FIG 2 也是。DCGAN(Radford 等,2016)总结的经验,如 Adam 取 \(\beta_1=0.5\)(比默认的 0.9 少一些动量,因为“目标”一直在动),一直沿用至今,本页也这样设。两个网络的学习率可以不同(TTUR,Heusel 等,2017)。

    Wasserstein GAN

    Wasserstein-1 距离(“推土机距离”)是把一堆土 \(p\) 搬成 \(q\) 的最小平均搬运距离;Kantorovich-Rubinstein 对偶把它写成对所有 1-Lipschitz 函数 \(f\) 取上确界:

    $$ W(p_{\text{data}},p_g)=\inf_{\pi\in\Pi(p_{\text{data}},p_g)}\mathbb E_{(x,y)\sim\pi}\|x-y\|=\sup_{\|f\|_{L}\le1}\ \mathbb E_{p_{\text{data}}}[f(x)]-\mathbb E_{p_g}[\hl{wgan}{f(x)}] $$

    WGAN 用一个网络(“评论家”,输出不过 sigmoid)近似这个 \(f\),评论家最大化上式,生成器最小化 \(-\mathbb E_{\mathbf z}[f(G(\mathbf z))]\)。难点是 Lipschitz 约束:原文把权重裁剪到 \([-c,c]\)(粗糙,容量受限),WGAN-GP(Gulrajani 等,2017)改为惩罚 \(\lambda\,\mathbb E_{\hat x}\big(\|\nabla_{\hat x}f(\hat x)\|-1\big)^2\),\(\hat x\) 取在真假样本的连线上;谱归一化(Miyato 等,2018)则直接把每层权重除以它的最大奇异值(1.12 节)。FIG 3 里两个等宽高斯的最优评论家是线性函数 \(f(x)=\pm x\),所以梯度恒为 1,不论分布离得多远。注意梯度惩罚需要“对梯度再求梯度”(二阶反向传播),本页的小工具箱不支持,所以 FIG 2 只用了标准的两种损失。

    博弈动力学

    把两人的参数拼成 \(\mathbf w=(\phi,\theta)\),同时梯度法就是 \(\mathbf w\leftarrow\mathbf w+\eta\,\mathbf v(\mathbf w)\),\(\mathbf v=(\nabla_\phi V,\,-\nabla_\theta V)\)。在平衡点处,它的收敛性由 \(\mathbf v\) 的雅可比 \(J\) 的特征值 \(\lambda\) 决定:离散更新的放大倍数是 \(|1+\eta\lambda|\)。普通的最小化里 \(J\) 是负的 Hessian,特征值为实数且非正;零和博弈里 \(J\) 有反对称部分,特征值可以是纯虚数,于是 \(|1+\eta\lambda|=\sqrt{1+\eta^2|\lambda|^2}>1\),无论 η 多小都发散,只是慢一些。Dirac GAN 里 \(\lambda=\pm\tfrac i2\),同时更新每步放大 \(\sqrt{1+\eta^2/4}\)(η = 0.1 时 1.00125);交替更新的矩阵行列式为 1(γ = 0 时),特征值落在单位圆上;R1 把 \(J\) 的实部变成 \(-\gamma/2\),从而收敛。

    条件 GAN

    给两个网络都喂一个条件 \(c\)(类别、图像、机器人观测):\(G(\mathbf z,c)\)、\(D(x,c)\),目标中的期望变成对 \((x,c)\) 的联合期望(Mirza 与 Osindero,2014)。同样的推导给出 \(D^*(x,c)=p_{\text{data}}(x|c)/(p_{\text{data}}(x|c)+p_g(x|c))\),最优解是对每个 \(c\) 都有 \(p_g(\cdot|c)=p_{\text{data}}(\cdot|c)\):一个条件分布的采样器,而不是条件均值。pix2pix(Isola 等,2017)用它做图像到图像的翻译,下一节用它生成多模态动作 \(\hl{cond}{G(\mathbf z,c)}\)。

    7机器人中的它:绕开障碍物的两种方式

    一个移动机器人(或机械臂末端)要从下方走到上方,中间有一个障碍物,它的横向位置 \(c\) 每次不同。示教者有时从左绕、有时从右绕:障碍物偏右时多半从左绕(概率 \(\sigma(3c)\)),偏左时多半从右绕。示教给出的是经过障碍物那一行时的横向位置 \(a=c\pm0.8\)(加一点噪声)。这是一个典型的多模态条件分布 \(p(a\,|\,c)\),和 19.1 节 FIG 6 里条件 VAE 解决的是同一类任务;这里换成对抗训练,看 GAN 能否同样学出两个分支。下图同时训练两个模型:一个用 MSE 回归 \(a\)(就是 22.1 节的行为克隆),一个条件 GAN,\(G(\mathbf z,c)\) 是 2→24→24→1 的 MLP(1 维噪声加 1 维条件),\(D(a,c)\) 是 2→24→24→1。

    FIG 6条件 GAN 生成多模态动作,MSE 回归撞上障碍物
    左:横轴是障碍物位置 \(c\),纵轴是机器人经过障碍物时的横向位置 \(a\)。紫点是 300 条示教,灰色斜带是会撞上障碍物的区域 \(|a-c|<0.45\)(障碍物半径 0.3 加机器人半径 0.15),红线是 MSE 回归,琥珀点是条件 GAN 在 400 个 \((c,\mathbf z)\) 上的样本,青色竖线是滑块选中的 \(c\)。右:选中的 \(c\) 下的俯视场景,灰圆是障碍物,琥珀色是 16 条 cGAN 采样的路径,红色是 MSE 给出的路径。“碰撞率”在 \(c\in[-1,1]\) 的均匀网格上统计。
    • 按“训练”,直到 cGAN 的碰撞率低于 3% 而 MSE 的碰撞率仍高于 30%(默认种子约 800 次迭代)。再把 \(c\) 拖到 0 附近:MSE 的红色路径径直穿过障碍物,cGAN 的路径分成左右两束。

    MSE 的最优解是条件均值 \(\mathbb E[a|c]=c+0.8\,(1-2\sigma(3c))\),在 \(|c|<0.42\) 时都落在碰撞带里,所以无论训练多久它在约 42% 的 \(c\) 上都会撞。cGAN 学的是整个条件分布:它在两个分支之间偶尔留下几个“桥”上的样本(FIG 2 里的同一现象),这就是残余的那一点碰撞率。在 \(c=0.5\) 处,数据从左绕的比例是 \(\sigma(1.5)\approx0.82\);默认种子下 cGAN 学到的比例在 0.74 左右(读数实时给出),两个分支都有,但比例只是近似。多模态动作和它对模仿学习的意义,22.1 节和 22.2 节会再系统地比较 MSE、ACT 和 Diffusion Policy。

    真实系统里

    判别器当奖励:GAIL。Ho 与 Ermon(2016)的生成对抗模仿学习把策略当生成器、把“专家的状态-动作对 vs 策略的状态-动作对”的分类器当判别器,策略用强化学习最大化判别器给出的奖励,不需要手写奖励函数;它和逆强化学习的关系在 20.6 节展开。 判别器当风格奖励:AMP。Peng 等(2021)的对抗运动先验让判别器区分“动作捕捉数据里的状态转移”与“策略产生的状态转移”,把它的输出作为风格奖励,与任务奖励相加,仿真角色便能用自然的步态完成任务;Escontrela 等(2022)把同样的方法用在了四足机器人上,用它代替一堆手工调的步态奖励项。 sim-to-real 图像翻译。GraspGAN(Bousmalis 等,2018)用像素级的 GAN 域适应把仿真图像变得像真实图像,用于训练抓取网络,减少了所需的真实数据;RCAN(James 等,2019)用条件 GAN 把随机化纹理的仿真图像和真实图像都“翻译”到同一个规范化的仿真外观;RL-CycleGAN(Rao 等,2020)把 CycleGAN(Zhu 等,2017)与强化学习结合。 对抗损失作为组件:今天很多图像自编码器和 tokenizer(例如 VQGAN,以及潜在扩散模型使用的自编码器)在重建损失之外加一个基于图像块的判别器损失,让重建更清晰;这类编码器也出现在一些视频生成模型和世界模型里。不过在动作生成本身,扩散模型(19.6 节)和 flow matching(19.7 节)基本已经取代了 GAN,原因正是本节讲的训练稳定性和模式覆盖。

    8常见误区

    误区 1:把损失曲线当成进度

    GAN 的两个损失是一场博弈的两边,它们来回摆动是正常的,下降也不代表样本变好(判别器变弱时生成器损失同样会下降)。“\(D\approx\tfrac12\)”只说明判别器分不开,不说明样本覆盖了全部数据:一个坍缩到少数模式、但每个样本都很逼真的生成器,也可能让一个小判别器分不开。要用样本本身评估:看图,算精确率/召回率(FIG 2)或 FID(Heusel 等,2017),对机器人则直接看任务成功率。

    误区 2:判别器越强越好

    理论里判别器“训练到最优”,实践里一个过强、过尖的判别器正是麻烦的来源:用原始损失时梯度饱和(FIG 3),用非饱和损失时梯度又大又吵,而两个分布不重叠时 JS 根本没有方向信息。好的判别器是“平滑地对”的:限制它的斜率(R1、梯度惩罚、谱归一化)、给输入加噪声、不要让它领先太多。反过来,判别器太弱时生成器得不到有用的信号,样本会有明显瑕疵。

    误区 3:没注意到模式坍缩

    坍缩的样本单个看都很好,所以很容易被漏掉。对机器人来说后果很具体:一个只学会“从左边抓”的抓取生成器,在杯子左边被挡住时就无计可施。要显式检查覆盖率:召回率、每个模式的样本比例(FIG 2 的峰数、FIG 4 的柱状图),或在固定的若干条件下看样本的多样性。若覆盖最重要,优先考虑按似然训练的模型(VAE、flow、扩散)。

    误区 4:把博弈当成普通的最小化

    “学习率调小就会收敛”在 GAN 里不成立(FIG 5:纯虚特征值下同时更新对任何 η 都发散),动量会加剧绕圈(所以 DCGAN 把 Adam 的 \(\beta_1\) 降到 0.5)。实现上的小坑也来自博弈结构:生成器那一步要么冻结判别器参数,要么在反向传播后丢掉它累积的梯度,否则判别器会在生成器的那一步里被朝“帮生成器”的方向更新;判别器那一步里,假样本要从计算图中断开(PyTorch 里的 detach()),否则生成器也会被意外更新。

    误区 5:指望 GAN 给出概率

    GAN 是一个隐式模型:能采样,但不能算 \(p_g(x)\)。所以不能拿它来评估“这个动作在示教里有多常见”、做似然比检验,或者直接做异常检测。训练后的判别器也不是一个校准过的“真实度”打分器:生成器收敛时它理论上处处输出 ½。需要密度时选 flow(19.3 节,精确似然)、自回归模型(19.4 节)或 VAE(ELBO 下界),需要能量或打分时看 19.5 节的 EBM。

    9小练习

    1. 在某个 \(x\) 处,\(p_{\text{data}}(x)=0.3\),\(p_g(x)=0.1\)。最优判别器 \(D^*(x)\) 是多少?
    \(D^*=p_{\text{data}}/(p_{\text{data}}+p_g)=0.3/0.4=0.75\),选项 C。它是“落在 \(x\) 的样本是真品”的后验概率(两类先验相等时)。选项 A 忘了归一化,选项 D 是密度比本身,那是 \(D^*\) 的 logit 取指数:\(\log(0.75/0.25)=\log3\)。
    2. 生成器的分布与数据分布的支撑完全不重叠,判别器是最优的。用原始的 minimax 损失 \(\log(1-D(G(\mathbf z)))\),生成器得到的梯度怎样?
    选项 B。原始损失对 logit 的导数是 \(-D\),生成样本处 \(D^*=0\),而且 \(D^*\) 在那里是平的;从散度看,JS 在支撑不相交时恒为 \(\log 2\),对参数没有导数(FIG 1、FIG 3)。非饱和损失把权重换成 \(1-D\) 解决了前一半问题;Wasserstein 距离在这种情形下仍随距离线性变化,解决了后一半。
    3. 关于非饱和生成器损失 \(-\log D(G(\mathbf z))\),哪一项是对的?
    选项 D。两个损失对 logit 的导数分别是 \(-D\) 和 \(-(1-D)\),方向相同、权重相反(FIG 2 的读数、FIG 3)。最优点仍是 \(p_g=p_{\text{data}}\)(排除 A);它只改生成器的损失,不影响判别器(排除 B);模式坍缩来自对过时判别器的最优回应(FIG 4),换损失并不能消除它,判别器最优时非饱和损失甚至含有偏向“抓峰”的反向 KL 项(排除 C)。
    4. 判别器固定不动,只训练生成器很多步(非饱和损失)。生成器的分布会趋向什么?
    选项 A。\(-\mathbb E_{p_g}[\log D]=-\int p_g(x)\log D(x)\,dx\) 对 \(p_g\) 是线性的,在概率分布上取最小时把全部质量放在 \(\log D\) 最大处(FIG 4 的“冻结”)。只有判别器不断更新、与生成器保持同步时,博弈的平衡点才是 \(p_g=p_{\text{data}}\)。判别器固定时梯度一般不为零(排除 D),它指向 \(D\) 更高的地方。
    5. 在 Dirac GAN 里用同时梯度更新,平衡点处线性化的特征值是 \(\pm\tfrac i2\)。把学习率从 0.1 减到 0.01,会怎样?
    选项 C。离散更新的放大倍数是 \(|1+\eta\lambda|=|1\pm\tfrac{i\eta}2|=\sqrt{1+\eta^2/4}\),对任何 \(\eta>0\) 都大于 1;η = 0.01 时约为 1.0000125,每步只放大一点点,但永不收敛。要收敛需要改变 \(J\) 本身,例如 R1 给它加上负实部(FIG 5)。精确的圆周运动是连续时间的极限,不是任何有限步长的同时更新(排除 D)。

    10延伸阅读

    • I. Goodfellow, J. Pouget-Abadie, M. Mirza, B. Xu, D. Warde-Farley, S. Ozair, A. Courville & Y. Bengio, Generative Adversarial Nets, NeurIPS 2014 — 原始论文:极小极大目标、最优判别器、JS 散度与非饱和损失
    • I. Goodfellow, NIPS 2016 Tutorial: Generative Adversarial Networks, arXiv:1701.00160, 2017 — 作者本人的长篇教程,包括模式坍缩与 min max / max min 的讨论
    • A. Radford, L. Metz & S. Chintala, Unsupervised Representation Learning with Deep Convolutional Generative Adversarial Networks, ICLR 2016 — DCGAN:让卷积 GAN 稳定训练的一组经验规则
    • M. Arjovsky & L. Bottou, Towards Principled Methods for Training Generative Adversarial Networks, ICLR 2017 — 支撑不相交、梯度消失与非饱和损失的分析
    • M. Arjovsky, S. Chintala & L. Bottou, Wasserstein Generative Adversarial Networks, ICML 2017; I. Gulrajani, F. Ahmed, M. Arjovsky, V. Dumoulin & A. Courville, Improved Training of Wasserstein GANs, NeurIPS 2017 — WGAN 与梯度惩罚
    • L. Mescheder, A. Geiger & S. Nowozin, Which Training Methods for GANs do actually Converge?, ICML 2018 — Dirac GAN、博弈的局部收敛与 R1 正则
    • M. Mirza & S. Osindero, Conditional Generative Adversarial Nets, arXiv:1411.1784, 2014; P. Isola, J.-Y. Zhu, T. Zhou & A. A. Efros, Image-to-Image Translation with Conditional Adversarial Networks, CVPR 2017 — 条件 GAN 与 pix2pix
    • J. Ho & S. Ermon, Generative Adversarial Imitation Learning, NeurIPS 2016 — GAIL:判别器当奖励的模仿学习
    • X. B. Peng, Z. Ma, P. Abbeel, S. Levine & A. Kanazawa, AMP: Adversarial Motion Priors for Stylized Physics-Based Character Control, ACM Transactions on Graphics (SIGGRAPH), 2021 — 用判别器做动作风格奖励
    • K. Bousmalis et al., Using Simulation and Domain Adaptation to Improve Efficiency of Deep Robotic Grasping, ICRA 2018 — GraspGAN:用 GAN 做 sim-to-real 的像素级域适应
    • T. Kynkäänniemi, T. Karras, S. Laine, J. Lehtinen & T. Aila, Improved Precision and Recall Metric for Assessing Generative Models, NeurIPS 2019 — 把“像不像”和“全不全”分开评估(FIG 2 的读数是它的简化版)