这篇博客分为三部分,先介绍GAN的loss函数,以及它存在的问题;接下来第二节介绍WGAN的loss函数由来,以及实现细节;最后介绍在程序中使用最多的WGAN-GP的loss函数。
- 传统GAN的训练困难原因
传统GAN的Loss,该Loss有些不足的地方,导致了GAN的训练十分困难,表现为:
1、模式坍塌,即生成样本的多样性不足;
2、不稳定,收敛不了。
原因总结如下:
用KL Divergence和JS Divergence作为两个概率的差异的衡量,最关键的问题是若两个概率的支撑集不重叠,就无法让那个参数化的、可移动的概率分布慢慢地移动过来,以拟合目标分布。(即KL散度和JS散度在两个概率分布没有重叠的情况下,无法反应两者之间的差异性,因此无法进行学习优化。)
GAN的误差函数:
判别器D的loss函数:
判别器判断真实样本的得分D(x)越高越好,判断生成样本的得分D(G(Z))越低越好
生成器G的loss函数:
生成器的目标是生成的样本在判别器得分D (G(Z))越高越好。
- WGAN
Wasserstein Distance:(两个概率分布的距离衡量指标)
定义如下:
第一句话的解释很漂亮:
W(Pr,Pg)是这两个概率分布的距离,它是两个在同一空间上(维度相同)的随机变量x,y之差的范数均值的下确界。
下确界:某个集合X 的子集 E 的下确界(英语:infimum 或infima,记为inf E )是小于或等于的E 所有其他元素的最大元素,其不一定在E 內。
转化为
f(x)是函数集 中的一个函数。 表示满足1-Lipschitz条件的函数集。(Lipschitz条件是一个比通常连续更强的光滑性条件。直觉上,Lipschitz连续函数限制了函数改变的速度,符合利Lipschitz条件的函数的斜率,必小于一个称为Lipschitz常数的实数)。
用K-Lipschitz条件代替:
Sup指上确界,inf指下确界
式要求得到上确界,上确界的具体函数形式我们不知道,但我们可以用神经网络来逼近它,这是判别器(Discriminator)的作用,也就是Discriminator网络充当了f(x)的角色,因此(4)等价于:
其中, 是样本函数平均值
判别器D,目标是这个距离越大越好,
因此判别器的损失函数:
生成器只能调节生成器参数,不能调节判别器参数,因此
这个距离越小越好.
参考:https://blog.csdn.net/StreamRock/article/details/81138621
其中的pytorch源码,清楚地解释了如果在程序中得到判别器和生成器的loss,其中WGAN对权重进行了修剪:
# Clip weights of discriminator
for p in discriminator.parameters():
p.data.clamp_(-opt.clip_value, opt.clip_value)
要保证fθ(x)满足K-Lipschitz条件,夹逼了判别器的参数。
关于WGAN的loss函数,我发现这个总结更为精辟:
WGAN中,判别器D和生成器G的loss函数分别是:
- WGAN-GP
参考: https://blog.csdn.net/omnispace/article/details/77790497(解释很精彩)
大部分程序中采用WGAN-GP(Gradient penalty)。
在引入梯度惩罚项之前,先介绍采用参数夹逼的方式存在的两个问题:
- 判别器loss希望尽可能拉大真假样本的分数差,然而weight clipping独立地限制每一个网络参数的取值范围,在这种情况下我们可以想象,最优的策略就是尽可能让所有参数走极端,要么取最大值(如0.01)要么取最小值(如-0.01)。
这样带来的结果就是,判别器会非常倾向于学习一个简单的映射函数(想想看,几乎所有参数都是正负0.01,都已经可以直接视为一个二值神经网络了,太简单了)。而作为一个深层神经网络来说,这实在是对自身强大拟合能力的巨大浪费!判别器没能充分利用自身的模型能力,经过它回传给生成器的梯度也会跟着变差。
- 第二个问题,weight clipping会导致很容易一不小心就梯度消失或者梯度爆炸。原因是判别器是一个多层网络,如果我们把clipping threshold设得稍微小了一点,每经过一层网络,梯度就变小一点点,多层之后就会指数衰减;反之,如果设得稍微大了一点,每经过一层网络,梯度变大一点点,多层之后就会指数爆炸。只有设得不大不小,才能让生成器获得恰到好处的回传梯度,然而在实际应用中这个平衡区域可能很狭窄,就会给调参工作带来麻烦。相比之下,gradient penalty就可以让梯度在后向传播的过程中保持平稳。
既然判别器希望尽可能拉大真假样本的分数差距,那自然是希望梯度越大越好,变化幅度越大越好,所以判别器在充分训练之后,其梯度norm其实就会是在K附近。知道了这一点,我们可以把上面的loss改成要求梯度norm离K越近越好,效果是类似的:
简单地把K定为1,再跟WGAN原来的判别器loss加权合并,就得到新的判别器loss:
三个loss项均是期望的形式,在实际中通过采样的方式获得。前面两个期望的采样我们都熟悉,第一个期望是从真样本集里面采,第二个期望是从生成器的噪声输入分布采样后,再由生成器映射到样本空间。可是第三个分布要求我们在整个样本空间 上采样,这完全不科学!由于所谓的维度灾难问题,如果要通过采样的方式在图片或自然语言这样的高维样本空间中估计期望值,所需样本量是指数级的,实际上没法做到。
我们其实没必要在整个样本空间上施加Lipschitz限制,只要重点抓住生成样本集中区域、真实样本集中区域以及夹在它们中间的区域就行了。具体来说,我们先随机采一对真假样本,还有一个0-1的随机数:
在 和 的连线上随机插值采样,
· weight clipping是对样本空间全局生效,但因为是间接限制判别器的梯度norm,会导致一不小心就梯度消失或者梯度爆炸;
· gradient penalty只对真假样本集中区域、及其中间的过渡地带生效,但因为是直接把判别器的梯度norm限制在1附近,所以梯度可控性非常强,容易调整到合适的尺度大小。
这个采用点的获取可以用下图表示:
- 从真实数据 PdataPdata 中采样得到一个点
- 从生成器生成的数据 PGPG 中采样得到一个点
- 为这两个点连线
- 在线上随机采样得到一个点作为 Ppenalty的点。
注意:由于我们是对每个样本独立地施加梯度惩罚,所以判别器的模型架构中不能使用Batch Normalization,因为它会引入同个batch中不同样本的相互依赖关系。如果需要的话,可以选择其他normalization方法,如Layer Normalization、Weight Normalization和Instance Normalization,这些方法就不会引入样本之间的依赖。论文推荐的是Layer Normalization。