BP算法雙向傳,鏈式求導最纏綿(深度學習入門係列之八)
更多深度文章,請關注:https://yq.aliyun.com/cloud
係列文章:
一入侯門“深”似海,深度學習深幾許(深度學習入門係列之一)
人工“碳”索意猶盡,智能“矽”來未可知(深度學習入門係列之二)
神經網絡不勝語,M-P模型似可尋(深度學習入門係列之三)
“機器學習”三重門,“中庸之道”趨若人(深度學習入門係列之四)
Hello World感知機,懂你我心才安息 (深度學習入門係列之五)
損失函數減肥用,神經網絡調權重(深度學習入門係列之六)
山重水複疑無路,最快下降問梯度(深度學習入門係列之七)
8.1 BP神經網絡極簡史
在神經網絡(甚至深度學習)參數訓練中,BP(Back Propagation)算法非常重要,它都占據舉足輕重的地位。在提及BP算法時,我們常將它與傑弗裏•辛頓(Geoffrey Hinton)的名字聯係在一起。但實際上,辛頓還真不是第一個提出BP算法的人,就像愛迪生不是第一個發明電燈的人一樣。但人們記住的,永遠都是那個讓電燈“飛入平常百姓家”的功勳人物愛迪生,而不是它的第一發明人美國人亨利·戈培爾(Henry Goebel)。
如果說辛頓就是BP算法的“愛迪生”,那誰是BP算法的“戈培爾”呢?他就是保羅·沃伯斯(Paul Werbos)。1974年,沃伯斯在哈佛大學博士畢業。在他的博士論文裏,首次提出了通過誤差的反向傳播來訓練人工神經網絡[1]。事實上,這位沃伯斯不光是BP算法的開創者,他還是循環神經網絡(Recurrent Neural Network,RNN)的早期開拓者之一。在後期的係列入門文章中,我們還會詳細介紹RNN,這裏暫且不表。
說到BP算法,我們通常強調的是反向傳播,但其實呢,它是一個典型的雙向算法。更確切來說,它的工作流程是分兩大步走:(1)正向傳播輸入信號,輸出分類信息(對於有監督學習而言,基本上都可歸屬於分類算法);(2)反向傳播誤差信息,調整全網權值(通過微調網絡參數,讓下一輪的輸出更加準確)。
下麵我們分別舉例,說明這兩個流程。為了簡化問題描述,我們使用如圖8-1所示的最樸素三層神經網絡。在這個網絡中,假設輸入層的信號向量是[-1, 1],輸出層的目標向量為[1, 0],“學習率”η為0.1,權值是隨機給的,這裏為了演示方便,分別給予或“1”或“-1”的值。下麵我們就詳細看看BP算法是如何運作的?

8.2.1正向傳播信息
正向傳播信息,簡單說來,就是把信號通過激活函數的加工,一層一層的向前“蔓延”,直到抵達輸出層。在這裏,假設神經元內部的激活函數為Sigmod(\( f(x) = \frac{1}{{1 + {e^{ - x}}}}\))。之所以選用這個激活函數,主要因為它的求導形式非常簡潔而優美:
$$
f'(x) = f(x)(1 - f(x))\tag{8.1}
$$
事實上,類似於感知機,每一個神經元的功能都可細分兩大部分:(1)匯集各路鏈接帶來的加權信息;(2)加權信息在激活函數的“加工”下,神經元給出相應的輸出,如圖8-2所示。

於是,在正向傳播過程中,對於\(f_1(e)\)神經元的更新如圖8-3所示,其計算過程如下所示:
$$
\begin{array}{l}
{f_1}(e) = {f_1}({w_{11}}{x_1} + {w_{21}}{x_2}) \\
{\rm{ }} = {f_1}(( - 1) \times 1 + 1 \times ( - 1)) \\
{\rm{ }} = {f_1}( - 2) \\
{\rm{ }} = \frac{1}{{1 + {e^{ - ( - 2)}}}} \\
{\rm{ }} = 0.12 \\
\end{array}
$$

接著,在同一層更新\(f_2(e)\)的值,過程和計算步驟類似於\(f_1(e)\),如圖8-4所示:
$$
\begin{array}{l}
{f_2}(e) = {f_2}({w_{12}}{x_1} + {w_{22}}{x_2}) \\
{\rm{ }} = {f_2}(1 \times 1 + 1 \times ( - 1)) \\
{\rm{ }} = {f_2}(0) \\
{\rm{ }} = \frac{1}{{1 + {e^0}}} \\
{\rm{ }} = 0.5\\
\end{array}
$$

接下來,信息正向傳播到下一層(即輸出層),更新神經元3的\(f_3(e)\)(即輸出\(y_1\)的值),如圖8-5所示。
$$
\begin{array}{l}
{y_1} = {f_3}(e) = {f_3}({w_{13}}{f_1} + {w_{23}}{f_2}) \\
{\rm{ }} = {f_3}(1 \times 0.12 + 1 \times 0.5) \\
{\rm{ }} = {f_3}(0.62) \\
{\rm{ }} = \frac{1}{{1 + {e^{ - 0.62}}}} \\
{\rm{ }} = 0.65 \\
\end{array}
$$

然後,類似地,計算同在輸出層求神經元\(f_4(e)\)(即輸出\(y_2\))的值,如圖8-6所示。
$$
\begin{array}{l}
{y_2} = {f_4}(e) = {f_4}({w_{14}}{f_1} + {w_{24}}{f_2}) \\
{\rm{ }} = {f_4}(( - 1) \times 0.12 + 1 \times 0.5) \\
{\rm{ }} = {f_4}(0.38)\\
{\rm{ }} = \frac{1}{{1 + {e^{ - 0.38}}}} \\
{\rm{ }} = 0.59 \\
\end{array}
$$

到此,在第一輪信號前向傳播中,實際輸出向量已計算得到\(y' = {[0.65,0.59]^T}\),但我們預期輸出的向量(即教師信號)是\(y = {[1,0]^T}\),這二者之間是存在“誤差”的。於是,重點來了,下麵我們就用“誤差”信息反向傳播,來逐層調整網絡參數。為了提高權值更新效率,這裏就要用到下文即將提到的“反向模式微分法則(chain rule)”。
8.2.2 求導中的鏈式法則
(砰!砰!砰!敲黑板!請注意:如下部分是BP算法最為精妙之處,值得細細品味!)
在前麵信號正向傳播的示例中,為了方便讀者理解,我們把所有的權值都暫時給予了確定之值。而實際上,這些值都是可以調整的,也就是說其實它們都是變量,除掉圖8-1中的所有確定的權值,把其視為變量,得就到更為一般化的神經網絡示意圖8-7。

這裏為了簡化理解,我們暫時假設神經元沒有激活函數(或稱激活函數為\(y=x\)),於是對於隱含層神經元,它的輸出可分別表示為:
$$
{f_1} = {x_1}{w_{11}} + {x_2}{w_{21}}\\
{f_2} = {x_1}{w_{12}} + {x_2}{w_{22}}
$$
然後,對於輸出層神經元有:
$$
\begin{array}{l}
{f_3} = {f_1}{w_{13}} + {f_2}{w_{23}} \\
= ({x_1}{w_{11}} + {x_2}{w_{21}}){w_{13}} + ({x_1}{w_{12}} + {x_2}{w_{22}}){w_{23}} \\
= {x_1}{w_{11}}{w_{13}} + {x_2}{w_{21}}{w_{13}} + {x_1}{w_{12}}{w_{23}} + {x_2}{w_{22}}{w_{23}} \\
\end{array}
$$
$$
\begin{array}{l}
{f_4} = {f_1}{w_{14}} + {f_2}{w_{24}} \\
= ({x_1}{w_{11}} + {x_2}{w_{21}}){w_{14}} + ({x_1}{w_{12}} + {x_2}{w_{22}}){w_{24}} \\
= {x_1}{w_{11}}{w_{14}} + {x_2}{w_{21}}{w_{14}} + {x_1}{w_{12}}{w_{24}} + {x_2}{w_{22}}{w_{24}} \\
\end{array}
$$
於是,損失函數\(L\)可表示為公式(8.2):
$$L({w_{11}},{w_{12}},...,{w_{ij}},...,{w_{mn}}) \\
= \frac{1}{2}{({y_i} - {f_i}({w_{11}},{w_{12}},...,{w_{ij}},...,{w_{mn}}))^2}\tag{8.2}
$$
這裏\(Y\)為預期輸出值向量(由\(y_1,y_2,...,y_i,...\)等元素構成),實際輸出向量為\({f_i}({w_{11}},{w_{12}},...,{w_{ij}},...,{w_{mn}})\)。對於有監督學習而言,在特定訓練集合下,輸入元素\(x_i\)和預期輸出\(y_i\)都可視為常量。由此可以看到,損失函數\(L\),在本質上,就是一個單純與權值\(w_{ij}\)相關的函數(即使把原本的激活函數作用加上去,除了使得損失函數的形式表現得更加複雜外,並不影響這個結論)。
於是,損失函數\(L\)梯度向量可表示為公式(8.3):
$$\begin{array}{l}
\nabla L = (\frac{{\partial L}}{{\partial {w_{11}}}},\frac{{\partial L}}{{\partial {w_{12}}}},...,\frac{{\partial L}}{{\partial {w_{mn}}}}) \\
{\rm{ }} = \frac{{\partial L}}{{\partial {w_{11}}}}{e_{11}} + \frac{{\partial L}}{{\partial {w_{12}}}}{e_{12}} + ... + \frac{{\partial L}}{{\partial {w_{mn}}}}{e_{mn}} \\
\end{array}\tag{8.3}
$$
其中,這裏的\(e_{ij}\)是正交單位向量。為了求出這個梯度,需要求出損失函數\(L\)對每一個權值\(w_{ij}\)的偏導數。
BP算法之所以經典,部分原因在於,它是求解這類“層層累進”的複合函數偏導數的利器。為啥這麼說呢?下麵,我們就列舉一個更為簡化但不失一般性的例子來說明這個觀點(以下案例參考了Chris Olah的博客文章[3])。
假設有如下一個三層但僅僅包括\(a\)、\(b\)、\(c\)、\(d\)和\(e\)等5個神經元的網絡,在傳遞過程中,\(c\)、\(d\)和\(e\)神經元對輸入信號做了簡單的加工,如圖8-8所示。

假設變量\(a\)影響\(c\),此時我們想弄清楚\(a\)是如何影響\(c\)的。於是我們考慮這麼一個問題,如果\(a\)變化一點點,那麼\(c\)是如何變化的呢?我們把這種影響關係定義為變量\(c\)相對於變量\(a\)的偏導數,記做\(\frac{{\partial c}}{{\partial a}}\)。
利用高等數學的知識,我們很容易求得,對於直接相連的神經元(如\(a\)對\(c\),或\(b\)對\(d\)),可利用“加法規則”或“乘法規則”直接求出。例如,利用加法規則,\(\frac{{\partial c}}{{\partial a}}\)可表示為:
$$\frac{{\partial c}}{{\partial a}} = \frac{{\partial (a + b)}}{{\partial a}} = \frac{{\partial a}}{{\partial a}} + \frac{{\partial b}}{{\partial a}} = 1
$$
而對於表達式為乘法的求偏導規則為:
$$
\frac{\partial }{{\partial u}}uv = u\frac{{\partial v}}{{\partial u}} + v\frac{{\partial u}}{{\partial u}} = v
$$
那麼,對於間接相連的神經元,比如\(a\)對\(e\),如果我們也想知道\(a\)變化一點點時\(e\)變化多少,怎麼辦呢?也就是說,偏導數\(\frac{{\partial e}}{{\partial a}}\)該如何求呢?這時,我們就需要用到鏈式法則了。
這裏假設\(a=2\),\(b=1\)。如果\(a\)的變化速率是1,那麼\(c\)的變化速率也是1(因為\(\frac{{\partial c}}{{\partial a}}=1\))。類似地,如果\(c\)的變化速率為1,那麼\(e\)的變化速率為2(因為\(\frac{{\partial e}}{{\partial c}}=d=2\))。所以相對於\(a\)變化1,\(e\)的變化為\(1 \times 2 = 2\)。這個過程就是我們常說的“鏈式法則”,其更為形式化的表達為(如圖8-9所示):
$$\frac{{\partial e}}{{\partial a}} = \frac{{\partial e}}{{\partial c}} \cdot \frac{{\partial c}}{{\partial a}} = d \times 1 = 2 \times 1 = 2
$$

\(a\)對\(e\)的“影響”屬於單路徑的影響,還比較容易求得,但這並不是我們關注的重點。因為在神經網絡中,神經元對神經元的連接,阡陌縱橫,其影響也是通過多條路徑“交織”在一起的。在圖8-9中,我們研究一下\(b\)對\(e\)的影響,就能比較好理解這一工作機理。顯然,\(b\)對\(e\)的影響,也可表達為一個偏導關係:
$$\begin{array}{l}
\frac{{\partial e}}{{\partial b}} = \frac{{\partial cd}}{{\partial b}} = d\frac{{\partial c}}{{\partial b}} + c\frac{{\partial d}}{{\partial b}} \\
= d \times 1 + c \times 1 \\
= 2 \times 1 + 3 \times 1 \\
= 5 \\
\end{array}$$
從圖8-9可以看出,\(b\)對\(e\)影響,其實是“兵分兩路”:(1)\(b\)通過影響\(c\),然後通過\(c\)影響\(e\);(2)\(b\)通過影響\(d\),然後通過\(d\)影響\(e\)。這就是多維變量(這裏“多”僅為2)鏈式法則的“路徑加和”原則。
這個原則,看起來簡單明了,但其實蘊藏著巨大代價。因為當網絡結構龐大時,這樣的“路徑加和”原則,很容易產生組合爆炸問題。例如,在如圖8-10所示的有向圖中,如果\(X\)到\(Y\)有三條路徑(即\(X\)分別以\(\alpha\)、\(\beta\)和\(\chi \)的比率影響\(Y\)),\(Y\)到\(Z\)也有三條路徑(\(Y\)分別以\(\delta \)、\(\varepsilon\)和\(\xi \)的比率影響\(Z\))。

於是,很容易根據路徑加和原則得到\(X\)對\(Z\)的偏導數:
$$\begin{array}{l}
\frac{{\partial Z}}{{\partial X}} = (\alpha \delta + \alpha \varepsilon + \alpha \xi ) + \\
{\rm{ (}}\beta \delta + \beta \varepsilon + \beta \xi ) + \\
{\rm{ (}}\chi \delta + \chi \varepsilon + \chi \xi ) \\
\end{array}\tag{8.4}
$$
上麵用到的求偏導數方法,可稱之為“前向模式微分(forward-mode differentiation)”,如圖8-11-(a)所示。當網絡結構簡單時,即使\(X\)到\(Z\)的每一個路徑都被“臨幸(遍曆)”一遍,總共才有 \(3 \times 3 = 9\) 條路徑,但一旦網絡結構的複雜度上去了,這種“前向模式微分”,就會讓求偏導數的次數和神經元個數的平方成正比。這個計算量,就很可能是成為機器“難以承受的計算之重”。
有道是“東方不亮西方亮”。為了避免這種海量求導模式,數學家們另辟蹊徑,提出了一種稱之為“反向模式微分(reverse-mode differentiation)”。取代公式(8.4)的那種簡易的表達方式,我們用公式(8.5)的表達方式來求\(X\)對\(Z\)的偏導:
$$
\frac{{\partial Z}}{{\partial X}} = (\alpha + \beta + \xi )(\delta + \varepsilon + \xi )\tag{8.5}
$$
或許你會不屑一顧,這又是在搞什麼鬼?把公式(8.4)恒等變換為公式(8.5)又有什麼用呢?

你可別急,這背後大有玄機,且聽我慢慢道來。
前文提到的前向模式微分方法,其實就是我們在高數課堂上學習的求導方式。在這種求導模式中,強調的是某一個輸入(比如\(X\))對某一個節點(如神經元)的影響。因此,在求導過程中,偏導數的分子部分,總是根據不同的節點總是不斷變化,而分母則鎖定為偏導變量“\(\partial X\)”,保持定不變(見圖8-11-(a))。
相比而言,反向模式微分方法則有很大不同。首先在求導方向上,它是從輸出端(output)到輸入端進行逐層求導。其次,在求導方法上,它不再是對每一條“路徑”加權相乘然後求和,而是針對節點采納“合並同類路徑”和“分階段求解”的策略。
拿8-11-(b)的例子來說,先求\(Y\)節點對\(Z\)節點的"總影響"(反向第一層):
$$
\frac{{\partial Z}}{{\partial Y}} = \delta + \varepsilon + \xi
$$
然後,再求節點\(X\)對節點\(Z\)的總影響(反向第二層):
$$
\frac{{\partial {\rm{Z}}}}{{\partial X}} = \frac{{\partial {\rm{Z}}}}{{\partial Y}}\frac{{\partial Y}}{{\partial X}} = (\delta + \varepsilon + \xi )(\alpha + \beta + \chi )
$$
特別需要注意的是,\( \frac{{\partial {\rm{Z}}}}{{\partial Y}} \)已經在第一層求導得到。在第二層僅僅需要求得\( \frac{{\partial {\rm{Y}}}}{{\partial X}} \),而\( \frac{{\partial {\rm{Y}}}}{{\partial X}} \) 容易求得\( (\alpha + \beta + \chi ) \),然後二者相乘即可得到所求。這樣一來,就大大減輕了第二層的求導負擔。在求導形式上,偏導數的分子部分(節點)不變,而分母部分總是隨著節點不同而變化,即\([\frac{{\partial Z}}{\partial }]\)。
這樣說來說去,好像還是不太明白!下麵我們還是用圖8-9所示的原始例子,對比二者的求導過程,一遍走下來,有了感性認識,你就能明白其中的差異。為了進一步方便讀者理解,我們將圖8-9重新繪製為圖8-12的樣子。

以求變量\(b\)偏導數的流程為例,我們先用前向模式微分法,來說明這種方法的求導過程。根據加法規則,對於求偏導值\(\frac{{\partial e}}{{\partial b}}\)的步驟可以分兩步走:(1)求得所有輸入(包括\(a\)和\(b\))到終點\(e\)的每條路徑上的偏導值乘積;(2)對所有條路徑的導數值進行加和操作。
從8-12所示的圖中,對於兩個輸入\(a\)和\(b\),它們共有3條路徑抵達終點\(e\)(分別計為①、②和③)。
對於第①條路徑而言,輸入\(a\)對\(e\)的影響為:
$$\frac{{\partial e}}{{\partial b}} = 0 \times 1 \times 1 \times 2 = 0$$
對於第②條路徑而言,輸入\(b\)對\(e\)的影響為:
$$\frac{{\partial e}}{{\partial b}} = 1 \times 1 \times 1 \times 2 = 2$$
對於第③條路徑而言,輸入\(b\)對\(e\)的影響為:
$$\frac{{\partial e}}{{\partial b}} = 1 \times 1 \times 1 \times 3 = 3$$
所以在整體上,輸入\(a\)和\(b\)從三條路徑上對e施加的“總影響”為:0+2+3=5.
或許讀者已經注意到了,有些路徑已經被冗餘遍曆了,比如在圖8-12所示中,\(a \to c \to e\)(第①條路)和\(b \to c \to e\)(第②條路)就都走了路徑\(c \to e\)。
這些局部性的冗餘也就罷了,更為“惡劣”的是,對於求\(\frac{{\partial e}}{{\partial a}}\),上述三條路徑,它們同樣還得“一個都不能少”地跑一遍,如果求得的變量多了,這到底得有多少冗餘啊!
可能你會疑問,對於\(\frac{{\partial e}}{{\partial b}}\)(\(\frac{{\partial e}}{{\partial a}}\)),第①(③)條路徑明明可以不走的嘛?這種明智,是對人的觀察而言的,而且是對於簡單網絡而言的。因為,如果網絡及其複雜,人們可能就沒有這麼“慧眼識珠”,識別其中的路徑冗餘。
此外,對於計算機而言,有些時候,局部操作的“優化”,相對於整體操作的“規範化”,頂多算得上“奇淫巧技”,其優勢可謂是“蕩然無存”。有過大規模並行編程經驗的讀者,可能對這個觀點會有更深的認知。
然而,同樣是利用鏈式法則,反向模式微分方法就能非常機智地避開了這種冗餘(下麵即將講到的BP算法,正是由於這麼幹,才有其優勢的)。在這種方法中,它能做到對每一條路徑隻“臨幸”一次,這是何等的節儉!下麵我們來看看它是如何工作的。

相比於“前向模式微分法”是以輸入(如圖8-13-(a)所示的\(a\)和\(b\))為錨點,正向遍曆每一條可能的路徑。反向模式微分法是以節點(或說神經元,如圖8-13-(a)所示的\(e\)、\(c\)和\(d\))為錨點,逐層分階段求導,然後匯集每一個節點的外部路徑(合並同類路徑)。
如圖8-13-(b)所示,在反向求導的第1層,對於節點\(c\)有:
$$
\frac{{\partial e}}{{\partial c}} = \frac{{\partial (c \times d)}}{{\partial c}} = d = 2
$$
類似的,對於節點\(d\)有:
$$
\frac{{\partial e}}{{\partial d}} = \frac{{\partial (c \times d)}}{{\partial d}} = c = 3
$$
在階段性的求解完畢第一層的導數之後,下麵開始求解第二層神經元變量的偏導。如圖8-13-(c)所示,在反向第2層,對於節點\(a\)有如圖8-14-(Ⅰ)所示的求導模式。

特別需要注意的是,8-14-(Ⅰ)所示的表達式“\(\frac{{\partial e}}{{\partial c}}\frac{{\partial c}}{{\partial a}}\)”中左部“\(\frac{{\partial e}}{{\partial c}}\)”,已經在第1層求解過了,並“存儲”在神經元\(c\)中。此時,采用“拿來主義”,拿來就能用!這就是反向模式微分的精華所在!
類似地,在反向求導第2層,對於節點\(b\),由於它匯集“兩路兵馬”的影響,所以需要合並同類路徑,有如圖8-14-(Ⅱ)所示結果。
這樣一來,如圖8-13反向模式微分方法,每個路徑僅僅遍曆一次,就可以求得所有輸出(如\(e\)節點)對輸入(如\(a\)或\(b\)節點)的偏導,幹淨利落,沒有任何冗餘!
在第七章中,我們曾提到,“BP算法把網絡權值糾錯的運算量,從原來的與神經元數目的平方成正比,下降到隻和神經元數目本身成正比。”其功勞,正是得益於這個反向模式微分方法節省的計算冗餘
8.2.3 誤差反向傳播
有了前麵“鏈式求導”的知識鋪墊,下麵我們就來細細講解誤差反向傳播的過程。鑒於我們的係列文章是寫給初學者(實踐者)看的,下麵我們盡量省略了其中較為複雜的推導公式,對該部分感興趣的讀者可參閱卡內基梅隆大學Tom Mitchell教授的經典著作《機器學習》[3](對公式不感冒的讀者,第一遍閱讀可以直接跳過公式,直達圖文解釋部分)。
誤差反向傳播通過梯度下降算法,迭代處理訓練集合中的樣例,一次處理一個樣例。對於樣例\(d\),如果它的預期輸出(即教師信號)和實際輸出有“誤差”,BP算法抓住這個誤差信號\(L_d\),以“梯度遞減”的模式修改權值。也就是說,對於每個訓練樣例\(d\),權值\({w_{ji}}\)的校正幅度為\(\Delta {w_{ji}}\)(需要說明的是,\({w_{ji}}\)和\({w_{ij}}\)其實都是同一個權值,\({w_{ji}}\)表示的是神經元\(j\)的第\(i\)個輸入相關的權值,這裏之所以把下標“\(j\)”置於“\(i\)”之前,僅僅表示這是一個反向更新過程而已):
$$
\Delta {w_{ji}} = - \eta \frac{{\partial {L_d}}}{{\partial {w_{ji}}}}\tag{8.6}
$$
在這裏,\(L_d\)表示的是訓練集合中樣例\(d\)的誤差,分解到輸出層的所有輸出向量,\(L_d\)可表示為:
$$
{L_d}(w) = \frac{1}{2}\sum\limits_{j \in outputs} {({y_j} - y_{j}^{'}} {)^2}\tag{8.7}
$$
其中:
\(y_j\)表示的是第\(j\)個神經單元的預期輸出值。
\(y^{'}_{j}\)表示的\(j\)個神經單元的實際輸出值。
\(outputs\)的範圍是網絡最後一層的神經元集合。
下麵我們推導出\(\frac{{\partial {L_d}}}{{\partial {w_{ji}}}}\)的一個表達式,以便在公式(8.7)中使用梯度下降規則。首先,我們注意到,權值\(w_{ji}\)僅僅能通過\(net_j\)影響其他相連的神經元。因此利用鏈式法則有:
$$
\begin{array}{l}
\frac{{\partial {L_d}}}{{\partial {w_{ji}}}} = \frac{{\partial {L_d}}}{{\partial ne{t_j}}}\frac{{\partial ne{t_j}}}{{\partial {w_{ji}}}} \
{\rm{ }} = \frac{{\partial {L_d}}}{{\partial ne{t_j}}}{x_{ji}} \
\end{array}\tag{8.8}
$$
在這裏,\(ne{t_j} = \sum\nolimits_i {{w_{ji}}{x_{ji}}} \),也就是神經元\(j\)輸入的加權和。\(x_{ji}\)表示的神經\(j\)的第\(i\)個輸入。需要注意的是,這裏的\(x_{ji}\)是個統稱,實際上,在反向傳播過程中,在經曆輸出層、隱含層和輸入層時,它的標記可能有所不同。
由於在輸出層和隱含層的神經元對“糾偏”工作,承擔的“責任”是不同的,至少是形式不同,所以需要我們分別給出推導。
(1)在輸出層,對第\(i\)個神經元而言,省略部分推導過程,公式(8.8)的左側第一項為:
$$
\frac{{\partial {L_d}}}{{\partial ne{t_j}}} = ({y_j} - y_{j}^{'})y_{j}^{'}(1 - y_{j}^{'})\tag{8.9}
$$
為了方便表達,我們用該神經元的糾偏“責任(responsibility)”\(\delta _j^{(1)}\)描述這個偏導,即:
$$
\delta _{j}^{(1)} = \frac{{\partial {L_d}}}{{\partial ne{t_j}}} \tag{8.10}
$$
這裏\(\delta _{j}^{(1)}\)的上標“(1)”,表示的是第1類(即輸出層)神經元的責任。如果上標為“(2)”,則表示第2類(即隱含層)神經元的責任,見下麵的描述。
(2)對隱含層神經元\(j\)的梯度法則(省略了部分推導過程),有:

其中:
\(f_j\)表示神經單元\(j\)的計算輸出。
\( net_j \)表示的是神經單元\(j\)的加權之和。
\( Downstream(j) \)表示的是在網絡中神經單元\(j\)的直接下遊單元集合。
隱含層神經元的糾差職責,是通過計算前一步輸出神經元的“責任”來實現的。
這裏說的每層神經元“責任”,或者更為確切來說是“糾偏責任”,其實就是在8.2.2節講到的“分階段求解”策略。
在明確了各個神經元“糾偏”的職責之後,下麵就可以依據類似於感知機學習,通過如下加法法則更新權值:
對於輸出層神經元有:
$$
w_{ji}^{(1)} = w_{ji}^{(1)} + \eta \Delta w_{ji}^{(1)} \\
= w_{ji}^{(1)} + \eta \delta _i^{(1)}{h_j} \tag{8.12}
$$
對於隱含層神經元有:

在這裏,\(\eta \in (0,1)\)表示學習率。在實際操作過程中,為了防止錯過極值,\(\eta\)通常取小於0.1的值。\(h_j\)為神經元j的輸出。\(x_{jk}\)表示的是神經單元\(j\)的第\(k\)個輸入。
上麵的公式依然比較抽象,難以理解。下麵我們還是以前麵的神經網絡拓撲結構為例,用實際運算過程給予詳細說明,以期望給與讀者感性認識。
從上麵的描述可以得知,針對輸出層的神經元3,它的輸出值\(y_{1}^{'}\)為0.65,而期望輸出值\(y_1\)為1,二者存在“誤差”:\({ e_1} = {y_1} - y_{1}^{'} = 1 - 0.65 = 0.35 \)。
在這裏,我們把每個神經元根據誤差調參的“責任”記為\(\delta \),那麼,根據公式(8.9)和(8.10),神經元3的“責任”可表示為:


從上麵分析可知,我們很容易計算出\( \delta _{3}^{(1)} \)的值:

於是,可以反向更新\(w_{31}^{(1)}\)的權值為:

在這裏,(具體推導見公式8.8-8.10),\(\eta \)為學習率,此處取值為0.1。\(f_1\)為神經元1的輸出(即\(y_{1}^{'}\))。
類似地,我們可以反向更新\(w_{_{32}}^{(1)}\))的權值:
$$\begin{array}{l}
w_{32}^{(1)} = w_{32}^{(1)} + \eta \Delta w_{32}^{(1)} \\
{\rm{ }} = w_{32}^{(1)} + \eta \delta _3^{(1)}{f_2} \\
{\rm{ }} = 1 + 0.1 \times 0.0796 \times 0.5 \\
{\rm{ }} = 1.00398 \\
\end{array}$$
同樣的操作,我們可以計算出\(\delta _4^{(1)}\)的值,如圖8-16所示。

從而可以反向更新\(w_{41}^{(1)}\)的權值:
$$\begin{array}{l}
w_{41}^{(1)} = w_{41}^{(1)} + \eta \Delta w_{41}^{(1)} \\
{\rm{ }} = w_{41}^{(1)} + \eta \delta _4^{(1)}{f_1} \\
{\rm{ }} = - 1 + 0.1 \times ( - 0.1427) \times 0.12 \\
{\rm{ }} = - 1.0017 \\
\end{array}$$
類似地,我們可以反向更新\(w_{42}^{(1)}\)的權值:
$$\begin{array}{l}
w_{42}^{(1)} = w_{42}^{(1)} + \eta \Delta w_{42}^{(1)} \\
{\rm{ }} = w_{42}^{(1)} + \eta \delta _4^{(1)}{f_2} \\
{\rm{ }} = 1 + 0.1 \times ( - 0.1427) \times 0.5 \\
{\rm{ }} = 0.9929 \\
\end{array}$$
在反向更新完畢輸出層的權值後,下麵。我們開始反向更新隱含層的網絡權值,示意圖如圖8-17所示。

如果我們把反向傳播誤差的“職責(即\({\delta _j}\))”,也看做一種特殊信息的話,那麼在隱藏層的每個神經元都會有一個加權和影響,記為\({\Delta _j}\),實際上,這裏的\({\Delta _j}\),就是公式(8.11)的加權求和\(Downstream(j)\)(其實也就是8.2.2所提及的“合並同類路徑”)。
對於隱含層神經1,則有:

有了這個權值影響,我們就可以很容易計算出神經元1承擔的“責任”\(\delta _{_1}^{(2)}\):
$$
\begin{array}{l}
\delta _{_1}^{(2)} = {f_1}(1 - {f_1}){\Delta _1} \\
= 0.12 \times (1 - 0.12) \times 0.2223 \\
= - 0.0235 \\
\end{array}
$$
在計算出計算神經元1承擔的“責任”之後,我們就可以更新與神經元1相連的兩個輸入變量權值:

類似的流程(示意圖如圖8-18所示),可以求得神經元2的累計加權影響有:


於是,計算神經元2承擔的“責任”\(\delta _2^{(2)}\):
$$
\begin{array}{l}
\delta _{_2}^{(2)} = {f_2}(1 - {f_2}){\Delta _2} \\
= 0.5 \times (1 - 0.5) \times ( - 0.0631) \\
= 0.0158 \\
\end{array}
$$
同樣,計算出計算神經元2承擔的“責任”之後,我們就可以更新與神經元2相連的兩個輸入變量權值:

從上麵的推導過程,我們可以看到,經過一輪的誤差逆傳播,神經網絡的權值前後確有不同。但由於學習率(即步長)較小(為0.1),所以前後的權值變化並不大(括號內的數值為原始權值),如圖8-19所示。

如此一來,整個網絡的權值就全部得以更新。接下來,網絡就可接受下一個訓練樣例,接著往下訓練了,直到輸出層的誤差小於預設的容忍度。
BP算法,在很多場所的確非常有用。例如,1989年,Yann Lecun(又一位當下的深度學習大牛)等人就用BP算法,在手寫郵政編碼識別上有著非常成功的應用[5],訓練好的係統,手寫數字錯誤率隻有5%。Lecun借此還申請了美國專利,開了公司,發了一筆小財。
在發表BP算法之後的30年,2006年,辛頓等人在發表的有關“深度信念網”的經典論文中指出[8],深度信念網(DBN)的組成元件就是受限玻爾茲曼機 (Restricted Boltzmann Machines, RBM)。而DBN的構建其實分兩步走的:(1)單獨“無監督”地訓練每一層RBM網絡,以確保特征向量在映射到不同特征空間時,能夠盡可能多地保留特征信息;(2)在DBN的最後一層,設置BP網絡,用以接收RBM的輸出特征向量作為它的輸入特征向量,然後“有監督”地訓練實體關係分類器,對網絡權值實施微調(Fine-Tune)。
現在你看到了,BP算法的影響力,一直滲透到“深度學習”骨子裏!這就是為什麼在講深度學習時,我們繞不過BP算法的原因。
8.4 小結
在本章中,我們詳細解釋了反向傳播(BP)算法,通過學習我們知道,BP算法其實並不僅僅是個反向算法,而是一個雙向算法。也就是說,它其實是分兩大步走:(1)正向傳播信號,輸出分類信息;(2)反向傳播誤差,調整網絡權值。如果沒有達到預期目的,重走回頭路(1)和(2)。
BP算法很成功。但我們也要看到BP算法的不足,比如說會存在“梯度擴散(Gradient Diffusion)”現象,其根源在於對於非凸函數,梯度一旦消失,就沒有指導意義,導致它可能限於局部最優。而且“梯度擴散”現象會隨著網絡層數增加而愈發嚴重,也就是說,隨著梯度的逐層消減,導致它對調整網絡權值的調整效益,作用越來越小,故此BP算法多用於淺層網絡結構(通常小於等於3),這就限製了BP算法的數據表征能力,從而也就限製了BP的性能上限。
再比如說,雖然相比於原生態的BP算法,雖然它降低了網絡參數的訓練量,但其網絡參數的訓練代價還是不小,耗時非常“可觀”。就拿LeCun的識別手寫郵編的案例說事,其訓練耗時就達3天之久。
再後來,與LeCun同在一個貝爾實驗室的同事Vladimir Vapnik(弗拉基米爾·萬普尼克),提出並發揚光大了支持向量機 (Support Vector Machine) 算法。
SVM作為一種分類算法,對於線性分類,自然不在話下。在數據樣本線性不可分時,它使用了所謂“核機製(kernel trick)”,將線性不可分的樣本,映射到高維特征空間 (high-dimensional feature space),從而使其線性可分。自上世紀九十年代初開始,SVM逐漸大顯神威,在圖像和語音識別等領域,獲得了廣泛而成功的應用。
在手寫郵政編碼的識別問題上,LeCun利用BP算法,把錯誤率整到5%左右,而SVM在1998年就把錯誤率降到低至0.8%。這遠超越同期的傳統神經網絡算法。
就這樣,萬普尼克又把神經網絡研究送到了一個新的低潮!
在下一章中,我們將來聊聊“卷積神經網絡”,這可是深度學習發展過程中的一個重要裏程碑,希望你能關注。
8.5 請你思考
通過本章的學習,請你思考如下問題:
(1)正是由於神經網絡具有強大的表示能力,“成也蕭何,敗也蕭何”,BP算法常常遭遇“過擬合(overfitting)”,它可能會把噪音當做有效信號,你知道有什麼策略來避免過擬合嗎?
(2)利用梯度遞減策略,BP算法常停止於局部最優解,而非全局最優解,這好比“隻因身在此山中”,卻不知“人外有人,山外有山”,你知道有什麼方法可以改善這一狀況嗎?
(3)在BP算法流程中,我們看到的是反反複複的權值調整,而傑弗裏•辛頓在文獻[4]中提到的特征表示(representation),體現在什麼地方?
【參考文獻】
[1] Paul J. Werbos. Beyond Regression: New Tools for Prediction and Analysis in the Behavioral Sciences. PhD thesis, Harvard University, 1974
[2] Christopher Olah. Calculus on Computational Graphs: Backpropagation
[3]Tom Mitchell著.曾華軍等譯. 機器學習. 機器工業出版社. 2007.4
[4] Williams D, Hinton G. Learning representations by back-propagating errors[J]. Nature, 1986, 323(6088): 533-538.
[5] LeCun Y, Boser B, Denker J S, et al. Backpropagation applied to handwritten zip code recognition[J]. Neural computation, 1989, 1(4): 541-551.
[6]周誌華. 機器學習. 清華大學出版社. 2016.1
[7] Mirosav Kubat著. 王勇等譯. 機器學習導論. 機械工業出版社. 2016.11
[8] Hinton G E, Osindero S, Teh Y W. A fast learning algorithm for deep belief nets[J]. Neural computation, 2006, 18(7): 1527-1554.
文章作者:張玉宏,著有《品味大數據》一書。聯係郵件:zhangyuhong001@gmail.com
審校:我是主題曲哥哥。
推薦閱讀
一入侯門“深”似海,深度學習深幾許(深度學習入門係列之一)
人工“碳”索意猶盡,智能“矽”來未可知(深度學習入門係列之二)
神經網絡不勝語, M-P模型似可尋(深度學習入門係列之三)
“機器學習”三重門,“中庸之道”趨若人(深度學習入門係列之四)
Hello World感知機,懂你我心才安息(深度學習入門係列之五)
損失函數減肥用,神經網絡調權重(深度學習入門係列之六)
山重水複疑無路,最快下降問梯度(深度學習入門係列之七)
BP算法雙向傳,鏈式求導最纏綿(深度學習入門係列之八)
全麵連接困何處,卷積網絡見解深(深度學習入門係列之九)
卷地風來忽吹散,積得飄零美如畫(深度學習入門係列之十)
局部連接來減參,權值共享肩並肩(深度學習入門係列之十一)
##(未完待續)
最後更新:2017-08-13 22:31:05