深度學習自動編碼器還能用於數據生成?這篇文章告訴你答案

2020-11-25 雷鋒網

雷鋒網(公眾號:雷鋒網)按:本文作者廖星宇,原載於作者知乎專欄,雷鋒網經授權發布。

  什麼是自動編碼器

自動編碼器(AutoEncoder)最開始作為一種數據的壓縮方法,其特點有:

到了2012年,人們發現在卷積網絡中使用自動編碼器做逐層預訓練可以訓練更加深層的網絡,但是很快人們發現良好的初始化策略要比費勁的逐層預訓練有效地多,2014年出現的Batch Normalization技術也是的更深的網絡能夠被被有效訓練,到了15年底,通過殘差(ResNet)我們基本可以訓練任意深度的神經網絡。

所以現在自動編碼器主要應用有兩個方面,第一是數據去噪,第二是進行可視化降維。然而自動編碼器還有著一個功能就是生成數據。

我們之前講過GAN,它與GAN相比有著一些好處,同時也有著一些缺點。我們先來講講其跟GAN相比有著哪些優點。

第一點,我們使用GAN來生成圖片有個很不好的缺點就是我們生成圖片使用的隨機高斯噪聲,這意味著我們並不能生成任意我們指定類型的圖片,也就是說我們沒辦法決定使用哪種隨機噪聲能夠產生我們想要的圖片,除非我們能夠把初始分布全部試一遍。但是使用自動編碼器我們就能夠通過輸出圖片的編碼過程得到這種類型圖片的編碼之後的分布,相當於我們是知道每種圖片對應的噪聲分布,我們就能夠通過選擇特定的噪聲來生成我們想要生成的圖片。

第二點,這既是生成網絡的優點同時又有著一定的局限性,這就是生成網絡通過對抗過程來區分「真」的圖片和「假」的圖片,然而這樣得到的圖片只是儘可能像真的,但是這並不能保證圖片的內容是我們想要的,換句話說,有可能生成網絡儘可能的去生成一些背景圖案使得其儘可能真,但是裡面沒有實際的物體。

  自動編碼器的結構

首先我們給出自動編碼器的一般結構

從上面的圖中,我們能夠看到兩個部分,第一個部分是編碼器(Encoder),第二個部分是解碼器(Decoder),編碼器和解碼器都可以是任意的模型,通常我們使用神經網絡模型作為編碼器和解碼器。輸入的數據經過神經網絡降維到一個編碼(code),接著又通過另外一個神經網絡去解碼得到一個與輸入原數據一模一樣的生成數據,然後通過去比較這兩個數據,最小化他們之間的差異來訓練這個網絡中編碼器和解碼器的參數。當這個過程訓練完之後,我們可以拿出這個解碼器,隨機傳入一個編碼(code),希望通過解碼器能夠生成一個和原數據差不多的數據,上面這種圖這個例子就是希望能夠生成一張差不多的圖片。

這件事情能不能實現呢?其實是可以的,下面我們會用PyTorch來簡單的實現一個自動編碼器。

首先我們構建一個簡單的多層感知器來實現一下。

class autoencoder(nn.Module):

    def __init__(self):

        super(autoencoder, self).__init__()

        self.encoder = nn.Sequential(

            nn.Linear(28*28, 128),

            nn.ReLU(True),

            nn.Linear(128, 64),

            nn.ReLU(True),

            nn.Linear(64, 12),

            nn.ReLU(True),

            nn.Linear(12, 3)

        )

        self.decoder = nn.Sequential(

            nn.Linear(3, 12),

            nn.ReLU(True),

            nn.Linear(12, 64),

            nn.ReLU(True),

            nn.Linear(64, 128),

            nn.ReLU(True),

            nn.Linear(128, 28*28),

            nn.Tanh()

        )


    def forward(self, x):

        x = self.encoder(x)

        x = self.decoder(x)

        return x

這裡我們定義了一個簡單的4層網絡作為編碼器,中間使用ReLU激活函數,最後輸出的維度是3維的,定義的解碼器,輸入三維的編碼,輸出一個28x28的圖像數據,特別要注意最後使用的激活函數是Tanh,這個激活函數能夠將最後的輸出轉換到-1 ~1之間,這是因為我們輸入的圖片已經變換到了-1~1之間了,這裡的輸出必須和其對應。

訓練過程也比較簡單,我們使用最小均方誤差來作為損失函數,比較生成的圖片與原始圖片的每個像素點的差異。

同時我們也可以將多層感知器換成卷積神經網絡,這樣對圖片的特徵提取有著更好的效果。

class autoencoder(nn.Module):

    def __init__(self):

        super(autoencoder, self).__init__()

        self.encoder = nn.Sequential(

            nn.Conv2d(1, 16, 3, stride=3, padding=1),  # b, 16, 10, 10

            nn.ReLU(True),

            nn.MaxPool2d(2, stride=2),  # b, 16, 5, 5

            nn.Conv2d(16, 8, 3, stride=2, padding=1),  # b, 8, 3, 3

            nn.ReLU(True),

            nn.MaxPool2d(2, stride=1)  # b, 8, 2, 2

        )

        self.decoder = nn.Sequential(

            nn.ConvTranspose2d(8, 16, 3, stride=2),  # b, 16, 5, 5

            nn.ReLU(True),

            nn.ConvTranspose2d(16, 8, 5, stride=3, padding=1),  # b, 8, 15, 15

            nn.ReLU(True),

            nn.ConvTranspose2d(8, 1, 2, stride=2, padding=1),  # b, 1, 28, 28

            nn.Tanh()

        )


    def forward(self, x):

        x = self.encoder(x)

        x = self.decoder(x)

        return x

這裡使用了 nn.ConvTranspose2d(),這可以看作是卷積的反操作,可以在某種意義上看作是反卷積。

我們使用卷積網絡得到的最後生成的圖片效果會更好,具體的圖片效果我就不再這裡放了,可以在我們的github上看到圖片的展示。github 地址:

http://t.cn/RK5gxpM

  變分自動編碼器(Variational Auto Encoder)

變分編碼器是自動編碼器的升級版本,其結構跟自動編碼器是類似的,也由編碼器和解碼器構成。

回憶一下我們在自動編碼器中所做的事,我們需要輸入一張圖片,然後將一張圖片編碼之後得到一個隱含向量,這比我們隨機取一個隨機噪聲更好,因為這包含著原圖片的信息,然後我們隱含向量解碼得到與原圖片對應的照片。

但是這樣我們其實並不能任意生成圖片,因為我們沒有辦法自己去構造隱藏向量,我們需要通過一張圖片輸入編碼我們才知道得到的隱含向量是什麼,這時我們就可以通過變分自動編碼器來解決這個問題。

其實原理特別簡單,只需要在編碼過程給它增加一些限制,迫使其生成的隱含向量能夠粗略的遵循一個標準正態分布,這就是其與一般的自動編碼器最大的不同。

這樣我們生成一張新圖片就很簡單了,我們只需要給它一個標準正態分布的隨機隱含向量,這樣通過解碼器就能夠生成我們想要的圖片,而不需要給它一張原始圖片先編碼。

在實際情況中,我們需要在模型的準確率上與隱含向量服從標準正態分布之間做一個權衡,所謂模型的準確率就是指解碼器生成的圖片與原圖片的相似程度。我們可以讓網絡自己來做這個決定,非常簡單,我們只需要將這兩者都做一個loss,然後在將他們求和作為總的loss,這樣網絡就能夠自己選擇如何才能夠使得這個總的loss下降。另外我們要衡量兩種分布的相似程度,如何看過之前一片GAN的數學推導,你就知道會有一個東西叫KL divergence來衡量兩種分布的相似程度,這裡我們就是用KL divergence來表示隱含向量與標準正態分布之間差異的loss,另外一個loss仍然使用生成圖片與原圖片的均方誤差來表示。

我們可以給出KL divergence 的公式

這裡變分編碼器使用了一個技巧「重新參數化」來解決 KL divergence 的計算問題。

這時不再是每次產生一個隱含向量,而是生成兩個向量,一個表示均值,一個表示標準差,然後通過這兩個統計量來合成隱含向量,這也非常簡單,用一個標準正態分布先乘上標準差再加上均值就行了,這裡我們默認編碼之後的隱含向量是服從一個正態分布的。這個時候我們是想讓均值儘可能接近0,標準差儘可能接近1。而論文裡面有詳細的推導如何得到這個loss的計算公式,有興趣的同學可以去看看具體推到過程:

https://arxiv.org/pdf/1606.05908.pdf

下面是PyTorch的實現:

reconstruction_function = nn.BCELoss(size_average=False)  # mse loss


def loss_function(recon_x, x, mu, logvar):

    """

    recon_x: generating images

    x: origin images

    mu: latent mean

    logvar: latent log variance

    """

    BCE = reconstruction_function(recon_x, x)

    # loss = 0.5 * sum(1 + log(sigma^2) - mu^2 - sigma^2)

    KLD_element = mu.pow(2).add_(logvar.exp()).mul_(-1).add_(1).add_(logvar)

    KLD = torch.sum(KLD_element).mul_(-0.5)

    # KL divergence

    return BCE + KLD

另外變分編碼器除了可以讓我們隨機生成隱含變量,還能夠提高網絡的泛化能力。

最後是VAE的代碼實現:

class VAE(nn.Module):

    def __init__(self):

        super(VAE, self).__init__()


        self.fc1 = nn.Linear(784, 400)

        self.fc21 = nn.Linear(400, 20)

        self.fc22 = nn.Linear(400, 20)

        self.fc3 = nn.Linear(20, 400)

        self.fc4 = nn.Linear(400, 784)


    def encode(self, x):

        h1 = F.relu(self.fc1(x))

        return self.fc21(h1), self.fc22(h1)


    def reparametrize(self, mu, logvar):

        std = logvar.mul(0.5).exp_()

        if torch.cuda.is_available():

            eps = torch.cuda.FloatTensor(std.size()).normal_()

        else:

            eps = torch.FloatTensor(std.size()).normal_()

        eps = Variable(eps)

        return eps.mul(std).add_(mu)


    def decode(self, z):

        h3 = F.relu(self.fc3(z))

        return F.sigmoid(self.fc4(h3))


    def forward(self, x):

        mu, logvar = self.encode(x)

        z = self.reparametrize(mu, logvar)

        return self.decode(z), mu, logvar

VAE的結果比普通的自動編碼器要好很多,下面是結果:

  

VAE的缺點也很明顯,他是直接計算生成圖片和原始圖片的均方誤差而不是像GAN那樣去對抗來學習,這就使得生成的圖片會有點模糊。現在已經有一些工作是將VAE和GAN結合起來,使用VAE的結構,但是使用對抗網絡來進行訓練,具體可以參考一下這篇論文:

https://arxiv.org/pdf/1512.09300.pdf

文中相關代碼連結:

http://t.cn/RK5gxpM

英文參考:

http://t.cn/RtoJRAa

雷鋒網相關閱讀:

深度學習全網最全學習資料匯總之模型介紹篇

Yann LeCun最新研究成果:可以幫助GAN使用離散數據的ARAE

雷鋒網原創文章,未經授權禁止轉載。詳情見轉載須知。

相關焦點

  • 簡單易懂的自動編碼器
    作者:葉虎編輯:田旭自動編碼器是一種無監督的神經網絡模型,它可以學習到輸入數據的隱含特徵,這稱為編碼(coding),同時用學習到的新特徵可以重構出原始輸入數據,稱之為解碼(decoding)。從直觀上來看,自動編碼器可以用於特徵降維,類似主成分分析PCA,但是其相比PCA其性能更強,這是由於神經網絡模型可以提取更有效的新特徵。除了進行特徵降維,自動編碼器學習到的新特徵可以送入有監督學習模型中,所以自動編碼器可以起到特徵提取器的作用。
  • 自編碼器數據降維實踐
    此前,我介紹過一種基於自動編碼器的降維方法 。然而,在那一段時間裡,我專注於如何使用自動編碼作為預測器,而現在我想把它們看作是一種降維技術。這篇文章的目的是解釋一下自動編碼器是如何工作的。它是從將原始數據壓縮成一個忽略噪聲的短代碼開始的。然後,該算法對該代碼進行解壓縮,以生成儘可能接近原始輸入的圖像。
  • 主流的深度學習模型有哪些?
    因為格式問題和傳播原因,我把原回答內容在這篇文章中再次向大家介紹。在更詳細的介紹各種網絡前,首先說明:大部分神經網絡都可以用深度(depth)和連接結構(connection)來定義,下面會具體情況具體分析。籠統的說,神經網絡也可以分為有監督的神經網絡和無/半監督學習,但其實往往是你中有我我中有你,不必死摳字眼。
  • 深度學習遇上稀缺數據就無計可施?這裡有幾個好辦法!
    本文作者 Tyler Folkman 針對這一問題,為大家介紹了幾個在有限的數據上使用深度學習的方法,讓深度學習即便在面臨數據稀缺時,也能大展身手。唯一的問題是你既不在谷歌工作,也不在臉書工作,你的數據是稀缺的,那麼你該怎麼辦?你是能繼續使用是深度學習的能力,還是已無計可施?下面就讓我介紹幾個在有限的數據上使用深度學習的方法,以及闡述為什麼我認為這可能是未來研究中最令人興奮的領域之一。
  • [ICML 2018]用於分子圖生成的聯結樹變分自動編碼器
    序我們決定推出一個新的系列,科研文章概覽。一方面為了激勵自己多看科研文章,另一方面為了把騰睿筆記真的做成筆記。
  • 代碼詳解:一文讀懂自動編碼器的前世今生
    全文共5718字,預計學習時長20分鐘或更長變分自動編碼器(VAE)可以說是最實用的自動編碼器,但是在討論VAE之前,還必須了解一下用於數據壓縮或去噪的傳統自動編碼器。變分自動編碼器的厲害之處假設你正在開發一款開放性世界端遊,且遊戲裡的景觀設定相當複雜。
  • 深度學習助力數據壓縮,一文讀懂相關理論
    但是,神經網絡是淺層網絡,模型的收斂速度、穩定性、權值更新的有效性等都存在不足,此外,神經網絡依賴於有標籤的預訓練數據,這在實際應用場景中很難滿足。2、基於深度學習的數據壓縮深度學習的引入有效解決了傳統方法存在的問題。
  • 條件變分自動編碼器CVAE:基本原理簡介
    變分自動編碼器(VAE)是一種有方向的圖形生成模型,已經取得了很好的效果,是目前生成模型的最先進方法之一。它假設數據是由一些隨機過程,涉及一個未被注意的連續隨機變量z假設生成的z是先驗分布Pθ(z)和條件生成數據分布Pθ(X | z),其中X表示這些數據。
  • 利用深度變體自動編碼器改進宏基因組的組裝
    利用深度變體自動編碼器改進宏基因組的組裝 作者:小柯機器人 發布時間:2021/1/5 16:19:03 丹麥哥本哈根大學Simon Rasmussen課題組的最新研究利用深度變體自動編碼器改進了宏基因組的組裝。
  • 盤點金融領域裡常用的深度學習模型
    作者 | Sonam Srivastava ,譯者 | sambodhi ,編輯 | Vincent ,AI前線出品| ID:ai-front在今天我們發布的這篇文章中,作者 Sonam Srivastava 介紹了金融中的三種深度學習用例及這些模型優劣的證據。
  • 自然語言處理深度學習的7個應用
    原文:7 Applications of Deep Learning for Natural Language Processing作者:Jason Brownlee翻譯:無阻我飛揚摘要:在這篇文章中,作者詳細介紹了自然語言處理深度學習的7種應用,以下是譯文。自然語言處理領域正在從統計方法轉變為神經網絡方法。
  • 入門| 獻給新手的深度學習綜述
    Naher 參與:翁俊堅、劉曉坤 這篇綜述論文列舉出了近年來深度學習的重要研究成果,從方法、架構,以及正則化、優化技術方面進行概述。機器之心認為,這篇綜述對於剛入門的深度學習新手是一份不錯的參考資料,在形成基本學術界圖景、指導文獻查找等方面都能提供幫助。
  • 深度| 理解深度學習中的卷積
    這篇外文既友好又深入,所以翻譯了過來。文章高級部分通過流體力學量子力學等解釋卷積的做法在我看來有點激進,這些領域恐怕比卷積更深奧,所以只需簡略看看即可。以下是正文:卷積現在可能是深度學習中最重要的概念。正是靠著卷積和卷積神經網絡,深度學習才超越了幾乎其他所有的機器學習手段。但卷積為什麼如此強大?它的原理是什麼?在這篇博客中我將講解卷積及相關概念,幫助你徹底地理解它。
  • 前沿|通用句子語義編碼器,谷歌在語義文本相似性上的探索
    近年來,基於神經網絡的自然語言理解研究取得了快速發展(尤其是學習語義文本表示),這些深度方法給人們帶來了全新的應用,且還可以幫助提高各種小數據集自然語言任務的性能。本文討論了兩篇關於谷歌語義表示最新進展的論文,以及兩種可在 TensorFlow Hub 上下載的新模型。
  • 深度學習在2016年都有哪些主要研究進展?(附開源平臺地址)| 盤點
    一、無監督學習無監督學習是指不需要額外信息就能從原始數據中提取模式和結構的任務,這點和需要建立標籤的監督學習相反。使用神經網絡解決這個問題的經典方法是自動編碼器。基本版本由多層感知器(MLP)組成,其中輸入和輸出層具有相同的大小,還有一個較小的隱藏層被訓練用於恢復輸入層。
  • GraphNVP | 用於分子圖生成的可逆流模型
    事實證明,深度學習的最新進展,尤其是深度生成模型在從頭藥物設計中具有不可估量的價值。將深度學習應用於分子生成的重要步驟是如何表示化合物。早期的模型依賴於SMILES的基於字符串的表示形式  。基於RNN的語言模型或變分自動編碼器(VAE)用於生成SMILES字符串,然後將其轉換為分子。
  • 當微軟研究院遇上CVPR,四篇論文搶鮮看 | CVPR 2017
    據悉,StyleBank和自動編碼器將以聯合的方式同時進行學習訓練。然後由於採用了顯示濾波器堆表徵(Explicit filter bank representation)這一結構所帶來的靈活性,使得網絡在學習過程中,自動編碼器不需要對任何圖像風格信息進行編碼。
  • 什麼是小樣本學習?這篇綜述文章用166篇參考文獻告訴你答案
    機器之心報導參與:魔王什麼是小樣本學習?它與弱監督學習等問題有何差異?其核心問題是什麼?來自港科大和第四範式的這篇綜述論文提供了解答。數據是機器學習領域的重要資源,在數據缺少的情況下如何訓練模型呢?小樣本學習是其中一個解決方案。來自香港科技大學和第四範式的研究人員綜述了該領域的研究發展,並提出了未來的研究方向。這篇綜述論文已被 ACM Computing Surveys 接收,作者還建立了 GitHub repo,用於更新該領域的發展。
  • ​大牛的《深度學習》筆記,Deep Learning速成教程
    項目負責人之一Andrew稱:「我們沒有像通常做的那樣自己框定邊界,而是直接把海量數據投放到算法中,讓數據自己說話,系統會自動從數據中學習。」另外一名負責人Jeff則說:「我們在訓練的時候從來不會告訴機器說:『這是一隻貓。』系統其實是自己發明或者領悟了「貓」的概念。」
  • MIT Taco項目:自動生成張量計算的優化代碼,深度學習加速效果提高...
    使用稀疏數據進行分析的算法最終做了大量的加法和乘法,而這大部分計算是無效的。通常,程式設計師通過編寫自定義代碼來優化和避免零條目,但這種代碼通常編寫起來複雜,而且通常適用範圍狹窄。雷鋒網發現,在ACM的系統、程序、語言和應用會議(SPLASH)上,麻省理工學院、法國替代能源和原子能委員會的研究人員和Adobe研究院的研究者們最近提出了一個針對稀疏數據自動生成優化代碼的系統。