1. GAN简介

最近几年,深度神经网络在图像识别、语音识别以及自然语言处理方面的应用有了爆炸式的增长,并且都达到了极高的准确率,某些方面甚至超过了人类的表现。然而人类的能力远超出图像识别和语音识别的任务,像很多需要创造力的任务却是机器很难做到的。但是GAN使得机器解决这些任务成为可能。

深度学习的领军人物Yann LeCun曾经说过:

生成对抗网络(GAN)及其变种已经成为最近10年以来机器学习领域最重要的思想。

为了能更好的了解GAN,做一个比喻,想象一下制作伪钞的犯罪嫌疑人和警察这个现实中的例子:

  • 想要成为一名成功的假钞制作者,犯罪嫌疑人需要蒙骗得了警察,使得警察无法区分出哪一张是假钞、哪一张是真钞。
  • 作为警察,需要尽可能高效地发现那些是假钞

整个过程被称为对抗性过程(adversarial process)GAN是由Ian Goodfellow 于2014年提出,它是一种两个神经网络相互竞争的特殊对抗过程。第一个网络生成数据,第二个网络试图区分真实数据与第一个网络创造出来的假数据。第二个网络会生成一个在[0, 1]范围内的标量,代表数据是真是数据的概率。

2.GAN的目的

GAN是生成模型的一种,主要在模型的分布中生成样本,它只能够制造数据而不是提供一个预测的密度函数。

下面是一些学习生成模型的理由:

    • 生成样本,这是最直接的理由。
    • 训练并不包含最大似然估计。
    • 由于生成器不会看到训练数据,过拟合风险更低。
    • GAN十分擅长捕获模式的分布。

3.GAN的组成

用Tensorflow实现DCGAN

GAN的计算流程与结构如图 所示。

GAN包含两个部分,即生成器generative和判别器discriminative。以生成图片为例,生成器主要用于学习真实图像分布从而让自身生成的图像更加真实,使得判别器分辨不出生成的数据是否是真实数据。判别器则需要对接受到的图片进行真假判别。整个过程可以看作是生成器和判别器的博弈,随着时间的推移,最终两个网络达到一个动态均衡:生成器生成的图像近似于真实图像分布,而判别器对给定图像的判别概率约为0.5,相当于盲猜。

假设真实数据data分布为,生成器G学习到的数据分布为,z为随机噪声,为噪声分布,为生成映射函数,将这个随机噪声转化为数据x,为判别映射函数,输出是判别x来自真实数据data而不是生成数据的概率。训练判别器D使得判别概率最大化,同时,训练生成器G最小化,这个优化过程可以被归结于一个‘二元极小极大博弈’(two-player minimax game),目标函数被定义如下:

用Tensorflow实现DCGAN

从判别器D的角度,D希望它自己能够尽可能地判别出真实数据和生成数据,即使得D(x)尽可能的达,D(G(z))尽可能的小,即V(D,G)尽可能的大。从生成器G的角度来说,G希望自己生成的数据尽可能地接近于真实数据,也就是希望D(G(z))尽可能地大,D(x)尽可能的小,即V(D,G)尽可能的小。两个模型相互对抗,最后达到全局最优。

4.DCGAN的实现

GAN出来后很多相关的应用和方法都是基于DCGAN的结构,DCGAN即”Deep Convolution GAN”,通常会有一些约定俗成的规则:

  • 在Discriminator和generator中大部分层都使用batch normalization,而在最后一层时通常不会使用batch normalizaiton,目的 是为了保证模型能够学习到数据的正确的均值和方差;

  • 因为会从random的分布生成图像,所以一般做需要增大图像的空间维度时如77->1414, 一般会使用strdie为2的deconv(transposed convolution);

  • 通常在DCGAN中会使用Adam优化算法而不是SGD。

实现结果大概是这样的:

用Tensorflow实现DCGAN

 

4.1导入数据:

import os 
import sys
import tensorflow as tf
from tensorflow import logging
from tensorflow import gfile
import pprint 
import pickle
import numpy as np
import random
import math
from PIL import Image
from tensorflow.examples.tutorials.mnist import input_data

mnist = input_data.read_data_sets('MNIST_data/', one_hot = True)

output_dir = './local_run'
if not gfile.Exists(output_dir):
    gfile.MakeDirs(output_dir)
    
def get_default_params():
    """设置默认参数"""
    return tf.contrib.training.HParams(
    z_dim = 100,
    init_conv_size = 4,
    g_channels = [128, 64, 32, 1],
    d_channels = [32, 64, 128, 256],
    batch_size = 128,
    learning_rate = 0.002,
    beta1 = 0.5,
    img_size = 32,
    )
hps = get_default_params()

class MnistData(object):
    """Mnist数据集预处理"""
    def __init__(self, mnist_train, z_dim, img_size):
        self._data = mnist_train
        self._example_num = len(self._data)
        self._z_data = np.random.standard_normal((self._example_num, z_dim))
        self._indicator = 0
        self._resize_mnist_img(img_size)
        self._random_shuffle()
       
    def _random_shuffle(self):
        """打乱数据集所有图片,使图片数据随机分布"""
        p = np.random.permutation(self._example_num)
        self._z_data = self._z_data[p]
        self._data = self._data[p]
    
    def _resize_mnist_img(self, img_size):
        """
        Resize mnist image to goal img_size.
        1. numpy -> PIL img
        2. PIL img -> resize
        3. PIL img -> numpy
        """
        data = np.asarray(self._data * 255, np.uint8)
        data = data.reshape((self._example_num, 1, 28, 28)) # [example_num, 784] - > [example_num, 28, 28]
        data = data.transpose((0, 2, 3, 1))
        new_data = []
        for i in range(self._example_num):
            img = data[i].reshape((28, 28))
            img = Image.fromarray(img)
            img = img.resize((img_size, img_size))
            img = np.asarray(img)
            img = img.reshape((img_size, img_size, 1))
            new_data.append(img)
        new_data = np.asarray(new_data, dtype=np.float32)
        new_data = new_data / 127.5 - 1
        # self._data: [num_example, img_size, img_size, 1]
        self._data = new_data
        
    def next_batch(self, batch_size):
        """使用mini-batch的方法加载数据集"""
        end_indicator = self._indicator + batch_size
        if end_indicator > self._example_num:
            self._random_shuffle()
            self._indicator = 0
            end_indicator = self._indicator + batch_size
        assert end_indicator < self._example_num
        
        batch_data = self._data[self._indicator: end_indicator]
        batch_z = self._z_data[self._indicator: end_indicator]
        self._indicator = end_indicator
        return batch_data, batch_z
            
mnist_data = MnistData(mnist.train.images, hps.z_dim, hps.img_size)
batch_data, batch_z = mnist_data.next_batch(5)

           
View Code(数据处理)

相关文章: