Generative Adversarial Network

这里我们将建立 一个对抗生成网络 (GAN)训练MNIST,并在最后生成新的手写数字。

这里先介绍几个Demo:

Pix2pix 基本上就是你画一个东西它就能生成类似的图片

Pix2pix生成的猫

CycleGAN 这里视频可以让马看起来像斑马。

gan_diagram

GAN背后的思想是你有一个生成器和辨别器,它们都处在这样的一个博弈中,生成器产生假图像,比如假数据,让它看起来更像真数据,然后辨别器努力辨识该数据是真或是假。所以生成器将假数据传递给辨别器,而你将真数据传递给辨别器,然后由辨别器判定它是真是假。当你在训练时,生成器会学习生成图像和数据,让它们看起来尽量与真实数据一样,在这个过程中它会模仿实际真实数据的概率分布,通过这种方式,你可以生成与真实世界中看起来一样的新图像、新数据。 这里导入包和数据集

%matplotlib inline

import pickle as pkl
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets('MNIST_data')

模型输入

这里创建两个输入,辨别器的输入为inputs_real,生成器的输入为inputs_z。

def model_inputs(real_dim, z_dim):
    inputs_real = tf.placeholder(tf.float32,(None ,real_dim),name ='input_real')
    inputs_z = tf.placeholder(tf.float32,(None,z_dim),name = 'input_z') 
    return inputs_real, inputs_z

gan_network

上图显示了整个网络的样子,这里生成器输入是我们的z,它只是一个随机向量,一种随机白噪声,我们会将其传入生成器,然后生成器学习如何将这个随机向量Z转变为tanh层中的图像,tanh的输出范围为-1到1,这意味我们需要做转化工作,需要转换MNIST,使其取值-1到1之间。然后再将其传入到辨别器网络。

生成器

def generator(z, out_dim, n_units=128, reuse=False,  alpha=0.01):
    ''' Build the generator network.
    
        Arguments
        ---------
        z : Input tensor for the generator
        out_dim : Shape of the generator output
        n_units : Number of units in hidden layer
        reuse : Reuse the variables with tf.variable_scope
        alpha : leak parameter for leaky ReLU
        
        Returns
        -------
        out, logits: 
    '''
    with tf.variable_scope('generator',reuse = reuse) :
        # Hidden layer
        h1 = tf.layers.dense(z,n_units,activation = None)
        # Leaky ReLU
        h1 = tf.maximum(alpha * h1,h1)
        
        # Logits and tanh output
        logits = tf.layers.dense(h1,out_dim)
        out = tf.tanh(logits)
        
        return out

使用tf.variable_scope,需要声明with tf.variable_scope('scope_name', reuse=False):这里我们使用generator作为域的名称,所以基本上所有的变量都将以generator开头。 这里我们选择重用,所以它将告诉作用域重用本网络中的变量。那么,我们从函数参数中获得reuse,默认情况下它是False。tf.layers.dense是一个全连接层,你可以直接使用层模块,因为它是高级的,它会为你执行所有权重初始化。

辨别器

辨别器和生成器构造方法差不多。

def discriminator(x, n_units=128, reuse=False, alpha=0.01):
    ''' Build the discriminator network.
    
        Arguments
        ---------
        x : Input tensor for the discriminator
        n_units: Number of units in hidden layer
        reuse : Reuse the variables with tf.variable_scope
        alpha : leak parameter for leaky ReLU
        
        Returns
        -------
        out, logits: 
    '''
    with tf.variable_scope('discriminator',reuse = reuse):
        # Hidden layer
        h1 =tf.layers.dense(x,n_units,activation = None)
        # Leaky ReLU
        h1 =tf.maximum(alpha * h1,h1)
        
        logits = tf.layers.dense(h1,1,activation = None)
        out =tf.sigmod(logits)
        
        return out, logits

超参数

# Size of input image to discriminator
input_size = 784 # 28x28 MNIST images flattened
# Size of latent vector to generator
z_size = 100
# Sizes of hidden layers in generator and discriminator
g_hidden_size = 128
d_hidden_size = 128
# Leak factor for leaky ReLU
alpha = 0.01
# Label smoothing 
smooth = 0.1

构建网络

tf.reset_default_graph()
# Create our input placeholders
input_real, input_z = model_inputs(input_size, z_size)

# Build the model
g_model = generator(input_z, input_size)
# g_model is the generator output

d_model_real, d_logits_real = discriminator(input_real)
d_model_fake, d_logits_fake = discriminator(g_model, reuse=True)

这里辨别器用相同的权重,所以reuse这里为true.

计算辨别器及生成器的损失

同时训练辨别器和生成器网络,我们需要这两个不同网络的损失。对辨别器总损失:是真实图像和假图像损失之和。 关于标签,对于真实图像,我们想让辨别器知道它们是真的,我们希望标签全部是1。为了帮助辨别器更好的泛化,我们要执行一个叫做标签平滑的操作,创建一个smooth的参数,略小于1。假数据辨别器损失也类似,设定这些标签全部为0。最后对于生成器,再次使用d_logits_fake,但这次我们的标签全部为1,我们想让生成器欺骗辨别器,我们想让辨别器认为假图像是真的

# Calculate losses
d_loss_real = tf.reduce_mean(
                  tf.nn.sigmoid_cross_entropy_with_logits(logits=d_logits_real, 
                                                          labels=tf.ones_like(d_logits_real) * (1 - smooth)))
d_loss_fake = tf.reduce_mean(
                  tf.nn.sigmoid_cross_entropy_with_logits(logits=d_logits_fake, 
                                                          labels=tf.zeros_like(d_logits_real)))
d_loss = d_loss_real + d_loss_fake

g_loss = tf.reduce_mean(
             tf.nn.sigmoid_cross_entropy_with_logits(logits=d_logits_fake,
                                                     labels=tf.ones_like(d_logits_fake)))

优化器

我们要分别更新生成器和辨别器变量,首先获取所有可训练的变量

# Optimizers
learning_rate = 0.002

# Get the trainable_variables, split into G and D parts
t_vars = tf.trainable_variables()
g_vars = [var for var in t_vars if var.name.startswith('generator')]
d_vars = [var for var in t_vars if var.name.startswith('discriminator')]

d_train_opt = tf.train.AdamOptimizer(learning_rate).minimize(d_loss, var_list=d_vars)
g_train_opt = tf.train.AdamOptimizer(learning_rate).minimize(g_loss, var_list=g_vars)

训练

batch_size = 100
epochs = 100
samples = []
losses = []
# Only save generator variables
saver = tf.train.Saver(var_list=g_vars)
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    for e in range(epochs):
        for ii in range(mnist.train.num_examples//batch_size):
            batch = mnist.train.next_batch(batch_size)
            
            # Get images, reshape and rescale to pass to D
            batch_images = batch[0].reshape((batch_size, 784))
            batch_images = batch_images*2 - 1
            
            # Sample random noise for G
            batch_z = np.random.uniform(-1, 1, size=(batch_size, z_size))
            
            # Run optimizers
            _ = sess.run(d_train_opt, feed_dict={input_real: batch_images, input_z: batch_z})
            _ = sess.run(g_train_opt, feed_dict={input_z: batch_z})
        
        # At the end of each epoch, get the losses and print them out
        train_loss_d = sess.run(d_loss, {input_z: batch_z, input_real: batch_images})
        train_loss_g = g_loss.eval({input_z: batch_z})
            
        print("Epoch {}/{}...".format(e+1, epochs),
              "Discriminator Loss: {:.4f}...".format(train_loss_d),
              "Generator Loss: {:.4f}".format(train_loss_g))    
        # Save losses to view after training
        losses.append((train_loss_d, train_loss_g))
        
        # Sample from generator as we're training for viewing afterwards
        sample_z = np.random.uniform(-1, 1, size=(16, z_size))
        gen_samples = sess.run(
                       generator(input_z, input_size, reuse=True),
                       feed_dict={input_z: sample_z})
        samples.append(gen_samples)
        saver.save(sess, './checkpoints/generator.ckpt')

# Save training generator samples
with open('train_samples.pkl', 'wb') as f:
    pkl.dump(samples, f)

结果

改进GAN

我向你展示的 GAN,在生成器和辨别器中只使用了一个隐藏层。这个 GAN 的结果已经非常不错了,但仍然有很多噪声图像,以及有些图像看起来不太像数字。但是,要让生成器生成的图像与 MNIST 数据集几乎一样,是完全可能的。

这来自一篇题为 Improved Techniques for Training GANs 的文章。那么,它们如何生成如此美观的图像呢?

批归一化

提醒一下,在三层情况下你可能无法使它很好地工作。网络会变得对权重的初始值非常敏感,导致无法训练。我们可以使用 批归一化(Batch Normalization) 来解决这个问题。原理很简单。就像我们对网络输入的做法一样,我们可以对每个层的输入进行归一化。也就是说,缩放层输入,使它具有零均值和标准差 1。经发现,批归一化对于构建深度 GAN 非常有必要。 欢迎大家看我以前写的Batch Normalization

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏DHUtoBUAA

编程求取直线一般式表达式,两直线交点

背景介绍   最近在水面无人艇(USV)模拟仿真中,用到了一些点和线的关系求解,本文主要讲述一下两点确认直线,点到直线距离,两条直线的交点等问题的解决方法,并给...

54970
来自专栏大数据和云计算技术

最小生成树

本篇我们会聊聊最小生成树,最小生成树和之前的无向图最大的区别是这个每一条边都是带有权重的。在聊最小生成树之前 我们要先聊两个理念,因为最小生成树是基于这两...

21410
来自专栏素质云笔记

keras系列︱Sequential与Model模型、keras基本结构功能(一)

不得不说,这深度学习框架更新太快了尤其到了Keras2.0版本,快到Keras中文版好多都是错的,快到官方文档也有旧的没更新,前路坑太多。 到发文为止...

4.4K80
来自专栏书山有路勤为径

Image Captioning(1)

首先,将图片传送到CNN中,使用预先训练的网络VGG-16或者ResNet。在这个网络的末尾是一个输出类别得分的softmax分类器。但我们不是要分类图像,我们...

31120
来自专栏机器之心

三天速成!香港科技大学TensorFlow课件分享

机器之心整理 参与:蒋思源 这是一套香港科技大学发布的极简 TensorFlow 入门教程,三天全套幻灯片教程已被分享到 Google Drive。机器之心将简...

594120
来自专栏漫漫深度学习路

tensorflow学习笔记(四十五):sess.run(tf.global_variables_initializer()) 做了什么?

当我们训练自己的神经网络的时候,无一例外的就是都会加上一句 sess.run(tf.global_variables_initializer()) ,这行代码的...

30160
来自专栏null的专栏

简单易学的机器学习算法——Rosenblatt感知机的对偶解法

一、Rosenblatt感知机回顾    image.png 二、Rosenblatt感知机的对偶形式    image.png 三、算法流程 image....

39050
来自专栏利炳根的专栏

学习笔记CB014:TensorFlow seq2seq模型步步进阶

神经网络。《Make Your Own Neural Network》,用非常通俗易懂描述讲解人工神经网络原理用代码实现,试验效果非常好。

60630
来自专栏杂文共赏

卷积神经网络究竟做了什么?

神经学习的一种主要方式就是卷积神经网络(CNN),有许多种方法去描述CNN到底做了什么,一般通过图像分类例子通过数学的或直观的方法来介绍如何训练和使用CNN。

52980
来自专栏书山有路勤为径

Batch Normalization怎么加入batch normalization

Batch Normalization 会使你的参数搜索问题变得很容易,使神经网络对超参数的选择更加稳定,超参数的范围会更加庞大,工作效果也很好,也会使你的训练...

9720

扫码关注云+社区

领取腾讯云代金券