影像生成:GAN

  • 2019 年 10 月 4 日
  • 筆記

版權聲明:本文為部落客原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。

本文鏈接:https://blog.csdn.net/chaipp0607/article/details/100859215

簡介

GAN,即生成對抗模型,是影像生成領域內的一種重要方法,它在2014年由Goodfellow提出,它的論文是《Generative Adversarial Networks》,GAN是在訓練兩個相互對抗的網路,一個生成器(Generator)和一個判別器(Descriminator)。當訓練達到平衡時,對於一個輸入雜訊zzz。G(z)G(z)G(z)就是最後生成出來的影像。

GAN原理

GAN結構

GAN的結構非常簡單,就像上圖這樣,它有一個生成器G(Generator)和一個判別器D(Discriminator):生成器的輸入是一組隨機的變數,輸出是生成的圖;判別器負責對生成的圖進行打分,輸出是一個0-1之間的置信度。 對於生成器G,希望生成的影像G(z)G(z)G(z)無限逼近於真實影像,而對於判別器D,希望無論生成的影像G(z)G(z)G(z)有多真實,判別器總是能把他和真實的影像區分開,所以說GAN是一個G和D博弈的過程。 這個過程在GAN訓練時體現的更為明顯,就像兩個人下棋一樣,一個人走棋時,另一個人要等對方走完才能走棋,GAN的訓練也是這樣,生成器G和判別器D的優化是分開的,並相互交替迭代。

上面這張圖中,訓練開始時,黑線、綠線和藍線分別代表真實樣本分布、生成器生成的樣本分布以及判別模型。

  • 圖(a)是訓練前最初的狀態;
  • 圖(b)是固定生成器G,訓練判別器D的結果,使判別器可以區分出生生成樣本分布和真實樣本分布;
  • 圖( c)是固定上一步的判別器D,訓練生成器G的結果,使生成的樣本分布更接近真實樣本分布,騙過當前的判別器;
  • 圖(d)是經過多次的迭代,生成器和判別器達到平衡,生產樣本無限接近真實樣本分布,判別器無法區分出來。

在實際的訓練中,生成器G和判別器D的優化不是逐次交替的,而是每訓練k次的判別器D後,訓練一次生成器G,這樣能保證G的變化足夠慢,使總是能D保持在其最佳解附近。

GAN損失函數

雖然GAN的優化是交替進行的,但是損失函數只有一個。GAN的損失函數: minGmaxDV(G,D)=Ex∼pdata(x))[logD(x)]+Ez∼pz(z))[log(1−(D(G(z)))]underset{G}{min}underset{D}{max}V(G,D)=mathbb{E}_{xsim p_{data}(x))}[logD(x)] +mathbb{E}_{zsim p_{z}(z))}[log(1-(D(G(z)))]Gmin​Dmax​V(G,D)=Ex∼pdata​(x))​[logD(x)]+Ez∼pz​(z))​[log(1−(D(G(z)))] 其中pdatap_{data}pdata​代表真實的樣本分布,pzp_{z}pz​代表生成的樣本分布,優化生成器G時,固定住當前的判別器D。判別器D的輸出結果在0-1之間,當輸出為1時認為是真實樣本。生成器G優化的目的是騙過判別器D,即D(G(z))D(G(z))D(G(z))趨近於1,1−D(G(z))1-D(G(z))1−D(G(z))趨近於0,而logD(x)logD(x)logD(x)的最大值也僅僅是0。所以優化生成器是最小化V(G,D)V(G,D)V(G,D): minGV(G,D)=Ex∼pdata(x))[logD(x)]+Ez∼pz(z))[log(1−(D(G(z)))]underset{G}{min}V(G,D)=mathbb{E}_{xsim p_{data}(x))}[logD(x)] +mathbb{E}_{zsim p_{z}(z))}[log(1-(D(G(z)))]Gmin​V(G,D)=Ex∼pdata​(x))​[logD(x)]+Ez∼pz​(z))​[log(1−(D(G(z)))] 另一種情況是,固定生成器G,優化判別器D。判別器D優化的目的是無論生成的樣本多麼接近真實樣本,都能判別出來。所以即D(G(z))D(G(z))D(G(z))趨近於0,1−D(G(z))1-D(G(z))1−D(G(z))趨近於1。所以優化判別器是最大化V(G,D)V(G,D)V(G,D): maxDV(G,D)=Ex∼pdata(x))[logD(x)]+Ez∼pz(z))[log(1−(D(G(z)))]underset{D}{max}V(G,D)=mathbb{E}_{xsim p_{data}(x))}[logD(x)] +mathbb{E}_{zsim p_{z}(z))}[log(1-(D(G(z)))]Dmax​V(G,D)=Ex∼pdata​(x))​[logD(x)]+Ez∼pz​(z))​[log(1−(D(G(z)))]

GAN訓練過程

實際的損失計算過程和上述公式有些差異,主要在於優化生成器的時候,Ex∼pdata(x))[logD(x)]mathbb{E}_{xsim p_{data}(x))}[logD(x)]Ex∼pdata​(x))​[logD(x)]不參與計算。對於判別器,雖然它的輸出是0-1之間的一個數,但是它的目的其實是二分類,因為一個被壓縮到0-1之間的結果相當於做二分類logist。 同時我們知道了分別優化生成器和判別器時,判別器的期望值,即最大化的判別器損失和最小化的生成器損失的區別在於判別器的期望值不同。所以這個損失可以用二值交叉熵來做,下面是一個PyTorch實現的例子: 假設我們定義好了生成器和判別器模型,分別叫做GeneratorDiscriminator,分別構建它們的optimizer。

#二值交叉熵損失  criterion = nn.BCELoss()  #生成器optimizer  g_optimizer = torch.optim.Adam(Generator.parameters(), lr=0.0002)  #判別器optimizer  d_optimizer = torch.optim.Adam(Discriminator.parameters(), lr=0.0002)   # 定義真實label為1 可以假設batch_size=1  real_label = Variable(torch.ones(batch_size)).cuda()  # 定義假的label為0 可以假設batch_size=1  fake_label = Variable(torch.zeros(batch_size)).cuda()  

訓練生成器G:

# 生成隨機雜訊z  z = Variable(torch.randn(batch_size, z_dimension)).cuda()  # 生成器通過z生成假的圖片fake_img  fake_img = Generator(z)  # fake_img得到判別結果output  output = Discriminator(fake_img)  # output的期望值為1,即real_label,計算生成器損失  # 只有一個損失  g_loss = criterion(output, real_label)  #優化Generator  g_optimizer.zero_grad()  g_loss.backward()  g_optimizer.step() 

訓練判別器D:

# 將真實的圖片放入判別器中,得到real_out  real_out = D(real_img)  # real_out 的期望值為1,即real_label,計算判別器損失1  d_loss_real = criterion(real_out, real_label)  # 生成隨機雜訊z  z = Variable(torch.randn(batch_size, z_dimension)).cuda()  # 生成器通過z生成假的圖片fake_img  fake_img = G(z)  # fake_img得到判別結果fake_out  fake_out = D(fake_img)  # fake_out 的期望值為0,即fake_label,計算生成器損失  d_loss_fake = criterion(fake_out, fake_label)  # 將真假圖片的loss加起來  # 有兩個損失  d_loss = d_loss_real + d_loss_fake  #優化Discriminator  d_optimizer.zero_grad()  d_loss.backward()  d_optimizer.step()  

GAN生成效果

GAN在MNIST,TFD和CIFAR-10三個數據集上測試了生成效果,分別是MNIST為圖a),TFD為圖b),CIFAR-10為圖c)和圖d)。 當然現在來看的話,這個結果照比BigGAN和styleGAN這樣的模型來說,差了很遠,但是在當時已經是相當驚艷了。

GAN、VAE和CNN

最後說明一下GAN,VAE和CNN的關係,GAN和VAE、CNN是相互獨立的,沒有包含或被包含的關係。它們的關係應該是這樣:

其中的交集是三種方法結合使用的部分。

AE和VAE

AVE(變成自編碼器)是一個比GAN還要早的生成模型,它是AE(自編碼器)的一種變體,下圖是一個AE結構,它的輸出是在還原輸入,Encoder的輸出就是編碼,AE更多的用來做數據的壓縮。

而VAE就可以用來生成新的東西了,VAE和AE的區別在於,AE不關心中間的編碼形式,只關心輸出是不是完全還原了輸入,而VAE除此之外,還要控制中間編碼向量的形式,如下所示。

當對z_log_var重新取樣的時候,就能控制新的輸出。

GAN和VAE

VAE一般採用MSE評估生成影像,即每一個像素上的均方差,這樣會使生成的影像變得模糊。但是VAE由於自身是帶條件控制的,所以VAE不會生成很多奇奇怪怪的影像。 GAN採用判別器評估生成的影像,由於沒了均方誤差損失,所以GAN生成影像更清晰,但是由於GAN很難訓練,同時原始的GAN沒有條件控制的能力,所以GAN生成的影像有些會很奇怪。 此外,由於GAN沒有編碼,所以它是一個隨機雜訊到影像的過程,而VAE是圖到圖的過程。 所以就有了將GAN和VAE結合的方法,《Autoencoding beyond pixels using a learned similarity metric》。

GAN和CNN

CNN就不用多說了,它和GAN也是獨立的,GAN的結構可以用任意模型做判別器和生成器,不見得是CNN結構。但是由於CNN強大的特徵自提取功能,不用來和GAN結合,簡直太可惜了,所以第一個這麼乾的就是DCGAN,《Unsupervised Representation Learning with Deep Convolutional Generative Adversarial Networks》,DCGAN解決了CNN用於GAN時不穩定的問題,於是到現在,幾乎所有的GAN模型,都是用CNN做生成器和判別器。