游戏力-读书简记 成功,动机与目标-读书简记 基因组:人种自传23章-读书简记 YOU身体使用手册-读书简记 登天之梯-读书简记 为什么学生不喜欢上学-读书简记 请停止无效努力-读书简记 麦肯基疗法-读书简记 跟简七学理财-课程简记 指数基金投资指南(2017中信版)-读书简记 指数基金投资指南(2015雪球版)-读书简记 让大脑自由:释放天赋的12条定律-读书简记 养育的选择-读书简记 GPU高性能编程CUDA实战-读书简记 百万富翁快车道-读书简记 原则-读书简记 穷查理宝典-读书简记 C++并发编程实战-读书简记 哲学家们都干了些什么-读书简记 Effective C++-读书简记 通往财富自由之路-读书简记 Linux命令行与Shell脚本编程大全-读书简记 刻意练习-读书简记 写给大家看的设计书-读书简记 习惯的力量-读书简记 好好学习-读书简记 硅谷最受欢迎的情商课-读书简记 富爸爸,穷爸爸-读书简记 如何说孩子才会听,怎么听孩子才会说-读书简记 阻力最小之路-读书简记 ProGit-读书简记 思考:快与慢-读书简记 C语言深度剖析-读书简记 编程珠玑-读书简记 Head First 设计模式-读书简记 反脆弱-读书简记 我的阅读书单 小强升职记-读书简记 观呼吸-读书简记 黑客与画家-读书简记 晨间日记的奇迹-读书简记 如何高效学习-读书简记 即兴的智慧-读书简记 精力管理-读书简记 C++编程思想-读书简记 拖延心理学-读书简记 自控力-读书简记 伟大是熬出来的-读书简记 生命不能承受之轻-读书简记 高效能人士的七个习惯-读书简记 没有任何借口-读书简记 一分钟的你自己-读书简记 人生不设限-读书简记 暗时间-读书简记
游戏力-读书简记 成功,动机与目标-读书简记 基因组:人种自传23章-读书简记 YOU身体使用手册-读书简记 登天之梯-读书简记 为什么学生不喜欢上学-读书简记 请停止无效努力-读书简记 麦肯基疗法-读书简记 跟简七学理财-课程简记 指数基金投资指南(2017中信版)-读书简记 指数基金投资指南(2015雪球版)-读书简记 让大脑自由:释放天赋的12条定律-读书简记 养育的选择-读书简记 GPU高性能编程CUDA实战-读书简记 百万富翁快车道-读书简记 原则-读书简记 穷查理宝典-读书简记 C++并发编程实战-读书简记 哲学家们都干了些什么-读书简记 Effective C++-读书简记 通往财富自由之路-读书简记 Linux命令行与Shell脚本编程大全-读书简记 刻意练习-读书简记 写给大家看的设计书-读书简记 习惯的力量-读书简记 好好学习-读书简记 硅谷最受欢迎的情商课-读书简记 富爸爸,穷爸爸-读书简记 如何说孩子才会听,怎么听孩子才会说-读书简记 阻力最小之路-读书简记 ProGit-读书简记 思考:快与慢-读书简记 C语言深度剖析-读书简记 编程珠玑-读书简记 Head First 设计模式-读书简记 反脆弱-读书简记 小强升职记-读书简记 观呼吸-读书简记 黑客与画家-读书简记 晨间日记的奇迹-读书简记 如何高效学习-读书简记 即兴的智慧-读书简记 精力管理-读书简记 C++编程思想-读书简记 拖延心理学-读书简记 自控力-读书简记 伟大是熬出来的-读书简记 生命不能承受之轻-读书简记 高效能人士的七个习惯-读书简记 没有任何借口-读书简记 一分钟的你自己-读书简记 人生不设限-读书简记 暗时间-读书简记

TensorFlow实现生成对抗网络GAN-翻译

2017年12月11日

写在前面


代码实现很有助于对算法的理解,看到了一篇很不错的博文,并根据博文使用TensorFlow实现了简单的GAN。文章很不错,原文地址点这里,下面是对其进行的翻译整理。


生成对抗网络(Generative Adversarial Nets,GAN)是一种非常流行的神经网络。它首先由Ian Goodfellow在2014年NIPS大会上发表。从论文被引用的次数中可以看出,该论文燃起了大家对神经网络中对抗学习的兴趣。一时之间,涌现出许多不同的GAN变形:DCGAN,Sequence-GAN,LSTM-GAN等。在NIPS 2016,甚至将会有一整场专门的对抗学习研讨会。

该文代码可以从这里得到。

下面首先让我们回顾一下论文的要点,之后我们会用TensorFlow来实现GAN,使用数据集MNIST进行测试。

生成对抗网络


让我们举一个假币制造商和警察的例子。假币制造商和警察各自的目标是什么呢?

◎ 一个成功的假币制造商会想尽方法骗过警察,使警察分不清假币与真币。

◎ 一个合格的警察会尽力分辨出假币和真币。

现在就产生了冲突。这种情况可以认为是博弈论中的最大最小游戏。这个过程称为对抗过程。

GAN是对抗过程的一个特例,它的组成(警察和假币制造商)是神经网络。第一个网络试图生成数据,第二个网络试图分辨出真实数据和第一个网络生成的伪造数据。第二个网络会输出表示真实数据概率的[0,1]之间的量。

在GAN中,第一个网络称为生成器G(Z),第二个网络称为判别器D(X)。

$$\min_G \max_D {\mathbb E}_{x\sim p_{\rm data}} \log D(x) + {\mathbb E}_{z\sim p_z}[\log (1-D(G(z)))] $$

在平衡点,也就是最大最小游戏中的最优点,第一个网络会生成真实数据,第二个网络输出的概率会是0.5,因为第一个网络生成了真实数据。

我们不禁会想“为什么要训练GAN呢?”,这是因为数据$P_{data}$的概率分布可能非常复杂,很难推断。所以使用对抗网络从分布$P_{data}$中生成样本而不用处理讨厌的概率分布问题会十分不错。如果我们拥有了这样的对抗网络,在另外需要数据$P_{data}$样本的情况下,我们能够很轻松的利用该网络生成这样的样本。

GAN的实现


根据GAN的定义我们需要两个网络。可以是任意的网络,比如卷积网络或仅仅是两层的感知器网络。首先我们使用简单的两层感知器网络。我们使用TensorFlow来实现这样的一个例子。

# Discriminator Net
X = tf.placeholder(tf.float32, shape=[None, 784], name='X')

D_W1 = tf.Variable(xavier_init([784, 128]), name='D_W1')
D_b1 = tf.Variable(tf.zeros(shape=[128]), name='D_b1')

D_W2 = tf.Variable(xavier_init([128, 1]), name='D_W2')
D_b2 = tf.Variable(tf.zeros(shape=[1]), name='D_b2')

theta_D = [D_W1, D_W2, D_b1, D_b2]

# Generator Net
Z = tf.placeholder(tf.float32, shape=[None, 100], name='Z')

G_W1 = tf.Variable(xavier_init([100, 128]), name='G_W1')
G_b1 = tf.Variable(tf.zeros(shape=[128]), name='G_b1')

G_W2 = tf.Variable(xavier_init([128, 784]), name='G_W2')
G_b2 = tf.Variable(tf.zeros(shape=[784]), name='G_b2')

theta_G = [G_W1, G_W2, G_b1, G_b2]

def generator(z):
    G_h1 = tf.nn.relu(tf.matmul(z, G_W1) + G_b1)
    G_log_prob = tf.matmul(G_h1, G_W2) + G_b2
    G_prob = tf.nn.sigmoid(G_log_prob)

    return G_prob


def discriminator(x):
    D_h1 = tf.nn.relu(tf.matmul(x, D_W1) + D_b1)
    D_logit = tf.matmul(D_h1, D_W2) + D_b2
    D_prob = tf.nn.sigmoid(D_logit)

    return D_prob, D_logit

以上代码中,generator(z)接受一个100维的矢量,输出一个784维的矢量(MNIST图片大小(28x28))。z是G(Z)的一个先验。在某种程度上,它学习了从先验空间到$P_{data}$的一个映射。

discriminator(x)接受MNIST图片作为输入,返回一个代表真实图片概率的张量。

现在让我们解释一下GAN的对抗过程。下面是论文中的训练算法:

G_sample = generator(Z)
D_real, D_logit_real = discriminator(X)
D_fake, D_logit_fake = discriminator(G_sample)

D_loss = -tf.reduce_mean(tf.log(D_real) + tf.log(1. - D_fake))
G_loss = -tf.reduce_mean(tf.log(D_fake))

上面我们对损失函数取负是因为它们需要最大化,而TensorFlow的优化器只能进行最小化。

另外根据论文的建议,最好最大化tf.reduce_mean(tf.log(D_fake)),而不是最小化tf.reduce_mean(1-tf.log(D_fake))。

接下来我们对生成网络和判别网络逐个进行对抗训练,损失函数利用上面提到的形式。

# Only update D(X)'s parameters, so var_list = theta_D
D_solver = tf.train.AdamOptimizer().minimize(D_loss, var_list=theta_D)
# Only update G(X)'s parameters, so var_list = theta_G
G_solver = tf.train.AdamOptimizer().minimize(G_loss, var_list=theta_G)

def sample_Z(m, n):
    '''Uniform prior for G(Z)'''
    return np.random.uniform(-1., 1., size=[m, n])

for it in range(1000000):
    X_mb, _ = mnist.train.next_batch(mb_size)

    _, D_loss_curr = sess.run([D_solver, D_loss], feed_dict={X: X_mb, Z: sample_Z(mb_size, Z_dim)})
    _, G_loss_curr = sess.run([G_solver, G_loss], feed_dict={Z: sample_Z(mb_size, Z_dim)})

这样我们就完成了!我们通过对G(Z)时而进行采样可以观察训练过程。如下图所示:

刚开始我们使用随机噪声作为输入,随着训练的进行,G(Z)开始越来越趋近$P_{data}$。从G(Z)生成的样本原来越像MNIST数据可以证实。

其他可选择的损失函数


我们可以使用不同的方法来表示D_loss和G_loss。让我们跟随直觉,这是受Brandon Amos关于图像修复的博文启示。

让我们想一想,discriminator(x)试图将所有的输出变为1,也就是我们想最大化真实数据的概率。而discriminator(G_sample)试图将所有的输出变为0,即D(G(Z))希望最小化伪造数据的概率。

那么generator(z)呢?它当然想最大化伪造数据的概率!它与D(G(Z))正相反!

因此,代码可以写成:

# Alternative losses:
D_loss_real = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(D_logit_real, tf.ones_like(D_logit_real)))
D_loss_fake = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(D_logit_fake, tf.zeros_like(D_logit_fake)))
D_loss = D_loss_real + D_loss_fake
G_loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(D_logit_fake, tf.ones_like(D_logit_fake)))

这里我们使用的是Logistic Loss。改变损失函数不会影响到GAN的训练,因为这只是思考和建模这个问题的不同方式而已。

小结


该篇文章首先介绍了Goodfellow等人在NIPS 2014提出的生成对抗网络GAN。我们研究了对抗过程的形成和它背后的直觉。

接下来,我们用两层神经网络实现了生成器和辨别器网络。然后我们遵循了Goodfellow,等人2014提出的算法来训练GAN。

最后,我们考虑了不同的方法来定义GAN损失函数。在替代损失函数中,我们直观地考虑了这两个网络,并利用逻辑损失来建立替代损失函数。

参考文献


[1] Goodfellow, Ian, et al. “Generative adversarial nets.” Advances in Neural Information Processing Systems. 2014.

[2] Image Completion with Deep Learning in TensorFlow

[3] 使用TensorFlow实现GAN


版权声明:本文为博主原创文章,转载请注明出处 本文总阅读量    次