使用PyTorch從理論到實踐理解變分自編碼器VAE

2021-01-11 deephub

變分自動編碼器(Variational Auto Encoders ,VAE)是種隱藏變量模型[1,2]。該模型的思想在於:由模型所生成的數據可以經變量參數化,而這些變量將生成具有給定數據的特徵。因此,這些變量被稱為隱藏變量。

而VAE背後的關鍵點在於:為了從樣本空間中找到能夠生成合適輸出的樣本(就是能輸出儘可能接近我們所規定分布的數據),它並沒有試圖去直接構造一個隱藏空間(隱藏變量所在的空間),而是構造了一個類似於具有編碼器和解碼器兩個部分的網絡:

編碼器部分能夠學習到根據輸入樣本X來形成一個特定分布,從中我們可以對一個隱藏變量進行採樣,而這個隱藏變量極有可能生成X裡面的樣本。換句話說,可以理解為編碼器通過學習一組參數θ1來得到一個能計算出Q(X,θ1)分布樣本的模型,通過抽樣能夠使得隱藏變量z的P(X|z)最大化。

而解碼器部分能夠學習到根據給定的一個隱藏變量z作為輸入,生成一個具有真實數據分布的輸出。換句話說,可以理解為解碼器通過學習一組參數θ2來得到一個能映射到隱藏空間分布的函數f(z,θ2),從而能夠輸出與真實數據具有相同分布的數據集。

為了充分理解VAE背後的數學意義,我們將通過對其理論講解以及與一些傳統方法進行比較來說明。

這篇文章將包含以下內容

如何對隱藏空間進行定義?

如何高效的從隱藏空間中生成數據?

VAE最終的框架是什麼?

通過一些實驗來展示VAE中的一些有趣特徵。

潛在變量模型

隱藏變量模型這一說法是根據:模型所生成的數據是通過對隱藏變量進行參數化而來。而這個名稱具有這樣一個事實:對於能夠生成我們所需數據的模型,我們並不需要知道這個模型在哪設置了隱藏變量。

在一些測試場合,對於一個在高維空間Z中的隱藏向量z,我們能夠很輕鬆的根據它的概率密度函數P(z)進行抽樣。這時,我們能夠得到一些較為確定的函數f(z;θ),其中θ能夠被參數化到Θ空間,具體表示為:f :Z×Θ→X。式中f是一個確定的映射關係,當z具有隨機性而θ是一個固定參數時,f(z;θ) 就是X張成空間中的隨機變量。

在訓練過程中,我們通過優化參數θ來使得根據P(z)抽取出的z具有更高的概率,從而通過f(z;θ)函數得到的數據能更加接近真實樣本X中的數據。總之為了實現這一目的,我們需要去找到這樣的參數θ:

在上式中,為了使得X與z的關係更加直觀,我們使用了總體概率密度進行計算,即採用P(X|z;θ)分布來替換f(z;θ)分布。此外,我們還做了另外一個假設:P(W|z;θ)遵循N(X|f(z; θ),σ*I)類型的高斯分布。(這樣做的目的是:可以認為生成的數據幾乎是X中的數據,但卻又不完全是X中的數據)

定義隱藏空間

正如開始介紹的那樣,隱藏空間是一個假設的模型,該空間中的一些變量能夠影響到我們數據分布中的一些特定的特徵。我們可以想像下,如果我們的數據假設為是由汽車組成的以及數據的分布類比於汽車的空間,那麼這個隱藏變量可以理解為影響汽車顏色、每個部件的位置以及車門的數量的因素。

然而,直接去明確每個隱藏變量是非常困難的,特別是當我們所需處理的數據具有上百個維度時。並且當其中一個隱藏變量與另一個隱藏變量存在一定耦合關係時,人工去定義這些隱藏變量將變得更加困難,換句話說就是對於P(z)的複雜分布很難通過人工去進行定義。

解決方案

為了解決這一問題,我們以反向傳播的方式,採用數學中概率分布的性質和神經網絡的能力來學習出這些樣本所服從的函數。

使得該問題能被更容易處理的數學性質:對於一個d維的任意分布,它都能夠通過選取一組d個服從正態分布的變量並將它們映射到一個足夠複雜的函數中來生成。因此,我們可以假定我們的隱藏變量服從高斯分布,然後構造出一個具體的函數將我們服從高斯分布的隱藏空間映射到一個更為複雜的分布當中,這樣我們就能通過取樣來生成我們需要的數據了。其中,這個具體的函數需要把簡單的隱藏分布映射成一個更為複雜的分布,而這樣的一個複雜分布可以看作是一個隱藏空間,這時就可以採用神經網絡來建立出一些參數,因此這些參數就能夠在訓練中進行微調了。

學會從潛在空間中生成數據

在進入本文最有趣的部分之前,讓我們先回顧一下最終的目標:我們有一個服從正態分布的d維隱藏空間,以及我們所要學習的f(z;θ2)函數能夠將隱藏分布映射到真實數據的分布。換句話說就是:我們先對隱藏變量進行採樣,然後將這個隱藏變量作為生成器的輸入,最後生成的數據樣本能夠儘可能的接近真實的數據。

我們需要解決以下兩件事情

1. 為了使得變量z的概率密度P(X|z)最大化,如何高效的對隱藏空間進行探索?(我們需要在訓練過程中為給定的X找到最為正確的z)

2. 如何使用反向傳播來訓練這整個過程?(我們需要找到一個具體對象來優化f:P(z)映射到P(X))

為我們的X找到正確的隱藏變量z

在絕大多數的實驗中,z和P(X|z)的數值都接近於零,因此我們對P(X)的估計幾乎沒有什麼意義。而VAE的核心思想在於:需要嘗試對可能產生X的z值進行不斷採樣,然後從這些值中計算出P(X)的大小。為了做到這一點,我們首先需要構建一個能夠給出X的值並給出可能產生z的值的X分布的這樣一個新函數Q(z|X),並希望在Q函數下的z值的空間大小比P(z)下的z值的空間大小要小得多。

對於VAE的編碼器與所假定出的Q函數,我們採用神經網絡來對其進行訓練,使得輸入X能映射到輸出Q(z|X)的分布中,從而幫助我們能夠找到一個最好的z來生成實際X中的數據。

使用反向傳播訓練模型

為了更好理解到我們的VAE是如何訓練出來的,首先我們需要定義一個明確的目標,而為了做到這一點,我們又需要做一些數學公式的推導。

讓我們從編碼器開始說起,我們是想讓Q(z|X)的分布無限接近於P(X|z)的分布,為了確定出這兩個分布到底有多接近,我們可以採用兩個分布間的Kullback-Leibler散度D來進行度量:

通過數學推導,我們可以把這個等式寫成更為有趣的形式。對P(z|X)使用貝葉斯定律後,等式如下:

還可以表示成如下等式:

花點時間看看這個公式

對於A部分:就是在等式左邊的這一項,它對於反向傳播來說並不是一個有利的設定(我們並不知道P (X)的表達式是多少),但是我們可以知道如果想要在給定z的情況下最大化log(P(X)),可以通過最小化減號右邊的部分來實現(這樣可以使得Q(z|x)的分布儘可能接近P(z|X)的分布),這也正是我們在一開始時提到的最終目標。

對於B部分:等式右邊的這一項就更加有趣,正如我們了解P(X|z)(這是解碼器部分->生成器)和Q(z|X)(這是我們的編碼器)。所以我們可以得出,為了最大化這一項,我們需要最大化log(P(X|z)),而這也就意味著我們不需要最大化log函數的極大似然概率和最小化Q(z|X)和P(z)之間的KL散度。

為了使得B部分更容易被計算,我們假設Q(z|X)是服從N(z|mu(X,θ1)或sigma(X,θ1))的高斯分布,其中θ1是在神經網絡中需要從數據集中所學到的參數。此外,在我們的公式中還有一個問題還沒被解決:就是如何計算反向傳播中的期望(損失函數)?

損失函數部分的操作

一種思路是採用多次前向傳遞的方式來計算出log(P(X|z))的期望,但是其計算效率較低。從而我們希望通過隨機訓練來解決這一問題,首先我們假定在第n輪迭代中使用的數據Xi能代表整個數據集,因此可以考慮我們從樣本Xi中所獲得的log(P(Xi|zi))和代表log(P(X|z))對Q分布的期望zi。最後,這個解碼器只是一個簡單的生成器模型,而我們希望去重建這個輸入圖像,因此一個簡單的方法是使用輸入圖像和生成圖像之間的均方誤差來作為其期望部分(損失函數),如下式。

VAE的最終框架

正如在一開始所介紹的那樣,我們知道VAE的最終結構由兩個部分的網絡所構成:

1. 編碼器部分能夠學習到根據輸入樣本X來形成一個特定分布,從中我們可以對一個隱藏變量進行採樣,而這個隱藏變量極有可能生成X裡面的樣本。為了使得Q(z|X)服從高斯分布,這部分需要被優化。

2. 解碼器部分能夠學習到根據給定的一個隱藏變量z作為輸入,生成一個具有真實數據分布的輸出。該部分將經過採樣後的z(最初來自正態分布)映射到一個更複雜的隱藏空間去(實際數據的空間),並通過這個複雜的隱藏變量z生成一個個的數據點,這些數據點十分接近我們真實數據的分布。

VAE的詳細架構。左邊的圖和右邊的圖是類似的,只是左邊示例中展示了反向傳播,實際使用圖一般為右邊的示例

VAE實驗分析

現在你已經了解到了VAE背後的數學理論,那麼現在讓我們看看通過VAE我們能夠生成哪些模型,實驗平臺為PyTorch。

PyTorch的全局架構

class VAE(nn.Module):

def __init__(self, latent_dim):

super().__init__()

self.encoder = nn.Sequential(nn.Linear(28 * 28, 256),

nn.ReLU(),

nn.Linear(256, 128))

self.mu = nn.Linear(128, latent_dim)

self.logvar = nn.Linear(128, latent_dim)

self.latent_mapping = nn.Linear(latent_dim, 128)

self.decoder = nn.Sequential(nn.Linear(128, 256),

nn.ReLU(),

nn.Linear(256, 28 * 28))

def encode(self, x):

x = x.view(x.size(0), -1)

encoder = self.encoder(x)

mu, logvar = self.mu(encoder), self.logvar(encoder)

return mu, logvar

def sample_z(self, mu, logvar):

eps = torch.rand_like(mu)

return mu + eps * torch.exp(0.5 * logvar)

def decode(self, z,x):

latent_z = self.latent_mapping(z)

out = self.decoder(latent_z)

reshaped_out = torch.sigmoid(out).view(x.shape[0],1, 28,28)

return reshaped_out

def forward(self, x):

mu, logvar = self.encode(x)

z = self.sample_z(mu, logvar)

output = self.decode(z,x)

return output

訓練模型

下圖展示了我們在訓練期過程中所得到的結果。為了演示,VAE已經在MNIST數據集[3]上經過了訓練,每10輪展示一次,我們繪製了輸入X和所生成的數據,而這些輸出的數據又作為VAE的輸入。

訓練樣本(輸入在上,輸出在下)——第1輪

訓練樣本(輸入在上,輸出在下)——第10輪

訓練樣本(輸入在上,輸出在下)——第20輪

訓練樣本(輸入在上,輸出在下)——第30輪

訓練樣本(輸入在上,輸出在下)——第40輪

訓練樣本(輸入在上,輸出在下)——第50輪

隱藏空間

其中關於VAE有一個有趣的事情:在訓練中學習到的隱藏空間有很好的連續性。為了能夠在二維空間中輕鬆地可視化我們的數據點,我們考慮通過二維可視化隱藏空間的特性來實現。

在訓練過程中,我們能夠發現在2維隱藏空間中MNIST數據集被重新劃分了,從中我們可以看到相似的數字被分在了一起(綠色的表示3且都被分在了一起,並且非常靠近數字8,說明這兩個數字非常相似)。

2維圖中可視化隱藏空間

一個更好地從視覺上去理解隱藏空間連續性的方法是:去觀察從隱藏空間中所生成的圖像。我們從下圖中可看出,數字在隱藏空間內進行移動時被平滑地轉換為了與之相似的數字。

二維隱藏空間中抽樣出的數字

結論

VAE是一個令人驚嘆的工具,它依靠神經網絡的幫助能夠解決一些具有挑戰性的問題:生成模型。與傳統方法相比,VAEs解決了兩個主要的問題: 1. 如何在隱藏空間中抽取最相關的隱藏變量來給到輸出。2.如何將隱藏空間中的數據分布映射到真實的數據分布中去。但是,VAE也存在著一些缺點:由於使用的是均方根誤差,它使得生成器是收斂到了平均最優,導致生成的圖像有一點模糊。

而生成對抗網絡(GANs)通過使用鑑別器而不是均方根誤差作為損失能解決這一問題,從而使得生成的圖像更為真實。但是,由於GAN的隱藏空間難以控制,使得它不具有像VAEs那樣的連續性,但這在某些應用場合中卻是必要的。

參考文獻:

[1] Doersch, C., 2016. Tutorial on variational autoencoders. arXiv preprint arXiv:1606.05908.

[2] Kingma, D.P. and Welling, M., 2019. An introduction to variational autoencoders. arXiv preprint arXiv:1906.02691.

[3] MNIST dataset,

作者: Emrick Sinitambirivoutin

Deephub翻譯組:李愛(Li Ai)

相關焦點

  • 變分自編碼器VAE面臨的挑戰與發展方向
    變分自編碼器(VAE)與生成對抗網絡(GAN)一樣,是無監督學習最具前景的方法之一。本文中,牛津大學統計系在讀博士 Adam Kosiorek 從原理上向我們介紹了 VAE 目前面臨的挑戰。同時,文中也提出了對於該方法的幾種改進方向。
  • 【乾貨】一文讀懂什麼是變分自編碼器
    我們知道,變分自編碼器是一種生成模型,在文本生成、圖像風格遷移等諸多任務中有顯著的效果,那麼什麼是變分自編碼器?它存在什麼問題?它有什麼改進算法?本文較為全面地講解了變分自編碼器的相關內容,分別介紹:標準變分自編碼器的結構、存在的問題以及相關的解決思路,並預測了變分自編碼器的改進方向,相信能給您的研究帶來一些啟發。
  • 再談變分自編碼器VAE:從貝葉斯觀點出發
    框架這裡通過直接對聯合分布進行近似的方式,簡明快捷地給出了 VAE 的理論框架。 直面聯合分布出發點依然沒變,這裡再重述一下。你的VAE已經送達到這裡,我們回顧初衷——為了得到生成模型,所以我們把 q(x,z) 寫成 q(x|z)q(z),於是就有:
  • PyTorch最佳實踐,教你寫出一手風格優美的代碼
    本文將介紹PyTorch的最佳實踐和代碼風格都是怎樣的。雖然這是一個非官方的 PyTorch 指南,但本文總結了一年多使用 PyTorch 框架的經驗,尤其是用它開發深度學習相關工作的最優解決方案。請注意,我們分享的經驗大多是從研究和實踐角度出發的。
  • 《PyTorch中文手冊》來了
    但是說到 PyTorch,其實應該先說 Torch。1.1.2 Torch 是什麼?Uber 的 "Pyro" 也是使用的這個庫。conda create -n pytorch python=3.6# 切換到 pytorch 環境activate pytorch#安裝 GPU 版本,根據 cuda 版本選擇 cuda80,
  • 變分自編碼器VAE:這樣做為什麼能成?
    注意,q(x|z) 只是一個概率分布,我們從q(z)中採樣出 z 後,代入 q(x|z) 後得到 q(x|z) 的具體形式,理論上我們還要從 q(x|z) 中再採樣一次才得到 x。但是,我們並沒有這樣做,我們直接把均值網絡 μ(z) 的結果就當成 x。
  • 準確理解規範法理論的實踐屬性
    準確理解規範法理論的實踐屬性 2018年10月17日 07:59 來源:中國社會科學網-中國社會科學報 作者:楊建 字號 內容摘要:實證理論有其理論的限度,它無法獨自完成理解和推進實踐的工作。
  • PyTorch可視化理解卷積神經網絡
    如果你是一個深度學習愛好者,你可能早已聽說過這種神經網絡,並且可能已經使用一些深度學習框架比如caffe、TensorFlow、pytorch實現了一些圖像分類器。然而,這仍然存在一個問題:數據是如何在人工神經網絡傳送以及計算機是如何從中學習的。為了從頭開始獲得清晰的視角,本文將通過對每一層進行可視化以深入理解卷積神經網絡。
  • 重磅| Torch7團隊開源PyTorch:Python優先的深度學習框架
    官網:http://pytorch.orgGitHub:https://github.com/pytorch/pytorchPyTorch 是一個 Python 軟體包,其提供了兩種高層面的功能:使用強大的 GPU 加速的 Tensor 計算(類似 numpy)構建於基於 tape 的 autograd 系統的深度神經網絡如有需要,你也可以復用你最喜歡的
  • 華為雲應用編排,手把手教您完成pytorch代碼部署
    更深入一些,在特性設計上,PyTorch對於抽象出的概念較少,易於理解,同時提供的API的設計理念與Torch一脈相承,符合人的一般思維,接口優雅。而框架最核心的性能方面,PyTorch的速度表現在許多評測中勝過TensorFlow和Keras等知名框架。
  • 圖靈獎得主力推:PyTorch 1.3 今天發布
    而使用 PyTorch 進行算法開發的公司也越來越多,其中不乏 Uber 等大公司。在 Reddit 中,研究者統計到:CVPR 2018-2019,用 PyTorch 的論文從 82 篇增長到 280 篇,TensorFlow 從 116 增長到 125;ACL 2018-2019,用 PyTorch 的論文數從 26 增長到 103,TensorFLow 從 34 到 33 反而降低了。
  • 從理論到實踐,奈奎斯特採樣定理,我終於鬧明白了!
    用理論指導實踐,但並沒有具體的說明。換句話說,香農定理並沒有告訴我們如何設計一個採樣系統;相反,它只幫助我們去理解採樣系統,並提供了一個指導和支持工程師工作的框架。因此,了解理論和實踐的差異是很重要的,在採樣理論中,也許最重要的差異就是所需的採樣率。
  • 使用Google Colab上的PyTorch YOLOv3
    weights = opt.weightsimg_size = opt.img_size# 初始化設備device = torch_utils.select_device(opt.device)# 初始化模型model = Darknet(opt.cfg, img_size)# 加載權重attempt_download(weights)if weights.endswith('.pt'): # pytorch
  • 「空談理論」是對實踐最大的幫助
    於是面對法學院,我總忐忑自己的文章是不是不夠聯繫實際,畢竟案例都是看得見摸得著的,文本啊理論啊都是從概念到概念的空轉。      首先我一直不知道舉小例子有什麼用。高中政治課上拿個杯子說「這是物質」,這種例子是為了讓我們「生動活潑地」理解物質是什麼。但很多舉例的做法好像雄心遠大於此,大概是想拿出三張女人的照片證明全世界的人都是女人。
  • Pytorch框架安裝方法(基於Anaconda環境和Pycharm IDE)
    1.Anaconda安裝下載連結:https://www.anaconda.com/1.1 點擊Next1.2 點擊同意1.3 點擊Next1.4 選擇目標文件夾,點擊下一步1.5 將Anaconda加入到系統變量安裝成功後,在CMD中檢查Anaconda時候加入到環境變量中。
  • 雲計算學習:用PyTorch實現一個簡單的分類器
    回想了一下自己關於 pytorch 的學習路線,一開始找的各種資料,寫下來都能跑,但是卻沒有給自己體會到學習的過程。有的教程一上來就是寫一個 cnn,雖然其實內容很簡單,但是直接上手容易讓人找不到重點,學的雲裡霧裡。有的教程又淺嘗輒止,師傅領到了門檻跟前,總感覺自己還沒有進門,教程就結束了。
  • 還不會使用PyTorch框架進行深度學習的小夥伴,看過來
    「反向傳遞」是指從右到左調整權重的過程,而正向傳遞則是從左到右調整權重的過程。「torch.autograd」是 PyTorch 中支持自動微分的庫。這個包的核心類是「torch.Tensor」。如果你想要跟蹤這個類的所有操作,請將「.requires_grad」設置為 True。如果要計算所有的梯度,請調用「.backward()」。
  • 新版PyTorch 1.2 已發布:功能更多、兼容更全、操作更快!
    用戶現在可以在 pytorch.org 上(https://pytorch.org/get-started/locally/)開始使用這些版本。PyTorch 1.2通過使用 PyTorch 1.2,開源 ML 框架在生產應用方面向前邁出了一大步,並增加了一個改進的、更加完善的 TorchScript 環境。
  • PyTorch中使用DistributedDataParallel進行多GPU分布式模型訓練
    這些梯度更新然後在gpu之間同步,一起平均,最後應用到模型。(同步步驟在技術上是可選的,但理論上更快的異步更新策略仍是一個活躍的研究領域)在模型並行化中,模型訓練作業是在模型上進行分割的。工作中的每個GPU接收模型的一個切片,例如它的層的一個子集。例如,一個GPU負責它的輸出頭,另一個負責輸入層,另一個負責中間的隱藏層。
  • 書單| 精神分析動力學Ⅰ:基礎入門的理論及實踐
    本書將整個心理動力學治療過程抽絲剝繭,從初始評估到治療終止,一步一步地將這一療法的真實過程呈現出來。書中創造性地區分了以揭露和支持為目的的治療技術,該技術使治療師能夠根據病人的情況來選擇最佳治療策略。這不僅大大提升了治療效果,更能幫助治療師理解和掌握心理動力學療法的核心技術。