1. 程式人生 > >Note——Neural Network and Deep Learning (1)[神經網路與深度學習學習筆記(1)]

Note——Neural Network and Deep Learning (1)[神經網路與深度學習學習筆記(1)]

一、初學神經網路的體會

正如書中作者說的神經網路可以被稱作最美的程式設計正規化之一,神經網路將我們需要解決的複雜問題,比如手寫字型分類,簡化成一個個簡單的步驟,而本人無需瞭解內部的具體結構引數變化等。關於神經網路已經有很多實用的庫,使用這些庫可以很快的解決問題。但是不滿足於使用別人造好的輪子,也為了瞭解幾年內都不會過時的原理,僅僅學習程式庫是遠遠不夠的,還是需要自己多花一花時間來了解了解輪子是怎麼造出來的。在看這本書的過程中,有一些比較簡單的數學推導需要自己去實現,既複習了已經落下很久的高數線代,也能更深入得了解模型背後的數學原理,這對於改進演算法瞭解演算法是至關重要的。

二、談談神經元

書中作者主要介紹了感知器和S型神經元(本質上就是大家常說的Logistic函式),這兩個比較簡單,與大家學過的與非門比較類似,不過本質區別在於我們可以設計學習演算法來自動更新權重和偏置從而得到不同的輸出,學習的本質在於自動更新權值和偏置從而達到令人滿意的效果。

三、梯度下降演算法和反向傳播演算法的數學推導

梯度下降演算法

一般而言對於網路的輸出的結果與實際偏差會選擇最小均方值誤差來衡量,當然在這裡沒必要去定義一個所謂的最小的閾值,因為對於分類問題來說誤差當然越小越好,沒有最好;而且目前來說實際應用的分類器的識別效果很難做到100%甚至是95%以上。這也設計到網路的優化問題,這裡我們就定義輸出層輸出值a與期望輸出y的代價函式如下:

訓練神經網路的目的是不斷減小代價函式C的值,我們將採用梯度下降演算法(GD)來達到這個目的。

我們假定每個輸入值權重為W1j,W2j,Wkj....輸出的偏置為Bj.其中k表示上一層神經元的第k神經元的輸出,j表示下一層神經元的第j個輸出。

所謂梯度下降,就是找到我們所關心的變數的最快的下降方向,在本研究中我們關心的是尋求更小的代價函式。當然我們求解最小值不是直接一步就可以得到,而是需要設定比較合適的梯度下降的步長。關於步長選取也是一門學問,這裡不多做深究。下面我們直接給出梯度下降的更新規則(η表示步長,在機器學習中我們稱之為學習速率):

上面這個公式可能看起來很簡單,但是在程式設計實現時可能會遇到比較多的困難,這一點在後面再談。下面我們把重點放在計算梯度的計算複雜度上,這是應用梯度下降演算法的主要挑戰,試想如果我們對每個權重和偏置按照上述公式來計算偏導將是一大筆計算開銷,例如在MNIST資料訓練中輸入資料是50000個手寫字型圖片,每個圖片是一個28X28的值域為(0~1)灰度資料,需要我們設計一個輸入層有784個神經元,輸出層為10的神經網路,每個神經元有各自的權重和偏置,一次迭代總共需要重複50000次這樣的操作,多次迭代計算量劇增。這樣會使學習速度顯著下降。

好在我們不需要在一次迭代中輸入全部的50000組資料,而是可以隨機的選取其中的訓練資料,這就是隨機梯度下降演算法(SGD)。通過隨機選取訓練資料來計算代價函式的梯度從而實現神經元的權重和偏置快速更新。SGD的基本思想是我們可以每次隨機的選取樣本量為m的訓練資料,假設m足夠大,我們期望這些樣本計算的到的代價函式的平均梯度等於整個訓練資料代價函式的平均梯度,因此我們可以將更新規則演變如下:

這就是我們在本次實踐中需要用的梯度下降演算法,原理上也不難理解,主要是在程式碼實現上如何與神經網路的結構結合起來是一個難點,這是我在學習中遇到的比較大的困難。

反向傳播演算法

反向傳播傳播的是什麼?答:傳播的是誤差。可以這麼理解,從輸入層到隱藏層再到輸出層,神經元的輸出不斷前向傳播,我們可以定義神經元的輸出是代價函式,那麼輸出層的誤差就是我們定義的代價函式。但是,各個隱藏層的誤差是什麼呢?我們能否通過輸出層的誤差反向推匯出各個隱藏層的誤差呢?答案是肯定的,因為我們可以讓誤差反向傳播,就如同一個反過來的神經元,輸入是第L+1層的誤差,輸出是第L層的誤差,這樣不斷向前傳播直到輸入層,從而實現神經元權重和偏置的更新。

關於反向傳播有以下四個公式:

關於公式符號的意義和前面兩個公式的推導大家可以看書,值得注意的是這裡的誤差δ定義的是關於z的函式。書中沒有給後面兩個公式的推導,下面給出:

公式推導的基本原理是鏈式求導法則,然後引用中間變數a和z。

下面直接摘錄書籍中關於演算法的原理虛擬碼:

四、程式碼實現

首先談談遇到的問題:

①不同的隨機訓練訓練集是否可以使用同一代價函式?

這裡我們給出假設:代價函式可以被寫成在每一個訓練樣本上的代價函式的均值。

②如何設計程式碼結構:

這裡主要參照了作者給出的程式碼,然後對程式碼邏輯進行歸納。

大致的邏輯是:資料匯入——>資料規整使其適應於神經網路輸入輸出結構——>隨機選取訓練集——>訓練集梯度下降演算法——>訓練集反向傳播演算法——>輸出訓練效果並迭代

③關於作者給的程式碼遇到的問題。

作者給出的程式碼是基於python2.7的,這裡需要在程式碼中做出微小的改動:

需要將cPickle包改成pickle包;

需將zip物件轉換為list才能對資料進行迴圈(轉為為可迭代物件);

將 print 'Epoch {0}: {1} / {2'.format(j, self.evaluate(test_data), n_test)改寫成print('Epoch {0}:{1}/{2}'.format(i,self.evaluate(test_data),n_test));

class內部函式呼叫,需要手動在呼叫函式前加上self,例如self.sigmoid()等等等

可以看出,該演算法準確率基本穩定在95%附近,效果還不錯。最主要的是除此迭代就到了90%的準確率,說明收斂速度還是很理想的。第一輪仿造車輪結束。