GAN的原理和實現
GAN,生成式對抗網路(Generative Adversarial Networks)是一種深度學習模型,是近幾年來複雜分佈上無監督學習最具前景的方法之一。
機器學習的模型可大體分為兩類,生成模型(Generative model)和判別模型(Discriminator model),判別模型需要輸入變數,通過某種模型來預測,生成模型是給定某種隱含資訊,來隨機產生資料。
GAN主要包括了兩個部分,即生成器generator與判別器discriminator。生成器主要用來學習真實影象分佈從而讓自身生成的影象更加的真實,以騙過判別器。判別器則需要對接受的圖片進行真假判別。
原理:
在訓練過程中,生成器努力地讓生成的影象更加真實,而判別器則努力地去識別影象的真假,這個過程相當於二人進行博弈,隨著時間的推移,生成器和判別器在不斷地進行對抗。最終兩個網路達到了一個動態平衡,生成器生成的影象接近於真實影象分佈,而判別器識別不出真假影象,對於給定影象的預測為真的概率基本接近0.5(相當於隨機猜測類別)。
最終的結果:
G可以生成足以'以假亂真'的圖片G(z),對於D來說,它難以判定G生成的圖片究竟是不是真實的,因此D(G(z))=0.5,目的就是為了得到一個生成模型G,可以用來生成圖片。
GAN的應用領域:
- 影象生成
- 影象增強
- 風格化
- 藝術的影象創造
GAN的簡單實現
import tensorflow as tf from tensorflow import keras from tensorflow.keras import layers import matplotlib.pyplot as plt import numpy as np import glob importos (train_images,train_labels),(_,_) = tf.keras.datasets.mnist.load_data() train_images = train_images.reshape(train_images.shape[0],28,28,1) train_images = tf.cast(train_images,tf.float32) train_images = (train_images - 127.5) / 127.5 BATCH_SIZE = 256 #None就是每個BATCH BUFFER_SIZE = 60000 datasets= tf.data.Dataset.from_tensor_slices(train_images) print(datasets) #<TensorSliceDataset shapes: (28, 28), types: tf.float32> datasets = datasets.shuffle(BUFFER_SIZE).batch(BATCH_SIZE) def generator_model(): model = tf.keras.Sequential() model.add(layers.Dense(256,input_shape=(100,),use_bias=False)) model.add(layers.BatchNormalization()) model.add(layers.LeakyReLU()) model.add(layers.Dense(512,use_bias=False)) model.add(layers.BatchNormalization()) model.add(layers.LeakyReLU()) model.add(layers.Dense(28*28*1,use_bias='False',activation='tanh')) model.add(layers.BatchNormalization()) model.add(layers.Reshape((28,28,1))) return model def discriminator_model(): model = tf.keras.Sequential() model.add(layers.Flatten()) model.add(layers.Dense(512,use_bias=False)) model.add(layers.BatchNormalization()) model.add(layers.LeakyReLU()) model.add(layers.Dense(256,use_bias=False)) model.add(layers.BatchNormalization()) model.add(layers.LeakyReLU()) #先不用進行啟用,可以利用損失函式 model.add(layers.Dense(1)) return model cross_entropy = tf.keras.losses.BinaryCrossentropy(from_logits='True') #告訴損失函式我們最後一層沒有啟用 def discriminator_loss(real_out,fake_out): #這裡希望讓真實影象被判定為1,假的影象判定為0 real_loss = cross_entropy(tf.ones_like(real_out),real_out) fake_loss = cross_entropy(tf.zeros_like(fake_out),fake_out) return real_loss + fake_loss #生成器接收假的的圖片並希望能夠被判為真 def generator_loss(fake_out): return cross_entropy(tf.ones_like(fake_out),fake_out) #建立生成器優化器 generator_optimizer = tf.keras.optimizers.Adam(1e-4) #建立判別器優化器 discriminator_optimizer = tf.keras.optimizers.Adam(1e-4) generator = generator_model() discriminator = discriminator_model() EOPCHS = 10 NOISE_DIM = 100 num_ex_to_generate = 16 #生成16個長度為100的向量 seed = tf.random.normal([num_ex_to_generate,NOISE_DIM]) def train_step(images): noise = tf.random.normal([BATCH_SIZE,NOISE_DIM]) with tf.GradientTape() as gen_tape,tf.GradientTape() as disc_tape: real_out = discriminator(images,training=True) gen_image = generator(noise,training=True) fake_out = discriminator(gen_image,training=True) gen_loss = generator_loss(fake_out) disc_loss = discriminator_loss(real_out,fake_out) gradient_gen = gen_tape.gradient(gen_loss,generator.trainable_variables) gradient_disc = disc_tape.gradient(disc_loss,discriminator.trainable_variables) generator_optimizer.apply_gradients(zip(gradient_gen,generator.trainable_variables)) discriminator_optimizer.apply_gradients(zip(gradient_disc,discriminator.trainable_variables)) #畫出這一個批次的圖片 def generate_plot_image(gen_model,test_noise): pre_images = gen_model(test_noise,training=False) fig = plt.figure(figsize=(4,4)) for i in range(pre_images.shape[0]): plt.subplot(4,4,i+1) #因為在生成圖片最後用啟用函式tanh把圖片對映到[-1,1]之間,現在要把取值範圍改變成[0,1]的範圍 plt.imshow(pre_images[i,:,:,0] + 1/ 2,cmap='gray') plt.axis('off') plt.show() def train(dataset,epochs): for epoch in range(epochs): print('Epoch',epoch + 1,':') for image_path in dataset: train_step(image_path) print('.',end='') generate_plot_image(generator,seed) print('\n') train(datasets,EOPCHS)
DCGAN
DCGAN就是將CNN和原始的GAN結合到了一起,生成的模型和判別模型都運用了深度卷積神經網路的生成對抗網路。這個網路架構由<<Unsupervised Representation Learning with Deep Convolutional Generative Adversarial Networks>>這篇論文提出,DCGAN對卷積神經網路的結構做了一些改變,以提高樣本的質量和收斂的速度。
DCGAN的主要設計技巧:
1.取消所用pooling層。生成器網路中使用轉置卷積(transposed convolution layer)進行上取樣,判別器網路中加入stride的卷積代替pooling。
2.去掉全連線層(FC),使網路變成全卷積網路。
3.生成器網路中使用Relu作為啟用函式,最後一層使用tanh。
4.判別器網路中使用LeakyRelu作為啟用函式。
5.在Generator和Discriminator上都使用BatchNorm解決初始化差的問題,幫助梯度傳播到每一層,防止Generator把所有樣本都收斂到同一個點,直接將BatchNorm應用到所有層會導致樣本震盪和模型不穩定,通過在Generator輸出層和Discriminator輸入層不採用BatchNorm可以防止這種現象。
6.使用Adam優化器,beta1(1階矩估計的指數衰弱率)的值設定為0.5
7.論文引數
LeakyReLU的引數設定為0.2、learning rate=0.002、batch size=128
def generator_model(): model = tf.keras.Sequential() model.add(layers.Dense(7*7*256,input_shape=(100,),use_bias=False)) model.add(layers.BatchNormalization()) model.add(layers.LeakyReLU()) model.add(layers.Reshape((7,7,256))) model.add(layers.Conv2DTranspose(128,(5,5),strides=(1,1),padding='same',use_bias=False)) model.add(layers.BatchNormalization()) model.add(layers.LeakyReLU()) model.add(layers.Conv2DTranspose(64,(5,5),strides=(2,2),padding='same',use_bias=False)) model.add(layers.BatchNormalization()) model.add(layers.LeakyReLU()) model.add(layers.Conv2DTranspose(1,(5,5),strides=(2,2),padding='same',use_bias=False,activation='tanh')) return model def discriminator_model(): model = tf.keras.Sequential() model.add(layers.Conv2D(64,(5,5),strides=(2,2),padding='same',input_shape=(28,28,1))) model.add(layers.LeakyReLU()) model.add(layers.Dropout(0.3)) model.add(layers.Conv2D(128,(5,5),strides=(2,2),padding='same')) model.add(layers.LeakyReLU()) model.add(layers.Dropout(0.3)) model.add(layers.Conv2D(256,(5,5),strides=(2,2),padding='same')) model.add(layers.LeakyReLU()) model.add(layers.Flatten()) model.add(layers.Dense(1)) return model