2018/12/4

Artificial Neural Networks (ANN, 人工神經網路)

09 Artificial Neural Networks (ANN, 人工神經網路)

Artificial Neural Networks (ANN) 中文稱人工神經網路或類神經網路,其組成的基本單元是:
  • Architecture, or topology (架構或稱拓撲): 描述神經元的種類及連接狀態。
  • activation functions: 所使用的作動函數,描述如何把合成訊號轉成輸出,最常見的是sigmoid function.
  • Learning algorithm: 描述神經網路學習的方式。
一個ANN 是由很多感知元所組成,若把感知元視成Neron (神經元)則ANN 可視成大腦,也因而在ANN裡的基本單元常被稱為Neron。因要執行errors 的後向傳播 (back propagation) 所以作動函數必需是可微分,因此常用sigmoid function。每個ANN 可能由數以千計的神經元組成,因而學習過程的計算量相當龐大,往往需用到 GPUs (Graph Processing Units) 並行處理,但sklearn 並不支援GPUs運算,所以只能處理較簡單的 ANN,若要處理複雜的問題則需專業的 Deep learning (深度學習)套件,如 Keras 或 Tensorflow。本單元先用簡單的 ANN 學習後向傳播誤差更新的演算法,這是 ANN 的基本原理,後續的單元再討論複雜的ANNs。

∎ Feed-forward and feedback ANNs
  • Feed-forward ANNs 是指網路單元是順向,沒有循環,適合處理時間前後輸入彼此是獨立的資料,如處理圖片分類或文字辨識。複雜的 Convolutional Neural Networks (CNNs,摺積神經網路) 就是屬於這一類型。
  • Feedback ANNs 是指網路單元的具有回授的連接,如此會構成循環,適合處理時間前後輸入彼此是相關的資料,如語音辨識及翻譯。複雜的 Recurrent Neural Networks (RNNs,遞迴神經網路) 就是屬於這一類型。
∎ Multi-layer network (多層網路)
在ANN 中多個神經元並列用以接收同一資料不同的特徵輸入或是上一級的輸入時,這並列的神經元就稱為一個layer (層),一般在 ANN 中特徵並列輸入叫輸入層 (Input layer),所以並列的特徵可看成是輸入層的寬度,輸出有時會有多個神經元並列輸出,這些並列的神經元構成輸出層 (Output layer),而多少個輸出神經元並列就是輸出層的寬度。若網路中只含有輸入層和輸出層,就如同上一個單元討論的感知元一樣,只是基本感知元的操作,因要學習的weight只有一層,可以依上一單元討論的規則更新,並不需用到後向傳播。而ANN是考慮的是多層網路,也就是在輸人和輸出層中至少含有一個隱藏層  (Hidden layer),如此一來就至少會有兩層的weights,而輸出端所得到誤差依一定的比例向後回傳至每一層用以更新weights,就是所謂的後向傳播。一般計算一個ANN網路的層數時是不計輸入層,若有一隱藏層和輸出層,則稱兩層網路,多少層串接就是指深度,一個多層網路就意謂著至要有兩層,而deep learning 所指的網路至少要有三層。

∎ Backpropagation (後向傳播)
我們以下列兩層 ANN 網路的架構來為例來討論後向傳播,假設使用的作動函數是 sigmoid function。

兩層 ANN 網路例子
首先用矩數形式來表示各參數,輸入的特徵可表示為(依一般慣例,各層變數以行表示)
${\textbf X}=\begin{bmatrix} X_0\\  X_1\\  X_2 \end{bmatrix}$,
隱藏層的係數為
$\textbf{w}=\begin{bmatrix} w_{01} &w_{02} \\  w_{11} &w_{12} \\  w_{21} & w_{22} \end{bmatrix}$,
隱藏層的輸入端為
${\textbf H}_{\rm {in}}=\begin{bmatrix} H_{1,in}\\  H_{2,in} \end{bmatrix}$, 則

${\textbf H}_{\rm {in}}= {\textbf w}^T\textbf X$,
輸出層係數為
${\textbf k}=\begin{bmatrix} k_0\\  k_1\\ k_2 \end{bmatrix}$,
隱藏層的輸出端為
${\textbf H}_{\rm {out}}=\begin{bmatrix} H_{0} \\ H_{1,out}\\  H_{2,out} \end{bmatrix}$, 
輸出層輸入端為
${O}_{in}= {\textbf k}^T{\textbf H}_{\rm {out}}$, 且

$H_{i,{\rm {out}}}= \frac{1}{1+e^{-H_{i,{\rm {in}}}}}$, for $i=1,2$,最後輸出是

$O_{out}= \frac{1}{1+e^{-O_{ in}}}$
權重係數更新的方法是計算係數對誤差的偏導數,代入更新規則中更新,假設誤差函數是
$E=\frac{1}{2}\sum_{i=1}^{n}(y_i-\hat y_i)^2$,
其中$\hat y_i$是預測第$i$個輸出,而$y_i$是目標值。本例子中只有一個輸出神經元,所以$n=1$。
係數更新的方法是是
$w_i(t+1)=w_i(t)-\eta \frac{\partial E}{\partial w_i}$.
因執行係數更新,每一神經元必需區分出輸入端和輸出點,分別用下標$in$和$out$表示,如$H_{1,\rm{in}}$ 和 $H_{1,\rm{out}}$,
對 sigmoid function 有
$\frac{\partial}{\partial x} f(x)=\frac{\partial}{\partial x}\frac{1}{1+e^{-x}}=f(x)(1-f(x))$,
求偏導數 時需使用連鎖律,如

$\frac{\partial E}{\partial w_i} =\frac{\partial E}{\partial O_{out}}\frac{\partial O_{out}}{\partial O_{in}}\frac{\partial O_{in}}{\partial w_i}$

 ∎ Backpropagation 更新例子
假設各項係數目前的值是
目前的值
且目前的輸入是[0.8 0.3],目 標輸出是0.5,由輸入端至輸出端計算輸出:
$H_{1,\rm in}=X_0 \cdot w_{01}+X_1 \cdot w_{11}+X_2 \cdot w_{21}$
           $=0.5+0.4 \times 0.8+0.8 \times 0.3=1.06$
因此$H_1$的輸出$H_{1,\rm out}$是
$H_{1,\rm out}=\frac{1}{1+e^{-1.06}}=0.743$
相同地,
$H_{2,\rm in}=X_0 \cdot w_{02}+X_1 \cdot w_{12}+X_2 \cdot w_{22}$
          $=0.2+0.8 \times 0.3+0.3 \times 0.1=0.47$
$H_{1,\rm out}=\frac{1}{1+e^{-1.06}}=0.743$,
$O_{\rm in}=H_0 \cdot k_0+H_{1,\rm out} \cdot k_1+H_{2,\rm out} \cdot k_2$
       $=0.9+0.743 \times 0.6+0.615 \times 0.2=1.4688$

◆ 後向求偏導數更新係數
係數$k_1$更新的方法
$\frac{\partial E}{\partial k_1} =\frac{\partial E}{\partial O_{out}}\frac{\partial O_{out}}{\partial O_{in}}\frac{\partial O_{in}}{\partial k_1}$

誤差偏導計算,必需計算出上式中三個連乘的偏導數
$E=\frac{1}{2}(y-O_{\rm out})^2$
$\frac{\partial E}{\partial O_{\rm out}}=-(y-O_{\rm out})$
            $=-(0.5-0.813)=0.313$
$\frac{\partial O_{\rm out}}{\partial O_{\rm in}}=O_{\rm out}(1-O_{\rm out})$
           $=0.813(1-0.813)=0.152$

$\frac{\partial O_{in}}{\partial k_1}=\frac{\partial (H_0 \cdot k_0+H_{1,\rm out} \cdot k_1+H_{2,\rm out} \cdot k_2)}{\partial k_1}$
                  $=H_{1,\rm out}$
                  $=0.743$
所以
$\frac{\partial E}{\partial k_1} =0.313 \times 0.152 \times 0.743 = 0.035$
更新規則(設$\eta=0.5$)

$k_1(t+1)=k_1(t)-\eta \frac{\partial E}{\partial k_1}$
                    $=0.6-0.5 \times 0.035 = 0.59125$

◆ 求偏導數更新係數的$\delta $
上述計算中可令
$\delta _O =\frac{\partial E}{\partial O_{\rm out}}\frac{\partial O_{\rm out}}{\partial O_{\rm in}}$
此項可稱為節點的更新常數,也就是求從輸出端至此節點輸入端的連鎖偏導數,要更新連進此節點的權重時,更新的量就是此值和連接前端輸出值的乘積,所以要更新$k_2$時,更新的量就是$H_{2,\rm out}\cdot\delta _O $,代入更新規則就可求出$k_2$新的權值。本例只有一個輸出單元,若有更多輸出單元並列時需考慮所有輸出神經元對係數更新的貢獻。

◆ 後向隱藏層係數更新:( 以$𝑤_{11}$為例)

$\frac{\partial E}{\partial w_{11}} =\frac{\partial E}{\partial O_{\rm out}}\frac{\partial O_{\rm out}}{\partial O_{\rm in}}\frac{\partial O_{\rm in}}{\partial H_{1,\rm out}}\frac{\partial H_{1,\rm out}}{\partial H_{1,\rm in}}\frac{\partial H_{1,\rm in}}{\partial w_{11}}$

其中等號右側前兩項相乘為$\delta_O$,第三項為$k_1$,第四項

$\frac{\partial H_{1,\rm out}}{\partial H_{1,\rm in}}=H_{1,\rm out}(1-H_{1,\rm out})$
               $=0.743\times (1-0.743)=0.19095$
我們可以定義前四項偏導連乘為$\delta_{H_1}$,得
$\delta_{H_1}=\delta_O \cdot k_1 \cdot 0.19095$
             $=0.047576 \cdot 0.6 \cdot 0.19095 = 0.00545$

因最後一項偏導數為$X_1$,則$w_{11}$更新的量為
$X_1 \cdot\delta_{H_1}= 0.8 \cdot 0.00545=0.00436$,
由此可知更新隱藏層係數和更新輸出層係數類似,可先求出該節點的更新常數,再以此常數和要更新係數的連接線前端的輸入值相乘。且要求節點的更新常數時可先求出該節點的輸出對輸入的偏導值乘上輸出端連接線的係數再乘上輸出端連接點的更新常數。
求出$\delta_{H_1}$後,$w_{21}$的更新量就是$\delta_{H_1}\cdot X_2$。用相同的方法求$\delta_{H_2}$再用以更新$w_{12}$ 和 $w_{22}$,這樣就完成一次更新。接著再輸入下一個的實例依此法進行係數更新。

注意本例中只有一個輸出所以和$H_1$輸出端連接的節點只有一個,若有多個輸出時連接的節點可能會有多個,則求更新常數時需求出對所有有連接的點分別求更新值,再求總和。

◆ 係數更新彙整
以下圖為例
更新彙整

假設$\delta_{j-1,1}$和$\delta_{j-1,2}$ 已求出,且令$\delta_{j,1}$的輸出值為$r$則
$\delta _{j,1}=r\cdot (1-r)\cdot w_1 \cdot \delta_{j-1,1} + r\cdot (1-r)\cdot w_2 \cdot \delta_{j-1,2}$,
$w_1'$的更新量為
$H_{j+1,\rm out}\cdot \delta_{j,1}$

 ∎ sklearn MLPClassifier class
sklearn 裡有個  MLPClassifier class可用以實現簡單ANN 網路,以下是個利用這個classifier 以完成XOR gate
 
from sklearn.model_selection import train_test_split
from sklearn.neural_network import MLPClassifier
y = [0, 1, 1, 0]
X = [[0, 0], [0, 1], [1, 0], [1, 1]]
clf = MLPClassifier(solver='lbfgs', activation='logistic',
 hidden_layer_sizes=(2,), random_state=20)
clf.fit(X, y)
predictions = clf.predict(X)
print('Accuracy: %s' % clf.score(X, y))
for i, p in enumerate(predictions):
    print('True: %s, Predicted: %s' % (y[i], p))
Accuracy: 1.0
True: 0, Predicted: 0
True: 1, Predicted: 1
True: 1, Predicted: 1
True: 0, Predicted: 0
solver='lbfgs'是指定最佳化的方式, hidden_layer_sizes=(2,)是一個tuple參數,activation='logistic'

參考文獻
Gavin Hackeling, Mastering Machine Learning with scikit-learn, 2nd, Packt Publishing, 2017

沒有留言:

張貼留言