1. 程式人生 > >神經網路和BP演算法推導

神經網路和BP演算法推導

我的原文:www.hijerry.cn/p/53364.htm…

感知機

感知機(perceptron)於1957年由Rosenblatt提出,是一種二分類線性模型。感知機以樣本特徵向量作為輸入,輸出為預測類別,取正、負兩類。感知機最終學習到的是將輸入空間(特徵空間)劃分為正、負兩類的分離超平面,屬於判別模型。為此,使用誤分類作為損失函式,利用梯度下降優化該函式,可求得感知機模型。感知機是神經網路與支援向量機的基礎。

單層感知機

單層感知機圖片

{i} 個樣本的預測值 \hat{y_i} = f(\vec{w} \cdot \vec{x_i} + b) ,其中 f(\cdot) 稱為啟用函式,f(\cdot) \in \{-1, 1\} ,損失為 L_i=\frac{1}{2}(\hat{y_i}-y_i)^2 。單層感知機的目的就是習得合適的 \vec{w}b ,使得所有樣本的損失之和 \sum_{x_i \in X} L_i 最小。

如果我們令 z =  \vec{w} \cdot \vec{x_i} + b

即感知機的輸入。那麼當 z < 0 時,f(z) = -1;當z > 0 時,f(z)=1 。因為 zx 線性組合,所以最終得到的是一個超平面 \vec{w} \cdot \vec{x}+b=0 ,超平面將輸入樣本分為了 y_i=1y_i= -1兩類。

當輸入 x=(x_1, x_2) 是二維向量時,用紅點表示 +1 的資料,黑點表示 -1 的資料,最終習得的是一條直線,將兩個資料分離開,如下圖所示。

決策超平面

因為單層感知機最終習得是超平面,所以只能用於解決線性可分問題。對於下面這樣的資料,單層感知機無能為力。

非線性可分

多層感知機

多層感知機也叫MLP,可以看做是一個有向圖。MLP由多層節點組成,每一層全連線到下一層,除輸入節點外,每個節點都是一個帶有非線性啟用函式的神經元(unit)。多層感知機可用於解決線性不可分問題。

因為神經網路的和多層感知器是一個意思,所以下面直接對單層前饋神經網路進行詳細說明。

決策線

單層前饋神經網路

下圖是一個輸入層節點數為3,隱藏層節點數為2,輸出層節點數為2的前饋神經網路,該網路可用於解決二分類問題。

3×2×2前饋神經網路結構圖

單層前饋神經網路本質上是一個多層感知機,有以下幾個特點:

  1. 全連線。每一層的節點都與右邊層的所有節點通過權重連線。
  2. 隱藏層只有一層。所以稱之為單層
  3. 資料單向流動。每一層節點只作用於其之後的層,所以叫作前饋
  4. 本質是數學函式。神經網路可以明確的用數學語言表達。

神經元

我們拿出隱藏層的一個神經元(unit)放大來看:

單節點詳解

神經元的任務就是接受輸入,產生輸出

z 表示神經元的輸入,a 是神經元的輸出。

輸入怎麼得來?就是上一層的神經元輸出與權重 的乘積之和再加上偏置

輸出怎麼得來?把輸入值帶入啟用函式 得到。

寫成數學表示式就是:

z^{(2)}_1 = w^{(1)}_{11}a^{(1)}_1+w^{(1)}_{21}a^{(1)}_2+w^{(1)}_{31}a^{(1)}_3+b^{(1)}_1

a^{(2)}_1=f(z^{(2)}_1)

f(\cdot) 是啟用函式,常見的有sigmoid、tanh、ReLU。

Sigmoid函式

Sigmoid的表示式為 S(x)=\frac{1}{1+e^{-x}},定義域為 R ,值域為 (0, 1)

x=0 處,函式值為 \frac{1}{2},其函式影象如下:

sigmoid函式影象

sigmoid函式有許多優美的性質,如:

  1. e^x 的複合函式,e 又名自然常數

  2. 1階導函式S'(x)=S(x)(1-S(x)) 。即函式在某一點的導數可由函式在這一點的函式值求得

  3. 曲線光滑,定義域內處處可導,且可以無限次求導

  4. 可以把任意輸入壓縮到 (0, 1) 範圍內

在反向傳播演算法(BP演算法)中,性質2、3起到了極大的作用,性質4起到了防溢位的作用。

前向傳播原理

現考慮一個樣本(x, y) ,其中 x \in R^3 是輸入資料,y \in \{[0,1],[1,0]\}是實際值。我們現在來手動計算 x 預測值 \hat{y}。預測值 \hat{y} 的計算過程是從輸入層開始從左往右計算的,所以這個過程也叫作前向傳播。

下圖表示,為了得到 a^{(3)}_1 ,有哪些神經元被激活了。

前向傳播

為了方便表述,用 w^{(l)}_{ij} 表示第l 層的第 i 個神經元與第 l+1 層的第 j 個神經元相連的權重,用 b^{(l)}_j 表示第l+1 層第 j 個神經元的偏置值。

輸入層

注意。輸入層沒有啟用函式,所以:

[a^{(1)}_1, a^{(1)}_2,a^{(1)}_3]=x

隱藏層

z^{(2)}_1 = w^{(1)}_{11}a^{(1)}_1+w^{(1)}_{21}a^{(1)}_2+w^{(1)}_{31}a^{(1)}_3+b^{(1)}_1

z^{(2)}_2 = w^{(1)}_{12}a^{(1)}_1+w^{(1)}_{22}a^{(1)}_2+w^{(1)}_{32}a^{(1)}_3+b^{(1)}_2

a^{(2)}_1=sigmoid(z^{(2)}_1)

a^{(2)}_2=sigmoid(z^{(2)}_2)

輸出層

如果我們把 a^{(3)}_1 作為類別為 0 的概率,將 a^{(3)}_2 作為類別為1的概率,則樣本 x_i 的預測值可以寫成 \hat{y_i}=\max \{a^{(3)}_1, a^{(3)}_2\} ,所以為了讓 a^{(3)}_1 + a^{(3)}_2 = 1 ,選用 softmax 作為輸出層的啟用函式。

z^{(3)}_1=w^{(2)}_{11}a^{(2)}_1+w^{(2)}_{21}a^{(2)}_2+b^{(2)}_1

z^{(3)}_2=w^{(2)}_{12}a^{(2)}_1+w^{(2)}_{22}a^{(2)}_2+b^{(2)}_2

g(z^{(k)})=\sum exp({z^{(k)}_i})exp(x)=e^x

a^{(3)}_1=softmax(z^{(3)}_1,z^{(3)})=\frac{exp({z^{(3)}_1)}}{g(z^{(3)})}

a^{(3)}_2=softmax(z^{(3)}_2,z^{(3)})=\frac{exp({z^{(3)}_2})}{g(z^{(3)})}

我們令 \hat{y}_1=a^{(3)}_1\hat{y}_2=a^{(3)}_2,那麼 \hat{y}=[\hat{y}_1, \hat{y}_2],同理設 y=[y_1, y_2]

神經網路可以明確的用數學語言表達,它的函式表示式,可以明確的寫出來
複製程式碼

如果真的將這個數學表示式寫出來,那麼這個數學函式 network(\cdot) 是一個包含 (3+1) \times 2 + (2+1) \times 2=14 個引數的函式,函式輸入 x 可得到預測值 \hat{y} ,這個表示式會非常長。

反向傳播原理

我們現在來優化網路中這10個權重引數和4個偏置引數。

定義輸出層的節點 i 的誤差,可用的損失函式有:

  1. 均方誤差:E = \sum_{j=1}^2\frac{1}{2} (\hat{y}_j-y_j)^2
  2. 交叉熵損失: CE=CE(\hat{y},y)=-\sum_{j=1}^{2}y_{j}ln\hat{y}_j

使用梯度下降演算法來優化損失函式,則需要求出損失函式對所有引數的導數,這個過程在計算上是從輸出層開始從右往左計算的,因為與計算預測值 \hat{y_i} 的過程恰巧相反,所以也叫作反向傳播。

權重的導數

以計算權重 w^{(2)}_{21} 的偏導數為例,根據鏈式法則不難得到:

\frac{\partial CE}{\partial w^{(2)}_{21}} = \frac{\partial CE}{\partial \hat{y_1}} \frac{\partial  \hat{y}_1}{\partial z^{(3)}_1} \frac{\partial z^{(3)}_1}{\partial w^{(2)}_{21}}

CE=-\sum_{j=1}^{2}y_jln\hat{y}_j=-(y_1ln\hat{y}_1+y_2ln\hat{y}_2) ,又 y_1+y_2=1\hat{y}_1+\hat{y}_2=1

CE =-(y_1ln\hat{y}_1+(1-y_1)ln(1-\hat{y}_1)) (注:這是二分類問題特有的交叉熵表示方式)

\frac{\partial CE}{\partial  \hat{y}_1}=-(\frac{y_1}{\hat{y}_1} - \frac{1-y_1}{1-\hat{y_1}})=\frac{\hat{y}_1-y_1}{\hat{y}_1(1-\hat{y}_1)}

\frac{\partial  \hat{y}_1}{\partial z^{(3)}_1}=\frac{exp(z^{(3)}_1)exp(z^{(3)}_2)}{(exp(z^{(3)}_1)+exp(z^{(3)}_2))^2}=\hat{y}_1\hat{y}_2=\hat{y_1}(1-\hat{y}_1)

\frac{\partial z^{(3)}_1}{\partial w^{(2)}_{21}}=a^{(2)}_2

故原偏導數可寫成:

\frac{\partial CE}{\partial w^{(2)}_{11}}=\frac{\hat{y}_1-y_1}{\hat{y}_1(1-\hat{y}_1)} \cdot \hat{y_1}(1-\hat{y}_1) \cdot a^{(2)}_1=(\hat{y}_1-y_1) \cdot a^{(2)}_2

更通用化的表達,如何計算 w^{(2)}_{ij} ?依葫蘆畫瓢得:

\frac{\partial CE}{\partial w^{(2)}_{ij}} = \frac{\partial CE}{\partial \hat{y_i}} \frac{\partial  \hat{y}_i}{\partial z^{(3)}_i} \frac{\partial z^{(3)}_i}{\partial w^{(2)}_{ij}}=(\hat{y}_j-y_j) \cdot a^{(2)}_i

\delta^{(3)}_j=\hat{y}_j-y_j 表示輸出層節點 j 的誤差值

則上式可寫成:

\frac{\partial CE}{\partial w^{(2)}_{ij}} =\delta^{(3)}_j \cdot a^{(2)}_i

如何理解?用 i 表示為隱藏層節點的位置, j 表示為輸出層節點的位置,那麼權重 w^{(2)}_{ij} 的導數為該權重前一層第i個節點的啟用值與後一層第j個節點的誤差值的乘積

下圖是反向傳播的示意圖,損失函式產生的誤差順著紅線一直往左邊傳,每經過一條紅線就求一次導數,直到要求的權重也覆蓋在紅線為止。下圖有三條紅線,也就是損失函式 CEw^{(2)}_{21} 的導數需要用三個偏導數乘積形成的鏈式求導才能得到,且最後一個偏導數值為 a^{(2)}_i

w221導數

如何計算 w^{(1)}_{ij}​ 呢?繼續使用鏈式法則 + 依葫蘆畫瓢可得:

\frac{\partial CE}{\partial w^{(1)}_{ij}} =\sum_{k=1}^2((\hat{y}_k-y_k)w^{(2)}_{jk}) \cdot a^{(2)}_j(1-a^{(2)}_j) \cdot a^{(1)}_i

\delta^{(2)}_j = \sum_{k=1}^2(\hat{y}_k-y_k)w^{(2)}_{jk} \cdot a^{(2)}_j(1-a^{(2)}_j)a^{(2)}_j誤差值 ,那麼上式可以寫成:

\frac{\partial CE}{\partial w^{(1)}_{ij}} =\delta^{(2)}_j \cdot a^{(1)}_i

觀察可以發現:

\delta^{(2)}_j=\sum_{k=1}^2(\delta^{(3)}_jw^{(2)}_{jk}) \cdot a^{(2)}_j(1-a^{(2)}_j)

如何理解?如果用 i 表示輸入層節點位置, j 表示隱藏層節點位置,那麼權重 w^{(1)}_{ij} 的導數為 該權重前一層第i個節點的啟用值與後一層第j個節點的誤差值的乘積每個節點的誤差值 等於 連線權重 與 權重另一端所連節點的誤差值 的乘積之和 與 本節點啟用值的導數 的乘積

詳細的推導過程讀者可以自己琢磨一下,這裡有個關鍵點需要注意:

  • 因為 y_1+y_2=1​\hat{y}_1+\hat{y}_2=1​ ,所以 CE =-(y_2ln\hat{y}_2+(1-y_2)ln(1-\hat{y}_2))​

偏置的導數

如何求 b^{(2)}_j 的導數?根據之前的邏輯推導即可:

\frac{\partial CE}{\partial b^{(2)}_j} = \frac{\partial CE}{\partial \hat{y_i}} \frac{\partial  \hat{y}_i}{\partial z^{(3)}_i} \frac{\partial z^{(3)}_i}{\partial b^{(2)}_j}=(\hat{y}_j-y_j) \cdot 1

如何求 b^{(1)}_j 的導數?鏈條太長,這裡直接給出答案:

\frac{\partial CE}{\partial b^{(1)}_j}=\sum_{k=1}^2((\hat{y}_k-y_k)w^{(2)}_{jk}) \cdot a^{(2)}_j(1-a^{(2)}_j) \cdot 1

與權重導數不同的地方就是,在求導過程中的最後一項 \frac{\partial z^{(l + 1)}_i}{\partial b^{(l)}_j} =1

如果加入偏置單元,也可以理解為偏置單元 a^{(l)}_0 的值為1,如下圖所示:

加入偏置單元

正則化項

正則化(regularation)是防止機器學習過擬合的一種手段。一種常見的手段是通過將權重的平方之和加入到損失函式來實現。那麼損失函式變為:

CE=-\sum_{j=1}^{2}y_jln\hat{y}_j+\frac{\lambda}{2}\sum_l\sum_i\sum_j(w^{(l)}_{ij})^2

所有權重、偏置之和稱為 正則項\lambda正則項係數,也叫 懲罰係數

加入正則化項後,w 的導數要多算一個平方項的導數,以 w^{(2)}_{ij} 為例

grad(w^{(2)}_{ij})=(\hat{y}_j-y_j) \cdot a^{(2)}_i+\lambda w^{(2)}_{ij}

向量化

我們假設輸入值 x 、 實際值 y 都是列向量。

觀察 z^{(2)}_1z^{(2)}_2 的表示式,進而發現可以用矩陣形式書寫為:

\left[\begin{matrix} w^{(1)}_{11} & w^{(1)}_{12} \\ w^{(1)}_{21} & w^{(1)}_{22} \\ w^{(1)}_{31} & w^{(1)}_{32} \end{matrix} \right]^T \left[ \begin{matrix} a^{(1)}_1  \\ a^{(1)}_2 \\ a^{(1)}_3 \end{matrix} \right] + \left[\begin{matrix} b^{(1)}_1 \\ b^{(1)}_2 \end{matrix} \right]= \left[\begin{matrix} z^{(2)}_1 \\ z^{(2)}_2 \end{matrix} \right]

不失一般性,設第 l 層的前向傳播:z^{(l+1)}=(w^{(l)})^Ta^{(l)}+b^{(l)},其中 a^{(l)}z^{(l+1)}b^{(l)} 均為列向量, W^{(l)} 為矩陣

啟用值 a^{(l)}=sigmoid(z^{(l)}),所以啟用值也是列向量。

損失函式向量化為:

CE=-\left[\begin{matrix} y_1 \\ y_2 \end{matrix} \right]^T  ln\left[\begin{matrix} \hat{y}_1 \\ \hat{y}_2 \end{matrix} \right] + \lambda(\sum_l\sum_i\sum_jw^{(l)}_{ij}+\sum_l\sum_ib^{(l)}_i)

=-y^Tln\hat{y}+\frac{\lambda}{2}\sum_{l=1}^2 sum(w^{(l)}*w^{(l)})

sum(\cdot) 表示把矩陣 \cdot 的所有元素之和

* 表示求哈達馬積,即兩個矩陣對應位置的元素的乘積所形成的一個新矩陣

輸出層誤差值向量化:

\delta^{(3)}= \left[\begin{matrix} \delta^{(3)}_1 \\ \delta^{(3)}_2 \end{matrix} \right]=\left[\begin{matrix} \hat{y}_1-y_1 \\ \hat{y}_2-y_2\end{matrix} \right] =\hat{y}-y

隱藏層誤差向量化:

\delta^{(2)}= \left[\begin{matrix} (\hat{y}_1-y_1)w^{(2)}_{11}+ (\hat{y}_2-y_2)w^{(2)}_{12} \\ (\hat{y}_1-y_1)w^{(2)}_{21}+ (\hat{y}_2-y_2)w^{(2)}_{22} \end{matrix} \right] * a^{(2)}_j(1-a^{(2)}_j)

=\left[\begin{matrix} w^{(2)}_{11} & w^{(2)}_{12} \\ w^{(2)}_{21} & w^{(2)}_{22} \end{matrix} \right] \left[\begin{matrix} \hat{y}_1-y_1 \\ \hat{y}_2-y_2\end{matrix} \right] * a^{(2)}_j(1-a^{(2)}_j)

=w^{(2)}(\hat{y}-y) * a^{(2)}_j(1-a^{(2)}_j)

引數 w^{(2)} 導數向量化:

grad(w^{(2)})= grad(\left[\begin{matrix} w^{(2)}_{11} & w^{(2)}_{12} \\ w^{(2)}_{21} & w^{(2)}_{22} \end{matrix} \right]) = \left[\begin{matrix} \delta^{(3)}_1a^{(2)}_1 & \delta^{(3)}_2a^{(2)}_1 \\ \delta^{(3)}_1a^{(2)}_2 & \delta^{(3)}_2a^{(2)}_2 \end{matrix} \right]

=\left[\begin{matrix} a^{(2)}_1 \\ a^{(2)}_2 \end{matrix} \right] \left[\begin{matrix} \delta^{(3)}_1 \\ \delta^{(3)}_2 \end{matrix} \right]^T =a^{(2)}(\delta^{(3)})^T

不失一般性,有:grad(w^{(l)})=a^{(l)}(\delta^{(l+1)})^T

小批量梯度下降

上述所有過程都是假設只有一個樣本。

當參與計算的樣本數量大於1時:

  • 單個損失函式 => 所有樣本損失值求平均
  • 單個樣本的輸出層誤差 => 所有樣本輸出層誤差求平均

你不用寫一個for迴圈來計算上述值,使用矩陣乘法會更為方便,這裡留給讀者思考。

實現

github:github.com/JerryCheese…

ann.py 是面向過程版本實現,且隱藏層數只能為1。

NN.py 是面向物件版本實現,支援多層隱藏層。