53_Auto-Encoders和Variational AutoEncoders(VAE)、PCA降维和Auto-Encoders降维的比较、Auto-Encoders变种、pytorch实现等
1.53.Auto-Encoders和Variational AutoEncoders(VAE)
1.53.1.無監(jiān)督學(xué)習(xí)
1.53.2.Auto-Encoders
1.53.3.How to Train?
1.53.4.Auto-Encoders的訓(xùn)練
1.53.5.PCA降維和Auto-Encoders降維的比較
1.53.6.Auto-Encoders變種
1.53.6.1.Denoising AutoEncoders,去噪 AutoEncoders
1.53.6.2.Dropout AutoEncoders
1.53.6.3.Adversarial AutoEncoders,對抗AutoEncoders
1.53.6.4.q分布和p分布
1.53.6.5.對 KL(p◎q)的直觀理解
1.53.6.6.Maximize Likelihood(極大似然)
1.53.6.7.Minimize KL Divergence (最小化KL散度)
1.53.6.8.在q(z)和p(z)之間怎么計算KL?
1.53.7.Variational AutoEncoders
1.53.8.AutoEncoder的PyTorch實現(xiàn)
1.53.9.Variational AutoEncoders
1.53.10.參考文章
1.53.Auto-Encoders和Variational AutoEncoders(VAE)
1.53.1.無監(jiān)督學(xué)習(xí)
無監(jiān)督學(xué)習(xí)常見的兩種類型是:數(shù)據(jù)集變換和聚類。
數(shù)據(jù)集變換,就是創(chuàng)建數(shù)據(jù)集新的表示算法,與數(shù)據(jù)的原始表示相比,新的表示可能更容易被人或其他機器學(xué)習(xí)算法所理解。
常見的應(yīng)用有降維,就是對許多特征表示的高維數(shù)據(jù),找到該數(shù)據(jù)的一種新方法,用較少的特征就可以概括其重要特征。另一個應(yīng)用就是找到”構(gòu)成”數(shù)據(jù)的各個組成部分,比如對文本文檔的關(guān)鍵字提取。
聚類,就是將數(shù)據(jù)劃分成不同的組,每組包含相似的物項。
1.53.2.Auto-Encoders
自編碼AutoEncoder是一種無監(jiān)督學(xué)習(xí)的算法,他利用反向傳播算法,讓目標(biāo)等于輸入值。什么意思呢,下面舉個例子:
有一個神經(jīng)網(wǎng)絡(luò),它在做的事情是,輸入一張圖片,通過一個Encoder神經(jīng)網(wǎng)絡(luò),輸出一個比較”濃縮的”feature map。之后將這個feature map通過一個Decoder網(wǎng)絡(luò),結(jié)果又將這張圖片還原回去了。
你也可以這么理解,整個Encoder + Decoder是一個神經(jīng)網(wǎng)絡(luò),中間的code只是暫存的數(shù)據(jù)。
感覺就像是,現(xiàn)在有一鍋紅糖水,你不停的煮它,最終水都被煮干了,只剩下紅糖,這個紅糖就是上圖的”Code”。然后你再向紅糖里面注水、加熱,結(jié)果又還原回了一鍋紅糖水。
假設(shè)上線的神經(jīng)網(wǎng)絡(luò)展開如下圖所示,可以看出,圖片經(jīng)過了一個壓縮,再解壓的工序。當(dāng)壓縮的時候,原有的圖片質(zhì)量被縮減。解壓時,用信息量少卻包含所有關(guān)鍵信息的文件恢復(fù)出了原本的圖片。為什么要這樣做呢?
因為有時候神經(jīng)網(wǎng)絡(luò)要接受大量的輸入信息,比如說輸入信息是高清圖片時,信息量可能高達(dá)上千萬,讓神經(jīng)網(wǎng)絡(luò)直接從上千萬信息中學(xué)習(xí)是很吃力的。所以,為何不壓縮一下,提取原圖片中最具代表性的信息,縮減信息量,再把縮減后的信息帶入進(jìn)行網(wǎng)絡(luò)學(xué)習(xí)。這樣學(xué)習(xí)起來就輕松多了。
在無監(jiān)督學(xué)習(xí)中,Auto-Encoders的目標(biāo)是重建自己,它是一個特殊的全連接層,輸入和輸出的維度是一樣的,這樣能保證自己能夠重建。中間有一個neck(脖子),這樣既可以升維也可以降維,這里降到兩維的好處是,二維的圖片是可視化的,不僅已經(jīng)降維,而且在空間中還保證了語義的相關(guān)性(通過無監(jiān)督的聚類可以發(fā)現(xiàn))。
1.53.3.How to Train?
1.53.4.Auto-Encoders的訓(xùn)練
?下面Loss Function,如果輸入是binary的,即01值,那么就用第一種。
?如果是實數(shù)作為輸入,Loss function就是第二種。
②MSE
1.53.5.PCA降維和Auto-Encoders降維的比較
PCA在高維數(shù)據(jù)中尋找方差最大的方向,只選擇方差最大的軸。然而,主成分分析(PCA)的線性性對可提取的特征維度的種類有很大的限制。
PCA V.S. AutoEncoder
同樣都是降維,PCA和AutoEncoder誰的效果更好呢?
首先從直覺上分析,PCA本質(zhì)上是線性的變換,所以它是有局限性的。而AutoEncoder是基于DNN的,由于有activation function的存在,所以可以進(jìn)行非線性變換,使用范圍更廣。
下圖展示了MNIST數(shù)據(jù)集分別經(jīng)過PCA和AutoEncoder 降維再還原 后的效果。第二行是使用AutoEncoder的方法,可以看到幾乎沒什么太大變化;而第四行的圖片很多都變得非常模糊了,說明PCA的效果是不如AutoEncoder的。
Auto-Encoders比PCA降維的效果要好。
1.53.6.Auto-Encoders變種
1.53.6.1.Denoising AutoEncoders,去噪 AutoEncoders
如果只在像素級別的重建,便不能發(fā)現(xiàn)一些更加深層次的特征,網(wǎng)路可能會記住一些特征,為了防止這種情況出現(xiàn),我們可以在原輸入圖片后加入隨機噪聲累加到原圖片上。
Vincent在2008的論文(http://www.iro.umontreal.ca/~lisa/publications2/index.php/publications/show/217)中提出了AutoEncoder的改良版----dA,論文標(biāo)題叫”Extracting and Composing Robust Features”,譯成中文就是”提取、編碼出具有魯棒性的特征”
首先我們考慮,為什么會產(chǎn)生這樣的變種AutoEncoder。如果我們僅僅只是在像素級別對一張圖片進(jìn)行Encode,然后再重建,這樣就無法發(fā)現(xiàn)更深層次的信息,很有可能會導(dǎo)致網(wǎng)絡(luò)記住了一些特征。為了防止這種情況產(chǎn)生,我們可以給輸入圖片加一些噪聲,比方說生成和圖片同樣大小的高斯分布的數(shù)據(jù),然后和圖像的像素值相加(見下圖)。如果這樣都能重建原來的圖片,意味著這個網(wǎng)絡(luò)能從這些混亂的信息中發(fā)現(xiàn)真正有用的特征,此時的Code才能代表輸入圖片的"精華"。
關(guān)鍵是,這樣胡亂給原始圖片加噪聲真的科學(xué)嗎?Vincent從大腦認(rèn)知角度給了解釋。Paper中說到:
人類具有認(rèn)識被阻擋的破損圖像的能力,源于我們高等的聯(lián)想記憶感受機能。
就是說,我們能以多種形式去記憶(比如圖像、聲音),所以即便是數(shù)據(jù)破損丟失,我們也能回想起來。
1.53.6.2.Dropout AutoEncoders
其實這個沒什么特別的,平時我們不論是CNN還是RNN幾乎都會用到Dropout。據(jù)說Dropout是當(dāng)時Hilton在給學(xué)生上課的時候提到的,用來幫助提升神經(jīng)網(wǎng)路訓(xùn)練效果的小Trick。具體關(guān)于Dropout的講解可以看我的這篇文章:https://wmathor.com/index.php/archives/1377/
在訓(xùn)練的時候隨機對某些連接進(jìn)行斷開(通過將該連接的w設(shè)置為0),那么將會迫使網(wǎng)絡(luò)盡可能地提升還存在的連接的表征能力,降低對多個神經(jīng)元的依賴程度。綠色圖的x軸是訓(xùn)練時loss的Dropout率,y是loss, 當(dāng)為1時表示全部斷開,loss最大,然而當(dāng)dropout率為0時,右邊藍(lán)色圖的y軸(test的acc)并不是最大,說明dropout率為0.2時在一定程度上可以緩解過擬合現(xiàn)象。
1.53.6.3.Adversarial AutoEncoders,對抗AutoEncoders
在AutoEncoder中可能存在這樣一個問題,圖片經(jīng)過Encode之后的vector并不符合我們希望的分布(例如高斯分布),他的分布很有可能如下圖所示。這其實是令我們不太滿意的(雖然我并不知道Code滿足分布到底有重要,但是既然別人認(rèn)為很重要那就重要吧),那么有什么解決辦法呢?
由University of Toronto、Google Brain和OpenAI合作的文章Adversarial Autoencoders(AAE)(https://arxiv.org/pdf/1511.05644.pdf)提出了一個使用Autoencoder進(jìn)行對抗學(xué)習(xí)的idea,某種程度上對上述問題提供了一些新思路
AAE的核心其實就是利用GAN的思想,利用一個生成器G和一個判別器D進(jìn)行對抗學(xué)習(xí),以區(qū)分Real data和Fake data。具體思路是這樣的,我現(xiàn)在需要一個滿足p(z)概率分布的 向量,但是 實際上滿足q(z)分布。那么我就首先生成一個滿足p(z)分布的z’向量,打上Real data的標(biāo)簽,然后將z向量打上Fake data(服從q(z)分布)。由于這里的p(z)可以是我們定義的任何一個概率分布,因此整個對抗學(xué)習(xí)的過程實際上是可以認(rèn)為是通過調(diào)整Encoder不斷讓其產(chǎn)生的數(shù)據(jù)的概率分布q(z)接近我們預(yù)定的p(z).
在原始的AutoEncoders中,沒有呈現(xiàn)出原有數(shù)據(jù)的分布,有可能生成的數(shù)據(jù)是一樣的,Adversarial AutoEncoders額外的添加了一個Discriminator(鑒別器),我們希望生成的Z符合真實的Z‘的分布,將真實的和生成的都送到鑒別器計算差距,如果屬于希望的分布就輸出為1,否則輸出為0。
1.53.6.4.q分布和p分布
假設(shè)p和q都服從
1.53.6.5.對 KL(p◎q)的直觀理解:
1.53.6.6.Maximize Likelihood(極大似然)
1.53.6.7.Minimize KL Divergence (最小化KL散度)
?Evidence Lower BOund
1.53.6.8.在q(z)和p(z)之間怎么計算KL?
1.53.7.Variational AutoEncoders
前面的各種AutoEncoder都是將輸入數(shù)據(jù)轉(zhuǎn)換為vector,其中每個維度代表學(xué)習(xí)到的數(shù)據(jù)。而Variational AutoEncoders(VAE)提供了一種概率分布的描述形式,VAE中Encoder描述的是每個潛在屬性的概率分布,而不是直接輸出一個值。
舉例來說,假設(shè)我們已經(jīng)在一個AutoEncoder上訓(xùn)練了一個6維的vector,這個6維的vector將學(xué)習(xí)面部的一些屬性,例如膚色、是否戴眼鏡等。
在上面的示例中,我們使用單個值來描述輸入圖像的潛在屬性。但是,我們可能更喜歡將每個潛在屬性表示為一個范圍。VAE就可以實現(xiàn)這個功能,如下圖所示:
通過這種方法,我們現(xiàn)在將給定輸入的每個潛在屬性表示為概率分布。從狀態(tài)解碼(Decode)時,我們將從每個潛在狀態(tài)分布中隨機采樣以生成向量來作為解碼器的輸入:
Sample()不可微
再參數(shù)化技巧
Too Complex!
生成模型,通過學(xué)習(xí)得到每一個特征的分布情況。
1.53.8.AutoEncoder的PyTorch實現(xiàn)
其實AutoEncoder就是非常簡單的DNN。在encoder中神經(jīng)元隨著層數(shù)的增加逐漸變少,也就是降維的過程。而在decoder中神經(jīng)元隨著層數(shù)的增加逐漸變多,也就是升維的過程
# -*- coding: UTF-8 -*-import torch""" 安裝pytorch的可視化工具——visdom: 安裝并更新,不更新不能正常使用,會卡在download script。pip install visdom -i https://pypi.tuna.tsinghua.edu.cn/simple pip install --upgrade visdom """ import visdom from torch.utils.data import DataLoader from torchvision import transforms, datasets from torch import nn, optim""" 其實AutoEncoder就是非常簡單的DNN。在encoder中神經(jīng)元隨著層數(shù)的增加逐漸變少,也就是降維的過程。而在decoder 中神經(jīng)元隨著層數(shù)的增加逐漸變多,也就是升維的過程。 """ class AE(nn.Module):def __init__(self):super(AE, self).__init__()self.encoder = nn.Sequential(# [b, 784] => [b, 256]nn.Linear(784, 256),nn.ReLU(),# [b, 256] => [b, 64]nn.Linear(256, 64),nn.ReLU(),# [b, 64] => [b, 20]nn.Linear(64, 20),nn.ReLU())self.decoder = nn.Sequential(# [b, 20] => [b, 64]nn.Linear(20, 64),nn.ReLU(),# [b, 64] => [b, 256]nn.Linear(64, 256),nn.ReLU(),# [b, 256] => [b, 784]nn.Linear(256, 784),nn.Sigmoid())"""上面代碼都是基本操作,有一個地方需要特別注意,在decoder網(wǎng)絡(luò)中,最后跟的不是ReLU而是Sigmoid函數(shù),因為我們想要將圖片打印出來看一下,而使用的數(shù)據(jù)集是MNIST,所以要將tensor里面的值最終都壓縮到0-1之間。"""def forward(self, x):""":param [b, 1, 28, 28]::return [b, 1, 28, 28]:"""batchsz = x.size(0)# flattenx = x.view(batchsz, -1)# encoderx = self.encoder(x)# decoderx = self.decoder(x)# reshapex = x.view(batchsz, 1, 28, 28)return xdef main():mnist_train = datasets.MNIST('mnist', train=True, transform=transforms.Compose([transforms.ToTensor()]), download=True)mnist_train = DataLoader(mnist_train, batch_size=32, shuffle=True)mnist_test = datasets.MNIST('mnist', train=False, transform=transforms.Compose([transforms.ToTensor()]), download=True)mnist_test = DataLoader(mnist_test, batch_size=32)epochs = 1000lr = 1e-3model = AE()# 由于input是0-1之間的實數(shù),所以Loss functionMSEcriteon = nn.MSELoss()optimizer = optim.Adam(model.parameters(), lr=lr)print(model)"""在通常(監(jiān)督學(xué)習(xí))情況下,我們需要將網(wǎng)絡(luò)的輸出output和訓(xùn)練集的label進(jìn)行對比,計算loss。但AutoEncoder是無監(jiān)督學(xué)習(xí),不需要label,我們只需要將網(wǎng)絡(luò)的輸出output和網(wǎng)絡(luò)的輸入input進(jìn)行對比,計算loss即可"""viz = visdom.Visdom(use_incoming_socket=False)for epoch in range(epochs):# 不需要label,所以用一個占位符"_"代替for batchidx, (x, _) in enumerate(mnist_train):x_hat = model(x)loss = criteon(x_hat, x)# backpropoptimizer.zero_grad()loss.backward()optimizer.step()if epoch % 10 == 0:print(epoch, 'loss:', loss.item())x, _ = iter(mnist_test).next()with torch.no_grad():x_hat = model(x)viz.images(x, nrow=8, win='x', opts=dict(title='x'))viz.images(x_hat, nrow=8, win='x_hat', opts=dict(title='x_hat'))if __name__ == '__main__':main()得到的效果如下圖所示,普通的AutoEncoder還是差了一點,可以看到很多圖片已經(jīng)看不清具體代表的數(shù)字了。
1.53.9.Variational AutoEncoders
最主要關(guān)注一下定義網(wǎng)絡(luò)的部分:
Encode以后的變量h要分成兩半兒,利用h.chunk(num, dim)實現(xiàn),num表示要分成幾塊,dim值表示在什么維度上進(jìn)行。然后隨機采樣出標(biāo)準(zhǔn)正態(tài)分布的數(shù)據(jù),用和對其進(jìn)行變換。這里的kld指的是KL Divergence,它是Loss的一部分:
輸出結(jié)果:
VAE((encoder): Sequential((0): Linear(in_features=784, out_features=256, bias=True)(1): ReLU()(2): Linear(in_features=256, out_features=64, bias=True)(3): ReLU()(4): Linear(in_features=64, out_features=20, bias=True)(5): ReLU())(decoder): Sequential((0): Linear(in_features=10, out_features=64, bias=True)(1): ReLU()(2): Linear(in_features=64, out_features=256, bias=True)(3): ReLU()(4): Linear(in_features=256, out_features=784, bias=True)(5): Sigmoid()) ) Setting up a new session... Without the incoming socket you cannot receive events from the server or register event handlers to your Visdom client. 0 loss: 0.05882733315229416 kld 0.005957949906587601 10 loss: 0.04458034038543701 kld 0.00900172907859087 20 loss: 0.046602990478277206 kld 0.008918660692870617 30 loss: 0.04872169345617294 kld 0.009532256051898003 40 loss: 0.04016539081931114 kld 0.009037637151777744 50 loss: 0.044585954397916794 kld 0.0095137795433402061.53.10.參考文章
https://www.cnblogs.com/pengzhonglian/p/12159970.html
https://blog.csdn.net/h__ang/article/details/90720579
https://www.cnblogs.com/jeshy/p/11204300.html
https://blog.csdn.net/z_feng12489/article/details/88851163
https://blog.csdn.net/fengdu78/article/details/104337519
https://blog.csdn.net/sleepinghm/article/details/105142959
https://www.cnblogs.com/yongjieShi/p/8371549.html
https://www.freesion.com/article/959958354/
https://blog.csdn.net/u013517182/article/details/93046229
https://blog.csdn.net/qq_41882866/article/details/108200444
總結(jié)
以上是生活随笔為你收集整理的53_Auto-Encoders和Variational AutoEncoders(VAE)、PCA降维和Auto-Encoders降维的比较、Auto-Encoders变种、pytorch实现等的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 带电池的奥特曼玩具能往客机上带吗?
- 下一篇: Sqoop导入导出的时候总是出现等待5分