反向傳播(英語:Backpropagation,縮寫爲BP)是「偏差反向傳播」的簡稱,是一種與最優化方法(如梯度降低法)結合使用的,用來訓練人工神經網絡的常見方法。該方法對網絡中全部權重計算損失函數的梯度。這個梯度會反饋給最優化方法,用來更新權值以最小化損失函數。 在神經網絡上執行梯度降低法的主要算法。該算法會先按前向傳播方式計算(並緩存)每一個節點的輸出值,而後再按反向傳播遍歷圖的方式計算損失函數值相對於每一個參數的偏導數。
咱們將以全鏈接層,激活函數採用 Sigmoid
函數,偏差函數爲 Softmax+MSE
損失函數的神經網絡爲例,推導其梯度傳播方式。python
回顧 sigmoid
函數的表達式:算法
$$ \sigma(x) = \frac{1}{1+e^{-x}} $$segmentfault
其導數爲:緩存
$$ \frac{d}{dx}\sigma(x) = \frac{d}{dx} \left(\frac{1}{1+e^{-x}} \right) $$網絡
$$ = \frac{e^{-x}}{(1+e^{-x})^2} $$函數
$$ = \frac{(1 + e^{-x})-1}{(1+e^{-x})^2} $$優化
$$ =\frac{1+e^{-x}}{(1+e^{-x})^2} - \left(\frac{1}{1+e^{-x}}\right)^2 $$spa
$$ = \sigma(x) - \sigma(x)^2 $$3d
$$ = \sigma(1-\sigma) $$code
能夠看到,Sigmoid
函數的導數表達式最終能夠表達爲激活函數的輸出值的簡單運算,利
用這一性質,在神經網絡的梯度計算中,經過緩存每層的 Sigmoid 函數輸出值,便可在需
要的時候計算出其導數。Sigmoid 函數導數的實現:
import numpy as np # 導入 numpy def sigmoid(x): # sigmoid 函數 return 1 / (1 + np.exp(-x)) def derivative(x): # sigmoid 導數的計算 return sigmoid(x)*(1-sigmoid(x))
均方差損失函數表達式爲:
$$ L = \frac{1}{2}\sum_{k=1}^{K}(y_k-o_k)^2 $$
其中$y_k$爲真實值,$o_k$爲輸出值。則它的偏導數$\frac{\partial L}{\partial o_i}$ 能夠展開爲:
$$ \frac{\partial L}{\partial o_i} = \frac{1}{2}\sum_{k=1}^{K}\frac{\partial}{\partial o_i}(y_k - o_k)^2 $$
利用鏈式法則分解爲
$$ \frac{\partial L}{\partial o_i} = \frac{1}{2}\sum_{k=1}^{K}\cdot2\cdot(y_k-o_k)\cdot\frac{\partial(y_k-o_k)}{\partial o_i} $$
$$ \frac{\partial L}{\partial o_i} = \sum_{k=1}^{K}(y_k-o_k)\cdot(-1)\cdot\frac{\partial o_k}{\partial o_i} $$
$\frac{\partial o_k}{\partial o_i}$僅當 k = i
時才爲 1
,其餘點都爲 0
, 也就是說 $\frac{\partial o_k}{\partial o_i}$只與第 i
號節點相關,與其餘節點無關,所以上式中的求和符號能夠去掉,均方差的導數能夠推導爲
$$ \frac{\partial L}{\partial o_i} = (o_i - y_i) $$
對於採用 Sigmoid
激活函數的神經元模型,它的數學模型能夠寫爲
$$ o^1 = \sigma(w^1x+b^1) $$
其中
x
表示網絡的輸入單個神經元模型以下圖所示
輸入節點數爲 J
上標表示權值屬於的層數,下標表示當前鏈接的起始節點號和終止節點號
下面咱們來計算均方差算是函數的梯度
因爲單個神經元只有一個輸出,那麼損失函數能夠表示爲
$$ L = \frac{1}{2}(o_1^1 - t)^2 $$
添加 $\frac{1}{2}$ 是爲了計算方便,咱們以權值鏈接的第 $j\in[1,J]$ 號節點的權值 $w_{j1}$ 爲例,考慮損失函數 $L$ 對其的偏導數 $\frac{\partial L}{\partial w_{j1}}$
$$ \frac{\partial L}{\partial w_{j1}} = (o_1 - t)\frac{\partial o_1}{\partial w_{j1}} $$
因爲 $o_1 = \sigma(z_1)$ ,由上面的推導可知 Sigmoid 函數的導數 $\sigma' = \sigma(1-\sigma)$
$$ \frac{\partial L}{\partial w_{j1}} = (o_1 - t)\frac{\partial \sigma(z_1)}{\partial w_{j1}} $$
$$ = (o_1-t)\sigma(z_1)(1-\sigma(z_1))\frac{\partial z_1}{\partial w_{j1}} $$
把 $\sigma(z_1)$ 寫成 $o_1$
$$ = (o_1-t)o_1(1-o_1)\frac{\partial z_1}{\partial w_{j1}} $$
因爲 $\frac{\partial z_1}{\partial w_{j1}} = x_j$
$$ \frac{\partial L}{\partial w_{j1}} = (o_1-t)o_1(1-o_1)x_j $$
從上式能夠看到,偏差對權值 $w_{j1}$ 的偏導數只與輸出值 $o_1$ 、真實值 t
以及當前權值鏈接的輸 $x_j$ 有關
咱們把單個神經元模型推廣到單層全鏈接層的網絡上,以下圖所示。輸入層經過一個全鏈接層獲得輸出向量 $o^1$ ,與真實標籤向量 t
計算均方差。輸入節點數爲 $J$ ,輸出節點數爲 K
。
與單個神經元不一樣,全連接層有多個輸出節點 $o_1^1, o_2^1, o_3^1,...,o_K^1$ ,每一個輸出節點對應不一樣真實標籤 $t_1, t_2, t_3,..., t_K$ ,均方偏差能夠表示爲
$$ L = \frac{1}{2}\sum_{i=1}^K(o_i^1-t_i)^2 $$
因爲 $\frac{\partial L}{\partial w_{jk}}$ 只與 $o_k^1$ 有關聯,上式中的求和符號能夠去掉,即 $i = k$
$$ \frac{\partial L}{\partial w_{jk}} = (o_k-t_k)\frac{\partial o_k}{\partial w_{jk}} $$
將 $o_k=\sigma(z_k)$ 帶入
$$ \frac{\partial L}{\partial w_{jk}} = (o_k-t_k)\frac{\partial \sigma(z_k)}{\partial w_{jk}} $$
考慮 $Sigmoid$ 函數的導數 $\sigma' = \sigma(1-\sigma)$
$$ \frac{\partial L}{\partial w_{jk}} = (o_k-t_k)\sigma(z_k)(1-\sigma(z_k))\frac{\partial z_k^1}{\partial w_{jk}} $$
將 $\sigma(z_k)$ 記爲 $o_k$
$$ \frac{\partial L}{\partial w_{jk}} = (o_k-t_k)o_k(1-o_k)\frac{\partial z_k^1}{\partial w_{jk}} $$
最終可得
$$ \frac{\partial L}{\partial w_{jk}} = (o_k-t_k)o_k(1-o_k)\cdot x_j $$
由此能夠看到,某條鏈接 $w_{jk}$ 上面的鏈接,只與當前鏈接的輸出節點 $o_k^1$ ,對應的真實值節點的標籤 $t_k^1$ ,以及對應的輸入節點 x
有關。
咱們令 $\delta_k = (o_k-t_k)o_k(1-o_k)$ ,則 $\frac{\partial L}{\partial w_{jk}}$ 能夠表達爲
$$ \frac{\partial L}{\partial w_{jk}}=\delta_k\cdot x_j $$
其中 $\delta _k$ 變量表徵鏈接線的終止節點的梯度傳播的某種特性,使用 $\delta_k$ 表示後,$\frac{\partial L}{\partial w_{jk}}$ 偏導數只與當前鏈接的起始節點 $x_j$,終止節點處 $\delta_k$ 有關,理解起來比較直觀。
看到這裏你們也不容易,畢竟這麼多公式哈哈哈,不過激動的時刻到了
先回顧下輸出層的偏導數公式
$$ \frac{\partial L}{\partial w_{jk}} = (o_k-t_k)o_k(1-o_k)\cdot x_j = \delta_k \cdot x_j $$
多層全鏈接層以下圖所示
K
,輸出 $o^k = [o_1^k, o_2^k, o_3^k,..., o_k^k]$J
,輸出爲 $o^J=[o_1^J, o_2^J,..., o_J^J]$I
,輸出爲 $o^I = [o_1^I, o_2^I,..., o_I^I]$
均方偏差函數
$$ \frac{\partial L}{\partial w_{ij}}=\frac{\partial}{\partial w_{ij}}\frac{1}{2}\sum_{k}(o_k-t_k)2 $$
因爲 $L$ 經過每一個輸出節點 $o_k$ 與 $w_i$ 相關聯,故此處不能去掉求和符號
$$ \frac{\partial L}{\partial w_{ij}}=\sum_k(o_k-t_k)\frac{\partial o_k}{\partial w_{ij}} $$
將 $o_k=\sigma(z_k)$ 帶入
$$ \frac{\partial L}{\partial w_{ij}}=\sum_k(o_k-t_k)\frac{\partial \sigma(z_k)}{\partial w_{ij}} $$
$Sigmoid$ 函數的導數 $\sigma' = \sigma(1-\sigma)$ ,繼續求導,並將 $\sigma(z_k)$ 寫回 $o_k$
$$ \frac{\partial L}{\partial w_{ij}}=\sum_k(o_k-t_k)o_k(1-o_k)\frac{\partial z_k}{\partial w_{ij}} $$
對於 $\frac{\partial z_k}{\partial w_{ij}}$ 能夠應用鏈式法則分解爲
$$ \frac{\partial z_k}{\partial w_{ij}} = \frac{\partial z_k}{o_j}\cdot \frac{\partial o_j}{\partial w_{ij}} $$
由圖可知 $\left(z_k = o_j \cdot w_{jk} + b_k\right)$ ,故有
$$ \frac{\partial z_k}{o_j} = w_{jk} $$
因此
$$ \frac{\partial L}{\partial w_{ij}}=\sum_k(o_k-t_k)o_k(1-o_k)w_{jk}\cdot\frac{\partial o_j}{\partial w_{ij}} $$
考慮到 $\frac{\partial o_j}{\partial w_{ij}}$ 與 k
無關,可將其提取出來
$$ \frac{\partial L}{\partial w_{ij}}=\frac{\partial o_j}{\partial w_{ij}}\cdot\sum_k(o_k-t_k)o_k(1-o_k)w_{jk} $$
再一次有 $o_k=\sigma(z_k)$ ,並利用 $Sigmoid$ 函數的導數 $\sigma' = \sigma(1-\sigma)$ 有
$$ \frac{\partial L}{\partial w_{ij}}= o_j(1-o_j)\frac{\partial z_j}{\partial w_{ij}} \cdot\sum_k(o_k-t_k)o_k(1-o_k)w_{jk} $$
因爲 $\frac{\partial z_j}{\partial w_{ij}} = o_i \left(z_j = o_i\cdot w_{ij} + b_j\right)$
$$ \frac{\partial L}{\partial w_{ij}}= o_j(1-o_j)o_i \cdot\sum_k(o_k-t_k)o_k(1-o_k)w_{jk} $$
其中 $\delta _k^K = (o_k-t_k)o_k(1-o_k)$ ,則
$$ \frac{\partial L}{\partial w_{ij}}= o_j(1-o_j)o_i \cdot\sum_k\delta _k^K\cdot w_{jk} $$
仿照輸出層的書寫方式,定義
$$ \delta_j^J = o_j(1-o_j) \cdot \sum_k \delta _k^K\cdot w_{jk} $$
此時 $\frac{\partial L}{\partial w_{ij}}$ 能夠寫爲當前鏈接的起始節點的輸出值 $o_i$ 與終止節點 $j$ 的梯度信息 $\delta _j^J$ 的簡單相乘運算:
$$ \frac{\partial L}{\partial w_{ij}} = \delta_j^J\cdot o_i^I $$
經過定義 $\delta$ 變量,每一層的梯度表達式變得更加清晰簡潔,其中 $ \delta $ 能夠簡單理解爲當前鏈接 $w_{ij}$ 對偏差函數的貢獻值。
輸出層:
$$ \frac{\partial L}{\partial w_{jk}} = \delta _k^K\cdot o_j $$
$$ \delta _k^K = (o_k-t_k)o_k(1-o_k) $$
倒數第二層:
$$ \frac{\partial L}{\partial w_{ij}} = \delta _j^J\cdot o_i $$
$$ \delta_j^J = o_j(1-o_j) \cdot \sum_k \delta _k^K\cdot w_{jk} $$
倒數第三層:
$$ \frac{\partial L}{\partial w_{ni}} = \delta _i^I\cdot o_n $$
$$ \delta _i^I = o_i(1-o_i)\cdot \sum_j\delta_j^J\cdot w_{ij} $$
其中 $o_n$ 爲倒數第三層的輸入,即倒數第四層的輸出
依照此規律,只須要循環迭代計算每一層每一個節點的 $\delta _k^K, \delta_j^J, \delta_i^I,...$ 等值便可求得當前層的偏導數,從而獲得每層權值矩陣 $W$ 的梯度,再經過梯度降低算法迭代優化網絡參數便可。
好了,反向傳播算法推導完畢,代碼實現能夠參考另外一篇博客神經網絡之動手實現反向傳播(BP)算法