GAN生成對抗網絡學習筆記
1.GAN誕生背后的故事:
GAN創始人 Ian Goodfellow 在酒吧微醉后與同事討論學術問題,當時靈光乍現提出了GAN初步的想法,不過當時並沒有得到同事的認可,在從酒吧回去后發現女朋友已經睡了,於是自己熬夜寫了代碼,發現還真有效果,於是經過一番研究后,GAN就誕生了,一篇開山之作。論文《Generative Adversarial Nets》首次提出GAN。
論文鏈接:https://arxiv.org/abs/1406.2661
2.GAN的原理:
GAN的主要靈感來源於博弈論中零和博弈的思想,應用到深度學習神經網絡上來說,就是通過生成網絡G(Generator)和判別網絡D(Discriminator)不斷博弈,進而使G學習到數據的分布,如果用到圖片生成上,則訓練完成后,G可以從一段隨機數中生成逼真的圖像。G, D的主要功能是:
G是一個生成式的網絡,它接收一個隨機的噪聲z(隨機數),通過這個噪聲生成圖像
D是一個判別網絡,判別一張圖片是不是“真實的”。它的輸入參數是x,x代表一張圖片,輸出D(x)代表x為真實圖片的概率,如果為1,就代表100%是真實的圖片,而輸出為0,就代表不可能是真實的圖片
訓練過程中,生成網絡G的目標就是盡量生成真實的圖片去欺騙判別網絡D。而D的目標就是盡量辨別出G生成的假圖像和真實的圖像。這樣,G和D構成了一個動態的“博弈過程”,最終的平衡點即納什均衡點.
通俗意思就是在犯罪分子造假幣和警察識別假幣的過程中
[1]生成模型G相當於制造假幣的一方,其目的是根據看到的錢幣情況和警察的識別技術,去盡量生成更加真實的、警察識別不出的假幣。
[2]判別模型D相當於識別假幣的一方,其目的是盡可能的識別出犯罪分子制造的假幣。這樣通過造假者和識假者雙方的較量和朝目的的改進,使得最后能達到生成模型能盡可能真的錢幣、識假者判斷不出真假的納什均衡效果(真假幣概率都為0.5)。
如圖所示:
3.GAN的原理圖:
4.GAN的特點:
相比較傳統的模型,他存在兩個不同的網絡,而不是單一的網絡,並且訓練方式采用的是對抗訓練方式
GAN中G的梯度更新信息來自判別器D,而不是來自數據樣本
5.GAN 的優點:
GAN是一種生成式模型,相比較其他生成模型(玻爾茲曼機和GSNs)只用到了反向傳播,而不需要復雜的馬爾科夫鏈
相比其他所有模型, GAN可以產生更加清晰,真實的樣本
GAN采用的是一種無監督的學習方式訓練,可以被廣泛用在無監督學習和半監督學習領域
相比於變分自編碼器, GANs沒有引入任何決定性偏置( deterministic bias),變分方法引入決定性偏置,因為他們優化對數似然的下界,而不是似然度本身,這看起來導致了VAEs生成的實例比GANs更模糊
相比VAE, GANs沒有變分下界,如果鑒別器訓練良好,那么生成器可以完美的學習到訓練樣本的分布.換句話說,GANs是漸進一致的,但是VAE是有偏差的
GAN應用到一些場景上,比如圖片風格遷移,超分辨率,圖像補全,去噪,避免了損失函數設計的困難,不管三七二十一,只要有一個的基准,直接上判別器,剩下的就交給對抗訓練了。
6.GAN的缺點:
訓練GAN需要達到納什均衡,有時候可以用梯度下降法做到,有時候做不到.我們還沒有找到很好的達到納什均衡的方法,所以訓練GAN相比VAE或者PixelRNN是不穩定的,但我認為在實踐中它還是比訓練玻爾茲曼機穩定的多
GAN不適合處理離散形式的數據,比如文本
GAN存在訓練不穩定、梯度消失、模式崩潰的問題(目前已解決)
7.訓練GAN的一些技巧:
輸入規范化到(-1,1)之間,最后一層的激活函數使用tanh(BEGAN除外)
使用wassertein GAN的損失函數,
如果有標簽數據的話,盡量使用標簽,也有人提出使用反轉標簽效果很好,另外使用標簽平滑,單邊標簽平滑或者雙邊標簽平滑
使用mini-batch norm, 如果不用batch norm 可以使用instance norm 或者weight norm
避免使用RELU和pooling層,減少稀疏梯度的可能性,可以使用leakrelu激活函數
優化器盡量選擇ADAM,學習率不要設置太大,初始1e-4可以參考,另外可以隨着訓練進行不斷縮小學習率,
給D的網絡層增加高斯噪聲,相當於是一種正則。
8.GAN的延伸有哪些:
DCGAN
CGAN
ACGAN
infoGAN
WGAN
SSGAN
Pix2Pix GAN
Cycle GAN
9.GAN可以做什么:答案是生成數據
生成音頻
生成圖片(動物:貓,狗等;人臉圖片,人臉圖轉動漫圖等)
.......
先來個美食圖緩一緩(學累就先吃一點東西,哈哈哈)
繼續!!!!!
10.GAN的經典案例:生成手寫數字圖片
源碼和數據集獲取方式在下方
有py格式和ipynb格式兩種(代碼是一樣的)
代碼如下:
# -*- coding: utf-8 -*-
"""
Created on 2020-10-31
@author: 李運辰
"""
#導入數據包
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
import matplotlib.pyplot as plt
#get_ipython().run_line_magic('matplotlib', 'inline')
import numpy as np
import glob
import os
# # 輸入
(train_images,train_labels),(_,_)=tf.keras.datasets.mnist.load_data()
train_images = train_images.astype('float32')
# # 數據預處理
train_images=train_images.reshape(train_images.shape[0],28,28,1).astype('float32')
#歸一化 到【-1,1】
train_images = (train_images -127.5)/127.5
BTATH_SIZE=256
BUFFER_SIZE=60000
#輸入管道
datasets = tf.data.Dataset.from_tensor_slices(train_images)
#打亂亂序,並取btath_size
datasets = datasets.shuffle(BUFFER_SIZE).batch(BTATH_SIZE)
# # 生成器模型
def generator_model():
model = tf.keras.Sequential()
model.add(layers.Dense(256,input_shape=(100,),use_bias=False))
#Dense全連接層,input_shape=(100,)長度100的隨機向量,use_bias=False,因為后面有BN層
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 = 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))#輸出數字,>0.5真實圖片
return model
# # loss函數
cross_entropy=tf.keras.losses.BinaryCrossentropy(from_logits=True)#from_logits=True因為最后的輸出沒有激活
# # 生成器損失函數
def generator_loss(fake_out):#希望fakeimage的判別輸出fake_out判別為真
return cross_entropy(tf.ones_like(fake_out),fake_out)
# # 判別器損失函數
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
# # 優化器
generator_opt=tf.keras.optimizers.Adam(1e-4)#學習速率
discriminator_opt=tf.keras.optimizers.Adam(1e-4)
EPOCHS=500
noise_dim=100 #長度為100的隨機向量生成手寫數據集
num_exp_to_generate=16 #每步生成16個樣本
seed=tf.random.normal([num_exp_to_generate,noise_dim]) #生成隨機向量觀察變化情況
# # 訓練
generator=generator_model()
discriminator=discriminator_model()
# # 定義批次訓練函數
def train_step(images):
noise = tf.random.normal([num_exp_to_generate,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_opt.apply_gradients(zip(gradient_gen,generator.trainable_variables))
discriminator_opt.apply_gradients(zip(gradient_disc,discriminator.trainable_variables))
# # 可視化
def generator_plot_image(gen_model,test_noise):
pre_images = gen_model(test_noise,training=False)
#繪圖16張圖片在一張4x4
fig = plt.figure(figsize=(4,4))
for i in range(pre_images.shape[0]):
plt.subplot(4,4,i+1) #從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):
for image_batch in dataset:
train_step(image_batch)
#print('第'+str(epoch+1)+'次訓練結果')
if epoch%10==0:
print('第'+str(epoch+1)+'次訓練結果')
generator_plot_image(generator,seed)
train(datasets,EPOCHS)
訓練結果:
第1次訓練結果
第100次訓練結果
結論:
在100次訓練后,可以明顯看到數字的內容,到訓練了300次之后就可以很清楚看到生成的數字效果,但300次之后,400,500次效果逐漸下降。圖片內容變模糊。
正文結束!!!!
源碼和數據集獲取方法
公眾號回復【GAN】免費獲取
歡迎關注公眾號:Python爬蟲數據分析挖掘
記錄學習python的點點滴滴;
回復【開源源碼】免費獲取更多開源項目源碼;
公眾號每日更新python知識和【免費】工具;
本文已同步到【開源中國】和【騰訊雲社區】;