1. 程式人生 > >【GAN】GAN的原理及推導

【GAN】GAN的原理及推導

把GAN的論文看完了, 也確實蠻厲害的懶得寫筆記了,轉一些較好的筆記,前面先貼一些 原論文裡推理部分,進行備忘。
GAN的解釋


演算法流程

GAN的理論推理



轉自:https://zhuanlan.zhihu.com/p/27295635

Generative Adversarial Network,就是大家耳熟能詳的GAN,由Ian Goodfellow首先提出,在這兩年更是深度學習中最熱門的東西,彷彿什麼東西都能由GAN做出來。我最近剛入門GAN,看了些資料,做一些筆記。

1.Generation

什麼是生成(generation)?就是模型通過學習一些資料,然後生成類似的資料。讓機器看一些動物圖片,然後自己來產生動物的圖片,這就是生成。

以前就有很多可以用來生成的技術了,比如auto-encoder(自編碼器),結構如下圖:

你訓練一個encoder,把input轉換成code,然後訓練一個decoder,把code轉換成一個image,然後計算得到的image和input之間的MSE(mean square error),訓練完這個model之後,取出後半部分NN Decoder,輸入一個隨機的code,就能generate一個image。

但是auto-encoder生成image的效果,當然看著很彆扭啦,一眼就能看出真假。所以後來還提出了比如VAE這樣的生成模型,我對此也不是很瞭解,在這就不細說。

上述的這些生成模型,其實有一個非常嚴重的弊端。比如VAE,它生成的image是希望和input越相似越好,但是model是如何來衡量這個相似呢?model會計算一個loss,採用的大多是MSE,即每一個畫素上的均方差。loss小真的表示相似嘛?

比如這兩張圖,第一張,我們認為是好的生成圖片,第二張是差的生成圖片,但是對於上述的model來說,這兩張圖片計算出來的loss是一樣大的,所以會認為是一樣好的圖片。

這就是上述生成模型的弊端,用來衡量生成圖片好壞的標準並不能很好的完成想要實現的目的。於是就有了下面要講的GAN。



2.GAN

大名鼎鼎的GAN是如何生成圖片的呢?首先大家都知道GAN有兩個網路,一個是generator,一個是discriminator,從二人零和博弈中受啟發,通過兩個網路互相對抗來達到最好的生成效果。流程如下:

主要流程類似上面這個圖。首先,有一個一代的generator,它能生成一些很差的圖片,然後有一個一代的discriminator,它能準確的把生成的圖片,和真實的圖片分類,簡而言之,這個discriminator就是一個二分類器,對生成的圖片輸出0,對真實的圖片輸出1。

接著,開始訓練出二代的generator,它能生成稍好一點的圖片,能夠讓一代的discriminator認為這些生成的圖片是真實的圖片。然後會訓練出一個二代的discriminator,它能準確的識別出真實的圖片,和二代generator生成的圖片。以此類推,會有三代,四代。。。n代的generator和discriminator,最後discriminator無法分辨生成的圖片和真實圖片,這個網路就擬合了。

這就是GAN,執行過程就是這麼的簡單。這就結束了嘛?顯然沒有,下面還要介紹一下GAN的原理。



3.原理

首先我們知道真實圖片集的分佈P_{data}(x),x是一個真實圖片,可以想象成一個向量,這個向量集合的分佈就是P_{data}。我們需要生成一些也在這個分佈內的圖片,如果直接就是這個分佈的話,怕是做不到的。

我們現在有的generator生成的分佈可以假設為P_G(x;\theta),這是一個由\theta控制的分佈,\theta是這個分佈的引數(如果是高斯混合模型,那麼\theta就是每個高斯分佈的平均值和方差)

假設我們在真實分佈中取出一些資料,\{x^1, x^2, \dots,x^m \},我們想要計算一個似然P_G(x^i;\theta)

對於這些資料,在生成模型中的似然就是L = \prod_{i=1}^{m}P_G(x^i;\theta)

我們想要最大化這個似然,等價於讓generator生成那些真實圖片的概率最大。這就變成了一個最大似然估計的問題了,我們需要找到一個\theta ^*來最大化這個似然。

\begin{align}
\theta ^* &= arg\ \max_{\theta}\prod_{i=1}^{m}P_G(x^i;\theta) \\
&=arg\ \max_{\theta}\ log\prod_{i=1}^{m}P_G(x^i;\theta) \\
&=arg\ \max_{\theta} \sum_{i=1}^{m}logP_G(x^i;\theta) \\
& \approx arg\ \max_{\theta}\ E_{x\sim P_{data}}[logP_G(x;\theta)] \\
& = arg\ \max_{\theta}\int_{x} P_{data}(x)logP_G(x;\theta)dx - \int_{x}P_{data}(x)logP_{data}(x)dx \\
&=arg\ \max_{\theta}\int_{x}P_{data}(x)(logP_G(x;\theta)-logP_{data}(x))dx \\
&=arg\ \min_{\theta}\int_{x}P_{data}(x)log \frac{P_{data}(x)}{P_G(x;\theta)}dx \\
&=arg\ \min_{\theta}\ KL(P_{data}(x)||P_G(x;\theta))
\end{align}

尋找一個\theta ^*來最大化這個似然,等價於最大化log似然。因為此時這m個數據,是從真實分佈中取的,所以也就約等於,真實分佈中的所有x在P_{G}分佈中的log似然的期望。

真實分佈中的所有x的期望,等價於求概率積分,所以可以轉化成積分運算,因為減號後面的項和\theta無關,所以添上之後還是等價的。然後提出共有的項,括號內的反轉,max變min,就可以轉化為KL divergence的形式了,KL divergence描述的是兩個概率分佈之間的差異。

所以最大化似然,讓generator最大概率的生成真實圖片,也就是要找一個\thetaP_G更接近於P_{data}

那如何來找這個最合理的\theta呢?我們可以假設P_G(x;\theta)是一個神經網路。

首先隨機一個向量z,通過G(z)=x這個網路,生成圖片x,那麼我們如何比較兩個分佈是否相似呢?只要我們取一組sample z,這組z符合一個分佈,那麼通過網路就可以生成另一個分佈P_G,然後來比較與真實分佈P_{data}

大家都知道,神經網路只要有非線性啟用函式,就可以去擬合任意的函式,那麼分佈也是一樣,所以可以用一直正態分佈,或者高斯分佈,取樣去訓練一個神經網路,學習到一個很複雜的分佈。

如何來找到更接近的分佈,這就是GAN的貢獻了。先給出GAN的公式:

V(G,D)=E_{x\sim P_{data}}[logD(x)] + E_{x\sim P_G}[log(1-D(x))]

這個式子的好處在於,固定G,\max\  V(G,D)就表示P_GP_{data}之間的差異,然後要找一個最好的G,讓這個最大值最小,也就是兩個分佈之間的差異最小。

G^*=arg\ \min_{G}\ \max_D\ V(G,D)

表面上看這個的意思是,D要讓這個式子儘可能的大,也就是對於x是真實分佈中,D(x)要接近與1,對於x來自於生成的分佈,D(x)要接近於0,然後G要讓式子儘可能的小,讓來自於生成分佈中的x,D(x)儘可能的接近1

現在我們先固定G,來求解最優的D

對於一個給定的x,得到最優的D如上圖,範圍在(0,1)內,把最優的D帶入 \max_D\ V(G,D),可以得到:

JS divergence是KL divergence的對稱平滑版本,表示了兩個分佈之間的差異,這個推導就表明了上面所說的,固定G, \max_D\ V(G,D)表示兩個分佈之間的差異,最小值是-2log2,最大值為0。

現在我們需要找個G,來最小化\max_D\ V(G,D),觀察上式,當P_G(x)=P_{data}(x)時,G是最優的。



4.訓練

有了上面推導的基礎之後,我們就可以開始訓練GAN了。結合我們開頭說的,兩個網路交替訓練,我們可以在起初有一個G_0D_0,先訓練D_0找到\max_D\ V(G_0,D_0),然後固定D_0開始訓練G_0,訓練的過程都可以使用gradient descent,以此類推,訓練D_1,G_1,D_2,G_2,\dots

但是這裡有個問題就是,你可能在D_0^*的位置取到了\max_D\ V(G_0,D_0)=V(G_0,D_0^*),然後更新G_0G_1,可能V(G_1,D_0^*)<V(G_0,D_0^*)了,但是並不保證會出現一個新的點D_1^*使得V(G_1,D_1^*) > V(G_0,D_0^*),這樣更新G就沒達到它原來應該要的效果,如下圖所示:

避免上述情況的方法就是更新G的時候,不要更新G太多。

知道了網路的訓練順序,我們還需要設定兩個loss function,一個是D的loss,一個是G的loss。下面是整個GAN的訓練具體步驟:

上述步驟在機器學習和深度學習中也是非常常見,易於理解。



5.存在的問題

但是上面G的loss function還是有一點小問題,下圖是兩個函式的影象:

log(1-D(x))是我們計算時G的loss function,但是我們發現,在D(x)接近於0的時候,這個函式十分平滑,梯度非常的小。這就會導致,在訓練的初期,G想要騙過D,變化十分的緩慢,而上面的函式,趨勢和下面的是一樣的,都是遞減的。但是它的優勢是在D(x)接近0的時候,梯度很大,有利於訓練,在D(x)越來越大之後,梯度減小,這也很符合實際,在初期應該訓練速度更快,到後期速度減慢。

所以我們把G的loss function修改為minimize\ V = -\frac{1}{m}\sum_{i=1}^{m}log(D(x^i)),這樣可以提高訓練的速度。

還有一個問題,在其他paper中提出,就是經過實驗發現,經過許多次訓練,loss一直都是平的,也就是\max_D\ V(G,D)=0,JS divergence一直都是log2,P_GP_{data}完全沒有交集,但是實際上兩個分佈是有交集的,造成這個的原因是因為,我們無法真正計算期望和積分,只能使用sample的方法,如果訓練的過擬合了,D還是能夠完全把兩部分的點分開,如下圖:

對於這個問題,我們是否應該讓D變得弱一點,減弱它的分類能力,但是從理論上講,為了讓它能夠有效的區分真假圖片,我們又希望它能夠powerful,所以這裡就產生了矛盾。

還有可能的原因是,雖然兩個分佈都是高維的,但是兩個分佈都十分的窄,可能交集相當小,這樣也會導致JS divergence算出來=log2,約等於沒有交集。

解決的一些方法,有新增噪聲,讓兩個分佈變得更寬,可能可以增大它們的交集,這樣JS divergence就可以計算,但是隨著時間變化,噪聲需要逐漸變小。

還有一個問題叫Mode Collapse,如下圖:

這個圖的意思是,data的分佈是一個雙峰的,但是學習到的生成分佈卻只有單峰,我們可以看到模型學到的資料,但是卻不知道它沒有學到的分佈。

造成這個情況的原因是,KL divergence裡的兩個分佈寫反了

這個圖很清楚的顯示了,如果是第一個KL divergence的寫法,為了防止出現無窮大,所以有P_{data}出現的地方都必須要有P_G覆蓋,就不會出現Mode Collapse



6.參考

這是對GAN入門學習做的一些筆記和理解,後來太懶了,不想打公式了,主要是參考了李巨集毅老師的視訊