動手實踐神經網路3: 用Excel實現多層全連接神經網路

前兩篇文章分享了單個神經元的訓練和調優,接下來我們進入多層(除了輸入和輸出層包含至少一個隱層)全連接神經網路。

這裡先不考慮使用Python或TensoFlow編程實現多層神經網路,而是使用Excel聯繫多層全連接神經網路的前向計算和誤差反向傳播,目標有兩點

1. 較之於程序代碼,Excel上手更容易,可以幫助初學者快速建立概念

2. 編程實現神經網路的過程中,最大的困難在於如何檢查實現結果是否正確。單純的Code Review顯然無法有效發現所有Bug,從軟體測試的角度,測試用例需要清晰的定義出程序的輸入和預期輸出。進一步,僅僅知道輸入和預期輸出還不夠,還需要運算中重要中間結果量,以便程序輸出結果與預期不符時,通過檢查不同階段的中間變數定位出問題的Root Cause。

基於上述考慮,我想到了通過電子表格計算出神經網路前向和反向的每一步結果,一方面可以作為自己寫的神經網路程序的單元測試例;另一方面也在計算的過程中更加形象的理解神經網路。

本文提到的表格可以從筆者GitHub得到,下載地址如下

github.com/wangyaobupt/

本文參考了斯坦福大學的BP演算法在線教程,參考文獻如下

[1]Backpropagation_Algorithm

網路結構定義

這裡我們考慮只包含一個輸入層、一個輸出層、一個隱含層的3層神經網路,每層兩個神經元,其結構如下圖所示

上述節點從輸入層開始編號,輸入層定義為第0層,隱層定義為第1層,輸出層定義為第2層。除了輸入層,每一層都包含與前一級的連接,每個連接都有權重值。激活函數選用signmoid函數。

上述神經網路可以在Excel中用如下形式表示,其中每一層的參數介紹如下

  • 「src節點j=0」與"dst節點i=0"的交叉點表示從上一層第0個節點到本層第0個節點的weight
  • "dst節點i=0"與「bias節點」的交叉點表示本層第0個節點的bias取值

從上圖可以看到,第一層和第二層的weight都使用[[1,-1], [2,-2]]初始化,bias節點統一初始化到1

前向計算

假定輸入數據為(1,2),輸入層(第0層)不包含計算邏輯,所以第0層的激活值就是(1,2)

此後的兩層,神經網路每個單元激活值來自於前一層的輸入、自己的weight、自己的bias三者計算的結果。

以下圖的格式為例,「第1層激活值」與「節點0」的交點表示第一層節點0的輸出,計算公式為

1/(1+EXP(-1*($C$12*$C5+$C$13*$D5+$E5)))

最終上圖中第2層激活值就是神經網路的輸出

標籤和Loss

將神經網路的訓練目標考慮為線性分隔問題,對於輸入數據(1,2),分為第二類。

分類結果用one-hot vector表示:第一類標籤定義為(1,0),第二類標籤定義為(0,1)

Loss值定義為神經網路輸出值與標籤的歐氏距離平方的一半,計算Loss的公式如上圖公式欄所示。神經網路的訓練目標定義為Loss值儘可能小

誤差反向傳播第一步:計算逐點誤差

所謂逐點誤差,就是這個神經元節點對最終誤差的"貢獻"是多少,在斯坦福大學的一份在線教材中(Backpropagation Algorithm)[1],定義如下

for each node i in layer l, we would like to compute an "error term" that measures how much that node was "responsible" for any errors in our output.

基於教材中的描述,筆者嘗試翻譯整理如下

1. 對於輸出層節點,每個神經元的逐點誤差就是Loss函數對這個神經元激活函數輸入值的導數。寫成公式表示為

delta^{n_l}_I = frac{dLoss}{d{z^{n_l}_i}} = -(y_i - a^{n_l}_i)f(z^{n_l}_i)

上述公式中y_i表示標籤中第i個維度的值,a^{n_l}_i表示輸出層第i個節點的值,z^{n_l}_i是輸出層第i個節點激活函數的輸入值。f(x)是激活函數,具體到我們的例子里,就是sigmoid函數,f(x)就是sigmoid函數的導函數,數學上給出frac{dsigmoid(x)}{dx} = sigmoid(x) * (1-sigmoid(x))

2. 對於隱層節點,每個神經元的逐點誤差

教材中給出的公式如下

上述公式可以用下圖形象化表示,圖中每個變數的上標都是層序號,下標表示在一層中的節點序號,黃色箭頭表示計算逐點誤差的方向

技術上述分析,電子表格中可以按照如下形式計算逐點誤差

誤差反向傳播第二步:計算誤差對每個變數的梯度

有了逐點誤差,梯度的計算就非常簡單,對於上述教材[1]中的數學公式,我這裡簡化描述如下

對於權重參數weight:每個節點的某個權重參數,梯度等於這個節點的逐點誤差 乘以 前一層另一個節點的激活值

對於偏置參數bias:這一層這個節點的逐點誤差

嚴格的數學公式由教材[1]給出

基於梯度調整權重並重新計算Loss

當得到Loss函數對每個參數的梯度之後,就可以按照梯度下降方向結合學習率調整參數。舉例來說,對於某個參數,梯度為2,這意味著這個參數增加1,最終Loss就增加2,所以必須將這個參數向小的方向調。即

調整後的參數值 = 調整前的參數值 + (-1)*梯度*學習率

學習率假定為0.03,神經網路調整如下

調整後重新計算Loss,比第0次前向計算的Loss下降,這體現了BP演算法對神經網路參數的訓練效果。

更多資料

這個系列整理自我的技術博客:王堯的技術博客。博客中的內容體系性不如在知乎整理的清楚,但會隨時記錄工作中的技術問題和發現,如有興趣歡迎圍觀。


推薦閱讀:

先睹為快:神經網路頂會ICLR 2018論文接受結果速覽
ML + System = ?
神經網路告訴我,誰是世界上最「美」的人?
論文解讀 | 基於神經網路的知識推理
從下往上看--新皮層資料的讀後感 第一部分:皮層細胞

TAG:深度學習DeepLearning | 神經網路 |