用計算圖理解和計算BP神經網絡的梯度

摘要

計算圖應用非常廣,例如,內存計算框架Spark的有向無環圖(DAG),Neo4J圖數據庫、深度學習中的神經網絡圖,以及TensorBoard中的可視化圖,都是計算圖的應用場景。本文所講的也是計算圖的一個應用場景:計算神經網絡的梯度,包括計算激活函數和典型神經結構(也叫卷積核)的梯度:
1、用計算圖分解和解決 激活函數 的導數的計算
2、用計算圖分解和解決 神經網絡 在反向傳播路徑上梯度的計算。

回顧上一篇 利用BP神經網絡逼近函數(Python)

引言

神經網絡的學習過程就是優化目標函數,目標函數的優化需要不斷的隨着迭代步驟更新神經網絡各層的權重和偏置,而更新的一個重要依據就是要計算反向傳播路徑上的各層的梯度,當神經網絡層數很多時,計算和傳遞就更復雜。這是神經網絡的一個核心問題,所以一種什麼方式來理解和計算梯度就顯得比較重要。

要正確理解和計算反向傳播法上梯度,有兩種方法:一種是基於數學式,常見於網上洋洋灑灑的公式推導;另一種是基於計算圖(computational graph)的。 關於BP反向傳播梯度推導,在網上和書上,筆者看了數次,但是當時覺得懂了,但是過了不久印象幾乎消失殆盡,大概是東方人擅長具象思維,西方人擅長邏輯思維的緣故吧。不知讀者是否有這樣的感覺。本文講述後者,計算圖作爲一種解決問題的方式,有着形象直觀,易於理解和掌握的優勢。關於什麼是梯度參見我的文章 神經網絡的數學基礎:張量和梯度,

目錄

  • 什麼是計算圖
  • 複合函數的計算圖式求導
  • 神經網絡反向(BP)求導
  • 小結

首先講述如何拆解複合函數求導,然後講述如何在神經網絡中傳導,然後,再結合實際的代碼加深理解,相信大家看完會有一定會有種“原來如此!”的感覺。

什麼是計算圖

首先定義計算圖的概念,計算圖是有向圖,神經網絡是其特殊形式, 其中節點對應於操作變量。變量可以將其值提供給操作,操作可以將其輸出提供給其他操作。這樣,圖中的每個節點都定義了變量的函數。進入節點並從節點出來的值稱爲張量(多維數組的另一別稱),它包含標量,向量和矩陣以及更高等級的張量。

計算圖將計算過程用圖形表示出來。這裏說的圖形是數據結構圖,通過多個節點和邊表示(連接節點的直線稱爲“邊”)
在這裏插入圖片描述

“從左向右進行計算”是一種正方向上的傳播,簡稱爲正向傳播(forward propagation)。正向傳播是從計算圖出發點到結束點的傳播。既然有正向傳播這個名稱,當然也可以考慮反向(從圖上看的話,就是從右向左)的傳播。實際上,這種傳播稱爲反向傳播(backward propagation)。傳播的是什麼?傳播的是線上的張量!

複合函數的計算圖式求導

複合函數是由多個函數構成的函數。比如,函數 z=(x+y)2z = (x + y)^2 是由下面兩個函數式子組成的:
z=t2z = t^2
t=x+y t = x + y
複合函數的求導,遵循鏈式法則,規則是這樣:如果某個函數是複合函數,則其導數可以用構成複合函數的各個函數的導數的乘積表示,例如上面公式對x的導數就可以由以下公式推導得出:
zx=zttx=2t.1=2(x+y)\frac {\partial z}{\partial x}=\frac {\partial z}{\partial t}\frac {\partial t}{\partial x}=2t.1=2(x+y)

可見,把複合函數分解爲幾個小的子函數,通過求子函數的導數,然後把它們乘起來,這樣大大降低了求導數的難度,而且理解起來也很容易,複合函數求導,在神經網絡中用的多場合是激活函數和損失函數,這裏我們以 激活函數sigmoidsigmoid 爲例說明,sigmoidsigmoid 函數由以下公式表示:
y=11+exp(x)y=\frac {1}{1+exp(-x)}

按照函數內進行的操作單元分解後,計算圖表示如下:

在這裏插入圖片描述
我們可以把xx理解爲神經網絡裏的信號,信號通過這個計算圖最終輸出yy,這是信號的正向傳播,這是我們常規思維容易理解的地方。下面我們看看反向傳播的流程。
第一步
在這裏插入圖片描述
先看一下反向的信號源頭,一般來說在神經網絡我們優化的都是損失函數 LossLoss,所以一般從損失函數對輸出求導,作爲信號起始點,標記爲 Ly\frac{\partial L}{\partial y},這是一個信號量。首先看這個信號通過 “/” 變成什麼?其實,“/”節點表示 y=1xy = \frac {1}{x},它的導數:
yx=1x2=y2\frac {\partial y}{\partial x} = -\frac {1}{x^2} = - y^2
所以經過"/"後,信號爲:Lyy2-\frac{\partial L}{\partial y}y^2

第二步
“+”節點將上游的值原封不動地傳給下游。計算圖如下所示:

在這裏插入圖片描述
第三步
“exp”節點表示y = exp(x),它的導數由下式表示:
yx=exp(x)\frac {\partial y}{\partial x}=exp(x)
計算圖中,上游的值乘以正向傳播時的輸出(這個例子中是exp(−x))後,再傳給下游。

在這裏插入圖片描述
第四步
“×”節點將正向傳播時的值翻轉後做乘法運算。因此,這裏要乘以−1。
在這裏插入圖片描述
最終反向傳播的輸出:Lyy2exp(x)\frac{\partial L}{\partial y}y^2exp(-x), 這個值只根據正向傳播時的輸入x和輸出y就可以算出來. 計算圖可以收縮爲神經網絡中的sigmoidsigmoid節點圖畫法,如下:
在這裏插入圖片描述
最終輸出結果還可以進一步整理爲如下:

Lyy2exp(x)=Ly1(1+exp(x))2exp(x)=Lyy(1y)\frac{\partial L}{\partial y}y^2exp(-x)=\frac{\partial L}{\partial y}\frac {1}{(1+exp^{(-x)})^2}exp(-x)=\frac{\partial L}{\partial y}y(1-y)

結論是Sigmoid 層的反向傳播,只根據正向傳播的輸出就能計算出來。
在這裏插入圖片描述

神經網絡的計算圖式求導

深度學習中,複雜的神經網絡一般都可以由以下這個典型神經網絡結構通過層層疊加而組成。所以,瞭解了這個基本結構的梯度計算,再複雜的網絡結構也就是同理可得了。這個典型網絡單元(也叫一個卷積核)由公式 Y=np.dot(X,W)+BY= np.dot(X,W) + B 描述,Y 經過激活函數轉換後,傳遞給下一層。這就是神經網絡正向傳播的流程. 結構可分解爲以下計算圖:一個矩陣相乘再加上偏置:

在這裏插入圖片描述
圖中括號內容表示該張量的形狀,當然裏面的數字是一個舉例的數字
這裏參與計算X,W,B都是矩陣或者叫做多維數組。以矩陣爲對象的反向傳播,按矩陣的各個元素進行計算時,步驟和以標量爲對象的計算圖相同。公式如下:
LX=LY.WT\frac {\partial L}{\partial X}=\frac {\partial L}{\partial Y}.W^T
LW=XT.LY\frac {\partial L}{\partial W}=X^T.\frac {\partial L}{\partial Y}

首先 LY\frac {\partial L}{\partial Y} 信號通過“+”後,信號不變到了dotdot節點,dotdot是矩陣相乘,導數需要對應的矩陣做轉置運算。以上述圖爲例:
WTW^T 的T表示轉置。轉置操作會把W的元素(i, j) 換成元素 (j, i)。用數學式表示的話,可以寫成下面這樣,
W=w11w12w13w21w22w23W=\left| \begin{matrix} w_{11} & w_{12} & w_{13}\\ w_{21} & w_{22} & w_{23}\\ \end{matrix} \right|

WT=w11w21w12w22w13w23W^T=\left| \begin{matrix} w_{11} & w_{21} \\ w_{12} & w_{22} \\ w_{13} & w_{23} \\ \end{matrix} \right|

如果W的形狀是(2, 3),WTW^T的形狀就是(3, 2)。
根據上述,我們可以寫出計算圖的反向傳播,如下
在這裏插入圖片描述

這個圖所示的X是一個一維數組的情形,如果X是批量數據,形狀是(samples features),計算圖如下:
在這裏插入圖片描述
用Python表示如下:

def backward(self, dout):
    dx = np.dot(dout, self.W.T)
    dW = np.dot(self.x.T, dout)
    db = np.sum(dout, axis=0)

    return dx, db, dW

再通過一個層級循環,就可以算出各層權重和偏置需要調整的值

for layer in layers:
    dout = layer.backward(dout)

然後再利用,類似如下代碼進行權重和偏置的更新

grad = network.gradient(x_batch, t_batch)

# 更新
for key in ('W1', 'b1', 'W2', 'b2'):
    network.params[key] -= learning_rate * grad[key]

完整例子可以參看這一篇 利用BP神經網絡逼近函數(Python)

小結

本文講述了計算過程可視化的計算圖,並使用計算圖,計算了複合函數求導和神經網絡單元求梯度。通過使用層進行模塊化,神經網絡中可以自由地組裝層,輕鬆構建出自己喜歡的網絡:
• 通過使用計算圖,可以直觀地把握計算過程。
• 計算圖的節點是由局部計算構成的,局部計算構成全局計算。
• 計算圖的正向傳播進行一般的計算,通過計算圖的反向傳播,可以計算各個節點的導數。
• 通過將神經網絡的組成元素實現爲層,可以高效地計算梯度(反向傳播法)

參考文獻

1、Hacker’s guide to Neural Networks
2、CS231n: Convolutional Neural Networks for Visual Recognition
3、Deep Learning From Scratch I: Computational Graphs
4、從頭學習Deep Learning

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章