GAN

作者: 潇萧之炎 | 来源:发表于2019-04-26 00:09 被阅读2次
#coding:utf-8

from tensorflow.examples.tutorials.mnist import input_data #连接远程服务器,下载数据集
import tensorflow as tf
import numpy as np
from skimage.io import imsave
import os #获取路径
import shutil
import sys
import six

#############
#定义模型参数
#############
# 图片尺寸
img_height= 28
img_width = 28
img_size = img_height * img_width#784

###################
#模型保存与加载参数
###################
to_train = True
to_restore = False #为了判断是否加载模型
output_path = 'D:\Python\GANTest\output'# 保存地址


###################
#网络及训练参数
###################
#生成模型的输入是100,随机变量的维度是100,
# 最后要变成784维,所以隐层是增的,第一个隐层是150,第二个是300,这是生成模型
# 判别模型要倒着来,输入是784,第一层300,第二层150,最后的输出是1维,映射到一个值,用0或者1全宇判别
z_size = 100
h1_size = 150
h2_size = 300
# 一次训练256个,因为图像像素也不高,可以一次多训练一点
batch_size = 256
# 深度学习一般都是1000,实际上收敛的时候,一般小于1000
max_epoch = 1000

###################
#DNN网络构建(多层感知机)
###################
# 生成模型做的: 就是给一个随机变量,返回一个生成的数值x_generate,和一套参数
def 生成模型(z_prior):
    # 从输入层向第一隐层的w,应该是100行,150列

    # truncated_normal:从截断的正态分布中输出随机值。
    # shape表示生成张量的维度,mean是均值,stddev是标准差。这个函数产生正太分布,均值和标准差自己设定。
    # 这是一个截断的产生正太分布的函数,就是说产生正太分布的值如果与均值的差值大于两倍的标准差,那就重新生成
    w1 = tf.Variable(tf.truncated_normal([z_size, h1_size], \
                                         # 方差 stddev = 0.1,均值不用写,均值默认是0
                                         stddev = 0.1), name = 'g_w1', \
                                         dtype=tf.float32)
    # 注意此时是:zeros
    b1 = tf.Variable(tf.zeros([h1_size]), name = 'g_b1', dtype = tf.float32)
    # 公式上是Wx+b,但矩阵运算时,x放前面
    h1 = tf.nn.relu(tf.matmul(z_prior, w1) + b1)

    # 从第一个隐层到第二个隐层
    w2 = tf.Variable(tf.truncated_normal([h1_size, h2_size], \
                                         stddev = 0.1), name = 'g_w2', \
                                         dtype=tf.float32)
    b2 = tf.Variable(tf.zeros([h2_size]), name = 'g_b2', dtype = tf.float32)

    # 注意此时是h1,也就是 隐层1激活之后的结果值
    h2 = tf.nn.relu(tf.matmul(h1, w2) + b2)

    w3 = tf.Variable(tf.truncated_normal([h2_size, img_size], \
                                         stddev = 0.1), name = 'g_w3', \
                                         dtype=tf.float32)
    b3 = tf.Variable(tf.zeros([img_size]), name = 'g_b3', dtype = tf.float32)
    # h3也能很大,也可能很小,如果是做分类,就用softmax激活,这里不用分类,选tanh激活
    h3 = tf.matmul(h2, w3) + b3
    x_generate = tf.nn.tanh(h3)#fake,生成模型,假的
    g_params = [w1, b1, w2, b2, w3, b3]#生成模型的参数,更新的参数,需要保存
    return x_generate, g_params

# x_data: 就是通过input_data下载的数据集,在后面的会话中给他喂,先写一个形参x_data就是y值
# x_generate:传两个
#  keep_prob:Dropout率,意思是每个元素被保留的概率,那么 keep_prob:1就是所有元素全部保留的意思。
# 一般在大量数据训练时,为了防止过拟合,添加Dropout层,设置一个0~1之间的小数
def 判别模型(x_data, x_generate, keep_prob):
    # 这两个值是并行输入的
    # tf.concat:tensorflow中用来拼接张量的函数。 tf.concat()拼接的张量只会改变一个维度,其他维度是保存不变的。
    # 比如两个shape为[2,3]的矩阵拼接,要么通过axis=0变成[4,3],要么通过axis=1变成[2,6]。改变的维度索引对应axis的值。
    # x_data(y值)和x_generate(y^值)都是一维的,所以拼接成两行的向量,但是他们不是相加,一起进网络,一起出网络
    # x_in代表判别模型的输入
    x_in = tf.concat([x_data, x_generate], 0)
    w1 = tf.Variable(tf.truncated_normal([img_size, h2_size], \
                                         stddev = 0.1), name = 'd_w1', \
                                         dtype=tf.float32)
    b1 = tf.Variable(tf.zeros([h2_size]), name = 'd_b1', dtype = tf.float32)
    # 这里比之前可以加一个dropout率
    h1 = tf.nn.dropout(tf.nn.relu(tf.matmul(x_in, w1) + b1),keep_prob)

    w2 = tf.Variable(tf.truncated_normal([h2_size, h1_size], \
                                         stddev = 0.1), name = 'd_w2', \
                                         dtype=tf.float32)
    b2 = tf.Variable(tf.zeros([h1_size]), name = 'd_b2', dtype = tf.float32)
    h2 = tf.nn.dropout(tf.nn.relu(tf.matmul(h1, w2) + b2),keep_prob)
    # w3只有一个值,注意b和后面的网络深度相同,因为前一层的b连的是后一层的cell
    w3 = tf.Variable(tf.truncated_normal([h1_size, 1], stddev = 0.1), \
                                        name = 'd_w3', dtype = tf.float32)
    b3 = tf.Variable(tf.zeros([1]), name = 'd_b3', dtype = tf.float32)
    h3 = tf.matmul(h2, w3) + b3
    print(h3)
    # 两维数组,上面一行是1*256(因为一次训练256个)
    # tf.slice(input_, begin, size):
    # “input_”是你输入的tensor,就是被切的那个。
    # “begin”是每一个维度的起始位置,这个下面详细说。
    # “size”相当于问每个维度拿几个元素出来。
    # 需要把y和y^分开,因为之前是黏在一起的,然后算损失
    #  为什么[batch_size, -1]是[256, 784]?累加?全连接层

    y_data = tf.nn.sigmoid(tf.slice(h3, [0, 0], [batch_size, -1]), name = None) #y
    # 二分类直接用sigmoid去激活
    # [batch_size, 0]中batch_size:从第256开始切,[-1, -1]:第一个-1,切剩下所有的
    y_generated = tf.nn.sigmoid(tf.slice(h3, [batch_size, 0], [-1, -1]), name = None) #y^
    d_params = [w1, b1, w2, b2, w3, b3]#判别模型的参数
    return y_data, y_generated, d_params

#########################################################
#定义图片展示的函数(即将生成模型的输出相片绘制成图片保存)
#########################################################
# 绘制一个8*8的格子,每个格子保存16张图片,每张图片就是28*28=784的图片
def 展示结果保存(batch_res, fname, grid_size=(8, 8), grid_pad=5):#show_result
    '''图片保存'''
    batch_res = 0.5 * batch_res.reshape((batch_res.shape[0], img_height, img_width)) + 0.5
    img_h, img_w = batch_res.shape[1], batch_res.shape[2]
    grid_h = img_h * grid_size[0] + grid_pad * (grid_size[0] - 1)
    grid_w = img_w * grid_size[1] + grid_pad * (grid_size[1] - 1)
    img_grid = np.zeros((grid_h, grid_w), dtype=np.uint8)
    for i, res in enumerate(batch_res):
        if i >= grid_size[0] * grid_size[1]:
            break
        img = (res) * 255
        img = img.astype(np.uint8)
        row = (i // grid_size[0]) * (img_h + grid_pad)
        col = (i % grid_size[1]) * (img_w + grid_pad)
        img_grid[row:row + img_h, col:col + img_w] = img
    imsave(fname, img_grid)

######################
#开始训练
######################
def 开始训练():
    # input_data是网上下载的,one_hot打开,one_hot指的是标签
    mnist = input_data.read_data_sets('MNIST_data', one_hot = True)
    # [batch_size, z_size]=[256,100], z_prior:输入给生成模型的,随机变量
    z_prior = tf.placeholder(tf.float32, [batch_size, z_size], name = 'z_prior')
    # [batch_size, img_size]=[256,784]   x_data:真实值
    x_data = tf.placeholder(tf.float32, [batch_size, img_size], name = 'x_data')
    keep_prob = tf.placeholder(tf.float32, name = 'keep_prob')
    # 步数,假设255步,trainable:不是训练的步长,是测试的步长
    global_step = tf.Variable(255, name = 'global_step', trainable = False)

    x_generate, g_params = 生成模型(z_prior)
    y_data, y_generated, d_params = 判别模型(x_data, x_generate, keep_prob)

    ##########
    #构建损失,两个损失,先更新d_loss,注意损失函数的区别
    ##########
    d_loss = -(tf.log(y_data)+tf.log(1-y_generated))
    g_loss = -tf.log(y_generated)
    # 优化器,要优化两次
    optimizer = tf.train.AdamOptimizer(0.0001)
    # d_params两个模型中的参数列表,run这两个模型就好了:d_train,g_train
    d_train = optimizer.minimize(d_loss, var_list = d_params)
    g_train = optimizer.minimize(g_loss, var_list = g_params)
    # 之前的写法也可以
    init = tf.initialize_all_variables()
    #####################
    #保存与加载模型
    #####################
    saver = tf.train.Saver()
    sess = tf.Session()
    # 先run(init),初始化变量
    sess.run(init)
    if to_restore:#加载模型
        chkpt_fname = tf.train.latest_checkpoint(output_path)
        # 把模型及上面的参数加载到会话中来
        saver.restore(sess, chkpt_fname)
    elif os.path.exists(output_path):
        # 存在,则删掉,重新创建
        shutil.rmtree(output_path)
        os.mkdir(output_path)
    # os.path.exists(output_path)
    # # 存在,则删掉,重新创建
    # shutil.rmtree(output_path)
    # os.mkdir(output_path)

    # 创建随机变量 0, 1,均值为0,方差为1,(batch_size, z_size) 256行*100维
    # z_sample_val = np.random.normal(0, 1, size = (batch_size, z_size)).astype(tf.float32)

    # 60000整个数据集有60000张图片
    steps = 60000//batch_size

    #for i in range(sess.run(global_step), max_epoch):
    for i in range(max_epoch):

        for j in range(steps):

            print("epoch序次:%d, 迭代次数:%d"%(i, j))

            ############
            #传入实参
            ############
            # 切batch_size个
            x_value, _ = mnist.train.next_batch(batch_size)
            # 归一化处理,图像一般都这样处理,*2-1,让像素分布在0的两边
            x_value = 2*x_value.astype(np.float32) - 1
            # x_value:真实值。z_value
            z_value = np.random.normal(0, 1, size = (batch_size, z_size)).astype(np.float32)

            # 先run判别模型
            sess.run(d_train, feed_dict = {x_data:x_value, z_prior:z_value, keep_prob:np.sum(0.7).astype(np.float32)})

            sess.run(g_train, feed_dict = {x_data:x_value, z_prior:z_value, keep_prob:np.sum(0.7).astype(np.float32)})
            # 每运行一遍,再运行x_generate
            x_gen_val = sess.run(x_generate, feed_dict={z_prior:z_value})

            展示结果保存(x_gen_val, 'D:\Python\GANTest\output_sample\sample{0}.jpg'.format(i))
            ################
            #保存模型
            ################
            sess.run(tf.assign(global_step, i+1))
            saver.save(sess, os.path.join(output_path, 'model'), global_step = global_step)

if __name__ =='__main__':

    开始训练()

相关文章

网友评论

    本文标题:GAN

    本文链接:https://www.haomeiwen.com/subject/vulxnqtx.html