GAN存在的问题
1.对于生成器-log(1-D(x))形式的损失函数, D在训练过程中不能训练太好, 网络难训练.(通过加噪声的方式, 可以得到改进)
2.对于生成器log(D(x))形式的损失函数, 模形易collapse mode, 训练过程中梯度不稳定.
3.没有衡量GAN训练进度的指标.
具体数学推导见 https://blog.youkuaiyun.com/bolun365/article/details/102790786
DCGAN
通过以下3个改进项增强了G网络的学习能力.
1.使用微步卷积代替上采样层和全连接层
2.生成器G和判别器D中几乎每一层都使用batchnorm层,将特征层的输出归一化到一起,加速了训练,提升了训练的稳定性。(生成器的最后一层和判别器的第一层不加batchnorm)
3.在判别器中使用leakrelu激活函数,而不是RELU,防止梯度稀疏,生成器中仍然采用relu,但是输出层采用tanh
WGAN
改进点
1.判别器最后一层去掉sigmoid
2.生成器和判别器的loss不取log
3.对更新后的权重强制截断到一定范围内,比如[-0.01,0.01], 以满足论文中提到的lipschitz连续性条件。作者认为D网络所有的参数在这个范围后, 输入样本的导数也会在某个范围, 因此一定能找到相应的K值.
4.论文中也推荐使用SGD, RMSprop等优化器,不要基于使用动量的优化算法,比如adam
WGAN改进意义
1.使用wassertein距离去衡量生成数据分布和真实数据分布之间的距离,理论上解决了训练不稳定的问题。
2.解决了模式崩溃的(collapse mode)问题,生成结果多样性更丰富。
3.对GAN的训练提供了一个指标, 判别器loss越大, 训练越好
WGAN不足
cut权重的方式, 不能充分发挥深度神经网络的拟合能力, 容易导致梯度消失或者梯度爆炸.
代码diff gan
102,103c99,102
< d_loss_real = - tf.reduce_mean(D_real_logits)
< d_loss_fake = tf.reduce_mean(D_fake_logits)
---
> d_loss_real = tf.reduce_mean(
> tf.nn.sigmoid_cross_entropy_with_logits(logits=D_real_logits, labels=tf.ones_like(D_real)))
> d_loss_fake = tf.reduce_mean(
> tf.nn.sigmoid_cross_entropy_with_logits(logits=D_fake_logits, labels=tf.zeros_like(D_fake)))
108c107,108
< self.g_loss = - d_loss_fake
---
> self.g_loss = tf.reduce_mean(
> tf.nn.sigmoid_cross_entropy_with_logits(logits=D_fake_logits, labels=tf.ones_like(D_fake)))
123,125d122
< # weight clipping
< self.clip_D = [p.assign(tf.clip_by_value(p, -0.01, 0.01)) for p in d_vars]
WGAN-GP
改进意义:
1.避免WGAN直接cut造成大部分权重都在-0.01和+0.01上
2.避免cut值设置不合理造成的梯度消失或爆炸
改进原理:
1.直接对x求梯度
2.使用真假差值混合样本, 来产生梯度, 这时网络的更新梯度应该比用真或者用假样本大得多. 所以梯度是接近WGAN中的K值的, 这里K取1, 也是就tf.reduce_mean((slopes - 1.) ** 2)中的1.
3.tf.reduce_mean((slopes - 1.) ** 2)的第二个功能为, 当梯度大于K时, 限制梯度.起到Lipschitz限制的作用.
注意项:
D网络不能使用batch normalization,因为这会引入通过batch中不同样本的依赖关系
比WGAN增加代码
alpha = tf.random_uniform(shape=self.inputs.get_shape(), minval=0.,maxval=1.)
differences = G - self.inputs # This is different from MAGAN
interpolates = self.inputs + (alpha * differences)
_,D_inter,_=self.discriminator(interpolates, is_training=True, reuse=True)
gradients = tf.gradients(D_inter, [interpolates])[0]
slopes = tf.sqrt(tf.reduce_sum(tf.square(gradients), reduction_indices=[1]))
gradient_penalty = tf.reduce_mean((slopes - 1.) ** 2)
self.d_loss += self.lambd * gradient_penalty