Deep Learning
上一篇主要是講了全連接神經(jīng)網(wǎng)絡(luò)龙宏,這里主要講的就是深度學(xué)習(xí)網(wǎng)絡(luò)的一些設(shè)計(jì)以及一些權(quán)值的設(shè)置。神經(jīng)網(wǎng)絡(luò)可以根據(jù)模型的層數(shù),模型的復(fù)雜度和神經(jīng)元的多少大致可以分成兩類:Shallow Neural Network和Deep Neural Network扒披。比較一下兩者:
Network Name | Time | complexity | theoretical |
---|---|---|---|
Shallow Neural Network | more efficient to train | simple | powerful enough |
Deep Nerual Network | need more time | sophisticated | more meaningful |
雖然說簡(jiǎn)單的神經(jīng)網(wǎng)絡(luò)訓(xùn)練時(shí)間短,但是目前常用的還是deep圃泡,因?yàn)槎鄬拥纳窠?jīng)網(wǎng)絡(luò)有利于提取圖像或者是語(yǔ)音的一些特征碟案,取TensorFlow的minist數(shù)據(jù)集為例,一個(gè)手寫字體的識(shí)別就是需要從圖像中提取特征:
比如想要識(shí)別數(shù)字1和5颇蜡,可以把數(shù)字的特征分開蟆淀,每一個(gè)不同的神經(jīng)元識(shí)別一部分,然后綜合結(jié)果澡匪。這些都是像素點(diǎn),所以每經(jīng)過一層神經(jīng)元就會(huì)從圖像中提取特征褒链。再對(duì)圖片進(jìn)行匹配和識(shí)別唁情。層數(shù)越多,就能提取更加復(fù)雜的特征甫匹,解決一些sophisticated的問題能力也就越強(qiáng)甸鸟。
①The challenge of deep learning
深度學(xué)習(xí)的挑戰(zhàn)主要有這么幾個(gè)問題:
1.difficult structural decisions惦费。對(duì)于網(wǎng)絡(luò)結(jié)構(gòu)的設(shè)計(jì)很難把握,但是這是可以使用一些相關(guān)領(lǐng)域的知識(shí)來做選擇的抢韭。比如薪贫,做圖像的識(shí)別,我們可以使用convolutional Network刻恭,因?yàn)榫矸e神經(jīng)網(wǎng)絡(luò)對(duì)于兩個(gè)相鄰的像素聯(lián)系會(huì)很大瞧省,也就是說,對(duì)于一個(gè)像素鳍贾,如果是用卷積神經(jīng)網(wǎng)絡(luò)鞍匾,那么只會(huì)考察它周圍的像素點(diǎn)的特征,而離他很遠(yuǎn)的像素是不會(huì)處理骑科。對(duì)于語(yǔ)音識(shí)別橡淑,LSTM,RNN這些神經(jīng)網(wǎng)絡(luò)用的就比較多咆爽,因?yàn)樗麄兛梢员A糁暗男畔ⅰ?br>
2.high model complexity梁棠。如果網(wǎng)絡(luò)的層數(shù)很多,很可能會(huì)出現(xiàn)過擬合的情況斗埂,如果是數(shù)據(jù)量非常大的話符糊,這種情況可以忽略。但如果數(shù)據(jù)量不大蜜笤,那么有可能會(huì)出現(xiàn)過擬合濒蒋。常用的解決過擬合的方法:drop out。訓(xùn)練神經(jīng)網(wǎng)絡(luò)的時(shí)候不全部訓(xùn)練把兔,只是訓(xùn)練一部分沪伙,比如訓(xùn)練百分之70.denoising。這種方法后面會(huì)詳解县好,主要就是假如一下雜訊一起訓(xùn)練围橡。
3.hard optimization problem。對(duì)于神經(jīng)網(wǎng)絡(luò)的訓(xùn)練也有很多需要注意的缕贡,因?yàn)樯窠?jīng)網(wǎng)絡(luò)經(jīng)過了多層的非線性轉(zhuǎn)換翁授,不再是一個(gè)山谷狀了,可能是凹凹凸凸的晾咪,這樣就導(dǎo)致有可能你只是到達(dá)了某一個(gè)山谷而不是全局的最優(yōu)收擦。這個(gè)時(shí)候我們就要選擇一個(gè)比較好的初始值了,如果我們選擇的初始值恰好就是在全局最優(yōu)的旁邊谍倦,那就穩(wěn)了塞赂。有一種方法就是pre-train。
4.huge computational complexity昼蛀。層數(shù)這么多宴猾,計(jì)算機(jī)復(fù)雜度看到很大圆存。這里已經(jīng)可以使用硬件解決了,GPU的計(jì)算得到仇哆。
比較關(guān)鍵的其實(shí)就是regularization和initialization沦辙。
②initialization
權(quán)值的初始值很重要,好的權(quán)值初始化是可以避免局部最優(yōu)解的出現(xiàn)讹剔。比較常用的方法就是pre-train油讯。先用pre-train訓(xùn)練得到一層權(quán)值,這些權(quán)值就作為初始值辟拷,之后在backprob訓(xùn)練撞羽。
一層一層的來,第一層的出來了第二層的依次決定衫冻。
首先要介紹一個(gè)概念是Autoencoder诀紊,自編碼器。
Autoencoder
什么是權(quán)重隅俘?在神經(jīng)網(wǎng)絡(luò)的模型里面權(quán)重代表的就是特征轉(zhuǎn)換(feature transform)邻奠。從編碼方面來說,權(quán)重也可以看成是一種編碼方式为居,把一個(gè)數(shù)據(jù)編碼成另一種數(shù)據(jù)碌宴。神經(jīng)網(wǎng)絡(luò)是一層一層的進(jìn)行的,所以如果是一個(gè)好的權(quán)重的話蒙畴,是應(yīng)該可以提取出數(shù)據(jù)的特征的贰镣,也就是information-preserving encoding,一種可以保留有用信息的編碼膳凝。第i層提取了特征碑隆,傳到了i+1層,i+1層在i層的基礎(chǔ)上再提取一些更加復(fù)雜的特征蹬音,傳到i+2層上煤。最后每一次都可以提取出特征來,這樣就可以最大限度的把數(shù)據(jù)的特征保留下來著淆。上面講到的手寫數(shù)字識(shí)別是可以把一個(gè)數(shù)字劃分成很多個(gè)筆畫劫狠,反過來,也可以由特征轉(zhuǎn)換回?cái)?shù)字永部。這種可逆的轉(zhuǎn)換叫做information-preserving独泞,通過神經(jīng)網(wǎng)絡(luò)轉(zhuǎn)換的特征最后是可以轉(zhuǎn)換回原來的輸入,這也正是pre-train要做到的苔埋。所以pre-train要滿足的特征就是要求information-preserving懦砂。因?yàn)槟玫搅颂卣饔挚梢杂玫玫降奶卣鞯玫皆斎耄C明得到的特征是可以代表整個(gè)數(shù)據(jù)的,沒有遺漏孕惜。
想要得到這樣的效果,只需要建立一個(gè)三層的神經(jīng)網(wǎng)絡(luò)即可晨炕。
這個(gè)神經(jīng)網(wǎng)絡(luò)經(jīng)過權(quán)重得到的結(jié)果就是encode之后的數(shù)據(jù)衫画,也就是通過feature transform提取特征的過程,經(jīng)過的就是解碼過程瓮栗,要求輸出層輸出的數(shù)據(jù)要和原數(shù)據(jù)差不多接近削罩。整個(gè)網(wǎng)絡(luò)是的結(jié)構(gòu),重點(diǎn)就在重構(gòu)费奸,輸入層到隱含層是特征轉(zhuǎn)換弥激,隱含層到輸出層是重構(gòu)。這種結(jié)構(gòu)我們叫autoencode愿阐,對(duì)應(yīng)編碼和解碼微服,整個(gè)過程就是在逼近indentity function(恒等函數(shù))
但是這樣好像多此一舉,既然輸出都是差不多的為什么要多此一舉缨历?對(duì)于監(jiān)督式學(xué)習(xí)以蕴,隱藏層其實(shí)就是特征轉(zhuǎn)換,乘上一些權(quán)值轉(zhuǎn)換成對(duì)應(yīng)特征的值辛孵。就好像手寫數(shù)字識(shí)別得到每一個(gè)數(shù)字的特征,包含了一些提取出有用的特征,可以得到一些數(shù)據(jù)具有代表性的信息儿奶。對(duì)于非監(jiān)督的學(xué)習(xí)喜滨,也可以使用autoencode來做density estimation,密度估計(jì)冶匹,如果密度較大习劫,說明可以提取到的特征很多,否則就是密度很小徙硅。也可以做outlier detection榜聂,異常值的檢測(cè),也就是孤立點(diǎn)嗓蘑,噪音须肆。找出哪些是典型的資料,哪些不是桩皿。
對(duì)于編碼器豌汇,我們更加關(guān)心的其實(shí)是中間的隱藏層,也就是特征轉(zhuǎn)換權(quán)重自然對(duì)應(yīng)的error function:
三層的autoencode也叫basic autoencode 因?yàn)樗亲詈?jiǎn)單的了泄隔。通常限定方便數(shù)字的編碼拒贱,數(shù)據(jù)集可以表示為所以可以看成是一個(gè)非監(jiān)督式的學(xué)習(xí),一個(gè)重要的限制條件是解碼權(quán)重等于編碼權(quán)重,這起到了regularization的作用逻澳。
深度學(xué)習(xí)中闸天,basic autoencoder的過程也就對(duì)應(yīng)著pre-training的過程,使用這種方法斜做,對(duì)無label的原始數(shù)據(jù)進(jìn)行編碼和解碼苞氮,得到的編碼權(quán)重就可以作為pre-trained的比較不錯(cuò)的初始化權(quán)重,也就是作為深度學(xué)習(xí)中層與層之間的初始化權(quán)重瓤逼。
所以笼吟,pre-train的訓(xùn)練過程:首先,autoencoder會(huì)對(duì)深度學(xué)習(xí)網(wǎng)絡(luò)第一層(即原始輸入)進(jìn)行編碼和解碼霸旗,得到編碼權(quán)重贷帮,作為網(wǎng)絡(luò)第一層到第二層的的初始化權(quán)重;然后再對(duì)網(wǎng)絡(luò)第二層進(jìn)行編碼和解碼诱告,得到編碼權(quán)重W(1)ij撵枢,作為網(wǎng)絡(luò)第二層到第三層的初始化權(quán)重,以此類推蔬啡,直到深度學(xué)習(xí)網(wǎng)絡(luò)中所有層與層之間都得到初始化權(quán)重诲侮。值得注意的是,對(duì)于l-1層的網(wǎng)絡(luò)箱蟆,autoencoder中的d?應(yīng)與下一層(即l層)的神經(jīng)元個(gè)數(shù)相同沟绪。
這里介紹的只是一種最簡(jiǎn)單的,還有很多的編碼器空猜,稀疏編碼器绽慈,去燥編碼器等等。
②regularization
控制模型的復(fù)雜度就是使用正則化了辈毯。
神經(jīng)網(wǎng)絡(luò)每一層都有很多的權(quán)重和神經(jīng)元坝疼,這就導(dǎo)致了模型的復(fù)雜度會(huì)很大,regularization是必要的谆沃。
我們之前介紹過一些方法:
1.structural decisions钝凶。架構(gòu)可以設(shè)計(jì)的簡(jiǎn)單點(diǎn),但是深度學(xué)習(xí)神經(jīng)網(wǎng)絡(luò)的結(jié)構(gòu)是不可能簡(jiǎn)單的唁影,這輩子的不可能耕陷。只能是相對(duì)來說用dropout減輕一些壓力。2.weight decay or weight elimination regularizers据沈∮茨可以使用正則化來減小權(quán)值。
3.early stop锌介。不要訓(xùn)練的這么準(zhǔn)確嗜诀,差不多差不多就夠了猾警。
下面是一種新的regularization的方式:
Denoising Autoencoder
回顧一下之前的overfit的原因:
和樣本數(shù)量,噪聲大小都有關(guān)系隆敢,如果數(shù)據(jù)量是不變的发皿,那么noise的影響就會(huì)非常大。那么這個(gè)時(shí)候?qū)崿F(xiàn)regularization的一個(gè)方法就是消除noise的影響拂蝎。
有一種方法是對(duì)數(shù)據(jù)clean操作雳窟,但是這樣費(fèi)時(shí)費(fèi)力。有一種更加牛逼的做法匣屡,就是在數(shù)據(jù)中添加一些noise再訓(xùn)練。
這種做法的初衷是想建立一個(gè)比較健壯拇涤,容錯(cuò)性高的autoencode捣作。在一個(gè)已經(jīng)訓(xùn)練好的autoencode中,g(x) ≈ x的鹅士,對(duì)于已經(jīng)容錯(cuò)性很高券躁,比較健壯的autoencode,得到的輸出是和x很接近的掉盅。比如手寫數(shù)字識(shí)別也拜,一個(gè)很規(guī)范很正的6輸進(jìn)去可以得到一個(gè)6,但是如果原始的圖片是歪歪的6趾痘,然后還是可以得到6的話那么這個(gè)自編碼器就是一個(gè)健壯的自編碼器了慢哈。比較不是每一個(gè)人寫6都是寫的正正,這就使得這個(gè)自編碼器的抗噪能力很強(qiáng)永票。
所以卵贱,最后我們要訓(xùn)練的樣本集
其中
所以使用這種autoencode的目的就是使得加入了有噪音的x都可以得到純凈的x。不僅能從純凈的樣本中編解碼得到純凈的樣本侣集,還能從混入noise的樣本中編解碼得到純凈的樣本键俱。這樣得到的權(quán)重初始值更好,因?yàn)樗哂懈玫目乖肼暷芰κ婪郑唇研院帽嗾瘛?shí)際應(yīng)用中,denoising autoencoder非常有用臭埋,在訓(xùn)練過程中踪央,輸入混入人工noise,輸出純凈信號(hào)斋泄,讓模型本身具有抗噪聲的效果杯瞻,讓模型健壯性更強(qiáng),最關(guān)鍵的是起到了regularization的作用炫掐。這也是之前說的去燥自編碼器魁莉。
linear autoencode
剛剛介紹的自編碼器是非線性的,因?yàn)橹虚g的tanh(x)函數(shù)就是非線性的。常見的autoencode常用于在深度學(xué)習(xí)中旗唁,這里要介紹的是線性的自編碼器畦浓,linear autoencode。對(duì)于一個(gè)線性的自編碼器检疫,只需要不包括非線性轉(zhuǎn)換就好了讶请。
所以,就變成
這里有三個(gè)限制條件:
①移除bias項(xiàng)屎媳,保持維度一致夺溢。
②編碼權(quán)重與解碼權(quán)重一致:
③
由于兩個(gè)權(quán)重是一樣的,W的維度是dxd'烛谊,x的維度是dx1风响,所以整個(gè)公式可以變?yōu)椋?img class="math-block" src="https://math.jianshu.com/math?formula=h_k(x)%20%3D%20WW%5ETx" alt="h_k(x) = WW^Tx" mathimg="1">
但是要求
所以error function
對(duì)于那個(gè)協(xié)方差矩陣首先可以進(jìn)行特征值分解其中Γ是一個(gè)對(duì)角矩陣,V矩陣滿足
而I矩陣有一個(gè)很重要的性質(zhì)丹禀,由于W是dxd'的状勤,d < d’。有I的非零元素的數(shù)量是不大于d'的双泪。
證明
對(duì)于一個(gè)矩陣W(dxd'持搜,d < d'),那么有Rank(W) <= d'焙矛。這個(gè)結(jié)論直接給出葫盼,不用證明。假設(shè)有兩個(gè)矩陣A,B村斟,C = AB剪返,那么AX = C的解就是B,也就是唯一解邓梅,也就是說Rank(A, C) = Rank(A )脱盲。證明:對(duì)于Rank(A,C)和Rank(A)無非就是兩種情況,=和>日缨。<是沒有的钱反,Rank(A)是不可能大于Rank(A,C)的。如果是Rank(A) < Rank(A,C)匣距,那么這個(gè)增廣矩陣(A,C)變換成初等矩陣之后面哥,最后一行就會(huì)出現(xiàn)的情況,0 毅待!= a尚卫,自然就是無解了。所以證明了上訴情況一定是有Rank(A) = Rank(A,C)
而由于R(C) <= R(A,C)尸红,所以R(C) <= R(A)吱涉,同理刹泄,也可以證明得R(C) <= R(B),而在這里所以怎爵,是不大于d'的特石,因?yàn)橐粋€(gè)矩陣的秩是不可以大于它最小的維度的。綜上所訴鳖链,更重要的是姆蘸,秩就是這個(gè)矩陣特征值的數(shù)量,而I矩陣的斜對(duì)角線就是WW^T矩陣的特征值芙委,所以才有I的非零元素的數(shù)量是不大于d'的逞敷。
回到正文。那么就可以推出
這樣就把表達(dá)式轉(zhuǎn)換成了一個(gè)求解V和Γ的方程:
所以第一個(gè)要解決的就是
到這里Γ的最優(yōu)解已經(jīng)知道了
最小化問題有點(diǎn)復(fù)雜,轉(zhuǎn)換一下:
當(dāng)d' = 1的時(shí)候顶瞳,那就只有V的第一行是有用,所以
條件是在做特征分解的時(shí)候得到的愕秫,這里也要繼承下來慨菱。
有條件的自然是拉格朗日乘子法了:
求導(dǎo)得0
仔細(xì)看一下,這個(gè)λ其實(shí)就是的特征值
既然d' = 1是這樣了戴甩,那么當(dāng)d' > 1的時(shí)候符喝,就是依次把d'個(gè)特征值求出來就好了,所以這個(gè)就是linear autoencoder的過程了甜孤。
過程和PCA很相似协饲,大致都是差不多的,但是PCA還需要減去一下平均值缴川,也就是對(duì)x輸入數(shù)據(jù)做去均值化的處理茉稠。
linear autoencode和PCA不完全一樣,至少出發(fā)點(diǎn)不是一樣的把夸,linear autoencode是用來pre-train而被發(fā)明的而线,雖然機(jī)器學(xué)習(xí)不太需要,但是既然引出了非線性的autoencode那順便把linear也探討一下恋日。但是膀篮,linear autoencode在公式的推導(dǎo)上是基本一致的,上面的推導(dǎo)其實(shí)也是可以做為PCA的推導(dǎo)岂膳。
Dimensionality Reduction——Principal Component Analysis
既然講到了降維誓竿,那順便把PCA也講了,Deep Learning的部分已經(jīng)講完谈截。
①數(shù)據(jù)降維
通常我們得到的數(shù)據(jù)有很多的維度筷屡,比如一個(gè)商店涧偷,可以有名字,年齡速蕊,出生日期嫂丙,性別,成交量等等规哲。而年齡和性別其實(shí)是表示一個(gè)東西跟啤,兩個(gè)表示完全是多余的。當(dāng)然我們也可以直接不做處理就使用這些數(shù)據(jù)來做機(jī)器學(xué)習(xí)唉锌。但是這樣會(huì)耗費(fèi)巨大的資源隅肥。在這種情況下自然就需要數(shù)據(jù)降維了。降維意味著會(huì)有數(shù)據(jù)丟失袄简,丟失是一定會(huì)有的腥放,所以只能保證丟失了多少而已。
舉個(gè)例子绿语,假如某學(xué)籍?dāng)?shù)據(jù)有兩列M和F秃症,其中M列的取值是如何此學(xué)生為男性取值1,為女性取值0吕粹;而F列是學(xué)生為女性取值1种柑,男性取值0。此時(shí)如果我們統(tǒng)計(jì)全部學(xué)籍?dāng)?shù)據(jù)匹耕,會(huì)發(fā)現(xiàn)對(duì)于任何一條記錄來說聚请,當(dāng)M為1時(shí)F必定為0,反之當(dāng)M為0時(shí)F必定為1稳其。在這種情況下驶赏,我們將M或F去掉實(shí)際上沒有任何信息的損失,因?yàn)橹灰A粢涣芯涂梢酝耆€原另一列既鞠。
②向量和基
先看一個(gè)向量的運(yùn)算:
這種乘積方式并不能看出有什么意義煤傍,換一種表達(dá)方式a為A和B的夾角。再進(jìn)一步|B| = 1嘱蛋,那么就可以看出來患久,當(dāng)向量B的模為1,則A與B的內(nèi)積值等于A向B所在直線投影的矢量長(zhǎng)度浑槽。這個(gè)結(jié)論很重要蒋失。
假設(shè)有一個(gè)點(diǎn)(3,2),那么在坐標(biāo)系中的表示:
向量(3,2)就從原點(diǎn)發(fā)射到(3,2)這個(gè)點(diǎn)的有向線段桐玻。在x軸上的投影值是3篙挽,在y軸上的投影值是2。也就是說我們其實(shí)隱式引入了一個(gè)定義:以x軸和y軸上正方向長(zhǎng)度為1的向量為標(biāo)準(zhǔn)镊靴。所以向量(x,y)實(shí)際上是一種線性組合:
所以链韭,可以用另外一種方法來描述,確定一組基煮落,然后給出在基所在的各個(gè)直線上的投影值敞峭,就可以了。不過一般直接忽略第一步蝉仇,比較可靠維度就知道了旋讹。但是事實(shí)上,基并不是一個(gè)固定的東西轿衔,任何一個(gè)線性無關(guān)的向量都可以成為一組基沉迹。例如,(1,1)和(-1,1)也可以成為一組基害驹。一般來說鞭呕,我們希望基的模是1,因?yàn)閺膬?nèi)積的意義可以看到宛官,如果基的模是1葫松,那么就可以方便的用向量點(diǎn)乘基而直接獲得其在新基上的坐標(biāo)了!實(shí)際上底洗,對(duì)應(yīng)任何一個(gè)向量我們總可以找到其同方向上模為1的向量腋么,只要讓兩個(gè)分量分別除以模就好了。
③基變換的矩陣表示
還是拿上面的(3枷恕,2)做為例子,比如我們現(xiàn)在有兩個(gè)基
那么把(3,2)變?yōu)樾碌幕系淖鴺?biāo)谭胚,則有
所以徐块,一般的,如果我們有M個(gè)N維向量灾而,想將其變換為由R個(gè)N維向量表示的新空間中胡控,那么首先將R個(gè)基按行組成矩陣A,然后將向量按列組成矩陣B旁趟,那么兩矩陣的乘積AB就是變換結(jié)果昼激,其中AB的第m列為A中第m列變換后的結(jié)果。
這里是R是要變換的維度锡搜,R是可以小于N的橙困。基于以上的理論,兩個(gè)矩陣相乘的意義是將右邊矩陣中的每一列列向量變換到左邊矩陣中每一行行向量為基所表示的空間中去
④協(xié)方差
上面討論了基已經(jīng)坐標(biāo)基于基的變換耕餐,如果基的數(shù)量是小于數(shù)據(jù)維度的就可以達(dá)到降維的效果了凡傅。但是,問題來了肠缔,基是無限多個(gè)的夏跷,如何選擇基是一個(gè)很大的問題哼转。
舉一個(gè)例子:
為了處理方便,首先先減去每行的均值槽华,這樣做的原因后面再說壹蔓。減去之后就是這樣:
問題來了,這5個(gè)數(shù)據(jù)都是2維度的猫态,現(xiàn)在想降到一維佣蓉,如果我們必須使用一維來表示這些數(shù)據(jù),又希望盡量保留原始的信息懂鸵,你要如何選擇偏螺?這個(gè)問題實(shí)際上是要在二維平面中選擇一個(gè)方向,將所有數(shù)據(jù)都投影到這個(gè)方向所在直線上匆光,用投影值表示原始記錄套像。這是一個(gè)實(shí)際的二維降到一維的問題。
一種直觀的看法是:希望投影后的投影值盡可能分散终息。同一個(gè)維度數(shù)據(jù)之間不"擠"在一起夺巩,因?yàn)閿D在一起表達(dá)不了數(shù)據(jù)本身了。而表征數(shù)據(jù)之間離散程度周崭,就考慮到了方差柳譬。具體做法就是 想辦法讓高維數(shù)據(jù)左乘一個(gè)矩陣,得到降維后的數(shù)據(jù)续镇,降維后的數(shù)據(jù)的方差最大化美澳。在線性代數(shù)中學(xué)過,一個(gè)矩陣可以看成是很多個(gè)列向量摸航,每一個(gè)向量代表著一個(gè)物體的數(shù)據(jù)制跟。要表達(dá)這個(gè)矩陣真的需要這么多數(shù)據(jù)嗎,顯然不一定酱虎,求解一個(gè)矩陣的秩R雨膨,看看R 的值,在絕大多數(shù)情況下读串,矩陣都不是滿秩的聊记,說明矩陣中的元素表達(dá)客觀世界中的物體有一些是多余的。
既然是求離散程度恢暖,那么就是方差了排监,對(duì)于每一個(gè)字段的方差如果已經(jīng)去除了均值那就可以直接轉(zhuǎn)換
對(duì)于上面二維降成一維的問題來說,找到那個(gè)使得方差最大的方向就可以了杰捂。不過對(duì)于更高維社露,還有一個(gè)問題需要解決∏砟铮考慮三維降到二維問題峭弟。與之前相同附鸽,首先我們希望找到一個(gè)方向使得投影后方差最大,這樣就完成了第一個(gè)方向的選擇瞒瘸,繼而我們選擇第二個(gè)投影方向坷备。但是如果第二次還是堅(jiān)持選擇方差最大的方向,那么肯定還是會(huì)和第一個(gè)方向相同的情臭,這樣表達(dá)的信息很有可能重合省撑,所以應(yīng)該要加上一些限制。從直觀上說俯在,讓兩個(gè)字段盡可能表示更多的原始信息竟秫,我們是不希望它們之間存在(線性)相關(guān)性的,因?yàn)橄嚓P(guān)性意味著兩個(gè)字段不是完全獨(dú)立跷乐,必然存在重復(fù)表示的信息肥败。
事實(shí)上兩個(gè)字段的相關(guān)性是可以用協(xié)方差來表示。協(xié)方差為0的時(shí)候愕提,兩個(gè)字段是互相獨(dú)立的馒稍。協(xié)方差為0所以只能在一個(gè)基的正交方向選擇第二個(gè)基。將一組N維向量降為K維(K大于0浅侨,小于N)纽谒,其目標(biāo)是選擇K個(gè)單位(模為1)正交基,使得原始數(shù)據(jù)變換到這組基上后如输,各字段兩兩間協(xié)方差為0鼓黔,而字段的方差則盡可能大(在正交的約束下,取最大的K個(gè)方差)不见。
⑤協(xié)方差矩陣的優(yōu)化
協(xié)方差矩陣的對(duì)角線代表了原來樣本在各個(gè)維度上的方差澳化,其他元素代表了各個(gè)維度之間的相關(guān)關(guān)系。所以我們需要把協(xié)方差對(duì)角化脖祈,因?yàn)槲覀冃枰幚淼木褪蔷S度中的關(guān)系肆捕,而不是維度之間的刷晋。設(shè)Y=PX盖高,則Y為X對(duì)P做基變換后的數(shù)據(jù)。設(shè)Y的協(xié)方差矩陣為D眼虱,則有:
所以現(xiàn)在明白了喻奥,我們要找的P就是使得可以對(duì)角化C的矩陣,最后按照得到的對(duì)角矩陣從大到小排列捏悬,取P的前k行作為基進(jìn)行轉(zhuǎn)換即可撞蚕。這其實(shí)就是求解特征值的過程。
總結(jié):一開始對(duì)數(shù)據(jù)進(jìn)行降維操作过牙,我們想到的就是要使得數(shù)據(jù)投影之后方差最大甥厦,那么就需要尋找一組基使達(dá)成這個(gè)條件纺铭。但是發(fā)現(xiàn)如果只是找最大的方差是會(huì)有重復(fù),比如第一個(gè)發(fā)現(xiàn)的基是最大的刀疙,那么第二個(gè)方向肯定也差不多是這個(gè)方向舶赔,這樣信息就有重復(fù),所以又相當(dāng)數(shù)據(jù)維度之間是應(yīng)該有非相關(guān)性的谦秧,于是就使用到了協(xié)方差來代表竟纳,但是我們需要的是數(shù)據(jù)里的非相關(guān)性最大化,數(shù)據(jù)間的最大化方差最大已經(jīng)處理了疚鲤,所以這個(gè)時(shí)候協(xié)方差只需要關(guān)注對(duì)角線锥累,自然就是對(duì)角化了。又發(fā)現(xiàn)對(duì)角化其實(shí)就是特征分解的一個(gè)過程集歇,最后求出結(jié)果桶略。
另一個(gè)方面,W我們可以看做是基的組合鬼悠,WX就是降維之后的數(shù)據(jù)就是要求了降維之后的數(shù)據(jù)要和原來的數(shù)據(jù)相差不遠(yuǎn)删性,為什么不是X-WX呢?首先這兩個(gè)東西不是同緯度的焕窝,不可能計(jì)算蹬挺,其次乘上一個(gè)轉(zhuǎn)置其實(shí)就是轉(zhuǎn)換回來的結(jié)果了。如果壓縮之后轉(zhuǎn)換回來的結(jié)果和原來差不多它掂,那不就證明了這個(gè)降維是OK的嗎巴帮?所以這就和Autoencode的思想一樣了,所以上面linear autoencode的過程也可以看做就是PCA的公式化推導(dǎo)虐秋。
⑤PCA算法過程:
①將原始數(shù)據(jù)按列組成n行m列矩陣X
②均值化操作榕茧。
③求協(xié)方差
④求特征值特征向量
⑤排列取前k大的特征值對(duì)應(yīng)的特征向量
⑥降維操作
Coding
Autoencode
編碼器有幾個(gè)很重要的特征:
①編碼器是數(shù)據(jù)相關(guān)的,這就意味著只能壓縮那些和訓(xùn)練數(shù)據(jù)相關(guān)的數(shù)據(jù)客给,比如用數(shù)字的圖像訓(xùn)練了然后有跑去壓縮人臉的圖片用押,這樣效果是很差的。
②編碼器無論是訓(xùn)練多少次靶剑,都是有損的蜻拨。
③自動(dòng)編碼器是從數(shù)據(jù)樣本中自動(dòng)學(xué)習(xí)的,這意味著很容易對(duì)指定類的輸入訓(xùn)練出一種特定的編碼器桩引,而不需要完成任何新工作
Tool
先介紹一下工具類:
import numpy as np
from keras.datasets import mnist
import matplotlib.pyplot as plt
def get_dataSets():
(x_train, _), (x_test, _) = mnist.load_data()
x_train = x_train.astype('float32')/255.
x_test = x_test.astype('float32')/255.
x_train = x_train.reshape(len(x_train), np.prod(x_train.shape[1:]))
x_test = x_test.reshape(len(x_test), np.prod(x_test.shape[1:]))
return x_train, x_test
pass
首先是引入數(shù)據(jù)缎讼,mnist.load_data()這個(gè)數(shù)據(jù)導(dǎo)入有點(diǎn)問題,上網(wǎng)百度了一下發(fā)現(xiàn)百分之90的博客都是有問題自己下的坑匠,所以不例外我也是自己下載了4個(gè)壓縮包放在了當(dāng)前目錄data下面血崭。
得到數(shù)據(jù)時(shí)候先進(jìn)行歸一化操作,然后reshape,因?yàn)楹竺嬉婚_始用到的是單層的編碼器夹纫,用的全連接神經(jīng)網(wǎng)絡(luò)咽瓷,所以應(yīng)該變成是二維的數(shù)據(jù)。
def show(orignal, x):
n = 10 # how many digits we will display
plt.figure(figsize=(20, 4))
for i in range(n):
ax = plt.subplot(2, n, i + 1)
plt.imshow(orignal[i].reshape(28, 28))
plt.gray()
ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)
ax = plt.subplot(2, n, i + 1 + n)
plt.imshow(x[i].reshape(28, 28))
plt.gray()
ax.get_xaxis().set_visible(False)
ax.get_yaxis().set_visible(False)
plt.show()
這個(gè)函數(shù)用于顯示舰讹,傳入的參數(shù)是原始圖像和預(yù)測(cè)的圖像忱详。好像都蠻直觀的。
雖然每一種編碼器都是用了一個(gè)類來封裝跺涤,但是每一個(gè)只有應(yīng)該create方法匈睁,返回一個(gè)已經(jīng)訓(xùn)練好的autoencode,所以下面所有的代碼都是在create里面桶错。
①單層自編碼器
單層自編碼器就是之前說的最簡(jiǎn)單的base autoencode航唆。使用Keras實(shí)現(xiàn)。
全部都封裝在一個(gè)類里面院刁,用類的create函數(shù)返回一個(gè)已經(jīng)訓(xùn)練好的autoencode糯钙。使用的數(shù)據(jù)集是mnist數(shù)據(jù)集。
def create(self):
x_train, x_test = get_dataSets()
encoding_dim = 32
input_img = Input(shape=(784,))
得到數(shù)據(jù)退腥,隱藏層神經(jīng)元的數(shù)量任岸,入口函數(shù)。
encoded = Dense(encoding_dim, activation='relu')(input_img)
decoded = Dense(784, activation='sigmoid')(encoded)
編碼層狡刘,最后那個(gè)小括號(hào)里面(input_img)就是輸入的內(nèi)容了享潜,解碼層就是從encoded輸入。Dense里面定義的是當(dāng)前層的神經(jīng)元嗅蔬,decoded層輸出了剑按,自然就是784 = 28 x 28個(gè)了。
autoencoder = Model(input=input_img, output=decoded)
encoder = Model(input=input_img, output=encoded)
encoded_input = Input(shape=(encoding_dim,))
decoder_layer = autoencoder.layers[-1]
decoder = Model(input=encoded_input, output=decoder_layer(encoded_input))
接下來的這幾個(gè)就是得到完整的模型澜术,使用Keras的Model API來構(gòu)建艺蝴。下面的幾個(gè)就是encoder得到編碼層,得到解碼層鸟废。都很直觀猜敢。
autoencoder.compile(optimizer='adadelta', loss='binary_crossentropy')
autoencoder.fit(x_train, x_train,
epochs=50,
batch_size=128,
shuffle=True,
validation_data=(x_test, x_test))
return autoencoder, encoder, decoder
之后就是模型的編譯,模型的訓(xùn)練了盒延。
最后的效果:
事實(shí)上還是可以的缩擂,達(dá)到了要求。
②多層自編碼器
其他差不多一樣兰英,就是多了幾層撇叁。
input_img = Input(shape=(784,))
encoded = Dense(128, activation='relu')(input_img)
encoded = Dense(64, activation='relu')(encoded)
encoded = Dense(32, activation='relu')(encoded)
decoded = Dense(64, activation='relu')(encoded)
decoded = Dense(128, activation='relu')(decoded)
decoded = Dense(784, activation='sigmoid')(decoded)
autoencoder = Model(input=input_img, output=decoded)
autoencoder.compile(optimizer='adadelta', loss='binary_crossentropy')
autoencoder.fit(x_train, x_train,
epochs=1,
batch_size=128,
shuffle=True,
validation_data=(x_test, x_test))
中間那幾層得到編碼層的那些去掉了供鸠。最后看看效果畦贸。
損失函數(shù)這些就不放了,因?yàn)橛?xùn)練的話是很容易給出的。
③稀疏自編碼器
稀疏自編碼器一般用來學(xué)習(xí)特征薄坏,以便用于像分類這樣的任務(wù)趋厉。稀疏正則化的自編碼器必須反映訓(xùn)練數(shù)據(jù)集的獨(dú)特統(tǒng)計(jì)特征,而不是簡(jiǎn)單地充當(dāng)恒等函數(shù)胶坠。以這種方式訓(xùn)練君账,執(zhí)行附帶稀疏懲罰的復(fù)制任務(wù)可以得到能學(xué)習(xí)有用特征的模型。使用L1范式懲罰項(xiàng)就好了沈善,但是效果不太好乡数,就不放結(jié)果了。
encoded = Dense(encoding_dim, activation='relu',
activity_regularizer=regularizers.l1(10e-5))(input_img)
decoded = Dense(784, activation='sigmoid')(encoded)
④卷積自編碼器
其實(shí)就是卷積神經(jīng)網(wǎng)絡(luò)做編碼而已闻牡。
x_train = np.reshape(x_train, (len(x_train), 28, 28, 1))
x_test = np.reshape(x_test, (len(x_test),28, 28, 1))
數(shù)據(jù)格式要正確只盹,因?yàn)槭蔷矸e處理了宰啦,要按照(個(gè)數(shù),長(zhǎng),寬园细,顏色)排列。
input_img = Input(shape=(28, 28, 1))
x = Convolution2D(16, (3, 3), activation='relu', border_mode='same')(input_img)
x = MaxPooling2D((2, 2), border_mode='same')(x)
x = Convolution2D(8, (3, 3), activation='relu', border_mode='same')(x)
x = MaxPooling2D((2, 2), border_mode='same')(x)
x = Convolution2D(8, (3, 3), activation='relu', border_mode='same')(x)
encoded = MaxPooling2D((2, 2), border_mode='same')(x)
x = Convolution2D(8, (3, 3), activation='relu', border_mode='same')(encoded)
x = UpSampling2D((2, 2))(x)
x = Convolution2D(8, (3, 3), activation='relu', border_mode='same')(x)
x = UpSampling2D((2, 2))(x)
x = Convolution2D(16, 3, 3, activation='relu')(x)
x = UpSampling2D((2, 2))(x)
decoded = Convolution2D(1, (3, 3), activation='sigmoid', border_mode='same')(x)
encode和decode是兩個(gè)對(duì)應(yīng)的東西接癌,反著來而已本讥,由于是一個(gè)圖片一個(gè)圖片的進(jìn)來,所以輸出就是一個(gè)严沥。
autoencoder = Model(input_img, decoded)
autoencoder.compile(optimizer='adadelta', loss='binary_crossentropy')
autoencoder.fit(x_train, x_train, epochs=20, batch_size=256,
shuffle=True,
validation_data=(x_test, x_test))
return autoencoder
最后就是常規(guī)操作了猜极。
這個(gè)訓(xùn)練時(shí)間有點(diǎn)長(zhǎng),電腦不行沒辦法消玄。效果:
最后損失到了0.10魔吐,還是很好的。
⑤去噪編碼器
這個(gè)是在卷積神經(jīng)網(wǎng)絡(luò)的基礎(chǔ)上做的莱找。用帶噪音的數(shù)據(jù)來訓(xùn)練酬姆。
def get_nosing(noise_factor):
(x_train, _), (x_test, _) = mnist.load_data()
x_train = x_train.astype('float32') / 255.
x_test = x_test.astype('float32') / 255.
x_train = np.reshape(x_train, (len(x_train), 28, 28, 1))
x_test = np.reshape(x_test, (len(x_test), 28, 28, 1))
noise_factor = noise_factor
x_train_noisy = x_train + noise_factor * np.random.normal(loc=0.0, scale=1.0, size=x_train.shape)
x_test_noisy = x_test + noise_factor * np.random.normal(loc=0.0, scale=1.0, size=x_test.shape)
x_train_noisy = np.clip(x_train_noisy, 0., 1.)
x_test_noisy = np.clip(x_test_noisy, 0., 1.)
return x_train, x_train_noisy, x_test, x_test_noisy
pass
時(shí)間就是使用高斯分布來得到了。
x_train, x_train_noisy, x_test, x_test_noisy = get_nosing(0.5)
input_img = Input(shape=(28, 28, 1))
x = Convolution2D(32, 3, 3, activation='relu', border_mode='same')(input_img)
x = MaxPooling2D((2, 2), border_mode='same')(x)
x = Convolution2D(32, 3, 3, activation='relu', border_mode='same')(x)
encoded = MaxPooling2D((2, 2), border_mode='same')(x)
x = Convolution2D(32, 3, 3, activation='relu', border_mode='same')(encoded)
x = UpSampling2D((2, 2))(x)
x = Convolution2D(32, 3, 3, activation='relu', border_mode='same')(x)
x = UpSampling2D((2, 2))(x)
decoded = Convolution2D(1, 3, 3, activation='sigmoid', border_mode='same')(x)
autoencoder = Model(input_img, decoded)
autoencoder.compile(optimizer='adadelta', loss='binary_crossentropy')
autoencoder.fit(x_train_noisy, x_train, shuffle=True,epochs=1, batch_size=128,
validation_data=(x_test_noisy, x_test))
return autoencoder
這里的網(wǎng)絡(luò)有些許不同奥溺,是因?yàn)楸阌谟?jì)算罷了辞色。過程是一樣,扔的數(shù)據(jù)不同而已浮定。效果:PCA
PCA就不用mnist數(shù)據(jù)集了相满,畢竟784維降到2維不是很好看,使用iris數(shù)據(jù)集桦卒。
獲取數(shù)據(jù)那些就不寫了立美,畢竟蠻簡(jiǎn)單的。
class pca(object):
def fit(self, data_features, y):
data_mean = np.mean(data_features, axis=0)
data_features -= data_mean
cov = np.dot(data_features.T, data_features)
eig_vals, eig_vecs = np.linalg.eig(cov)
eig_pairs = [(np.abs(eig_vals[i]), eig_vecs[:, i]) for i in range(len(eig_vals))]
a = np.matrix(eig_pairs[0][1]).T
b = np.matrix(eig_pairs[1][1]).T
u = np.hstack((a, b))
data_new = np.dot(data_features, u)
return data_new
def show(self, data_new):
plt.scatter(data_new[:, 0].tolist(), data_new[:, 1].tolist(), c='red')
plt.show()
pass
步驟其實(shí)很簡(jiǎn)單方灾,均值化求特征值排序組合向量基對(duì)原數(shù)據(jù)做乘法建蹄。
最后降維效果碌更。
最后附上GitHub代碼:https://github.com/GreenArrow2017/MachineLearning/tree/master/MachineLearning/Autoencode