變分自編碼器解析

概述

在討論變分自編碼器前,我覺得有必要先討論清楚它與自編碼器的區別是什麼,它究竟是幹什麼用的。否則看了一堆公式也不知道變分自編碼器究竟有什麼用。

衆所周知,自編碼器是一種數據壓縮方式,它把一個數據點$x$有損編碼爲低維的隱向量$z$,通過$z$可以解碼重構回$x$。這是一個確定性過程,我們實際無法拿它來生成任意數據,因爲我們要想得到$z$,就必須先用$x$編碼。變分自編碼器可以用來解決這個問題,它可以直接通過模型生成隱向量$z$,並且生成的$z$是既包含了數據信息又包含了噪聲,因此用各不相同的$z$可以生成無窮無盡的新數據。所以問題的關鍵就是怎麼生成這種$z$呢。

我們更加具體地描述一下需求。我們要生成和原數據相似的數據,那當然得有一個模塊能夠學習到數據的分佈信息,這個被稱爲編碼器。這個編碼器獲得了數據分佈信息,應該融入一些隨機性,所以引入了高斯噪聲。這兩部分信息融合後,應該由另一個模塊解碼生成新的數據吧,所以又需要一個解碼器。如此下來,就出現了VAE的大致結構,如下圖這樣。

那麼還有一個問題,GAN也是生成模型,變分自編碼器VAE和GAN有什麼區別呢。我的理解是,VAE和GAN都能生成新數據,但在生成質量的判斷上,它們的做法不同。VAE使用概率思想,通過計算生成數據分佈與真實數據分佈的相似度(KL散度)來判斷。但GAN直接使用神經網絡訓練一個判別器,用判別器判斷生成的數據是不是真的和原分佈差不多。

在對變分自編碼器有一個基本的瞭解後,我們可以來看看它究竟是怎麼做的。但問題又來了,變分自編碼器既涉及到神經網絡,又涉及到概率模型,結果就是搞神經網絡和搞概率模型的都看不懂。參照Jaan Altosaar的教程,本文將從神經網絡和概率模型兩個角度對變分自編碼器進行講解。

神經網絡角度

以神經網絡語言描述的話,VAE包含編碼器、解碼器和損失函數三部分。編碼器將數據壓縮到隱空間$(z)$中。 解碼器根據隱狀態$z$重建數據。

編碼器是一個神經網絡,它的輸入是數據點$x$,輸出是隱向量$z$,它的參數是$\theta$,因此編碼器可以表示爲$q_{\theta}(z|x)$。爲了更具體地說明,假設$x$是784維的黑白圖片向量。編碼器需要將728維的數據$x$編碼到隱空間$z$,而且$z$的維度要比784小很多,這就要求編碼器必須學習將數據有效壓縮到此低維空間的方法。此外,我們假設$z$是服從高斯分佈的,編碼器輸出$z$的過程實際上可以分解成兩步:1)首先編碼器輸出高斯分佈的參數(均值、方差),這個參數對於每個數據點都是不一樣的;2)將噪聲與該高斯分佈融合並從中採樣獲得$z$。

解碼器也是一個神經網絡,它的輸入是隱向量$z$,輸出是數據的概率分佈,它的參數是$\phi$,因此解碼器可以表示爲$p_{\phi}(x|z)$。還是以上面例子講解,假設每個像素取值是0或者1,一個像素的概率分佈可以用伯努利分佈表示。因此解碼器輸入$z$之後,輸出784個伯努利參數,每個參數表示圖中的一個像素是取0還是取1。原始784維圖像$x$的信息是無法獲取的,因爲解碼器只能看到壓縮的隱向量$z$。這意味着存在信息丟失問題。

變分自編碼器的損失函數是帶正則項的負對數似然函數。因爲所有數據點之間沒有共享隱向量,因此每個數據點的損失$l_i$是獨立的,總損失$\mathcal{L}=\sum_{i=1}^N l_i$是每個數據點損失之和。而數據點$x_i$的損失$l_i$可以表示爲: $$ l_i(\theta,\phi)=-\mathbb{E}{z \sim p{\theta}(z|x_i)}[\log_{p_{\phi}}(x_i|z)] + KL(p_{\theta}(z|x_i)||p(z)) $$ 第一項是重構損失,目的是讓生成數據和原始數據儘可能相近。第二項KL散度是正則項,它衡量了兩個分佈的近似程度。

重構損失好理解,它保證了數據壓損的質量嘛,但是正則項該如何理解呢?在變分自編碼器中,$p(z)$被指定爲標準正態分佈,也就是$p(z)=\text{Normal}(0,1)$。那正則項的存在就是要讓$p_{\theta}(z|x_i)$也接近正態分佈。如果沒有正則項,模型爲了減小重構損失,會不斷減小隨機性,也就是編碼器輸出的方差,沒有了隨機性變分自編碼器也就無法生成各種數據了。因此,變分自編碼器需要讓編碼的$z$,即$p_{\theta}(z|x_i)$接近正態分佈。如果編碼器輸出的$z$不服從標準正態分佈,將會在損失函數中對編碼器施加懲罰。這樣理解之後,變分自編碼器應該長下面這樣:

概率模型角度

現在,讓我們忘掉所有深度學習和神經網絡知識,從概率模型的角度重新看變分自編碼器。在最後,我們仍然會回到神經網絡。

變分自編碼器可以用下面概率圖模型表示;

隱向量$z$從先驗分佈$p(z)$中採樣得到,然後數據點$x$從以$z$爲條件的分佈$p(x|z)$中產生。整個模型定義了數據和隱向量的聯合分佈$p(x,z)=p(x|z)p(z)$,對於手寫數字而言,$p(x|z)$就是伯努利分佈。

上面所說的是根據隱變量$z$重構數據$x$的過程,但我們如何得到數據$x$對應的隱向量$z$呢?或者說如何計算後驗概率$p(z|x)$。根據貝葉斯定理: $$ p(z|x)=\frac{p(x|z)p(z)}{p(x)} $$ 考慮分母$p(x)$,它可以通過$p(x)=\int p(x|z)p(z)dz$計算。但不幸的是,該積分需要指數時間來計算,因爲需要對所有隱變量進行計算。沒辦法直接求解,就只能近似該後驗分佈了。

假設我們使用分佈$q_{\lambda}(z|x)$來近似後驗分佈,$\lambda$是一個參數。在變分自編碼器裏,後驗分佈是高斯分佈,因此$\lambda$就是每個數據點隱向量的均值和方差$\lambda_{x_i}=(\mu_{x_i},\sigma_{x_i}^2)$。這也說明了每個數據點的後驗分佈是不一樣的,我們實際上是要求$q_{\lambda}(z|x_i)$,要得到每個數據點所對應的$\lambda_{x_i}$。

那麼怎麼知道用分佈$q_{\lambda}(z|x)$近似真實的後分布$p(z|x)$到底好不好呢?我們可以用KL散度來衡量: $$ KL\left(q_{\lambda}(z|x)||p(z|x)\right) = \ \mathbb{E}q[\log q{\lambda}(z|x)] - \mathbb{E}q[\log p(x,z)] + \log p(x) $$ 現在的目標就變成了找到使得KL散度最小的參數$\lambda^*$。最優的後驗分佈就可以表示爲: $$ q{\lambda^*}(z|x)=\arg\min_{\lambda}KL\left(q_{\lambda}(z|x)||p(z|x)\right) $$ 但是這依然無法進行計算,因爲仍然會涉及到$p(x)$,我們還需要繼續改進。接下來就要引入下面這個函數: $$ ELBO(\lambda)= \mathbb{E}q[\log p(x,z)] - \mathbb{E}q[\log q{\lambda}(z|x)] $$ 我們可以將ELBO與上面的KL散度計算公式結合,得到: $$ \log p(x)= ELBO(\lambda) + KL\left(q{\lambda}(z|x)||p(z|x)\right) $$ 由於KL散度始終是大於等於0的,而$\log p(x)$是一個定值,這意味着最小化KL散度等價於最大化ELBO。ELBO(Evidence Lower BOund)讓我們能夠對後驗分佈進行近似推斷,可以從最小化KL散度中解脫出來,轉而最大化ELBO。而後者在計算上是比較方便的。

在變分自編碼器模型中,每個數據點的隱向量$z$是獨立的,因此ELBO可以被分解成所有數據點對應項之和。這使得我們可以用隨機梯度下降來進行學習,因爲mini-batch之間獨立,我們只需要最大化一個mini-batch的ELBO就可以了。每個數據點的ELBO表示如下: $$ ELBO_i(\lambda)=\mathbb{E}{z \sim q{\lambda}(z|x_i)}[\log p(x_i|z)] - KL(q_{\lambda}(z|x_i)||p(z)) $$

現在可以再用神經網絡來進行描述了。我們使用一個推斷網絡(或編碼器)$q_{\theta}(z|x)$建模$q_{\lambda}(z|x)$,該推斷網絡輸入數據$x$然而輸出參數$\lambda$。再使用一個生成網絡(或解碼器)$p_{\phi}(x|z)$建模$p(x|z)$,該生成網絡輸入隱向量和參數,輸出重構數據分佈。$\theta$和$\phi$是推斷網絡和生成網絡的參數。此時我們可以使用這兩個網絡來重寫上述ELBO: $$ ELBO_i(\theta,\phi)=\mathbb{E}{z \sim q{\theta}(z|x_i)}[\log p_{\phi}(x_i|z)] - KL(q_{\theta}(z|x_i)||p(z)) $$ 可以看到,$ELBO_i(\theta,\phi)$和我們之前從神經網絡角度提到的損失函數就差一個符號,即$ELBO_i(\theta,\phi)=-l_i(\theta,\phi)$。一個需要最大化,一個需要最小化,所以本質上是一樣的。我們仍然可以將KL散度看作正則項,將期望看作重構損失。但是概率模型清楚解釋了這些項的意義,即最小化近似後驗分佈$q_{\lambda}(z|x)$和模型後驗分佈$p(z|x)$之間的KL散度。

重參數化技巧

實現變分自編碼器的最後一件事是如何對隨機變量的參數求導數。我們用$q_{\theta}(z|x)$確定一個高斯分佈,然後從中採樣$z$,但採樣操作是不可導的,進而導致模型無法反向傳播。

這個問題可以使用重參數化技巧實現。從均值$\mu$和標準偏差$\sigma$的正態分佈中採樣,等價於先從標準正態分佈中採樣$\epsilon$,然後再對其進行下列變換: $$ z = \mu + \sigma \odot \epsilon $$ 從$\epsilon$到$z$只涉及了線性操作,這是可導的。而$\epsilon$的分佈是確定的,不需要學習。採樣$\epsilon$的操作不參與梯度下降,採樣得到$\epsilon$值才參與梯度下降。

這張圖表示了重參數化的形式,其中圓是隨機節點,菱形是確定性節點。

實驗

現在可以使用模型進行一些實驗了,可以參考Pytorch Examples給出的代碼:https://github.com/pytorch/examples/tree/master/vae ,代碼比我想象中的的簡單。

Mean-field推斷和amortized推斷

Mean-field變分推斷是指在沒有共享參數的情況下對$N$個數據點進行分佈推斷: $$ q(z)=\prod_i^N q(z_i;\lambda_i) $$ 這意味着每個數據點都有自由參數$\lambda_i$(例如對於高斯隱變量,$\lambda_i =(\mu_i,\sigma_i)$)。對於新數據點,我們需要針對其mean-field參數$\lambda_i$最大化ELBO。

amortized推斷是指“攤銷”數據點之間的推斷成本。一種方法是在數據點之間共享(攤銷)變分參數$\lambda$。例如,在變分自編碼器中,推斷網絡的參數$\theta$,這些全局參數在所有數據點之間共享。如果我們看到一個新的數據點並想看一下它的近似後驗$q(z_i)$,我們可以再次運行變分推斷(最大化ELBO直到收斂),或者直接使用現有的共享參數。與Mean-field變分推斷相比,這很明顯可以節省時間。

哪一個更靈活呢?Mean-field變分推斷嚴格來說更具表達性,因爲它沒有共享參數。每個數據點獨立的參數$\lambda_i$可以確保近似後驗最準確。但另一方面,通過在數據點之間共享參數可以限制近似分佈族的容量或表示能力,加入更多約束。

條件變分自編碼器

變分自編碼器的生成過程是無監督的,這意味着我們沒辦法生成特定的數據。比如想要生成數字“2”的圖片,我們沒辦法把信息傳遞給變分自編碼器。

條件變分自編碼器(Conditional VAE, CVAE)就是用來解決這個問題的,它可以實現給定一些變量來控制生成某一類數據。

變分自編碼器的優化目標是: $$ ELBO_i(\theta,\phi)=\mathbb{E}{z \sim q{\theta}(z|x_i)}[\log p_{\phi}(x_i|z)] - KL(q_{\theta}(z|x_i)||p(z)) $$ 編碼器生成$z$只和$x$有關,而解碼器重構$x$也只與$z$有關,這就是爲什麼沒辦法融合數據$x$的其他信息(比如標籤)。現在假設對於$x$還有額外的信息$c$,我們可以這樣修改VAE的優化目標: $$ ELBO_i(\theta,\phi)=\mathbb{E}{z \sim q{\theta}(z|x_i,c)}[\log p_{\phi}(x_i|z,c)] - KL(q_{\theta}(z|x_i,c)||p(z|c)) $$ 現在,編碼器和解碼器都已經和$c$聯繫起來了。此外,$p(z|c)$表示對於每個$c$,都有一個$z$的分佈與之對應。

條件變分自編碼器的代碼實現可以參考 https://github.com/wiseodd/generative-models

參考資料

  1. https://jaan.io/what-is-variational-autoencoder-vae-tutorial/
  2. https://toutiao.io/posts/387ohs/preview
  3. https://zhuanlan.zhihu.com/p/27549418
  4. https://wiseodd.github.io/techblog/2016/12/17/conditional-vae/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章