一、程序代碼
程序主要實現上篇文章中所提到的隨機噪聲擬合高斯分布的過程,話不多說,直接上代碼:
#引入必要的包import argparseimport numpy as npfrom scipy.stats import normimport tensorflow as tfimport matplotlib.pyplot as pltimport seaborn as snssns.set(color_codes=True)#設置種子,用於隨機初始化seed =42np.random.seed(seed)tf.set_random_seed(seed)#定義真實的數據分布,這裡為高斯分布classDataDistribution(object):def __init__(self):#高斯分布參數#均值為4self.mu =4#標準差為0.5self.sigma =0.5def sample(self, N): samples = np.random.normal(self.mu,self.sigma, N) samples.sort()return samples#隨機初始化一個分布,做為G網絡的輸入classGeneratorDistribution(object):def __init__(self, range):self.range = rangedef sample(self, N):return np.linspace(-self.range,self.range, N)+ \ np.random.random(N)*0.01#定義線性運算函數,其中參數output_dim=h_dim*2=8def linear(input, output_dim, scope=None, stddev=1.0):#定義一個隨機初始化 norm = tf.random_normal_initializer(stddev=stddev)#b初始化為0const= tf.constant_initializer(0.0)with tf.variable_scope(scope or'linear'):#聲明w的shape,輸入為(12,1)*w,故w為(1,8),w的初始化方式為高斯初始化 w = tf.get_variable('w',[input.get_shape()[1], output_dim], initializer=norm)#b初始化為常量 b = tf.get_variable('b',[output_dim], initializer=const)#執行線性運算return tf.matmul(input, w)+ b#def generator(input, h_dim): h0 = tf.nn.softplus(linear(input, h_dim,'g0')) h1 = linear(h0,1,'g1')return h1#初始化w和b的函數,其中h0,h1,h2,h3為層,將mlp_hidden_size=4傳給h_dimdef discriminator(input, h_dim):#linear 控制w和b的初始化,這裡linear函數的第二個參數為4*2=8#第一層 h0 = tf.tanh(linear(input, h_dim *2,'d0'))#第二層輸出,隱藏層神經元個數還是為8 h1 = tf.tanh(linear(h0, h_dim *2,'d1'))#h2為第三層輸出值 h2 = tf.tanh(linear(h1, h_dim *2, scope='d2'))#最終的輸出值 h3 = tf.sigmoid(linear(h2,1, scope='d3'))return h3#優化器 採用學習率衰減的方法def optimizer(loss, var_list, initial_learning_rate): decay =0.95 num_decay_steps =150 batch = tf.Variable(0)#調用學習率衰減的函數 learning_rate = tf.train.exponential_decay( initial_learning_rate, batch, num_decay_steps, decay, staircase=True)#梯度下降求解 optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize( loss, global_step=batch, var_list=var_list)#返回return optimizer#構造模型class GAN(object):def __init__(self, data, gen, num_steps, batch_size, log_every):self.data = dataself.gen = genself.num_steps = num_stepsself.batch_size = batch_sizeself.log_every = log_every#隱藏層神經元個數self.mlp_hidden_size =4#學習率self.learning_rate =0.03#通過placeholder格式來創造模型self._create_model()def _create_model(self):#創建一個名叫D_pre的域,先構造一個D_pre網絡,用來訓練出真正D網絡初始化網絡所需要的參數with tf.variable_scope('D_pre'):#輸入的shape為(12,1),一個batch一個batch的訓練,#每個batch的大小為12,要訓練的數據為1維的點self.pre_input = tf.placeholder(tf.float32, shape=(self.batch_size,1))self.pre_labels = tf.placeholder(tf.float32, shape=(self.batch_size,1))#調用discriminator來初始化w和b參數,其中self.mlp_hidden_size=4,為discriminator函數的第二個參數 D_pre = discriminator(self.pre_input,self.mlp_hidden_size)#預測值和label之間的差異self.pre_loss = tf.reduce_mean(tf.square(D_pre -self.pre_labels))#定義優化器求解self.pre_opt = optimizer(self.pre_loss,None,self.learning_rate)# This defines the generator network - it takes samples from a noise# distribution as input, and passes them through an MLP.#真正的G網絡with tf.variable_scope('Gen'):self.z = tf.placeholder(tf.float32, shape=(self.batch_size,1))#生產網絡只有兩層self.G = generator(self.z,self.mlp_hidden_size)# The discriminator tries to tell the difference between samples from the# true data distribution (self.x) and the generated samples (self.z).## Here we create two copies of the discriminator network (that share parameters),# as you cannot use the same network with different inputs in TensorFlow.#D網絡with tf.variable_scope('Disc')as scope:self.x = tf.placeholder(tf.float32, shape=(self.batch_size,1))#構造D1網絡,真實的數據self.D1 = discriminator(self.x,self.mlp_hidden_size)#重新使用一下變量,不用重新定義 scope.reuse_variables()#D2,生成的數據self.D2 = discriminator(self.G,self.mlp_hidden_size)# Define the loss for discriminator and generator networks (see the original# paper for details), and create optimizers for both#定義判別網絡損失函數self.loss_d = tf.reduce_mean(-tf.log(self.D1)- tf.log(1-self.D2))#定義生成網絡損失函數self.loss_g = tf.reduce_mean(-tf.log(self.D2))self.d_pre_params = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, scope='D_pre')self.d_params = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, scope='Disc')self.g_params = tf.get_collection(tf.GraphKeys.TRAINABLE_VARIABLES, scope='Gan')#優化,得到兩組參數self.opt_d = optimizer(self.loss_d,self.d_params,self.learning_rate)self.opt_g = optimizer(self.loss_g,self.g_params,self.learning_rate)def train(self):with tf.Session()as session: tf.global_variables_initializer().run()# pretraining discriminator#先訓練D_pre網絡 num_pretrain_steps =1000for step in range(num_pretrain_steps):#隨機生成數據 d =(np.random.random(self.batch_size)-0.5)*10.0 labels = norm.pdf(d, loc=self.data.mu, scale=self.data.sigma) pretrain_loss, _ = session.run([self.pre_loss,self.pre_opt],{self.pre_input: np.reshape(d,(self.batch_size,1)),self.pre_labels: np.reshape(labels,(self.batch_size,1))})#拿出預訓練好的數據self.weightsD = session.run(self.d_pre_params)# copy weights from pre-training over to new D networkfor i, v in enumerate(self.d_params): session.run(v.assign(self.weightsD[i]))#訓練真正的網絡for step in range(self.num_steps):# update discriminator x =self.data.sample(self.batch_size)#z是一個隨機生成的噪音 z =self.gen.sample(self.batch_size)#優化判別網絡 loss_d, _ = session.run([self.loss_d,self.opt_d],{self.x: np.reshape(x,(self.batch_size,1)),self.z: np.reshape(z,(self.batch_size,1))})# update generator#隨機初始化 z =self.gen.sample(self.batch_size)#迭代優化 loss_g, _ = session.run([self.loss_g,self.opt_g],{self.z: np.reshape(z,(self.batch_size,1))})#列印if step %self.log_every ==0:print('{}: {}\t{}'.format(step, loss_d, loss_g))#畫圖if step %100==0or step==0or step ==self.num_steps -1:self._plot_distributions(session)def _samples(self, session, num_points=10000, num_bins=100): xs = np.linspace(-self.gen.range,self.gen.range, num_points) bins = np.linspace(-self.gen.range,self.gen.range, num_bins)# data distribution d =self.data.sample(num_points) pd, _ = np.histogram(d, bins=bins, density=True)# generated samples zs = np.linspace(-self.gen.range,self.gen.range, num_points) g = np.zeros((num_points,1))for i in range(num_points // self.batch_size): g[self.batch_size * i:self.batch_size *(i +1)]= session.run(self.G,{self.z: np.reshape( zs[self.batch_size * i:self.batch_size *(i +1)],(self.batch_size,1))}) pg, _ = np.histogram(g, bins=bins, density=True)return pd, pgdef _plot_distributions(self, session): pd, pg =self._samples(session) p_x = np.linspace(-self.gen.range,self.gen.range, len(pd)) f, ax = plt.subplots(1) ax.set_ylim(0,1) plt.plot(p_x, pd, label='real data') plt.plot(p_x, pg, label='generated data') plt.title('1D Generative Adversarial Network') plt.xlabel('Data values') plt.ylabel('Probability density') plt.legend() plt.show()def main(args): model = GAN(#定義真實數據的分布DataDistribution(),#創造一些噪音點,用來傳入G函數GeneratorDistribution(range=8),#迭代次數 args.num_steps,#一次迭代12個點的數據 args.batch_size,#隔多少次列印當前loss args.log_every,) model.train()def parse_args(): parser = argparse.ArgumentParser() parser.add_argument('--num-steps', type=int,default=3000, help='the number of training steps to take') parser.add_argument('--batch-size', type=int,default=12, help='the batch size') parser.add_argument('--log-every', type=int,default=10, help='print loss after this many steps')return parser.parse_args()if __name__ =='__main__': main(parse_args())二、程序運行結果
1、程序運行初始狀態
其中左邊為隨機初始化的數據,右邊為真實的呈高斯分布的數據。
2、程序迭代運行1200次後的狀態
這裡不知道為什麼原因,程序沒有正常的擬合真實的數據,將迭代次數增加之後,程序也沒有太大的變化,D和G網絡的兩個Loss的變化都很小,這裡還望大家幫忙找一找原因。可能和GAN網絡容易訓練跑偏的一些原因有關。
留言,加入人工智慧深度學習社群,跟小編一起討論吧!