这篇代码与上两篇博客紧密相连,在上篇博客的注意部分提到,feed_dict需要喂numpy.array这种数据,但是我自己用的方法生成队列batch的数据类型为tensor
,那么就没法喂到feed_dict
里面了,所以查了各种Stack Overflow后发现,绕开feed_dict
的形式,去掉placeholder
在图创建的时候,直接输入数据,就可以了。具体细节见下面代码。
为了博文的完整性,仍然本博客贴出完整代码。其共分成两部分:第一部分为generator和discriminator的model.py
以及训练(无feeed_dict
)的train.py
两部分。有心的同学请仔细学习train.py
文件,会发现跟之前博客(含有feed_dict
)有所不同的。
- 顺便说一句,tf在训练的时候可以接受array和tensor这两种数据结构,之间会相互转化(猜测是由于自带的convolution之类的函数进行了转化)。因为仔细去看MNIST的数据集是array的形式。
model.py
# -*- coding: utf-8 -*-
"""
Created on Tue Jul 24 20:33:14 2018
E-mail: Eric2014_Lv@sjtu.edu.cn
@author: DidiLv
"""
import tensorflow as tf
import numpy as np
# import data
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("MNIST_data/") # MNIST dataset
# pooling and convolution definition
def conv2d(x, W):
return tf.nn.conv2d(input = x, filter = W, strides = [1,1,1,1], padding = 'SAME')
def avg_pool_2x2(x):
return tf.nn.avg_pool(x, ksize = [1,2,2,1], strides = [1,2,2,1], padding = 'SAME')
def xavier_init(size):
in_dim = size[0]
xavier_stddev = 1. / tf.sqrt(in_dim / 2.)
return tf.random_normal(shape=size, stddev=xavier_stddev)
def sample_z(shape):
return np.random.uniform(-1., 1., size=shape)
# discriminator
def discriminator(x_image, reuse=False):
with tf.variable_scope('discriminator') as scope:
if (reuse):
tf.get_variable_scope().reuse_variables()
#First Conv and Pool Layers
W_conv1 = tf.get_variable('d_wconv1', shape = [5, 5, 1, 8], initializer=tf.truncated_normal_initializer(stddev=0.02))
b_conv1 = tf.get_variable('d_bconv1', shape = [8], initializer=tf.constant_initializer(0))
h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)
h_pool1 = avg_pool_2x2(h_conv1)
#Second Conv and Pool Layers
W_conv2 = tf.get_variable('d_wconv2', shape = [5, 5, 8, 16], initializer=tf.truncated_normal_initializer(stddev=0.02))
b_conv2 = tf.get_variable('d_bconv2', shape = [16], initializer=tf.constant_initializer(0))
h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)
h_pool2 = avg_pool_2x2(h_conv2)
#First Fully Connected Layer
W_fc1 = tf.get_variable('d_wfc1', [7 * 7 * 16, 32], initializer=tf.truncated_normal_initializer(stddev=0.02))
b_fc1 = tf.get_variable('d_bfc1', [32], initializer=tf.constant_initializer(0))
h_pool2_flat = tf.reshape(h_pool2, [-1, 7*7*16])
h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)
#Second Fully Connected Layer
W_fc2 = tf.get_variable('d_wfc2', [32, 1], initializer=tf.truncated_normal_initializer(stddev=0.02))
b_fc2 = tf.get_variable('d_bfc2', [1], initializer=tf.constant_initializer(0))
#Final Layer
y_conv=(tf.matmul(h_fc1, W_fc2) + b_fc2)
return y_conv
# generator from DCGAN, take a d-dimensional vector as input and upsample it to become a 28*28 image
# the structure is from https://arxiv.org/pdf/1511.06434v2.pdf
def generator(z, batch_size, z_dim, reuse = False):
with tf.variable_scope('generator') as scope:
if (reuse):
tf.get_variable_scope().reuse_variables()
## number of filters for the first layer of generator
g_dim = 64
## color dimension of output
c_dim = 1
## size of output image
s = 28
s2, s4, s8, s16 = int(s/2), int(s/4), int(s/8), int(s/16)
# h0 dimension is [batch_size, z_width, z_height, z_channel]
h0 = tf.reshape(z, [batch_size, s16+1, s16+1, 25])
h0 = tf.nn.relu(h0)
##Dimensions of h0 = batch_size x 2 x 2 x 25
# first decovolution layer (fractionally-strided convolution layer)
## useful link for convolution :
## https://blog.csdn.net/mao_xiao_feng/article/details/71713358
output1_shape = [batch_size, s8, s8, g_dim*4]
## W_conv1 shape = [filter_height, filter_width, out_channels, in_channels]
W_conv1 = tf.get_variable('g_wconv1', shape = [5,5,output1_shape[-1],int(h0.get_shape()[-1])],
initializer=tf.truncated_normal_initializer(stddev = 0.1)
)
b_conv1 = tf.get_variable('g_bconv1', shape = [output1_shape[-1]], initializer=tf.constant_initializer(.1))
## H_conv1: h0 * W_conv1.T
H_conv1 = tf.nn.conv2d_transpose(h0, W_conv1, output_shape = output1_shape, strides = [1,2,2,1],
padding = 'SAME')
H_conv1 = tf.add(H_conv1, b_conv1)
H_conv1 = tf.contrib.layers.batch_norm(inputs = H_conv1, center=True, scale=True, is_training=True, scope="g_bn1")
H_conv1 = tf.nn.relu(H_conv1)
##Dimensions of H_conv1 = batch_size x 3 x 3 x 256
# second deconvolution layer
output2_shape = [batch_size, s4-1, s4-1, g_dim*2]
W_conv2 = tf.get_variable('g_wconv2', shape = [5,5,output2_shape[-1], int(H_conv1.get_shape()[-1])],
initializer=tf.truncated_normal_initializer(stddev = 0.1))
b_conv2 = tf.get_variable('g_bconv2', shape = [output2_shape[-1]], initializer=tf.truncated_normal_initializer(0.1))
H_conv2 = tf.nn.conv2d_transpose(H_conv1, W_conv2, output_shape = output2_shape, strides = [1,2,2,1],
padding = 'SAME')
H_conv2 = tf.add(H_conv2, b_conv2)
H_conv2 = tf.contrib.layers.batch_norm(inputs = H_conv2, center=True, scale=True, is_training=True, scope="g_bn2")
##Dimensions of H_conv2 = batch_size x 6 x 6 x 128
H_conv2 = tf.nn.relu(H_conv2)
#third DeConv Layer
output3_shape = [batch_size, s2 - 2, s2 - 2, g_dim*1]
W_conv3 = tf.get_variable('g_wconv3', [5, 5, output3_shape[-1], int(H_conv2.get_shape()[-1])],
initializer=tf.truncated_normal_initializer(stddev=0.1))
b_conv3 = tf.get_variable('g_bconv3', [output3_shape[-1]], initializer=tf.constant_initializer(.1))
H_conv3 = tf.nn.conv2d_transpose(H_conv2, W_conv3, output_shape=output3_shape, strides=[1, 2, 2, 1],
padding='SAME')
H_conv3 = tf.add(H_conv3, b_conv3)
H_conv3 = tf.contrib.layers.batch_norm(inputs = H_conv3, center=True, scale=True, is_training=True, scope="g_bn3")
H_conv3 = tf.nn.relu(H_conv3)
#Dimensions of H_conv3 = batch_size x 12 x 12 x 64
#Fourth DeConv Layer
output4_shape = [batch_size, s, s, c_dim]
W_conv4 = tf.get_variable('g_wconv4', [5, 5, output4_shape[-1], int(H_conv3.get_shape()[-1])],
initializer=tf.truncated_normal_initializer(stddev=0.1))
b_conv4 = tf.get_variable('g_bconv4', [output4_shape[-1]], initializer=tf.constant_initializer(.1))
H_conv4 = tf.nn.conv2d_transpose(H_conv3, W_conv4, output_shape=output4_shape, strides=[1, 2, 2, 1],
padding='VALID')
H_conv4 = tf.add(H_conv4, b_conv4)
H_conv4 = tf.nn.tanh(H_conv4)
#Dimensions of H_conv4 = batch_size x 28 x 28 x 1
return H_conv4
train.py
# -*- coding: utf-8 -*-
"""
Created on Wed Jul 25 09:42:35 2018
E-mail: Eric2014_Lv@sjtu.edu.cn
@author: DidiLv
"""
import model
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
import random
# import data
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("MNIST_data/") # MNIST dataset
# reset the graph to reset all variables we test before
tf.reset_default_graph()
batch_size = 16
z_dimensions = 2*2*25 # details can be found in module of model: reshape of h0
##---------------------------------------------------------------------------------------------
## 去掉feed_dict,在图创建时应该做的更改
# discriminator for input
#x_placeholder = tf.placeholder(dtype = tf.float32, shape = [None, 28, 28, 1])
x_placeholder = np.reshape(mnist.train.next_batch(batch_size)[0], [batch_size, 28, 28, 1])
#z_placeholder = tf.placeholder(dtype = tf.float32, shape = [None,z_dimensions])
# 注意z随机做出来的是np.array的结构是float64,TF里面基本上都是float32所以要进行转换
z_placeholder = tf.Variable(np.random.normal(-1, 1, size=[batch_size, z_dimensions]), dtype = tf.float32)
##--------------------------------------------------------------------------------------------
Dx = model.discriminator(x_placeholder) # for real training data
Gz = model.generator(z_placeholder, batch_size, z_dimensions)
Dg = model.discriminator(Gz, reuse=True)
g_loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=Dg, labels=tf.ones_like(Dg)))
d_loss_real = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=Dx, labels = tf.ones_like(Dx)))
d_loss_fake = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=Dg, labels = tf.zeros_like(Dx)))
d_loss = d_loss_real + d_loss_fake
tvars = tf.trainable_variables()
d_vars = [var for var in tvars if 'd_' in var.name]
g_vars = [var for var in tvars if 'g_' in var.name]
with tf.variable_scope(tf.get_variable_scope(), reuse = False):
# var_list: tf.Variable to update to minimize loss
trainerD = tf.train.AdadeltaOptimizer(learning_rate = 1e-3).minimize(d_loss, var_list = d_vars)
trainerG = tf.train.AdadeltaOptimizer(learning_rate = 1e-3).minimize(g_loss, var_list = g_vars)
sess = tf.Session()
sess.run(tf.global_variables_initializer())
iterations = 3000
##----------------------------------------------------------------------------------------------------------------------------------------------
#for i in range(iterations):
# z_batch = np.random.normal(-1, 1, size=[batch_size, z_dimensions])
# real_image_batch = mnist.train.next_batch(batch_size)
# real_image_batch = np.reshape(real_image_batch[0],[batch_size,28,28,1])
# _,dLoss = sess.run([trainerD, d_loss],feed_dict={z_placeholder:z_batch,x_placeholder:real_image_batch}) #Update the discriminator
# _,gLoss = sess.run([trainerG, g_loss],feed_dict={z_placeholder:z_batch}) #Update the generator
# print((dLoss+gLoss))
##------------------------------------------------------------------------------------------------------------------------------------------------
## 去掉feed_dict的写法
for i in range(iterations):
_,dLoss = sess.run([trainerD, d_loss]) #Update the discriminator
_,gLoss = sess.run([trainerG, g_loss]) #Update the generator
print((dLoss+gLoss))