1. 程式人生 > >稀疏自編碼器及事實上現——怎樣搞基

稀疏自編碼器及事實上現——怎樣搞基

disk initial 圖片 app .com 沒有 back ext 稀疏

自編碼器是什麽?

自編碼器本身就是一種BP神經網絡。

它是一種無監督學習算法

我們都知道神經網絡能夠從隨意精度逼近隨意函數,這裏我們讓神經網絡目標值技術分享等於輸出值x,也就是模擬一個恒等函數

技術分享

太無聊了,是嗎?輸入等於輸出,這網絡有什麽意義?可是。當我們把自編碼神經網絡增加某些限制,事情就發生了變化。

如圖1所看到的,這就是一個主要的自編碼神經網絡。能夠看到隱含層節點數量要少於輸入層節點數量。

技術分享

圖1

舉個樣例,假設我們輸入一張10*10的圖像,這樣就有100個像素,所以輸入層和輸出層的節點數量就是100。

而我們取隱藏層節點數量為25。

註意。這樣就會迫使隱藏層節點學習得到輸入數據的壓縮表示方法。逼得隱藏層要用25維數據重構出100維的數據。這樣也就完畢了學習過程。

這和我們學習的過程非常像,如果一共同擁有100個考點,可是僅僅同意你用25個知識點概括全部這些考點,這就是學習的過程。

稀疏自編碼器又是什麽?

更一般的,假設隱藏層節點數量非常大,甚至比輸入層節點數量還要多時。我們仍然能夠使用自編碼算法,可是這時須要增加稀疏性限制。這就是稀疏自編碼器。

什麽是稀疏性限制?

簡單說就是要保證隱藏神經元在大多數情況下是被抑制的狀態。詳細表現就是sigmoid函數的輸出大多數狀態是0,tanh函數的輸出大多數狀態是-1。這樣有什麽優點?這樣可以迫使隱藏神經元發揮最大的潛力,在非常不利的條件下學習到真正的特征。

怎麽衡量某個隱藏神經元的激活度?

取平均就好了,如果技術分享表示在給定輸入x的情況下,隱藏神經元j的激活度,那麽自然就有平均激活度

技術分享

稀疏性懲處項——相對熵

為了保證這個稀疏度小到我們希望的那麽多。比方說技術分享,即

技術分享

我們須要在優化目標函數中增加一個額外的懲處因子。這個罰因子基於相對熵(KLdivergence):

技術分享

因此這個罰因子會有例如以下性質,當技術分享時(這裏取稀疏性參數為0.2),技術分享等於0,而兩者差異越來越大時,相對熵會高速趨近於無窮大,如圖2所看到的:

技術分享

圖2

稀疏自編碼器訓練方式與BP神經網絡相對照

稀疏自編碼神經網絡的代價函數是BP神經網絡的代價函數加上一個稀疏性懲處項:

技術分享

對應地,殘差叠代公式也要進行修正

技術分享

實現一個稀疏自編碼器


數據概覽

採用的是Andrew著名的UFLDL給出的例子。當中數據文件叫做IMAGES,這是一個512*512*10的三維數組,裏面存了10張圖片,每張都是262144像素。運行

<span style="font-size:14px;">loadIMAGES;
imagesc(IMAGES(:,:,6))
colormapgray;</span>


能夠看看第6張圖的樣子,如圖3所看到的。是一張關於森林和雪山的圖像。

技術分享

圖3


數據採樣

因為數據的圖片挺大,我們總不能一上來搞一個每層都2萬多節點的神經網絡訓練吧。我們先採樣,這裏從10張圖片裏面隨機採樣10000個小patch。每一個小patch是一個8*8像素小碎片。我們定義訓練集是64*10000的矩陣。每一列就是把剛剛的小patch拉成列向量的結果。

這裏代碼例如以下

<span style="font-size:14px;">loadIMAGES;    % load images from disk
patchsize= 8;  % we'll use 8x8 patches
%numpatches = 10;
numpatches= 10000;
%Initialize patches with zeros.  Your codewill fill in this matrix--one
%column per patch, 10000 columns.
patches= zeros(patchsize*patchsize, numpatches);
tic
image_size=size(IMAGES);
i=randi(image_size(1)-patchsize+1,1,numpatches);
j=randi(image_size(2)-patchsize+1,1,numpatches);
k=randi(image_size(3),1,numpatches);
fornum=1:numpatches
patches(:,num)=reshape(IMAGES(i(num):i(num)+patchsize-1,j(num):j(num)+patchsize-1,k(num)),1,[]);
end
toc</span>

這裏randi函數。randi(iMax。m,n)在閉區間[1,iMax]生成m*n型隨機矩陣。而reshape函數的作用是把每一個小patch拉成一個列向量。

前200個patch的樣子如圖4所看到的:

技術分享

圖4

sparseAutoencoderCost.m

這部分代碼是最核心也是最重要的,正如前面所說。如今優化目標函數有了3個部分:均方差項、權重衰減項、稀疏懲處項。

這裏程序須要一部分一部分地調試,否則很easy得到看似正確但實際效果沒有正確代碼好的錯誤結果。這裏附上我最新改動版本號的代碼,去掉了全部顯式for循環,使用矢量化編程,簡潔了代碼,增強執行效率,但也減弱了可讀性。

<span style="font-size:14px;">numpatches=size(patches,2);
a2=sigmoid(W1*patches+repmat(b1,1,numpatches));
a3=sigmoid(W2*a2+repmat(b2,1,numpatches));
Rho=sum(a2,2)/numpatches;
Penalty=-sparsityParam./Rho+(1-sparsityParam)./(1-Rho);
Delta3=(a3-patches).*a3.*(1-a3);
Delta2=(W2'*Delta3+beta*repmat(Penalty,1,numpatches)).*a2.*(1-a2);
cost1=sumsqr(a3-patches)/numpatches/2;
cost2=(sumsqr(W1)+sumsqr(W2))*lambda/2;
cost3=beta*sum(sparsityParam*log(sparsityParam./Rho)+(1-sparsityParam)*log((1-sparsityParam)./(1-Rho)));
cost=cost1+cost2+cost3;
W2grad=Delta3*a2'/numpatches+lambda*W2;
b2grad=sum(Delta3,2)/numpatches;
W1grad=Delta2*patches'/numpatches+lambda*W1;
b1grad=sum(Delta2,2)/numpatches;</span>

這裏repmat的反復使用是用來復制矩陣的,一定要不遺余力去掉這部分代碼中全部的顯式for循環。否則運行起來時間會非常長。

梯度校驗

梯度校驗是代碼調試的大殺器,這一部分我用到了for循環,效率確實很低了,所以調試的時候要把校驗參數做些調整。令隱藏節點數量為2。採樣數量為100,這樣就能大大加快校驗速度。

否則要等相當久的時間。

<span style="font-size:14px;">EPSILON=0.0001;
thetaspslion=zeros(size(theta));
fori=1:size(theta)
thetaspslion(i)=EPSILON;
numgrad(i)=(J(theta+thetaspslion)-J(theta-thetaspslion))/2/EPSILON;
thetaspslion(i)=0;
end</span>

註意:最後執行時一定要關掉梯度校驗,不然就要卡死機了。。

這個梯度校驗對於目標函數的3部分的調試一定要循序漸進。心急吃不了熱豆腐。均方差項調試正確了以後,會得到如圖5所看到的的圖像

技術分享

圖5

而當,均方差項和權重衰減項都調試通過後,得到的圖片是這種

技術分享

圖6

而當全部的目標函數都調試通過以後,接下來就是見證奇跡的時刻

技術分享

圖7

這就是圖像的基。通過稀疏自編碼器。我們學習得到了25個8*8的基,這些圖像的基就相當於咱們每一個視神經細胞所示東西,當這些細胞組成陣列,壘成層層疊疊,我們就能看到全部的東西了。

稀疏自編碼器作為無監督學習的一層基本模塊,這就是我們DeepLearning萬裏長城的第一步:搞基

稀疏自編碼器及事實上現——怎樣搞基