摘要:深度卷積對抗生成網絡是的變體,是一種將卷積引入模型的網絡。特點是判別器使用來替代空間池化,生成器使用反卷積使用穩(wěn)定學習,有助于處理初始化不良導致的訓練問題生成器輸出層使用激活函數,其它層使用激活函數。
介紹
如圖所示,GAN網絡會同時訓練兩個模型。生成器:負責生成數據(比如:照片);判別器:判別所生成照片的真假。訓練過程中,生成器生成的照片會越來越接近真實照片,直到判別器無法區(qū)分照片真假。
DCGAN(深度卷積對抗生成網絡)是GAN的變體,是一種將卷積引入模型的網絡。特點是:
判別器使用strided convolutions來替代空間池化,生成器使用反卷積
使用BN穩(wěn)定學習,有助于處理初始化不良導致的訓練問題
生成器輸出層使用Tanh激活函數,其它層使用Relu激活函數。判別器上使用Leaky Relu激活函數。
本次案例我們將使用mnist作為數據集訓練DCGAN網絡,程序最后將使用GIF的方式展示訓練效果。
數據導入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加載數據
BUFFER_SIZE=60000 BATCH_SIZE=256 # 優(yōu)化輸入管道需要從:讀取,轉換,加載三方面考慮。 train_dataset=tf.data.Dataset.from_tensor_slices(train_images).shuffle(buffer_size=BUFFER_SIZE).batch(BATCH_SIZE)生成模型
該生成模型將使用反卷積層,我們首先創(chuàng)建全連接層然后通過兩次上采樣將圖片分辨率擴充至28x28x1。我們將逐步提升分辨率降低depth,除最后一層使用tanh激活函數,其它層都使用Leaky Relu激活函數。
def make_generator_model(): # 反卷積,從后往前 model=tf.keras.Sequential() model.add( tf.keras.layers.Dense( input_dim=7*7*256, # 不使用bias的原因是我們使用了BN,BN會抵消掉bias的作用。 # bias的作用: # 提升網絡擬合能力,而且計算簡單(只要一次加法)。 # 能力的提升源于調整輸出的整體分布 use_bias=False, # noise dim input_shape=(100,) ) ) """ 隨著神經網絡的訓練,網絡層的輸入分布會發(fā)生變動,逐漸向激活函數取值兩端靠攏,如:sigmoid激活函數, 此時會進入飽和狀態(tài),梯度更新緩慢,對輸入變動不敏感,甚至梯度消失導致模型難以訓練。 BN,在網絡層輸入激活函數輸入值之前加入,可以將分布拉到均值為0,標準差為1的正態(tài)分布,從而 使激活函數處于對輸入值敏感的區(qū)域,從而加快模型訓練。此外,BN還能起到類似dropout的正則化作用,由于我們會有 ‘強拉’操作,所以對初始化要求沒有那么高,可以使用較大的學習率。 """ model.add(tf.keras.layers.BatchNormalization()) """ relu 激活函數在輸入為負值的時候,激活值為0,此時神經元無法學習 leakyrelu 激活函數在輸入為負值的時候,激活值不為0(但值很?。?,神經元可以繼續(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()) # 卷積核為奇數:圖像兩邊可以對稱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激活函數值區(qū)間[-1,1],均值為0關于原點中心對稱。、 # sigmoid激活函數梯度在反向傳播過程中會出全正數或全負數,導致權重更新出現Z型下降。 activation="tanh" )) assert model.output_shape == (None,28,28,1) return model判別模型
判別器使用strided convolutions來替代空間池化,比如這里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常見于全連接層,其實卷積層也是可以使用的。 # 這里簡單翻譯下dropout論文觀點: """ 可能很多人認為因為卷積層參數較少,過擬合發(fā)生概率較低,所以dropout作用并不大。 但是,dropout在前面幾層依然有幫助,因為它為后面的全連接層提供了加噪聲的輸入,從而防止過擬合。 """ 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損失函數
獲取模型:
generator = make_generator_model() discriminator = make_discriminator_model()
生成器損失函數:
損失函數使用sigmoid cross entropy,labels使用值全為1的數組。
def generator_loss(generator_output): return tf.losses.sigmoid_cross_entropy( multi_class_labels=tf.ones_like(generator_output), logits=generator_output )
判別器損失函數
判別器損失函數接受兩種輸入,生成器生成的圖像和數據集中的真實圖像,損失函數計算方法如下:
使用sigmoid cross entropy損失函數計算數據集中真實圖像的損失,labels使用值全為1的數組。
使用sigmoid cross entropy損失函數計算生成器圖像的損失,labels使用值全為0的數組。
將以上損失相加得到判別器損失。
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
模型保存:
# 兩種模型同時訓練,自然需要使用兩種優(yōu)化器,學習率為: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)模型訓練
訓練參數配置:
# 數據集迭代次數 EPOCHS = 50 # 生成器噪聲維度 noise_dim = 100 # 可視化效果數量設置 num_examples_to_generate = 16 random_vector_for_generation = tf.random_normal([num_examples_to_generate, noise_dim])
生成器將我們設定的正態(tài)分布的噪聲向量作為輸入,用來生成圖像。判別器將同時顯示數據集真實圖像和生成器生成的圖像用于判別。隨后,我們計算生成器和判斷器損失函數對參數的梯度,然后使用梯度下降進行更新。
def train_step(images): # 正態(tài)分布噪聲作為生成器輸入 noise = tf.random_normal([BATCH_SIZE, noise_dim]) # tf.GradientTape進行記錄 with tf.GradientTape() as gen_tape, tf.GradientTape() as disc_tape: generated_images = generator(noise, training=True) # 判別器中真實圖像和生成器的假圖像 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))
開始訓練:
加速計算節(jié)約內存,但是不可以使用"pdb","print"。
train_step = tf.contrib.eager.defun(train_step)
def train(dataset, epochs): for epoch in range(epochs): start = time.time() # 迭代數據集 for images in dataset: train_step(images) display.clear_output(wait=True) # 保存圖像用于后面的可視化 generate_and_save_images(generator, epoch + 1, random_vector_for_generation) # 每迭代15次數據集保存一次模型 # 如需部署至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 不訓練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)可視化模型訓練結果
展示照片:
def display_image(epoch_no): return PIL.Image.open("image_at_epoch_{:04d}.png".format(epoch_no))
動畫展示訓練結果:
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")總結
DCGAN中生成器判別器都使用卷積網絡來提升生成和判別能力,其中生成器利用反卷積,判別器利用常規(guī)卷積。生成器用隨機噪聲向量作為輸入來生成假圖像,判別器通過對真實樣本的學習判斷生成器圖像真?zhèn)?,如果判斷為假,生成器重新調校訓練,直到判別器無法區(qū)分真實樣本圖像和生成器的圖像。
本文代碼部分參考Yash Katariya,在此表示感謝。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規(guī)行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://systransis.cn/yun/42754.html
摘要:很多人可能會問這個故事和生成式對抗網絡有什么關系其實,只要你能理解這段故事,就可以了解生成式對抗網絡的工作原理。 男:哎,你看我給你拍的好不好?女:這是什么鬼,你不能學學XXX的構圖嗎?男:哦……男:這次你看我拍的行不行?女:你看看你的后期,再看看YYY的后期吧,呵呵男:哦……男:這次好點了吧?女:呵呵,我看你這輩子是學不會攝影了……男:這次呢?女:嗯,我拿去當頭像了上面這段對話講述了一位男...
摘要:目前,生成對抗網絡的大部分應用都是在計算機視覺領域。生成對抗網絡生成對抗網絡框架是由等人于年設計的生成模型。在設置中,兩個由神經網絡進行表示的可微函數被鎖定在一個游戲中。我們提出了深度卷積生成對抗網絡的實現。 讓我們假設這樣一種情景:你的鄰居正在舉辦一場非??岬木蹠惴浅O肴⒓?。但有要參加聚會的話,你需要一張?zhí)貎r票,而這個票早就已經賣完了。而對于這次聚會的組織者來說,為了讓聚會能夠成功舉...
摘要:自年提出生成對抗網絡的概念后,生成對抗網絡變成為了學術界的一個火熱的研究熱點,更是稱之為過去十年間機器學習領域最讓人激動的點子。 自2014年Ian Goodfellow提出生成對抗網絡(GAN)的概念后,生成對抗網絡變成為了學術界的一個火熱的研究熱點,Yann LeCun更是稱之為過去十年間機器學習領域最讓人激動的點子。生成對抗網絡的簡單介紹如下,訓練一個生成器(Generator,簡稱G...
摘要:近日,谷歌大腦發(fā)布了一篇全面梳理的論文,該研究從損失函數對抗架構正則化歸一化和度量方法等幾大方向整理生成對抗網絡的特性與變體。他們首先定義了全景圖損失函數歸一化和正則化方案,以及最常用架構的集合。 近日,谷歌大腦發(fā)布了一篇全面梳理 GAN 的論文,該研究從損失函數、對抗架構、正則化、歸一化和度量方法等幾大方向整理生成對抗網絡的特性與變體。作者們復現了當前較佳的模型并公平地對比與探索 GAN ...
閱讀 2422·2021-08-18 10:21
閱讀 2531·2019-08-30 13:45
閱讀 2161·2019-08-30 13:16
閱讀 2125·2019-08-30 12:52
閱讀 1372·2019-08-30 11:20
閱讀 2631·2019-08-29 13:47
閱讀 1629·2019-08-29 11:22
閱讀 2769·2019-08-26 12:11