Some methods of deep learning and dimensionality reduction

Deep Learning

上一篇主要是講了全連接神經網絡,這裏主要講的就是深度學習網絡的一些設計以及一些權值的設置。神經網絡可以根據模型的層數,模型的複雜度和神經元的多少大致可以分成兩類: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

10624272-2990e2de61541f0e.png

雖然說簡單的神經網絡訓練時間短,但是目前常用的還是deep,因爲多層的神經網絡有利於提取圖像或者是語音的一些特徵,取TensorFlow的minist數據集爲例,一個手寫字體的識別就是需要從圖像中提取特徵:
10624272-dcf594cdeff522a4.png

比如想要識別數字1和5,可以把數字的特徵分開,每一個不同的神經元識別一部分,然後綜合結果。這些都是像素點,所以每經過一層神經元就會從圖像中提取特徵。再對圖片進行匹配和識別。層數越多,就能提取更加複雜的特徵,解決一些sophisticated的問題能力也就越強。

①The challenge of deep learning

深度學習的挑戰主要有這麼幾個問題:
1.difficult structural decisions。對於網絡結構的設計很難把握,但是這是可以使用一些相關領域的知識來做選擇的。比如,做圖像的識別,我們可以使用convolutional Network,因爲卷積神經網絡對於兩個相鄰的像素聯繫會很大,也就是說,對於一個像素,如果是用卷積神經網絡,那麼只會考察它周圍的像素點的特徵,而離他很遠的像素是不會處理。對於語音識別,LSTM,RNN這些神經網絡用的就比較多,因爲他們可以保留之前的信息。
2.high model complexity。如果網絡的層數很多,很可能會出現過擬合的情況,如果是數據量非常大的話,這種情況可以忽略。但如果數據量不大,那麼有可能會出現過擬合。常用的解決過擬合的方法:drop out。訓練神經網絡的時候不全部訓練,只是訓練一部分,比如訓練百分之70.denoising。這種方法後面會詳解,主要就是假如一下雜訊一起訓練。
3.hard optimization problem。對於神經網絡的訓練也有很多需要注意的,因爲神經網絡經過了多層的非線性轉換,不再是一個山谷狀了,可能是凹凹凸凸的,這樣就導致有可能你只是到達了某一個山谷而不是全局的最優。這個時候我們就要選擇一個比較好的初始值了,如果我們選擇的初始值恰好就是在全局最優的旁邊,那就穩了。有一種方法就是pre-train。
4.huge computational complexity。層數這麼多,計算機複雜度看到很大。這裏已經可以使用硬件解決了,GPU的計算得到。

10624272-82e99a6dfae09582.png

比較關鍵的其實就是regularization和initialization。

②initialization

權值的初始值很重要,好的權值初始化是可以避免局部最優解的出現。比較常用的方法就是pre-train。先用pre-train訓練得到一層權值,這些權值就作爲初始值,之後在backprob訓練。

10624272-8ef4b5ce515c2b99.png

一層一層的來,第一層的出來了第二層的依次決定。
首先要介紹一個概念是Autoencoder,自編碼器。

Autoencoder

什麼是權重?在神經網絡的模型裏面權重代表的就是特徵轉換(feature transform)。從編碼方面來說,權重也可以看成是一種編碼方式,把一個數據編碼成另一種數據。神經網絡是一層一層的進行的,所以如果是一個好的權重的話,是應該可以提取出數據的特徵的,也就是information-preserving encoding,一種可以保留有用信息的編碼。第i層提取了特徵,傳到了i+1層,i+1層在i層的基礎上再提取一些更加複雜的特徵,傳到i+2層。最後每一次都可以提取出特徵來,這樣就可以最大限度的把數據的特徵保留下來。上面講到的手寫數字識別是可以把一個數字劃分成很多個筆畫,反過來,也可以由特徵轉換回數字。這種可逆的轉換叫做information-preserving,通過神經網絡轉換的特徵最後是可以轉換回原來的輸入,這也正是pre-train要做到的。所以pre-train要滿足的特徵就是要求information-preserving。因爲拿到了特徵又可以用得到的特徵得到原輸入,證明得到的特徵是可以代表整個數據的,沒有遺漏。

10624272-552544733aa7014d.png

想要得到這樣的效果,只需要建立一個三層的神經網絡即可。
10624272-00de76fd05e374d1.png

這個神經網絡經過權重得到的結果就是encode之後的數據,也就是通過feature transform提取特徵的過程,經過的就是解碼過程,要求輸出層輸出的數據要和原數據差不多接近。整個網絡是的結構,重點就在重構,輸入層到隱含層是特徵轉換,隱含層到輸出層是重構。這種結構我們叫autoencode,對應編碼和解碼,整個過程就是在逼近indentity function(恆等函數)
10624272-92aef192adf41550.png

但是這樣好像多此一舉,既然輸出都是差不多的爲什麼要多此一舉?對於監督式學習,隱藏層其實就是特徵轉換,乘上一些權值轉換成對應特徵的值。就好像手寫數字識別得到每一個數字的特徵,包含了一些提取出有用的特徵,可以得到一些數據具有代表性的信息。對於非監督的學習,也可以使用autoencode來做density estimation,密度估計,如果密度較大,說明可以提取到的特徵很多,否則就是密度很小。也可以做outlier detection,異常值的檢測,也就是孤立點,噪音。找出哪些是典型的資料,哪些不是。
10624272-8e990181d8651edc.png

對於編碼器,我們更加關心的其實是中間的隱藏層,也就是特徵轉換權重自然對應的error function:
10624272-e72f97f927c52210.png

三層的autoencode也叫basic autoencode 因爲它是最簡單的了。通常限定方便數字的編碼,數據集可以表示爲所以可以看成是一個非監督式的學習,一個重要的限制條件是解碼權重等於編碼權重,這起到了regularization的作用。
10624272-3b8b1b86f7700a02.png

深度學習中,basic autoencoder的過程也就對應着pre-training的過程,使用這種方法,對無label的原始數據進行編碼和解碼,得到的編碼權重就可以作爲pre-trained的比較不錯的初始化權重,也就是作爲深度學習中層與層之間的初始化權重。
10624272-24901b94e788bcbe.png

所以,pre-train的訓練過程:首先,autoencoder會對深度學習網絡第一層(即原始輸入)進行編碼和解碼,得到編碼權重,作爲網絡第一層到第二層的的初始化權重;然後再對網絡第二層進行編碼和解碼,得到編碼權重W(1)ij,作爲網絡第二層到第三層的初始化權重,以此類推,直到深度學習網絡中所有層與層之間都得到初始化權重。值得注意的是,對於l-1層的網絡,autoencoder中的d˘應與下一層(即l層)的神經元個數相同。
10624272-98f03ef9b3edb42a.png

這裏介紹的只是一種最簡單的,還有很多的編碼器,稀疏編碼器,去燥編碼器等等。

②regularization

控制模型的複雜度就是使用正則化了。

10624272-8b02b555d09e665a.png

神經網絡每一層都有很多的權重和神經元,這就導致了模型的複雜度會很大,regularization是必要的。
我們之前介紹過一些方法:
1.structural decisions。架構可以設計的簡單點,但是深度學習神經網絡的結構是不可能簡單的,這輩子的不可能。只能是相對來說用dropout減輕一些壓力。2.weight decay or weight elimination regularizers。可以使用正則化來減小權值。
3.early stop。不要訓練的這麼準確,差不多差不多就夠了。

10624272-1366f4241cbb243e.png

下面是一種新的regularization的方式:

Denoising Autoencoder

回顧一下之前的overfit的原因:

10624272-a2c2329f9fb36965.png

和樣本數量,噪聲大小都有關係,如果數據量是不變的,那麼noise的影響就會非常大。那麼這個時候實現regularization的一個方法就是消除noise的影響。
有一種方法是對數據clean操作,但是這樣費時費力。有一種更加牛逼的做法,就是在數據中添加一些noise再訓練。
10624272-f202c961a88cb159.png

這種做法的初衷是想建立一個比較健壯,容錯性高的autoencode。在一個已經訓練好的autoencode中,g(x) ≈ x的,對於已經容錯性很高,比較健壯的autoencode,得到的輸出是和x很接近的。比如手寫數字識別,一個很規範很正的6輸進去可以得到一個6,但是如果原始的圖片是歪歪的6,然後還是可以得到6的話那麼這個自編碼器就是一個健壯的自編碼器了。比較不是每一個人寫6都是寫的正正,這就使得這個自編碼器的抗噪能力很強。
所以,最後我們要訓練的樣本集
其中
所以使用這種autoencode的目的就是使得加入了有噪音的x都可以得到純淨的x。不僅能從純淨的樣本中編解碼得到純淨的樣本,還能從混入noise的樣本中編解碼得到純淨的樣本。這樣得到的權重初始值更好,因爲它具有更好的抗噪聲能力,即健壯性好。實際應用中,denoising autoencoder非常有用,在訓練過程中,輸入混入人工noise,輸出純淨信號,讓模型本身具有抗噪聲的效果,讓模型健壯性更強,最關鍵的是起到了regularization的作用。這也是之前說的去燥自編碼器。
10624272-b93bd7e40cfb141e.png

linear autoencode

剛剛介紹的自編碼器是非線性的,因爲中間的tanh(x)函數就是非線性的。常見的autoencode常用於在深度學習中,這裏要介紹的是線性的自編碼器,linear autoencode。對於一個線性的自編碼器,只需要不包括非線性轉換就好了。
所以,就變成
這裏有三個限制條件:
①移除bias項,保持維度一致。
②編碼權重與解碼權重一致:

由於兩個權重是一樣的,W的維度是dxd',x的維度是dx1,所以整個公式可以變爲:
但是要求
所以error function
對於那個協方差矩陣首先可以進行特徵值分解其中Γ是一個對角矩陣,V矩陣滿足
而I矩陣有一個很重要的性質,由於W是dxd'的,d < d’。有I的非零元素的數量是不大於d'的。

證明

對於一個矩陣W(dxd',d < d'),那麼有Rank(W) <= d'。這個結論直接給出,不用證明。假設有兩個矩陣A,B,C = AB,那麼AX = C的解就是B,也就是唯一解,也就是說Rank(A, C) = Rank(A )。證明:對於Rank(A,C)和Rank(A)無非就是兩種情況,=和>。<是沒有的,Rank(A)是不可能大於Rank(A,C)的。如果是Rank(A) < Rank(A,C),那麼這個增廣矩陣(A,C)變換成初等矩陣之後,最後一行就會出現的情況,0 != a,自然就是無解了。所以證明了上訴情況一定是有Rank(A) = Rank(A,C)
而由於R(C) <= R(A,C),所以R(C) <= R(A),同理,也可以證明得R(C) <= R(B),而在這裏所以,是不大於d'的,因爲一個矩陣的秩是不可以大於它最小的維度的。綜上所訴,更重要的是,秩就是這個矩陣特徵值的數量,而I矩陣的斜對角線就是WW^T矩陣的特徵值,所以纔有I的非零元素的數量是不大於d'的。

回到正文。那麼就可以推出

10624272-704ef0ac0a56b4ba.png

這樣就把表達式轉換成了一個求解V和Γ的方程:
提取一下公因式

所以第一個要解決的就是
這樣自然是越接近越好了,所以Γ最好就是對角線上有d'個1。
10624272-0f3430e0f5fb136a.png

到這裏Γ的最優解已經知道了
10624272-7ee34d18e6ad9a3c.png

最小化問題有點複雜,轉換一下:
10624272-1f06e503a63d50fd.png

當d' = 1的時候,那就只有V的第一行是有用,所以
10624272-c3e910903337aa07.png

條件是在做特徵分解的時候得到的,這裏也要繼承下來。
有條件的自然是拉格朗日乘子法了:
求導得0
仔細看一下,這個λ其實就是的特徵值

既然d' = 1是這樣了,那麼當d' > 1的時候,就是依次把d'個特徵值求出來就好了,所以這個就是linear autoencoder的過程了。
10624272-968ff6a5337f1f51.png

過程和PCA很相似,大致都是差不多的,但是PCA還需要減去一下平均值,也就是對x輸入數據做去均值化的處理。
10624272-8ac19117871c9116.png

10624272-68ef5b4a8eabd292.png

linear autoencode和PCA不完全一樣,至少出發點不是一樣的,linear autoencode是用來pre-train而被髮明的,雖然機器學習不太需要,但是既然引出了非線性的autoencode那順便把linear也探討一下。但是,linear autoencode在公式的推導上是基本一致的,上面的推導其實也是可以做爲PCA的推導。

Dimensionality Reduction——Principal Component Analysis

既然講到了降維,那順便把PCA也講了,Deep Learning的部分已經講完。

①數據降維

通常我們得到的數據有很多的維度,比如一個商店,可以有名字,年齡,出生日期,性別,成交量等等。而年齡和性別其實是表示一個東西,兩個表示完全是多餘的。當然我們也可以直接不做處理就使用這些數據來做機器學習。但是這樣會耗費巨大的資源。在這種情況下自然就需要數據降維了。降維意味着會有數據丟失,丟失是一定會有的,所以只能保證丟失了多少而已。
舉個例子,假如某學籍數據有兩列M和F,其中M列的取值是如何此學生爲男性取值1,爲女性取值0;而F列是學生爲女性取值1,男性取值0。此時如果我們統計全部學籍數據,會發現對於任何一條記錄來說,當M爲1時F必定爲0,反之當M爲0時F必定爲1。在這種情況下,我們將M或F去掉實際上沒有任何信息的損失,因爲只要保留一列就可以完全還原另一列。

②向量和基

先看一個向量的運算:
這種乘積方式並不能看出有什麼意義,換一種表達方式a爲A和B的夾角。再進一步|B| = 1,那麼就可以看出來,當向量B的模爲1,則A與B的內積值等於A向B所在直線投影的矢量長度。這個結論很重要。
假設有一個點(3,2),那麼在座標系中的表示:

10624272-b8e64036957e7c44.png

向量(3,2)就從原點發射到(3,2)這個點的有向線段。在x軸上的投影值是3,在y軸上的投影值是2。也就是說我們其實隱式引入了一個定義:以x軸和y軸上正方向長度爲1的向量爲標準。所以向量(x,y)實際上是一種線性組合:
而(1,0)和(0,1)就是這個空間裏面的一組基。
10624272-7c86ab21a2556dbf.png

所以,可以用另外一種方法來描述,確定一組基,然後給出在基所在的各個直線上的投影值,就可以了。不過一般直接忽略第一步,比較可靠維度就知道了。但是事實上,基並不是一個固定的東西,任何一個線性無關的向量都可以成爲一組基。例如,(1,1)和(-1,1)也可以成爲一組基。一般來說,我們希望基的模是1,因爲從內積的意義可以看到,如果基的模是1,那麼就可以方便的用向量點乘基而直接獲得其在新基上的座標了!實際上,對應任何一個向量我們總可以找到其同方向上模爲1的向量,只要讓兩個分量分別除以模就好了。

③基變換的矩陣表示

還是拿上面的(3,2)做爲例子,比如我們現在有兩個基
那麼把(3,2)變爲新的基上的座標,則有

所以,一般的,如果我們有M個N維向量,想將其變換爲由R個N維向量表示的新空間中,那麼首先將R個基按行組成矩陣A,然後將向量按列組成矩陣B,那麼兩矩陣的乘積AB就是變換結果,其中AB的第m列爲A中第m列變換後的結果。

10624272-aec419e766ae9e9c.png

這裏是R是要變換的維度,R是可以小於N的。基於以上的理論,兩個矩陣相乘的意義是將右邊矩陣中的每一列列向量變換到左邊矩陣中每一行行向量爲基所表示的空間中去

④協方差

上面討論了基已經座標基於基的變換,如果基的數量是小於數據維度的就可以達到降維的效果了。但是,問題來了,基是無限多個的,如何選擇基是一個很大的問題。
舉一個例子:
爲了處理方便,首先先減去每行的均值,這樣做的原因後面再說。減去之後就是這樣:

問題來了,這5個數據都是2維度的,現在想降到一維,如果我們必須使用一維來表示這些數據,又希望儘量保留原始的信息,你要如何選擇?這個問題實際上是要在二維平面中選擇一個方向,將所有數據都投影到這個方向所在直線上,用投影值表示原始記錄。這是一個實際的二維降到一維的問題。
一種直觀的看法是:希望投影后的投影值儘可能分散。同一個維度數據之間不"擠"在一起,因爲擠在一起表達不了數據本身了。而表徵數據之間離散程度,就考慮到了方差。具體做法就是 想辦法讓高維數據左乘一個矩陣,得到降維後的數據,降維後的數據的方差最大化。在線性代數中學過,一個矩陣可以看成是很多個列向量,每一個向量代表着一個物體的數據。要表達這個矩陣真的需要這麼多數據嗎,顯然不一定,求解一個矩陣的秩R,看看R 的值,在絕大多數情況下,矩陣都不是滿秩的,說明矩陣中的元素表達客觀世界中的物體有一些是多餘的。
既然是求離散程度,那麼就是方差了,對於每一個字段的方差如果已經去除了均值那就可以直接轉換
對於上面二維降成一維的問題來說,找到那個使得方差最大的方向就可以了。不過對於更高維,還有一個問題需要解決。考慮三維降到二維問題。與之前相同,首先我們希望找到一個方向使得投影后方差最大,這樣就完成了第一個方向的選擇,繼而我們選擇第二個投影方向。但是如果第二次還是堅持選擇方差最大的方向,那麼肯定還是會和第一個方向相同的,這樣表達的信息很有可能重合,所以應該要加上一些限制。從直觀上說,讓兩個字段儘可能表示更多的原始信息,我們是不希望它們之間存在(線性)相關性的,因爲相關性意味着兩個字段不是完全獨立,必然存在重複表示的信息。
事實上兩個字段的相關性是可以用協方差來表示。協方差爲0的時候,兩個字段是互相獨立的。協方差爲0所以只能在一個基的正交方向選擇第二個基。將一組N維向量降爲K維(K大於0,小於N),其目標是選擇K個單位(模爲1)正交基,使得原始數據變換到這組基上後,各字段兩兩間協方差爲0,而字段的方差則儘可能大(在正交的約束下,取最大的K個方差)。

⑤協方差矩陣的優化

協方差矩陣的對角線代表了原來樣本在各個維度上的方差,其他元素代表了各個維度之間的相關關係。所以我們需要把協方差對角化,因爲我們需要處理的就是維度中的關係,而不是維度之間的。設Y=PX,則Y爲X對P做基變換後的數據。設Y的協方差矩陣爲D,則有:

10624272-819fc8e3dd9dfcc5.png

所以現在明白了,我們要找的P就是使得可以對角化C的矩陣,最後按照得到的對角矩陣從大到小排列,取P的前k行作爲基進行轉換即可。這其實就是求解特徵值的過程。

總結:一開始對數據進行降維操作,我們想到的就是要使得數據投影之後方差最大,那麼就需要尋找一組基使達成這個條件。但是發現如果只是找最大的方差是會有重複,比如第一個發現的基是最大的,那麼第二個方向肯定也差不多是這個方向,這樣信息就有重複,所以又相當數據維度之間是應該有非相關性的,於是就使用到了協方差來代表,但是我們需要的是數據裏的非相關性最大化,數據間的最大化方差最大已經處理了,所以這個時候協方差只需要關注對角線,自然就是對角化了。又發現對角化其實就是特徵分解的一個過程,最後求出結果。
另一個方面,W我們可以看做是基的組合,WX就是降維之後的數據就是要求了降維之後的數據要和原來的數據相差不遠,爲什麼不是X-WX呢?首先這兩個東西不是同緯度的,不可能計算,其次乘上一個轉置其實就是轉換回來的結果了。如果壓縮之後轉換回來的結果和原來差不多,那不就證明了這個降維是OK的嗎?所以這就和Autoencode的思想一樣了,所以上面linear autoencode的過程也可以看做就是PCA的公式化推導。

⑤PCA算法過程:

①將原始數據按列組成n行m列矩陣X
②均值化操作。
③求協方差
④求特徵值特徵向量
⑤排列取前k大的特徵值對應的特徵向量
⑥降維操作

Coding

Autoencode

編碼器有幾個很重要的特徵:
①編碼器是數據相關的,這就意味着只能壓縮那些和訓練數據相關的數據,比如用數字的圖像訓練了然後有跑去壓縮人臉的圖片,這樣效果是很差的。
②編碼器無論是訓練多少次,都是有損的。
③自動編碼器是從數據樣本中自動學習的,這意味着很容易對指定類的輸入訓練出一種特定的編碼器,而不需要完成任何新工作

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

首先是引入數據,mnist.load_data()這個數據導入有點問題,上網百度了一下發現百分之90的博客都是有問題自己下的,所以不例外我也是自己下載了4個壓縮包放在了當前目錄data下面。
得到數據時候先進行歸一化操作,然後reshape,因爲後面一開始用到的是單層的編碼器,用的全連接神經網絡,所以應該變成是二維的數據。

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()

這個函數用於顯示,傳入的參數是原始圖像和預測的圖像。好像都蠻直觀的。
雖然每一種編碼器都是用了一個類來封裝,但是每一個只有應該create方法,返回一個已經訓練好的autoencode,所以下面所有的代碼都是在create裏面。

①單層自編碼器

單層自編碼器就是之前說的最簡單的base autoencode。使用Keras實現。
全部都封裝在一個類裏面,用類的create函數返回一個已經訓練好的autoencode。使用的數據集是mnist數據集。

    def create(self):
        x_train, x_test = get_dataSets()
        encoding_dim = 32
        input_img = Input(shape=(784,))

得到數據,隱藏層神經元的數量,入口函數。

        encoded = Dense(encoding_dim, activation='relu')(input_img)
        decoded = Dense(784, activation='sigmoid')(encoded)

編碼層,最後那個小括號裏面(input_img)就是輸入的內容了,解碼層就是從encoded輸入。Dense裏面定義的是當前層的神經元,decoded層輸出了,自然就是784 = 28 x 28個了。

        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))

接下來的這幾個就是得到完整的模型,使用Keras的Model API來構建。下面的幾個就是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

之後就是模型的編譯,模型的訓練了。
最後的效果:


10624272-d3eb7ea4dddc6ae4.png

事實上還是可以的,達到了要求。

②多層自編碼器

其他差不多一樣,就是多了幾層。

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))

中間那幾層得到編碼層的那些去掉了。最後看看效果。


10624272-43e31a6a462ce4fc.png

損失函數這些就不放了,因爲訓練的話是很容易給出的。

③稀疏自編碼器

稀疏自編碼器一般用來學習特徵,以便用於像分類這樣的任務。稀疏正則化的自編碼器必須反映訓練數據集的獨特統計特徵,而不是簡單地充當恆等函數。以這種方式訓練,執行附帶稀疏懲罰的複製任務可以得到能學習有用特徵的模型。使用L1範式懲罰項就好了,但是效果不太好,就不放結果了。

 encoded = Dense(encoding_dim, activation='relu',
                        activity_regularizer=regularizers.l1(10e-5))(input_img)
        decoded = Dense(784, activation='sigmoid')(encoded)

④卷積自編碼器

其實就是卷積神經網絡做編碼而已。

 x_train = np.reshape(x_train, (len(x_train), 28, 28, 1))
 x_test = np.reshape(x_test, (len(x_test),28, 28, 1))

數據格式要正確,因爲是卷積處理了,要按照(個數,長,寬,顏色)排列。

        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是兩個對應的東西,反着來而已,由於是一個圖片一個圖片的進來,所以輸出就是一個。

        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

最後就是常規操作了。
這個訓練時間有點長,電腦不行沒辦法。效果:


10624272-6470af4d4af1f080.png

10624272-6d981e2f856b97f1.png

最後損失到了0.10,還是很好的。

⑤去噪編碼器

這個是在卷積神經網絡的基礎上做的。用帶噪音的數據來訓練。

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

時間就是使用高斯分佈來得到了。

        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

這裏的網絡有些許不同,是因爲便於計算罷了。過程是一樣,扔的數據不同而已。效果:
10624272-5257d25aa3abf963.png

10624272-5293fdebcdb45c6c.png

PCA

PCA就不用mnist數據集了,畢竟784維降到2維不是很好看,使用iris數據集。
獲取數據那些就不寫了,畢竟蠻簡單的。

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

步驟其實很簡單,均值化求特徵值排序組合向量基對原數據做乘法。


10624272-bacd931b1958c96c.png

最後降維效果。

最後附上GitHub代碼:https://github.com/GreenArrow2017/MachineLearning/tree/master/MachineLearning/Autoencode

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