摘要:深度卷積對(duì)抗生成網(wǎng)絡(luò)是的變體,是一種將卷積引入模型的網(wǎng)絡(luò)。特點(diǎn)是判別器使用來(lái)替代空間池化,生成器使用反卷積使用穩(wěn)定學(xué)習(xí),有助于處理初始化不良導(dǎo)致的訓(xùn)練問(wèn)題生成器輸出層使用激活函數(shù),其它層使用激活函數(shù)。
介紹
如圖所示,GAN網(wǎng)絡(luò)會(huì)同時(shí)訓(xùn)練兩個(gè)模型。生成器:負(fù)責(zé)生成數(shù)據(jù)(比如:照片);判別器:判別所生成照片的真假。訓(xùn)練過(guò)程中,生成器生成的照片會(huì)越來(lái)越接近真實(shí)照片,直到判別器無(wú)法區(qū)分照片真假。
DCGAN(深度卷積對(duì)抗生成網(wǎng)絡(luò))是GAN的變體,是一種將卷積引入模型的網(wǎng)絡(luò)。特點(diǎn)是:
判別器使用strided convolutions來(lái)替代空間池化,生成器使用反卷積
使用BN穩(wěn)定學(xué)習(xí),有助于處理初始化不良導(dǎo)致的訓(xùn)練問(wèn)題
生成器輸出層使用Tanh激活函數(shù),其它層使用Relu激活函數(shù)。判別器上使用Leaky Relu激活函數(shù)。
本次案例我們將使用mnist作為數(shù)據(jù)集訓(xùn)練DCGAN網(wǎng)絡(luò),程序最后將使用GIF的方式展示訓(xùn)練效果。
數(shù)據(jù)導(dǎo)入import tensorflow as tf import glob import imageio import matplotlib.pyplot as plt import numpy as np import os import tensorflow.contrib as tcon import PIL import time from IPython import display # shape:(60000,28,28) (train_images,train_labels),(_,_)=tf.keras.datasets.mnist.load_data() # shape:[batch_size,height,width,channel] train_images_reshape=tf.reshape(train_images,shape=(train_images.shape[0],28,28,1)).astype(tf.float32) # 縮放圖片[-1,1] train_images_nor=(train_images-127.5)/127.5
dataset加載數(shù)據(jù)
BUFFER_SIZE=60000 BATCH_SIZE=256 # 優(yōu)化輸入管道需要從:讀取,轉(zhuǎn)換,加載三方面考慮。 train_dataset=tf.data.Dataset.from_tensor_slices(train_images).shuffle(buffer_size=BUFFER_SIZE).batch(BATCH_SIZE)生成模型
該生成模型將使用反卷積層,我們首先創(chuàng)建全連接層然后通過(guò)兩次上采樣將圖片分辨率擴(kuò)充至28x28x1。我們將逐步提升分辨率降低depth,除最后一層使用tanh激活函數(shù),其它層都使用Leaky Relu激活函數(shù)。
def make_generator_model(): # 反卷積,從后往前 model=tf.keras.Sequential() model.add( tf.keras.layers.Dense( input_dim=7*7*256, # 不使用bias的原因是我們使用了BN,BN會(huì)抵消掉bias的作用。 # bias的作用: # 提升網(wǎng)絡(luò)擬合能力,而且計(jì)算簡(jiǎn)單(只要一次加法)。 # 能力的提升源于調(diào)整輸出的整體分布 use_bias=False, # noise dim input_shape=(100,) ) ) """ 隨著神經(jīng)網(wǎng)絡(luò)的訓(xùn)練,網(wǎng)絡(luò)層的輸入分布會(huì)發(fā)生變動(dòng),逐漸向激活函數(shù)取值兩端靠攏,如:sigmoid激活函數(shù), 此時(shí)會(huì)進(jìn)入飽和狀態(tài),梯度更新緩慢,對(duì)輸入變動(dòng)不敏感,甚至梯度消失導(dǎo)致模型難以訓(xùn)練。 BN,在網(wǎng)絡(luò)層輸入激活函數(shù)輸入值之前加入,可以將分布拉到均值為0,標(biāo)準(zhǔn)差為1的正態(tài)分布,從而 使激活函數(shù)處于對(duì)輸入值敏感的區(qū)域,從而加快模型訓(xùn)練。此外,BN還能起到類(lèi)似dropout的正則化作用,由于我們會(huì)有 ‘強(qiáng)拉’操作,所以對(duì)初始化要求沒(méi)有那么高,可以使用較大的學(xué)習(xí)率。 """ model.add(tf.keras.layers.BatchNormalization()) """ relu 激活函數(shù)在輸入為負(fù)值的時(shí)候,激活值為0,此時(shí)神經(jīng)元無(wú)法學(xué)習(xí) leakyrelu 激活函數(shù)在輸入為負(fù)值的時(shí)候,激活值不為0(但值很小),神經(jīng)元可以繼續(xù)學(xué)習(xí) """ model.add(tf.keras.layers.LeakyReLU()) model.add(tf.keras.layers.Reshape(input_shape=(7,7,256))) assert model.output_shape == (None,7,7,256) model.add(tf.keras.layers.Conv2DTranspose( filters=128, kernel_size=5, strides=1, padding="same", use_bias="False" )) assert model.output_shape == (None,7,7,128) model.add(tf.keras.layers.BatchNormalization()) model.add(tf.keras.layers.LeakyReLU()) # 卷積核為奇數(shù):圖像兩邊可以對(duì)稱(chēng)padding 00xxxx00 model.add(tf.keras.layers.Conv2DTranspose( filters=64, kernel_size=5, strides=2, padding="same", use_bias="False" )) assert model.output_shape == (None,14,14,64) model.add(tf.keras.layers.BatchNormalization()) model.add(tf.keras.layers.LeakyReLU()) model.add(tf.keras.layers.Conv2DTranspose( filters=1, kernel_size=5, strides=2, padding="same", use_bias="False", # tanh激活函數(shù)值區(qū)間[-1,1],均值為0關(guān)于原點(diǎn)中心對(duì)稱(chēng)。、 # sigmoid激活函數(shù)梯度在反向傳播過(guò)程中會(huì)出全正數(shù)或全負(fù)數(shù),導(dǎo)致權(quán)重更新出現(xiàn)Z型下降。 activation="tanh" )) assert model.output_shape == (None,28,28,1) return model判別模型
判別器使用strided convolutions來(lái)替代空間池化,比如這里strided=2。卷積層使用LeakyReLU替代Relu,并使用Dropout為全連接層提供加噪聲的輸入。
def make_discriminator_model(): # 常規(guī)卷積操作 model = tf.keras.Sequential() model.add(tf.keras.layers.Conv2D(64, (5, 5), strides=(2, 2), padding="same")) model.add(tf.keras.layers.LeakyReLU()) # dropout常見(jiàn)于全連接層,其實(shí)卷積層也是可以使用的。 # 這里簡(jiǎn)單翻譯下dropout論文觀點(diǎn): """ 可能很多人認(rèn)為因?yàn)榫矸e層參數(shù)較少,過(guò)擬合發(fā)生概率較低,所以dropout作用并不大。 但是,dropout在前面幾層依然有幫助,因?yàn)樗鼮楹竺娴娜B接層提供了加噪聲的輸入,從而防止過(guò)擬合。 """ model.add(tf.keras.layers.Dropout(0.3)) model.add(tf.keras.layers.Conv2D(128, (5, 5), strides=(2, 2), padding="same")) model.add(tf.keras.layers.LeakyReLU()) model.add(tf.keras.layers.Dropout(0.3)) model.add(tf.keras.layers.Flatten()) model.add(tf.keras.layers.Dense(1)) return model損失函數(shù)
獲取模型:
generator = make_generator_model() discriminator = make_discriminator_model()
生成器損失函數(shù):
損失函數(shù)使用sigmoid cross entropy,labels使用值全為1的數(shù)組。
def generator_loss(generator_output): return tf.losses.sigmoid_cross_entropy( multi_class_labels=tf.ones_like(generator_output), logits=generator_output )
判別器損失函數(shù)
判別器損失函數(shù)接受兩種輸入,生成器生成的圖像和數(shù)據(jù)集中的真實(shí)圖像,損失函數(shù)計(jì)算方法如下:
使用sigmoid cross entropy損失函數(shù)計(jì)算數(shù)據(jù)集中真實(shí)圖像的損失,labels使用值全為1的數(shù)組。
使用sigmoid cross entropy損失函數(shù)計(jì)算生成器圖像的損失,labels使用值全為0的數(shù)組。
將以上損失相加得到判別器損失。
def discriminator_loss(real_output, generated_output): # real:[1,1,...,1] real_loss = tf.losses.sigmoid_cross_entropy(multi_class_labels=tf.ones_like(real_output), logits=real_output) #:generated:[0,0,...,0] generated_loss = tf.losses.sigmoid_cross_entropy(multi_class_labels=tf.zeros_like(generated_output), logits=generated_output) # 總損失為兩者相加 total_loss = real_loss + generated_loss return total_loss
模型保存:
# 兩種模型同時(shí)訓(xùn)練,自然需要使用兩種優(yōu)化器,學(xué)習(xí)率為:0.0001 generator_optimizer = tf.train.AdamOptimizer(1e-4) discriminator_optimizer = tf.train.AdamOptimizer(1e-4)
checkpoint_dir = "./training_checkpoints" checkpoint_prefix = os.path.join(checkpoint_dir, "ckpt") # checkpoint配置 checkpoint = tf.train.Checkpoint(generator_optimizer=generator_optimizer, discriminator_optimizer=discriminator_optimizer, generator=generator, discriminator=discriminator)模型訓(xùn)練
訓(xùn)練參數(shù)配置:
# 數(shù)據(jù)集迭代次數(shù) EPOCHS = 50 # 生成器噪聲維度 noise_dim = 100 # 可視化效果數(shù)量設(shè)置 num_examples_to_generate = 16 random_vector_for_generation = tf.random_normal([num_examples_to_generate, noise_dim])
生成器將我們?cè)O(shè)定的正態(tài)分布的噪聲向量作為輸入,用來(lái)生成圖像。判別器將同時(shí)顯示數(shù)據(jù)集真實(shí)圖像和生成器生成的圖像用于判別。隨后,我們計(jì)算生成器和判斷器損失函數(shù)對(duì)參數(shù)的梯度,然后使用梯度下降進(jìn)行更新。
def train_step(images): # 正態(tài)分布噪聲作為生成器輸入 noise = tf.random_normal([BATCH_SIZE, noise_dim]) # tf.GradientTape進(jìn)行記錄 with tf.GradientTape() as gen_tape, tf.GradientTape() as disc_tape: generated_images = generator(noise, training=True) # 判別器中真實(shí)圖像和生成器的假圖像 real_output = discriminator(images, training=True) generated_output = discriminator(generated_images, training=True) gen_loss = generator_loss(generated_output) disc_loss = discriminator_loss(real_output, generated_output) gradients_of_generator = gen_tape.gradient(gen_loss, generator.variables) gradients_of_discriminator = disc_tape.gradient(disc_loss, discriminator.variables) generator_optimizer.apply_gradients(zip(gradients_of_generator, generator.variables)) discriminator_optimizer.apply_gradients(zip(gradients_of_discriminator, discriminator.variables))
開(kāi)始訓(xùn)練:
加速計(jì)算節(jié)約內(nèi)存,但是不可以使用"pdb","print"。
train_step = tf.contrib.eager.defun(train_step)
def train(dataset, epochs): for epoch in range(epochs): start = time.time() # 迭代數(shù)據(jù)集 for images in dataset: train_step(images) display.clear_output(wait=True) # 保存圖像用于后面的可視化 generate_and_save_images(generator, epoch + 1, random_vector_for_generation) # 每迭代15次數(shù)據(jù)集保存一次模型 # 如需部署至tensorflow serving需要使用savemodel if (epoch + 1) % 15 == 0: checkpoint.save(file_prefix = checkpoint_prefix) print ("Time taken for epoch {} is {} sec".format(epoch + 1, time.time()-start)) display.clear_output(wait=True) generate_and_save_images(generator, epochs, random_vector_for_generation)
可視化生成器圖像:
def generate_and_save_images(model, epoch, test_input): # training:False 不訓(xùn)練BN predictions = model(test_input, training=False) fig = plt.figure(figsize=(4,4)) for i in range(predictions.shape[0]): plt.subplot(4, 4, i+1) plt.imshow(predictions[i, :, :, 0] * 127.5 + 127.5, cmap="gray") plt.axis("off") plt.savefig("image_at_epoch_{:04d}.png".format(epoch)) plt.show() train(train_dataset, EPOCHS)可視化模型訓(xùn)練結(jié)果
展示照片:
def display_image(epoch_no): return PIL.Image.open("image_at_epoch_{:04d}.png".format(epoch_no))
動(dòng)畫(huà)展示訓(xùn)練結(jié)果:
with imageio.get_writer("dcgan.gif", mode="I") as writer: filenames = glob.glob("image*.png") filenames = sorted(filenames) last = -1 for i,filename in enumerate(filenames): frame = 2*(i**0.5) if round(frame) > round(last): last = frame else: continue image = imageio.imread(filename) writer.append_data(image) image = imageio.imread(filename) writer.append_data(image) os.system("cp dcgan.gif dcgan.gif.png") display.Image(filename="dcgan.gif.png")總結(jié)
DCGAN中生成器判別器都使用卷積網(wǎng)絡(luò)來(lái)提升生成和判別能力,其中生成器利用反卷積,判別器利用常規(guī)卷積。生成器用隨機(jī)噪聲向量作為輸入來(lái)生成假圖像,判別器通過(guò)對(duì)真實(shí)樣本的學(xué)習(xí)判斷生成器圖像真?zhèn)危绻袛酁榧伲善髦匦抡{(diào)校訓(xùn)練,直到判別器無(wú)法區(qū)分真實(shí)樣本圖像和生成器的圖像。
本文代碼部分參考Yash Katariya,在此表示感謝。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/42754.html
摘要:很多人可能會(huì)問(wèn)這個(gè)故事和生成式對(duì)抗網(wǎng)絡(luò)有什么關(guān)系其實(shí),只要你能理解這段故事,就可以了解生成式對(duì)抗網(wǎng)絡(luò)的工作原理。 男:哎,你看我給你拍的好不好?女:這是什么鬼,你不能學(xué)學(xué)XXX的構(gòu)圖嗎?男:哦……男:這次你看我拍的行不行?女:你看看你的后期,再看看YYY的后期吧,呵呵男:哦……男:這次好點(diǎn)了吧?女:呵呵,我看你這輩子是學(xué)不會(huì)攝影了……男:這次呢?女:嗯,我拿去當(dāng)頭像了上面這段對(duì)話講述了一位男...
摘要:目前,生成對(duì)抗網(wǎng)絡(luò)的大部分應(yīng)用都是在計(jì)算機(jī)視覺(jué)領(lǐng)域。生成對(duì)抗網(wǎng)絡(luò)生成對(duì)抗網(wǎng)絡(luò)框架是由等人于年設(shè)計(jì)的生成模型。在設(shè)置中,兩個(gè)由神經(jīng)網(wǎng)絡(luò)進(jìn)行表示的可微函數(shù)被鎖定在一個(gè)游戲中。我們提出了深度卷積生成對(duì)抗網(wǎng)絡(luò)的實(shí)現(xiàn)。 讓我們假設(shè)這樣一種情景:你的鄰居正在舉辦一場(chǎng)非常酷的聚會(huì),你非常想去參加。但有要參加聚會(huì)的話,你需要一張?zhí)貎r(jià)票,而這個(gè)票早就已經(jīng)賣(mài)完了。而對(duì)于這次聚會(huì)的組織者來(lái)說(shuō),為了讓聚會(huì)能夠成功舉...
摘要:自年提出生成對(duì)抗網(wǎng)絡(luò)的概念后,生成對(duì)抗網(wǎng)絡(luò)變成為了學(xué)術(shù)界的一個(gè)火熱的研究熱點(diǎn),更是稱(chēng)之為過(guò)去十年間機(jī)器學(xué)習(xí)領(lǐng)域最讓人激動(dòng)的點(diǎn)子。 自2014年Ian Goodfellow提出生成對(duì)抗網(wǎng)絡(luò)(GAN)的概念后,生成對(duì)抗網(wǎng)絡(luò)變成為了學(xué)術(shù)界的一個(gè)火熱的研究熱點(diǎn),Yann LeCun更是稱(chēng)之為過(guò)去十年間機(jī)器學(xué)習(xí)領(lǐng)域最讓人激動(dòng)的點(diǎn)子。生成對(duì)抗網(wǎng)絡(luò)的簡(jiǎn)單介紹如下,訓(xùn)練一個(gè)生成器(Generator,簡(jiǎn)稱(chēng)G...
摘要:近日,谷歌大腦發(fā)布了一篇全面梳理的論文,該研究從損失函數(shù)對(duì)抗架構(gòu)正則化歸一化和度量方法等幾大方向整理生成對(duì)抗網(wǎng)絡(luò)的特性與變體。他們首先定義了全景圖損失函數(shù)歸一化和正則化方案,以及最常用架構(gòu)的集合。 近日,谷歌大腦發(fā)布了一篇全面梳理 GAN 的論文,該研究從損失函數(shù)、對(duì)抗架構(gòu)、正則化、歸一化和度量方法等幾大方向整理生成對(duì)抗網(wǎng)絡(luò)的特性與變體。作者們復(fù)現(xiàn)了當(dāng)前較佳的模型并公平地對(duì)比與探索 GAN ...
閱讀 2412·2021-08-18 10:21
閱讀 2519·2019-08-30 13:45
閱讀 2154·2019-08-30 13:16
閱讀 2096·2019-08-30 12:52
閱讀 1362·2019-08-30 11:20
閱讀 2622·2019-08-29 13:47
閱讀 1621·2019-08-29 11:22
閱讀 2760·2019-08-26 12:11