AE(Auto Encoder, 自動編碼器)
AE的結構

如上圖所示,自動編碼器主要由兩部分組成:編碼器(Encoder)和解碼器(Decoder)。編碼器和解碼器可以看作是兩個函數,一個用於將高維輸入(如圖片)映射為低維編碼(code),另一個用於將低維編碼(code)映射為高維輸出(如生成的圖片)。這兩個函數可以是任意形式,但在深度學習中,我們用神經網絡去學習這兩個函數。
那如何去學呢?這里以圖片為例,只需要輸入一張圖片(\(X\)),經過編碼器(Encoder)網絡,輸出編碼(code),再將編碼(code)作為解碼器網絡(Decoder)的輸入,輸出一張新的圖片(\(\hat X\)),最后最小化\(X\)與\(\hat X\)之間的差距(通常可用MSE誤差)即可。
這時候我們直觀想象只要拿出Decoder部分,隨機生成一個code然后輸入,就可以得到一張生成的圖像。但實際上這樣的生成效果並不好(下面解釋原因),因此AE多用於數據壓縮,而數據生成則使用下面所介紹的VAE更好。

AE的缺陷
由上面介紹可以看出,AE的Encoder是將圖片映射成“數值編碼”,Decoder是將“數值編碼”映射成圖片。這樣存在的問題是,在訓練過程中,隨着不斷降低輸入圖片與輸出圖片之間的誤差,模型會過擬合,泛化性能不好。也就是說對於一個訓練好的AE,輸入某個圖片,就只會將其編碼為某個確定的code,輸入某個確定的code就只會輸出某個確定的圖片,並且如果這個code來自於沒見過的圖片,那么生成的圖片也不會好。下面舉個例子來說明:
假設我們訓練好的AE將“新月”圖片encode成code=1(這里假設code只有1維),將其decode能得到“新月”的圖片;將“滿月”encode成code=10,同樣將其decode能得到“滿月”圖片。這時候如果我們給AE一個code=5,我們希望是能得到“半月”的圖片,但由於之前訓練時並沒有將“半月”的圖片編碼,或者將一張非月亮的圖片編碼為5,那么我們就不太可能得到“半月”的圖片。因此AE多用於數據的壓縮和恢復,用於數據生成時效果並不理想。

那如何解決以上問題呢?這時候我們轉變思路,不將圖片映射成“數值編碼”,而將其映射成“分布”。還是剛剛的例子,我們將“新月”圖片映射成\(\mu=1\)的正態分布,那么就相當於在1附近加了噪聲,此時不僅1表示“新月”,1附近的數值也表示“新月”,只是1的時候最像“新月”。將"滿月"映射成\(\mu=10\)的正態分布,10的附近也都表示“滿月”。那么code=5時,就同時擁有了“新月”和“滿月”的特點,那么這時候decode出來的大概率就是“半月”了。這就是VAE的思想。

VAE(Variational Auto-Encoder, 變分自動編碼器)
VAE的結構

如上圖所示,VAE與AE整體結構類似,不同的地方在於AE的Encoder直接輸出code,而VAE的Encoder輸出的是若干個正態分布的均值(\(\mu_1,\mu_2...\mu_n\))和標准差(\(\sigma_1,\sigma_2...\sigma_n\)),然后從每個正態分布\(\mathcal{N}\left(\mu_{1}, \sigma_{1}^2\right),\mathcal{N}\left(\mu_{2}, \sigma_{2}^2\right)...\mathcal{N}\left(\mu_{n}, \sigma_{n}^2\right)\)采樣得到編碼code\((Z_1,Z_2...Z_n)\),再將code送入Decoder進行解碼。
那如何進行訓練呢?在訓練過程中,VAE的Loss函數由兩部分組成:
- 為了讓輸出和輸入盡可能像,所以要讓輸出和輸入的差距盡可能小,此部分用MSELoss來計算,即最小化MSELoss。
- 訓練過程中,如果僅僅使輸入和輸出的誤差盡可能小,那么隨着不斷訓練,會使得\(\sigma\)趨近於0,這樣就使得VAE越來越像AE,對數據產生了過擬合,編碼的噪聲也會消失,導致無法生成未見過的數據。因此為了解決這個問題,我們要對\(\mu\)和\(\sigma\)加以約束,使其構成的正態分布盡可能像標准正態分布,具體做法是計算\(\mathcal{N}\left(\mu_{}, \sigma_{}^2\right)\)與\(\mathcal{N}\left(0, 1\right)\)之間的KL散度,即最小化下式(具體推導過程下面介紹):
但是我們注意到這里的code是通過從正態分布中采樣得到的,這個采樣的操作是不可導的,這會導致在反向傳播時\(Z\)對\(\mu\)和\(\sigma\)無法直接求導,因此這里用到一個trick:重參數化技巧(reparametrize)。具體思想是:從\(\mathcal{N}\left(0, 1\right)\)中采樣一個\(\varepsilon\),然后讓\(Z=\mu+\varepsilon\times\sigma\),這就相當於直接從\(\mathcal{N}\left(\mu_{}, \sigma_{}^2\right)\)中采樣\(Z\)。具體過程如下所示:

KL Loss推導
先導知識
連續隨機變量下KL散度公式:
連續隨機變量下期望公式:
設連續型隨機變量\(X\)的概率密度函數為\(f(x)\),且積分絕對收斂,則期望為:
若隨機變量\(Y\)符合\(Y=g(X)\),\(X\)的概率密度函數為\(f(x)\),且\(g(x)f(x)\)的積分絕對收斂,則期望為:
方差公式:
正態分布公式:
\(X \sim N\left(\mu, \sigma^{2}\right)\)的概率密度函數:
KL Loss推導過程
其中展開可以分為三項:
第一項:
此處注意:概率密度函數的積分為1
第二項:
這里的化簡技巧是:根據\(E(Y)=E(g(X))=\int_{-\infty}^{\infty} g(x) f(x) d x\),將上式中\(\frac{1}{\sqrt{2 \pi \sigma^{2}}} \exp\bigg({-(x-\mu)^{2} / 2 \sigma^{2}}\bigg)\)看作\(f(x)\),將\(x^2\)看作\(g(x)\),則有:
其中\(X \sim N\left(\mu, \sigma^{2}\right)\)
第三項:
這里的化簡技巧同上面第二項的化簡類似,將上式中\(\frac{1}{\sqrt{2 \pi \sigma^{2}}} \exp\bigg({-(x-\mu)^{2} / 2 \sigma^{2}}\bigg)\)看作\(f(x)\),將\((x-\mu)^2=\big(x-\mathrm E(\mathrm X)\big)^2\)看作\(g(x)\),則有:
綜上所述:
代碼
有關VAE的代碼實現:Github
實驗效果:

從正態分布中隨機采樣100個code輸入訓練好的Decoder生成結果:

小結
- AE主要用於數據的壓縮與還原,在生成數據上使用VAE。
- AE是將數據映直接映射為數值code,而VAE是先將數據映射為分布,再從分布中采樣得到數值code。
- VAE的缺點是生成的數據不一定那么“真”,如果要使生成的數據“真”,則要用到GAN。
注:本文主要還是對VAE比較直觀的介紹,關於其中具體的數學原理(如估計訓練集的概率分布、混合高斯思想等),可以參考原論文或者其他博主的文章。另外,本文部分內容僅個人見解,如有錯誤也歡迎讀者批評指正。
參考
https://datawhalechina.github.io/leeml-notes/#/chapter29/chapter29