標籤:ram 隨機 活躍 標準 影響 存在 間接 gen log
目前為止,我們已經討論了神經網路在有監督學習中的應用。在有監督學習中,訓練樣本是有類別標籤的。現在假設我們只有一個沒有帶類別標籤的訓練樣本集合 ,其中 。自編碼神經網路是一種無監督學習演算法,它使用了反向傳播演算法,並讓目標值等於輸入值,比如 。是一個自編碼神經網路的樣本。
自編碼神經網路嘗試學習一個 的函數。換句話說,它嘗試逼近一個恒等函數,從而使得輸出 接近於輸入 。恒等函數雖然看上去不太有學習的意義,但是當我們為自編碼神經網路加入某些限制,比如限定隱藏神經元的數量,我們就可以從輸入資料中發現一些有趣的結構。舉例來說,假設某個自編碼神經網路的輸入 是一張 映像(共100個像素)的像素灰階值,於是 ,其隱藏層 中有50個隱藏神經元。注意,輸出也是100維的 。由於只有50個隱藏神經元,我們迫使自編碼神經網路去學習輸入資料的壓縮表示,也就是說,它必須從50維的隱藏神經元啟用度向量 中重構出100維的像素灰階值輸入 。如果網路的輸入資料是完全隨機的,比如每一個輸入 都是一個跟其它特徵完全無關的獨立同分布高斯隨機變數,那麼這一壓縮表示將會非常難學習。但是如果輸入資料中隱含著一些特定的結構,比如某些輸入特徵是彼此相關的,那麼這一演算法就可以發現輸入資料中的這些相關性。事實上,這一簡單的自編碼神經網路通常可以學習出一個跟主元分析(PCA)結果非常相似的輸入資料的低維表示。
我們剛才的論述是基於隱藏神經元數量較小的假設。但是即使隱藏神經元的數量較大(可能比輸入像素的個數還要多),我們仍然通過給自編碼神經網路施加一些其他的限制條件來發現輸入資料中的結構。具體來說,如果我們給隱藏神經元加入稀疏性限制,那麼自編碼神經網路即使在隱藏神經元數量較多的情況下仍然可以發現輸入資料中一些有趣的結構。
稀疏性可以被簡單地解釋如下。如果當神經元的輸出接近於1的時候我們認為它被啟用,而輸出接近於0的時候認為它被抑制,那麼使得神經元大部分的時間都是被抑制的限制則被稱作稀疏性限制。這裡我們假設的神經元的啟用函數是sigmoid函數。如果你使用tanh作為啟用函數的話,當神經元輸出為-1的時候,我們認為神經元是被抑制的。
注意到 表示隱藏神經元 的啟用度,但是這一表示方法中並未明確指出哪一個輸入 帶來了這一啟用度。所以我們將使用 來表示在給定輸入為 情況下,自編碼神經網路隱藏神經元 的啟用度。 進一步,讓
表示隱藏神經元 的平均活躍度(在訓練集上取平均)。我們可以近似的加入一條限制
其中, 是稀疏性參數,通常是一個接近於0的較小的值(比如 )。換句話說,我們想要讓隱藏神經元 的平均活躍度接近0.05。為了滿足這一條件,隱藏神經元的活躍度必須接近於0。
為了實現這一限制,我們將會在我們的最佳化目標函數中加入一個額外的懲罰因子,而這一懲罰因子將懲罰那些 和 有顯著不同的情況從而使得隱藏神經元的平均活躍度保持在較小範圍內。懲罰因子的具體形式有很多種合理的選擇,我們將會選擇以下這一種:
這裡, 是隱藏層中隱藏神經元的數量,而索引 依次代表隱藏層中的每一個神經元。如果你對相對熵(KL divergence)比較熟悉,這一懲罰因子實際上是基於它的。於是懲罰因子也可以被表示為
其中 是一個以 為均值和一個以 為均值的兩個伯努利隨機變數之間的相對熵。相對熵是一種標準的用來測量兩個分布之間差異的方法。(如果你沒有見過相對熵,不用擔心,所有你需要知道的內容都會被包含在這份筆記之中。)
這一懲罰因子有如下性質,當 時 ,並且隨著 與 之間的差異增大而單調遞增。舉例來說,在中,我們設定 並且畫出了相對熵值 隨著 變化的變化。
我們可以看出,相對熵在 時達到它的最小值0,而當 靠近0或者1的時候,相對熵則變得非常大(其實是趨向於)。所以,最小化這一懲罰因子具有使得 靠近 的效果。 現在,我們的總體代價函數可以表示為
其中 如之前所定義,而 控制稀疏性懲罰因子的權重。 項則也(間接地)取決於 ,因為它是隱藏神經元 的平均啟用度,而隱藏層神經元的啟用度取決於 。
為了對相對熵進行導數計算,我們可以使用一個易於實現的技巧,這隻需要在你的程式中稍作改動即可。具體來說,前面在後向傳播演算法中計算第二層( )更新的時候我們已經計算了
現在我們將其換成
就可以了。
有一個需要注意的地方就是我們需要知道 來計算這一項更新。所以在計算任何神經元的後向傳播之前,你需要對所有的訓練樣本計算一遍前向傳播,從而擷取平均啟用度。如果你的訓練樣本可以小到被整個存到記憶體之中(對於編程作業來說,通常如此),你可以方便地在你所有的樣本上計算前向傳播並將得到的啟用度存入記憶體並且計算平均啟用度 。然後你就可以使用事先計算好的啟用度來對所有的訓練樣本進行後向傳播的計算。如果你的資料量太大,無法全部存入記憶體,你就可以掃過你的訓練樣本並計算一次前向傳播,然後將獲得的結果累積起來並計算平均啟用度 (當某一個前向傳播的結果中的啟用度 被用於計算平均啟用度 之後就可以將此結果刪除)。然後當你完成平均啟用度 的計算之後,你需要重新對每一個訓練樣本做一次前向傳播從而可以對其進行後向傳播的計算。對於後一種情況,你對每一個訓練樣本需要計算兩次前向傳播,所以在計算上的效率會稍低一些。
證明上面演算法能達到梯度下降效果的完整推導過程不再本教程的範圍之內。不過如果你想要使用經過以上修改的後向傳播來實現自編碼神經網路,那麼你就會對目標函數 做梯度下降。使用梯度驗證方法,你可以自己來驗證梯度下降演算法是否正確。。
編程過程如下:
1.實驗基礎:
其實實現該功能的主要步驟還是需要計算出網路的損失函數以及其偏導數,具體的公式可以參考前面的博文Deep learning:八(Sparse Autoencoder)。下面用簡單的語言大概介紹下這個步驟,方便大家理清演算法的流程。
1. 計算出網路每個節點的輸入值(即程式中的z值)和輸出值(即程式中的a值,a是z的sigmoid函數值)。
2. 利用z值和a值計算出網路每個節點的誤差值(即程式中的delta值)。
3. 這樣可以利用上面計算出的每個節點的a,z,delta來表達出系統的損失函數以及損失函數的偏導數了,當然這些都是一些數學推導,其公式就是前面的博文Deep learning:八(Sparse Autoencoder)了。
其實步驟1是前向進行的,也就是說按照輸入層——》隱含層——》輸出層的方向進行計算。而步驟2是方向進行的(這也是該演算法叫做BP演算法的來源),即每個節點的誤差值是按照輸出層——》隱含層——》輸入層方向進行的。
一些malab函數:
bsxfun:
C=bsxfun(fun,A,B)表達的是兩個數組A和B間元素的二值操作,fun是函數控制代碼或者m檔案,或者是內嵌的函數。在實際使用過程中fun有很多選擇比如說加,減等,前面需要使用符號’@’.一般情況下A和B需要尺寸大小相同,如果不相同的話,則只能有一個維度不同,同時A和B中在該維度處必須有一個的維度為1。比如說bsxfun(@minus, A, mean(A)),其中A和mean(A)的大小是不同的,這裡的意思需要先將mean(A)擴充到和A大小相同,然後用A的每個元素減去擴充後的mean(A)對應元素的值。
rand:
產生均勻分布的偽隨機數。分布在(0~1)之間
主要文法:rand(m,n)產生m行n列的均勻分布的偽隨機數
rand(m,n,‘double‘)產生指定精度的均勻分布的偽隨機數,參數還可以是‘single‘
rand(RandStream,m,n)利用指定的RandStream(我理解為隨機種子)產生偽隨機數
randn:
產生標準常態分佈的偽隨機數(均值為0,方差為1)。主要文法:和上面一樣
randi:
產生均勻分布的偽隨機整數
主要文法:randi(iMax)在閉區間(0,iMax)產生均勻分布的偽隨機整數
randi(iMax,m,n)在閉區間(0,iMax)產生mXn型隨機矩陣
r = randi([iMin,iMax],m,n)在閉區間(iMin,iMax)產生mXn型隨機矩陣
exist:
測試參數是否存在,比如說exist(‘opt_normalize‘, ‘var‘)表示檢測變數opt_normalize是否存在,其中的’var’表示變數的意思。
colormap:
設定當前常見的顏色值表。
floor:
floor(A):取不大於A的最大整數。
ceil:
ceil(A):取不小於A的最小整數。
imagesc:
imagesc和image類似,可以用於顯示映像。比如imagesc(array,‘EraseMode‘,‘none‘,[-1 1]),這裡的意思是將array中的資料線性映射到[-1,1]之間,然後使用當前設定的顏色表進行顯示。此時的[-1,1]充滿了整個顏色表。背景擦除模式設定為node,表示不擦除背景。
repmat:
該函數是擴充一個矩陣並把原來矩陣中的資料複製進去。比如說B = repmat(A,m,n),就是建立一個矩陣B,B中複製了共m*n個A矩陣,因此B矩陣的大小為[size(A,1)*m size(A,2)*m]。
使用函數控制代碼的作用:
不使用函數控制代碼的情況下,對函數多次調用,每次都要為該函數進行全面的路徑搜尋,直接影響計算速度,藉助控制代碼可以完全避免這種時間損耗。也就是直接指定了函數的指標。函數控制代碼就像一個函數的名字,有點類似於C++程式中的引用。
以上部分摘自部落格:
http://www.cnblogs.com/tornadomeet/archive/2013/03/20/2970724.html
Andrew ng原文:http://deeplearning.stanford.edu/wiki/index.php/Exercise:Sparse_Autoencoder
源碼以及資料:http://ufldl.stanford.edu/wiki/resources/sparseae_exercise.zip
2.程式過程解析
step0:參數初始化
visibleSize = 8*8; % 輸入特徵數,也是每個小圖片的維數
hiddenSize = 25; % 隱層節點數
sparsityParam = 0.01; % 期望稀疏值
lambda = 0.0001; % 權值懲罰參數
beta = 3;
step1:調用sampleIMAGES函數,載入並處理資料
1)sampleIMAGE函數關鍵區段解析
for imageNum = 1:10%在每張圖片中隨機選取1000個patch,共10000個patch
[rowNum colNum] = size(IMAGES(:,:,imageNum));
for patchNum = 1:1000%實現每張圖片選取1000個patch
xPos = randi([1,rowNum-patchsize+1]);%randi用於生產隨機整數矩陣randi([min max],m,n)
yPos = randi([1, colNum-patchsize+1]);
patches(:,(imageNum-1)*1000+patchNum) = reshape(IMAGES(xPos:xPos+7,yPos:yPos+7,...
imageNum),64,1);%reshap函數,將8*8的方陣,變形為64*1的列向量
end
end
處理資料
patches = normalizeData(patches);normalizeData()函數先使用標準差使資料範圍變為-1到1,之後再變換到[0.1,0.9],以便和sigmoid函數輸出值匹配
2)initializeParameters函數
通過輸入層和隱層節點數,初始化權值矩陣和偏置項矩陣。
初始化權值矩陣是,是通過在[-r, r]區間內隨機初始化矩陣r = sqrt(6) / sqrt(hiddenSize+visibleSize+1)=0.2582;(這個我不不清楚為啥,只知道Andrew教程中權值初始值要隨機,且隨機數值不應過大)
theta = [W1(:) ; W2(:) ; b1(:) ; b2(:)];把矩陣向量化,通過向量來傳遞參數;個人猜測應該是通過向量傳參效率高
STEP 2: 實現 sparseAutoencoderCost,稀疏損失函數
1)通過反轉向量,把向量還原為權值矩陣
2)計算損失函數和梯度
由於畫圖和矩陣的原因,原稿使用ppt來製作的,現在就只能通過貼圖的方式展現了,有需要ppt的可以私信我
最後把矩陣權值向量化,當做參數傳遞出來
grad = [W1grad(:) ; W2grad(:) ; b1grad(:) ; b2grad(:)];
STEP 3: 通過l-bfgs演算法最佳化
STEP4:可視化學習到的權值矩陣W1.
七、Sparse Autoencoder介紹