作者:李理
目前就職于環(huán)信,即時(shí)通訊云平臺和全媒體智能客服平臺,在環(huán)信從事智能客服和智能機器人相關(guān)工作,致力于用深度學(xué)習來(lái)提高智能機器人的性能。
相關(guān)文章:
前面我們講過(guò)了反向傳播算法的詳細推導過(guò)程,大家可能會(huì )覺(jué)得有些復雜。事實(shí)上其實(shí)就是鏈式求導法則的應用。今天我們將會(huì )繼續討論這個(gè)問(wèn)題,不過(guò)是從Computational Graphs的角度,也就是我們之前說(shuō)過(guò)的自動(dòng)求導(Automatic Differentiationor Reverse-mode Differentiation)。并且通過(guò)CS231n的Assignment2來(lái)學(xué)習使用這種方法,通過(guò)這種方法來(lái)實(shí)現一個(gè)多層的神經(jīng)網(wǎng)絡(luò )。
Calculus on Computational Graphs:Backpropagation
首先我們介紹一篇博客文章:https://colah.github.io/posts/2015-08-Backprop/基本是翻譯過(guò)來(lái),不過(guò)部分地方是我自己的理解,建議讀者結合這篇文章一起閱讀。
簡(jiǎn)介
反向傳播算法是神經(jīng)網(wǎng)絡(luò )的核心算法,不過(guò)這個(gè)算法在不同的領(lǐng)域被多次”發(fā)現“過(guò),因此有不同的名稱(chēng)。
計算圖(Computational Graphs)
考慮一個(gè)簡(jiǎn)單的函數e=(a+b)∗(b+1)e=(a+b)∗(b+1)。這個(gè)函數有兩個(gè)操作(函數),加法和乘法。為了指代方便,我們引入兩個(gè)中間變量,c和d。
c=a+b
d=b+1
e=c*d
下面我們把它畫(huà)成一個(gè)計算圖,每一個(gè)操作是圖中一個(gè)節點(diǎn),最基本的變量a和b也是一個(gè)節點(diǎn)。每個(gè)節點(diǎn)和它的輸入變量直接有一條邊。比如d的輸入變量是b,那么d和b直接就有一條邊。
任何一個(gè)顯示定義的函數(隱函數不行,不過(guò)我們定義的神經(jīng)網(wǎng)絡(luò )肯定不會(huì )通過(guò)隱函數來(lái)定義)都可以分解為一個(gè)有向無(wú)環(huán)圖(樹(shù)),其中葉子節點(diǎn)是最基本的無(wú)依賴(lài)的自變量,而中間節點(diǎn)是我們引入的中間變量,而樹(shù)根就是我們的函數。比如上面的例子,計算圖如下所示:

給定每一個(gè)自變量的值,我們可以計算最終的函數值,對應與神經(jīng)網(wǎng)絡(luò )就是feedforward計算。具體用”算法“怎么計算呢?首先因為計算圖是一個(gè)有向無(wú)環(huán)圖,因此我們可以拓撲排序,先是葉子節點(diǎn)a和b,他們的值已經(jīng)給定,然后刪除a和b出發(fā)的邊,然后c和d沒(méi)有任何未知依賴(lài),可以計算,最后計算e。計算過(guò)程如下圖:

計算圖的導數計算
首先我們可以計算每條邊上的導數,也就是邊的終點(diǎn)對起點(diǎn)的導數,而且導數是在起點(diǎn)的取前向計算值時(shí)的導數,具體過(guò)程如圖所示:

有些邊的導數不依賴(lài)于輸入的值,比如:

但是還有很多邊的導數是依賴(lài)于輸入值的,比如:

因為在“前向”計算的過(guò)程中,每個(gè)節點(diǎn)的值都計算出來(lái)了,所以邊的計算很簡(jiǎn)單,也不需要按照什么的順序。
不過(guò)我們一般比較感興趣的是最終函數對某個(gè)自變量的導數,比如

根據鏈式法則,只要找到這兩個(gè)節點(diǎn)的所有路徑,然后把路徑的邊乘起來(lái)就得到這條邊的值,然后把所有邊加起來(lái)就可以了。
比如上面的例子b到e有兩條路徑:b->c->e和b->d->e,所以

如果用“鏈式”法則來(lái)寫(xiě)就是

路徑反過(guò)來(lái)而已。
使用上面的方法,我們可以計算任何一個(gè)點(diǎn)(上面的變量)對另外一個(gè)點(diǎn)(上面的變量)的導數。不過(guò)我們一般的情況是計算樹(shù)根對所有葉子的導數,當然我們可以使用上面的算法一個(gè)一個(gè)計算,但是這樣會(huì )有很多重復的計算。
比如a->e的路徑是a->c->e,b->e有一條邊是b->c->e,其中c->e是重復的【這個(gè)例子不太好,我們可以想像c->e是一條很長(cháng)的路徑】,每次都重復計算c->e這個(gè)“子”路徑是多余的。我們可以從后往前計算,也就是每個(gè)節點(diǎn)都是存放樹(shù)根變量(這個(gè)例子是e)對當前節點(diǎn)的導數(其實(shí)也就是樹(shù)根到當前節點(diǎn)的所有路徑的和)。
反向導數計算

計算流程文字描述如下:
首先還是對這個(gè)圖進(jìn)行拓撲排序,不過(guò)是反過(guò)來(lái)。
首先是

這個(gè)沒(méi)什么好說(shuō)的。
然后計算

然后計算

然后計算

計算

前向導數計算
如果我們需要計算每一個(gè)變量對某一個(gè)變量的導數,就可以使用前向計算的方法。不過(guò)我們的神經(jīng)網(wǎng)絡(luò )都是相反——計算某個(gè)一個(gè)變量(一般是損失函數)對所有變量的導數,所以這里就不詳細介紹了。
至此,本系列文章的第四部分告一段落。在接下來(lái)的文章中,作者將為大家詳細講述關(guān)于Optimization、常見(jiàn)的深度學(xué)習框架/工具的使用方法、使用自動(dòng)求導來(lái)實(shí)現多層神經(jīng)網(wǎng)絡(luò )等內容,敬請期待。