查看全课大纲(第 92 / 93 节)
  1. 1.计算机视觉概述
  2. 2.计算机视觉应用场景
  3. 3.困难与挑战
  4. 4.开源库介绍
  5. 5.图像显示与存储
  6. 6.CLAHE
  7. 7.腐蚀膨胀与开闭运算
  8. 8.滤波与边缘填充
  9. 9.各种滤波
  10. 10.图像金字塔
  11. 11.傅里叶变换
  12. 12.短时傅里叶变换与小波变换
  13. 13.颜色特征与颜色直方图
  14. 14.几何特征_边缘
  15. 15.几何特征-角点与斑点
  16. 16.局部特征-SIFT特征描述子
  17. 17.局部特征-SURF特征描述子
  18. 18.局部特征-ORB特征描述子
  19. 19.其他特征描述子
  20. 20.传统图像分割技术
  21. 21.GraphCut
  22. 22.GrabCut
  23. 23.人脸检测的传统方法
  24. 24.行人检测的传统方法HOG+SVM
  25. 25.行人检测DPM
  26. 26.人工神经网络的架构
  27. 27.目标函数与梯度下降
  28. 28.误差反向传播
  29. 29.可手算的神经网络
  30. 30.改进目标函数与克服梯度消散
  31. 31.神经网络之传统神经网络与深度网络的差异
  32. 32.各种梯度下降算法
  33. 33.如何选择合适的梯度下降算法
  34. 34.避免过适应
  35. 35.CNN的架构
  36. 36.CNN的误差反向传播_卷积层
  37. 37.CNN的误差反向传播_池化层
  38. 38.分类所用的数据集
  39. 39.Alexnet详解
  40. 40.VGG详解
  41. 41.GoogLeNet_v1
  42. 42.BatchNormalization
  43. 43.GoogLeNet_v3v4
  44. 44.ResNet
  45. 45.ResNeXt
  46. 46.CNN设计准则
  47. 47.图像检索与推土机距离
  48. 48.基于颜色相似性
  49. 49.基于形状相似性
  50. 50.基于纹理相似性
  51. 51.基于局部特征相似性
  52. 52.DL的二值哈希编码
  53. 53.高维空间中检索KDTree
  54. 54.高维空间中检索LSH
  55. 55.目标识别任务综述
  56. 56.RCNN
  57. 57.SPP-Net
  58. 58.Fast R-CNN
  59. 59.Faster R-CNN
  60. 60.R-CNN系列模型回顾
  61. 61.R-FCN的设计思路
  62. 62.R-FCN的实现
  63. 63.YOLOv1
  64. 64.YOLOv2_9000
  65. 65.YOLOv3
  66. 66.图像分割应用场景与数据集
  67. 67.上采样的实现方式
  68. 68.FCN网络架构的由来
  69. 69.FCN构建细节
  70. 70.DeepLabv1
  71. 71.CRF
  72. 72.DeepLabv2
  73. 73.DeepLabv3
  74. 74.特定的医学影像分割任务
  75. 75.U-Net
  76. 76.3D U-Net
  77. 77.V-Net
  78. 78.DenseNet
  79. 79.病理切片分析任务及数据集
  80. 80.病理切片分析
  81. 81.图说任务及其传统处理方法
  82. 82.深度语言模型与RNN
  83. 83.LSTM及其变种
  84. 84.NIC模型
  85. 85.SAT模型
  86. 86.图说的性能指标
  87. 87.判别模型与生成模型
  88. 88.KL散度与JS散度
  89. 89.VAE
  90. 90.GAN的基本原理
  91. 91.DCGAN与CGAN
  92. 92.Wasserstein GAN
  93. 93.SRGAN

Wasserstein GAN

小象实战讲义 · 基于深度学习的计算机视觉

在上一节我们探讨了DCGAN,它通过一系列精妙的工程技巧显著提升了GAN的训练稳定性和生成效果。然而,这些技巧更像是“实验出来的”,缺乏坚实的理论支撑。为什么原始GAN的训练如此困难?为什么会出现模式崩溃?这些问题需要一个根本性的理论解答。本节我们将学习Wasserstein GAN (WGAN),它从理论层面剖析了原始GAN的核心缺陷,并引入Wasserstein距离作为新的度量,从根本上解决了训练不稳定与梯度消失的问题,并基本解决了模式崩溃。值得一提的是,Arjovsky 先写一篇论文论证原始GAN“病在哪”,第二篇论文才给出解法,本节的展开顺序也正对应这两篇工作。学完本节,你将理解WGAN仅通过四点“微小”改动,就实现了GAN训练的革命性进步。

💡 核心导读

  • 理论溯源:深入分析原始GAN在最优判别器下,生成器损失函数与JS散度的关系,揭示其梯度消失和优化目标荒谬的理论根源。
  • 新度量登场:理解Wasserstein距离(推土机距离) 相比KL散度和JS散度的核心优势——即便两个分布没有重叠,它也能提供连续、有意义的梯度信号。
  • 四点改动:掌握WGAN对原始GAN的四项具体修改:去掉判别器最后一层的Sigmoid、损失函数不取对数、对判别器参数进行权重裁剪、使用不带动量的优化器,并理解每一项修改背后的理论依据。
  • 显著优势:了解WGAN带来的革命性改进:训练过程稳定、有明确的指标(Wasserstein距离)指导训练、无需精心设计网络结构也能有效工作,并基本解决了模式崩溃问题。

原始GAN的理论困境回顾

在深入WGAN之前,我们必须先理解原始GAN到底“病”在哪里。Goodfellow提出的原始GAN,其价值函数(Value Function)为:

min⁡Gmax⁡DV(D,G)=Ex∼pdata(x)[log⁡D(x)]+Ez∼pz(z)[log⁡(1−D(G(z)))]\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)))]

其中,pdatap_{data}是真实数据分布,pgp_g是生成器GG定义的分布。判别器DD的目标是最大化这个函数,以区分真实和生成样本;生成器GG的目标是最小化它,以欺骗判别器。

理论分析表明,对于固定的生成器GG,最优判别器D∗D^* 为:

D∗(x)=pdata(x)pdata(x)+pg(x)D^*(x) = \frac{p_{data}(x)}{p_{data}(x) + p_g(x)}

这个式子的含义很直白:分母是“真实样本密度 + 生成样本密度”构成的全集,分子只取真实样本那一部分,因此D∗(x)D^*(x)恰好是“该样本来自真实数据”的概率——在所有判别器中,它把真实样本与生成样本分得最开。

将这个最优判别器D∗D^*代回生成器的优化目标中,会发生什么呢?Goodfellow在原始论文中实际上给出了两种生成器损失函数形式。

第一种形式(最小化判别器判断为假的概率): LG(1)=Ez∼pz(z)[log⁡(1−D∗(G(z)))]L_G^{(1)} = \mathbb{E}_{z \sim p_z(z)}[\log (1 - D^*(G(z)))]

需要说明的是,单看 LG(1)L_G^{(1)} 这一项并不能直接化成 JS 散度(它等于 KL(pg∥M)−log⁡2KL(p_g \Vert M) - \log 2,其中 M=12(pdata+pg)M=\frac{1}{2}(p_{data}+p_g))。JS 散度的等价式属于完整的价值函数:把 D∗D^* 同时代回判别器那一项,可以证明 V(G,D∗)=Ex∼pdata[log⁡D∗(x)]+Ez∼pz(z)[log⁡(1−D∗(G(z)))]=2⋅JS(pdata∥pg)−2log⁡2V(G, D^*) = \mathbb{E}_{x \sim p_{data}}[\log D^*(x)] + \mathbb{E}_{z \sim p_z(z)}[\log (1 - D^*(G(z)))] = 2 \cdot JS(p_{data} \Vert p_g) - 2\log 2 也就是说,在最优判别器下,价值函数恰好是真实分布pdatap_{data}与生成分布pgp_g之间JS散度(Jensen-Shannon Divergence) 的线性函数。这里不能把 Ex∼pdata[log⁡D∗(x)]\mathbb{E}_{x \sim p_{data}}[\log D^*(x)] 当作“与 GG 无关的常数”略去:D∗D^* 里含 pgp_g,这一项随 GG 变化。因此,在最优判别器下,最小化生成器目标等价于最小化两个分布的 JS 散度。

这里,JS(p∥q)=12KL(p∥p+q2)+12KL(q∥p+q2)JS(p \Vert q) = \frac{1}{2} KL(p \Vert \frac{p+q}{2}) + \frac{1}{2} KL(q \Vert \frac{p+q}{2}),KLKL是KL散度。

第二种形式(最大化判别器判断为真的概率): 由于log⁡(1−D(G(z)))\log(1-D(G(z)))在训练早期梯度很小,Goodfellow提出改为最大化D(G(z))D(G(z)),即: LG(2)=−Ez∼pz(z)[log⁡D∗(G(z))]L_G^{(2)} = -\mathbb{E}_{z \sim p_z(z)}[\log D^*(G(z))]

同样地,把 D∗D^* 代回后可以推出: LG(2)=KL(pg∥pdata)−2⋅JS(pdata∥pg)+Ex∼pdata[log⁡D∗(x)]+2log⁡2L_G^{(2)} = KL(p_g \Vert p_{data}) - 2 \cdot JS(p_{data} \Vert p_g) + \mathbb{E}_{x \sim p_{data}}[\log D^*(x)] + 2\log 2 最后一项 Ex∼pdata[log⁡D∗(x)]\mathbb{E}_{x \sim p_{data}}[\log D^*(x)] 同样随 pgp_g(也就是随 GG)变化,不是可以随意丢弃的常数。

问题根源:JS散度与KL散度的缺陷

上述推导将GAN的对抗训练,与衡量两个分布差异的散度(JS和KL)联系了起来。问题就出在这些散度度量本身。

  1. JS散度的梯度消失问题(对应LG(1)L_G^{(1)}): 当两个分布pdatap_{data}和pgp_g的支撑集(support,即概率非零的区域)没有重叠或者重叠部分可忽略不计时,它们的JS散度会等于一个常数:log⁡2\log 2。

    • 为什么没有重叠的概率很大? 直观理解,pdatap_{data}是高维空间中的一个低维流形(比如所有真实人脸图像的分布),而初始的pgp_g(来自随机噪声)是另一个低维流形。两个低维流形在高维空间中“撞上”的概率极低——就像平面上的两条任意曲线,即便相交也只是有限个点,长度(测度)为0;三维空间中的两张曲面即使相交,交出的也只是一条曲线,面积(测度)为0,同样可以认为没有重叠。
    • 后果:此时按上式 V(G,D∗)=2⋅log⁡2−2log⁡2=0V(G, D^*) = 2 \cdot \log 2 - 2\log 2 = 0,且对生成器参数的梯度为0。生成器无法获得有效的梯度来更新自己,训练停滞,这就是梯度消失。
  2. KL散度导致的优化目标荒谬与模式崩溃(对应LG(2)L_G^{(2)}): LG(2)L_G^{(2)}的目标是同时最小化KL(pg∥pdata)KL(p_g \Vert p_{data})和最大化JS(pdata∥pg)JS(p_{data} \Vert p_g),这本身就是一个矛盾的目标。 更严重的是,KL散度是不对称的。KL(pg∥pdata)KL(p_g \Vert p_{data})惩罚的是“生成器生成了不真实的样本”(即pgp_g在pdatap_{data}为零的地方不为零),惩罚极重;而对于“生成器没能生成某些真实样本”(即pdatap_{data}在某些地方不为零而pgp_g为零),惩罚却很轻。

    • 后果:生成器为了最小化KL(pg∥pdata)KL(p_g \Vert p_{data}),会倾向于生成“安全”的、重复的样本,避免因生成不真实的样本而受到巨大惩罚。这直接导致了模式崩溃(Mode Collapse)——生成样本多样性急剧下降。

因此,原始GAN训练困难的本质是:判别器训练得太好,JS散度饱和导致生成器梯度消失;判别器训练得不好,梯度不准,生成器乱学。需要小心翼翼地平衡两者,而这个“火候”极难掌握。

Wasserstein距离:一个更好的分布度量

为了克服JS散度和KL散度的缺陷,WGAN的作者Martin Arjovsky等人引入了Wasserstein距离,也称为推土机距离(Earth Mover’s Distance, EMD)。Arjovsky 在 2017 年的《Wasserstein GAN》中正式提出这一方案。

直观理解:想象有两个土堆,分布pp和qq。Wasserstein距离衡量的是,将分布pp的“土”搬运成分布qq的形状,所需要的最小“工作量”(土方量乘以运输距离)。

数学定义(简化):对于两个分布pp和qq,其1阶Wasserstein距离定义为: W(p,q)=inf⁡γ∈Π(p,q)E(x,y)∼γ[∥x−y∥]W(p, q) = \inf_{\gamma \in \Pi(p, q)} \mathbb{E}_{(x, y) \sim \gamma} [\Vert x - y \Vert ] 其中,Π(p,q)\Pi(p, q)是所有以pp和qq为边缘分布的联合分布γ(x,y)\gamma(x, y)的集合。γ\gamma可以理解为一种“运输方案”。

Wasserstein距离的关键优势:

  • 即使分布没有重叠,它也能提供有意义的距离。两个分布哪怕完全不重合,只要它们“靠近”,W距离就会小;远离,W距离就会大。这解决了JS散度在无重叠时恒为常数的问题。
  • 它是一个连续的度量。W距离随分布的变化是平滑的,能提供稳定的梯度信号,非常适合作为优化目标。

然而,直接计算Wasserstein距离是非常困难的。幸运的是,根据Kantorovich-Rubinstein对偶性,它可以转化为一个更易处理的形式: W(p,q)=sup⁡∥f∥L≤1(Ex∼p[f(x)]−Ex∼q[f(x)])W(p, q) = \sup_{\Vert f \Vert _L \leq 1} \left( \mathbb{E}_{x \sim p}[f(x)] - \mathbb{E}_{x \sim q}[f(x)] \right) 其中,上确界(sup⁡\sup,可理解为最大值)是在所有满足1-Lipschitz连续的函数ff中取的。

Lipschitz连续:存在一个常数KK,使得对于定义域内任意x1,x2x_1, x_2,都有∣f(x1)−f(x2)∣≤K⋅∣x1−x2∣|f(x_1) - f(x_2)| \leq K \cdot |x_1 - x_2|。当K=1K=1时,就是1-Lipschitz连续。直观上,它限制了函数ff的变化速度不能太快。

这个对偶形式告诉我们:Wasserstein距离等于,在所有变化不太快(1-Lipschitz)的函数ff中,真实分布和生成分布在ff下的期望之差的最大值。

WGAN的算法实现

如何利用这个对偶形式来构建GAN呢?WGAN的做法非常巧妙:

  1. 用判别器网络DD来拟合函数ff。在WGAN中,判别器不再是一个二分类器,而是一个拟合对偶式中函数ff的回归器(因此常被称为评论家,Critic)。它的目标是最大化 Ex∼pdata[D(x)]−Ez∼pz[D(G(z))]\mathbb{E}_{x \sim p_{data}}[D(x)] - \mathbb{E}_{z \sim p_z}[D(G(z))];而由对偶式可知,这个期望差本身就是对W距离的估计。
  2. 对判别器DD施加Lipschitz约束。为了满足对偶形式中ff需要是1-Lipschitz连续的条件,WGAN提出了一个简单而有效的约束方法:权重裁剪(Weight Clipping)。即强制判别器所有参数ww的绝对值不超过一个固定常数cc(例如c=0.01c=0.01)。每次参数更新后,都执行:w←clip(w,−c,c)w \leftarrow \text{clip}(w, -c, c)。

基于以上两点,WGAN的算法流程和损失函数就确定了。对比原始GAN,它只做了以下四点改动:

改动一:判别器最后一层去掉Sigmoid

原始GAN的判别器做二分类,输出概率,所以用Sigmoid。WGAN的判别器是回归器,输出一个分数(score),用于计算Wasserstein距离,因此去掉最后一层的Sigmoid激活函数。

改动二:生成器和判别器的损失函数不取log

原始GAN的损失函数包含log⁡D(x)\log D(x)和log⁡(1−D(G(z)))\log(1-D(G(z)))。作者给出的解释是:log⁡\log的导数1/x1/x在x→0x \to 0时无上界,与Lipschitz约束(要求变化率有界)相冲突。因此WGAN直接使用判别器的原始输出值来构造损失。

  • 判别器损失:LD=−Ex∼pdata[D(x)]+Ez∼pz[D(G(z))]L_D = -\mathbb{E}_{x \sim p_{data}}[D(x)] + \mathbb{E}_{z \sim p_z}[D(G(z))] (判别器希望最大化真实样本的分数,最小化生成样本的分数,因此取负号用于梯度下降)
  • 生成器损失:LG=−Ez∼pz[D(G(z))]L_G = -\mathbb{E}_{z \sim p_z}[D(G(z))] (生成器希望生成样本能获得高的判别器分数)

改动三:每次更新判别器参数后,进行权重裁剪

这是为了近似地满足判别器函数的1-Lipschitz连续性约束。虽然方法简单,但在实践中被证明是有效的。

改动四:推荐使用不带动量的优化器

原始GAN的优化目标是寻找一个鞍点(Saddle Point)。带动量的优化器(如Momentum、Adam)设计初衷之一是帮助模型逃离鞍点。但WGAN的目标是稳定地停留在那个鞍点(纳什均衡点)。因此,作者推荐使用Hinton提出的RMSProp(只保留自适应学习率这一“二阶”部分,不带一阶动量),退一步用普通SGD也可以,关键是不要“带冲量”,以免因“冲过头”而带来不稳定性。

下面我们用一段伪代码来展示WGAN的核心训练循环,并与原始GAN进行对比。

# 伪代码:WGAN 训练循环(对比原始GAN)
# 仅示意算法流程,不可直接运行;d_loss / g_loss 用 PyTorch 风格书写。

# 超参数
n_critic = 5  # 判别器更新次数 : 生成器更新次数 = 5 : 1
clip_value = 0.01

for epoch in range(num_epochs):
    for batch in data_loader:
        # --- 训练判别器 D (Critic) ---
        for _ in range(n_critic):
            real_data = batch  # 示意:真实实现中每次更新判别器都取新的一批真实样本
            noise = sample_noise(batch_size)
            fake_data = generator(noise)
            
            # WGAN 判别器损失
            d_loss = -torch.mean(discriminator(real_data)) + torch.mean(discriminator(fake_data))
            # 原始GAN判别器损失 (对比):
            # d_loss = -torch.mean(torch.log(discriminator(real_data) + eps)) 
            #          - torch.mean(torch.log(1 - discriminator(fake_data) + eps))
            
            optimizer_D.zero_grad()
            d_loss.backward()
            optimizer_D.step()
            
            # WGAN 特有: 权重裁剪
            for p in discriminator.parameters():
                p.data.clamp_(-clip_value, clip_value)
        
        # --- 训练生成器 G ---
        noise = sample_noise(batch_size)
        fake_data = generator(noise)
        
        # WGAN 生成器损失
        g_loss = -torch.mean(discriminator(fake_data))
        # 原始GAN生成器损失 (对比):
        # g_loss = -torch.mean(torch.log(discriminator(fake_data) + eps)) # 第二种形式
        
        optimizer_G.zero_grad()
        g_loss.backward()
        optimizer_G.step()

WGAN的优势与实验效果

WGAN的这些改动带来了革命性的优势:

  1. 训练稳定性极大提升:不再需要小心平衡生成器和判别器的训练程度。判别器可以(也应该)训练到接近最优,因为它给出的Wasserstein距离估计越准,生成器获得的梯度信号就越可靠。
  2. 基本解决模式崩溃:W距离按“搬土”的实际代价衡量差异,对“漏掉某些真实模式”和“生成不真实样本”给出的是同一套距离意义下的惩罚,不存在KL散度那种“重准确性、轻多样性”的倾斜,生成器也就没有动机只生成单一模式。在原论文及后续报道的实验里,几乎观察不到模式崩溃。
  3. 有意义的训练监控指标:判别器损失(的负数)可以看作是Wasserstein距离的估计值。这个值在训练过程中会(理论上应该)不断下降,其大小直观反映了生成样本的质量。我们终于有了一个像分类准确率那样明确的指标来指导训练何时停止。
  4. 对网络架构不敏感:WGAN不需要像DCGAN那样精心设计网络结构(如特定的层数、学习率、BatchNorm的使用等)。即使是简单的多层感知机(MLP),也能稳定训练并产生不错的结果。

下图示意了训练过程中,Wasserstein距离估计值与生成图像质量的关系:

训练阶段: 早期 | W距离估计: 高       | 生成图像: 接近噪声
训练阶段: 中期 | W距离估计: 持续下降 | 生成图像: 出现模糊轮廓
训练阶段: 后期 | W距离估计: 低       | 生成图像: 清晰、接近真实

(随着训练进行,W距离估计值下降,生成图像质量提升)

📝 动手练一练

  1. 概念辨析:为什么WGAN的作者认为原始GAN的第二种生成器损失函数 LG(2)=−E[log⁡D(G(z))]L_G^{(2)} = -\mathbb{E}[\log D(G(z))] 的优化目标是“荒谬”的?请从KL散度和JS散度的角度简要说明。
👉 点击查看参考答案

在最优判别器下,最小化 LG(2)L_G^{(2)} 对应的是 KL(pg∥pdata)−2⋅JS(pdata∥pg)KL(p_g \Vert p_{data}) - 2 \cdot JS(p_{data} \Vert p_g) 与一个随 pgp_g 变化的项之和。这个目标同时包含 KL(pg∥pdata)KL(p_g \Vert p_{data}) 和 −JS(pdata∥pg)-JS(p_{data} \Vert p_g)。前者要求 pgp_g 向 pdatap_{data} 靠近,后者却要求 JSJS 散度变大,即 pgp_g 远离 pdatap_{data}。这两个目标相互矛盾,因此被称为“荒谬”的优化目标。此外,KLKL 散度的不对称性导致生成器更害怕生成不真实的样本(惩罚重),而不怕缺失多样性(惩罚轻),从而诱发模式崩溃。

  1. 代码思考:在WGAN的权重裁剪操作中,如果将裁剪阈值 clip_value 设置得过大(比如10)或过小(比如0.0001),可能会对训练产生什么影响?请结合Lipschitz约束的概念进行分析。
👉 点击查看参考答案
  • 裁剪阈值过大(如10):相当于几乎没有施加有效的Lipschitz约束。判别器函数的变化速度可能不受控制,导致其对偶形式中要求的1-Lipschitz连续性无法满足,最终无法准确逼近Wasserstein距离,训练可能变得不稳定,失去WGAN的理论保障优势。
  • 裁剪阈值过小(如0.0001):对判别器网络的容量限制过于严格,可能导致其表达能力严重不足,无法拟合一个足够复杂的函数来有效区分真实和生成分布,即无法准确估计W距离。这会使得生成器获得的梯度信号非常弱,训练缓慢甚至无法收敛。在实践中,clip_value通常设置为0.01左右,需要根据具体任务进行微调。

本章小结

Wasserstein GAN是GAN发展史上的一个里程碑。它不再依赖网络结构上的经验技巧,而是从分布度量的理论高度,直指原始GAN训练不稳定的核心矛盾——JS散度和KL散度在分布无重叠时的失效。通过引入具有良好性质的Wasserstein距离,并巧妙地利用其对偶形式和权重裁剪来实现,WGAN仅用四点简洁的修改,就实现了训练稳定性、样本多样性和训练可监控性的巨大飞跃。

需要如实定位的是:权重裁剪只是一个便于实现的近似手段,它会把参数推向边界、压缩判别器的表达能力,因此很快被WGAN-GP的梯度惩罚(2017)和谱归一化(2018)等更精细的Lipschitz约束取代;而2020年DDPM之后,图像生成的主流已转向扩散模型,WGAN在今天更多是理解“用分布距离指导训练”这一思想的经典范例,而非首选方案。

📋 行动清单

  • 理解原始GAN的损失函数在最优判别器下与JS/KL散度的等价关系,及其导致的梯度消失和模式崩溃问题。
  • 掌握Wasserstein距离(推土机距离)的直观含义及其相对于JS/KL散度的核心优势。
  • 记住WGAN对比原始GAN的四点具体改动,并能解释每一项改动背后的原因(如:为什么去掉Sigmoid?为什么要权重裁剪?)。
  • 运行一个简单的WGAN示例(例如在MNIST数据集上),观察判别器损失(W距离估计)随训练下降的过程,并与生成图像质量的变化相关联。

—— 小象教研组