生成对抗网络——GAN(一)
Generative adversarial network
據有關媒體統計:CVPR2018的論文里,有三分之一的論文與GAN有關
由此可見,GAN在視覺領域的未來多年內,將是一片沃土(CVer們是時候入門GAN了)。而發現這片礦源的就是GAN之父,Goodfellow大神。
文末有基于keras的GAN代碼,有助于理解GAN的原理
生成對抗網絡GAN,是當今的一大熱門研究方向。在2014年,被Goodfellow大神提出來,當時的G神還只是蒙特利爾大學的博士生而已。
GAN之父的主頁:
http://www.iangoodfellow.com/
GAN的論文首次出現在NIPS2014上,論文地址如下:
https://arxiv.org/pdf/1406.2661.pdf
入坑GAN,首先需要理由,GAN能做什么,為什么要學GAN。
GAN的初衷就是生成不存在于真實世界的數據,類似于使得 AI具有創造力或者想象力。應用場景如下:
以上的場景都可以找到相應的paper。而且GAN的用處也遠不止此,期待我們繼續挖掘,是發論文的好方向哦
GAN的原理介紹
這里介紹的是原生的GAN算法,雖然有一些不足,但提供了一種生成對抗性的新思路。放心,我這篇博文不會堆一大堆公式,只會提供一種理解思路。
理解GAN的兩大護法G和D
G是generator,生成器: 負責憑空捏造數據出來
D是discriminator,判別器: 負責判斷數據是不是真數據
這樣可以簡單的看作是兩個網絡的博弈過程。在最原始的GAN論文里面,G和D都是兩個多層感知機網絡。首先,注意一點,GAN操作的數據不一定非得是圖像數據,不過為了更方便解釋,我在這里用圖像數據為例解釋以下GAN:
稍微解釋以下上圖,z是隨機噪聲(就是隨機生成的一些數,也就是GAN生成圖像的源頭)。D通過真圖和假圖的數據(相當于天然label),進行一個二分類神經網絡訓練(想各位必再熟悉不過了)。G根據一串隨機數就可以捏造一個“假圖像”出來,用這些假圖去欺騙D,D負責辨別這是真圖還是假圖,會給出一個score。比如,G生成了一張圖,在D這里得分很高,那證明G是很成功的;如果D能有效區分真假圖,則G的效果還不太好,需要調整參數。GAN就是這么一個博弈的過程。
那么,GAN是怎么訓練呢?
根據GAN的訓練算法,我畫一張圖:
GAN的訓練在同一輪梯度反傳的過程中可以細分為2步,先訓練D在訓練G;注意不是等所有的D訓練好以后,才開始訓練G,因為D的訓練也需要上一輪梯度反傳中G的輸出值作為輸入。
當訓練D的時候,上一輪G產生的圖片,和真實圖片,直接拼接在一起,作為x。然后根據,按順序擺放0和1,假圖對應0,真圖對應1。然后就可以通過,x輸入生成一個score(從0到1之間的數),通過score和y組成的損失函數,就可以進行梯度反傳了。(我在圖片上舉的例子是batch = 1,len(y)=2*batch,訓練時通??梢匀≥^大的batch)
當訓練G的時候, 需要把G和D當作一個整體,我在這里取名叫做’D_on_G’。這個整體(下面簡稱DG系統)的輸出仍然是score。輸入一組隨機向量,就可以在G生成一張圖,通過D對生成的這張圖進行打分,這就是DG系統的前向過程。score=1就是DG系統需要優化的目標,score和y=1之間的差異可以組成損失函數,然后可以反向傳播梯度。注意,這里的D的參數是不可訓練的。這樣就能保證G的訓練是符合D的打分標準的。這就好比:如果你參加考試,你別指望能改變老師的評分標準
需要注意的是,整個GAN的整個過程都是無監督的(后面會有監督性GAN比如cGAN),怎么理解這里的無監督呢?
這里,給的真圖是沒有經過人工標注的,你只知道這是真實的圖片,比如全是人臉,而系統里的D并不知道來的圖片是什么玩意兒,它只需要分辨真假。G也不知道自己生成的是什么玩意兒,反正就是學真圖片的樣子騙D。
正由于GAN的無監督,在生成過程中,G就會按照自己的意思天馬行空生成一些“詭異”的圖片,可怕的是D還能給一個很高的分數。比如,生成人臉極度扭曲的圖片。這就是無監督目的性不強所導致的,所以在同年的NIPS大會上,有一篇論文conditional GAN就加入了監督性進去,將可控性增強,表現效果也好很多。
from __future__ import print_function, divisionfrom keras.datasets import mnist from keras.layers import Input, Dense, Reshape, Flatten, Dropout from keras.layers import BatchNormalization, Activation, ZeroPadding2D from keras.layers.advanced_activations import LeakyReLU from keras.layers.convolutional import UpSampling2D, Conv2D from keras.models import Sequential, Model from keras.optimizers import Adamimport matplotlib.pyplot as pltimport sysimport numpy as npclass GAN():def __init__(self):self.img_rows = 28self.img_cols = 28self.channels = 1self.img_shape = (self.img_rows, self.img_cols, self.channels)self.latent_dim = 100optimizer = Adam(0.0002, 0.5)# Build and compile the discriminatorself.discriminator = self.build_discriminator()self.discriminator.compile(loss='binary_crossentropy',optimizer=optimizer,metrics=['accuracy'])# Build the generatorself.generator = self.build_generator()# The generator takes noise as input and generates imgsz = Input(shape=(self.latent_dim,))img = self.generator(z)# For the combined model we will only train the generatorself.discriminator.trainable = False# The discriminator takes generated images as input and determines validityvalidity = self.discriminator(img)# The combined model (stacked generator and discriminator)# Trains the generator to fool the discriminatorself.combined = Model(z, validity)self.combined.compile(loss='binary_crossentropy', optimizer=optimizer)def build_generator(self):model = Sequential()model.add(Dense(256, input_dim=self.latent_dim))model.add(LeakyReLU(alpha=0.2))model.add(BatchNormalization(momentum=0.8))model.add(Dense(512))model.add(LeakyReLU(alpha=0.2))model.add(BatchNormalization(momentum=0.8))model.add(Dense(1024))model.add(LeakyReLU(alpha=0.2))model.add(BatchNormalization(momentum=0.8))model.add(Dense(np.prod(self.img_shape), activation='tanh'))model.add(Reshape(self.img_shape))model.summary()noise = Input(shape=(self.latent_dim,))img = model(noise)return Model(noise, img)def build_discriminator(self):model = Sequential()model.add(Flatten(input_shape=self.img_shape))model.add(Dense(512))model.add(LeakyReLU(alpha=0.2))model.add(Dense(256))model.add(LeakyReLU(alpha=0.2))model.add(Dense(1, activation='sigmoid'))model.summary()img = Input(shape=self.img_shape)validity = model(img)return Model(img, validity)def train(self, epochs, batch_size=128, sample_interval=50):# Load the dataset(X_train, _), (_, _) = mnist.load_data()# Rescale -1 to 1X_train = X_train / 127.5 - 1.X_train = np.expand_dims(X_train, axis=3)# Adversarial ground truthsvalid = np.ones((batch_size, 1))fake = np.zeros((batch_size, 1))for epoch in range(epochs):# ---------------------# Train Discriminator# ---------------------# Select a random batch of imagesidx = np.random.randint(0, X_train.shape[0], batch_size)imgs = X_train[idx]noise = np.random.normal(0, 1, (batch_size, self.latent_dim))# Generate a batch of new imagesgen_imgs = self.generator.predict(noise)# Train the discriminatord_loss_real = self.discriminator.train_on_batch(imgs, valid)d_loss_fake = self.discriminator.train_on_batch(gen_imgs, fake)d_loss = 0.5 * np.add(d_loss_real, d_loss_fake)# ---------------------# Train Generator# ---------------------noise = np.random.normal(0, 1, (batch_size, self.latent_dim))# Train the generator (to have the discriminator label samples as valid)g_loss = self.combined.train_on_batch(noise, valid)# Plot the progressprint ("%d [D loss: %f, acc.: %.2f%%] [G loss: %f]" % (epoch, d_loss[0], 100*d_loss[1], g_loss))# If at save interval => save generated image samplesif epoch % sample_interval == 0:self.sample_images(epoch)def sample_images(self, epoch):r, c = 5, 5noise = np.random.normal(0, 1, (r * c, self.latent_dim))gen_imgs = self.generator.predict(noise)# Rescale images 0 - 1gen_imgs = 0.5 * gen_imgs + 0.5fig, axs = plt.subplots(r, c)cnt = 0for i in range(r):for j in range(c):axs[i,j].imshow(gen_imgs[cnt, :,:,0], cmap='gray')axs[i,j].axis('off')cnt += 1fig.savefig("images/%d.png" % epoch)plt.close()if __name__ == '__main__':gan = GAN()gan.train(epochs=30000, batch_size=32, sample_interval=200)
總結
以上是生活随笔為你收集整理的生成对抗网络——GAN(一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: iOS动画-CAAnimation使用详
- 下一篇: Java 内部类详解