在上一章,我們看到了神經(jīng)網(wǎng)絡(luò)如何使用梯度下降算法來學(xué)習(xí)他們自身的權(quán)重和偏差。但是,這里還留下了一個(gè)問題:我們并沒有討論如何計(jì)算代價(jià)函數(shù)的梯度。這是很大的缺失!在本章,我們會(huì)解釋計(jì)算這些梯度的快速算法,也就是反向傳播。
反向傳播算法最初在 1970 年代被發(fā)現(xiàn),但是這個(gè)算法的重要性直到 David Rumelhart、Geoffrey Hinton 和 Ronald Williams 的 1986年的論文 中才被真正認(rèn)可。這篇論文描述了對(duì)一些神經(jīng)網(wǎng)絡(luò)反向傳播要比傳統(tǒng)的方法更快,這使得使用神經(jīng)網(wǎng)絡(luò)來解決之前無法完成的問題變得可行?,F(xiàn)在,反向傳播算法已經(jīng)是神經(jīng)網(wǎng)絡(luò)學(xué)習(xí)的重要組成部分了。
本章在全書的范圍內(nèi)要比其他章節(jié)包含更多的數(shù)學(xué)內(nèi)容。如果你不是對(duì)數(shù)學(xué)特別感興趣,那么可以跳過本章,將反向傳播當(dāng)成一個(gè)黑盒,忽略其中的細(xì)節(jié)。那么為何要研究這些細(xì)節(jié)呢?
答案當(dāng)然是理解。反向傳播的核心是對(duì)代價(jià)函數(shù) $$C$$ 關(guān)于 $$w$$ (或者 $$b$$)的偏導(dǎo)數(shù) $$\partial C/\partial w$$ 的計(jì)算表示。該表示告訴我們?cè)跈?quán)重和偏差發(fā)生改變時(shí),代價(jià)函數(shù)變化的快慢。盡管表達(dá)式會(huì)有點(diǎn)復(fù)雜,不過里面也包含一種美感,就是每個(gè)元素其實(shí)是擁有一種自然的直覺上的解釋。所以反向傳播不僅僅是一種學(xué)習(xí)的快速算法。實(shí)際上它還告訴我們一些細(xì)節(jié)的關(guān)于權(quán)重和偏差的改變影響整個(gè)網(wǎng)絡(luò)行為方面的洞察。因此,這也是學(xué)習(xí)反向傳播細(xì)節(jié)的重要價(jià)值所在。
如上面所說,如果你想要粗覽本章,或者直接跳到下一章,都是可以的。剩下的內(nèi)容即使你是把反向傳播看做黑盒也是可以掌握的。當(dāng)然,后面章節(jié)中也會(huì)有部分內(nèi)容涉及本章的結(jié)論,所以會(huì)常常給出本章的參考。不過對(duì)這些知識(shí)點(diǎn),就算你對(duì)推導(dǎo)的細(xì)節(jié)不太清楚你還是應(yīng)該要理解主要的結(jié)論的。
在討論反向傳播前,我們先熟悉一下基于矩陣的算法來計(jì)算網(wǎng)絡(luò)的輸出。事實(shí)上,我們?cè)谏弦徽碌淖詈笠呀?jīng)能夠看到這個(gè)算法了,但是我在那里很快地略過了,所以現(xiàn)在讓我們仔細(xì)討論一下。特別地,這樣能夠用相似的場景幫助我們熟悉在反向傳播中使用的矩陣表示。
我們首先給出網(wǎng)絡(luò)中權(quán)重的清晰定義。我們使用 $$w_{jk}^l$$ 表示從 $$(l-1)^{th}$$ 層的 $$k^{th}$$ 個(gè)神經(jīng)元到 $$(l)^{th}$$ 層的 $$l^{th}$$ 個(gè)神經(jīng)元的鏈接上的權(quán)重。例如,下圖給出了第二隱藏層的第四個(gè)神經(jīng)元到第三隱藏層的第二個(gè)神經(jīng)元的鏈接上的權(quán)重:
http://wiki.jikexueyuan.com/project/neural-networks-and-deep-learning-zh-cn/images/3.png" alt="" />
這樣的表示粗看比較奇怪,需要花一點(diǎn)時(shí)間消化。但是,后面你會(huì)發(fā)現(xiàn)這樣的表示會(huì)比較方便也很自然。奇怪的一點(diǎn)其實(shí)是下標(biāo) $$j$$ 和 $$k$$ 的順序。你可能覺得反過來更加合理。但我接下來會(huì)告訴你為什么要這樣做。
我們對(duì)網(wǎng)絡(luò)偏差和激活值也會(huì)使用類似的表示。顯式地,我們使用 $$b_J^l$$ 表示在 $$l^{th}$$ 層 $$j^{th}$$ 個(gè)神經(jīng)元的偏差,使用 $$a_j^l$$ 表示 $$l^{th}$$ 層 $$j^{th}$$ 個(gè)神經(jīng)元的激活值。下面的圖清楚地解釋了這樣表示的含義:
http://wiki.jikexueyuan.com/project/neural-networks-and-deep-learning-zh-cn/images/4.png" alt="" />
有了這些表示, $$l^{th}$$ 層的 $$j^{th}$$ 個(gè)神經(jīng)元的激活值 $$a_j^l$$ 就和 $$l^{th}$$ 層關(guān)聯(lián)起來了(對(duì)比公式(4) 和上一章的討論)
http://wiki.jikexueyuan.com/project/neural-networks-and-deep-learning-zh-cn/images/5.png" alt="" />
其中求和是在 $$(l-1)^{th}$$ 層的所有神經(jīng)元上進(jìn)行的。為了用矩陣的形式重寫這個(gè)表達(dá)式,我們對(duì)每一層 $$l$$ 都定義一個(gè)權(quán)重矩陣 $$w^l$$,在 $$j^{th}$$ 行第$$k^{th}$$ 列的元素是 $$w_{jk}^l$$。類似的,對(duì)每一層 $$l$$,定義一個(gè)偏差向量,$$b^l$$。你已經(jīng)猜到這些如何工作了——偏差向量的每個(gè)元素其實(shí)就是前面給出的 $$b_j^l$$,每個(gè)元素對(duì)應(yīng)于 $$l^{th}$$ 層的每個(gè)神經(jīng)元。最后,我們定義激活向量 $$a^l$$,其元素是那些激活值 $$a_j^l$$。
最后我們需要引入向量化函數(shù)(如 $$\sigma$$)來按照矩陣形式重寫公式(23) 。在上一章,我們其實(shí)已經(jīng)碰到向量化了,其含義就是作用函數(shù)(如 $$\sigma$$)到向量 $$v$$ 中的每個(gè)元素。我們使用 $$\sigma(v)$$ 表示這種按元素進(jìn)行的函數(shù)作用。所以,$$\sigma(v)$$ 的每個(gè)元素其實(shí)滿足 $$\sigma(v)_j = \sigma(v_j)$$。給個(gè)例子,如果我們的作用函數(shù)是 $$f(x) = x^2$$,那么向量化的 $$f$$ 的函數(shù)作用就起到下面的效果:
http://wiki.jikexueyuan.com/project/neural-networks-and-deep-learning-zh-cn/images/6.png" alt="" />
也就是說,向量化的 $$f$$ 僅僅是對(duì)向量的每個(gè)元素進(jìn)行了平方運(yùn)算。
了解了這些表示,方程(23)就可以寫成下面的這種美妙而簡潔的向量形式了:
http://wiki.jikexueyuan.com/project/neural-networks-and-deep-learning-zh-cn/images/7.png" alt="" />
這個(gè)表達(dá)式給出了一種更加全局的思考每層的激活值和前一層的關(guān)聯(lián)方式:我們僅僅用權(quán)重矩陣作用在激活值上,然后加上一個(gè)偏差向量,最后作用 $$\sigma$$ 函數(shù)。
其實(shí),這就是讓我們使用之前的矩陣下標(biāo) $$w_{jk}^l$$ 表示的初因。如果我們使用 $$j$$ 來索引輸入神經(jīng)元,$$k$$ 索引輸出神經(jīng)元,那么在方程(25)中我們需要將這里的矩陣換做其轉(zhuǎn)置。這只是一個(gè)小小的困惑的改變,這會(huì)使得我們無法自然地講出(思考)“應(yīng)用權(quán)重矩陣到激活值上”這樣的簡單的表達(dá)。
這種全局的觀點(diǎn)相比神經(jīng)元層面的觀點(diǎn)常常更加簡明(沒有更多的索引下標(biāo)了?。?strong>其實(shí)可以看做是在保留清晰認(rèn)識(shí)的前提下逃離下標(biāo)困境的方法。在實(shí)踐中,表達(dá)式同樣很有用,因?yàn)榇蠖鄶?shù)矩陣庫提供了實(shí)現(xiàn)矩陣乘法、向量加法和向量化的快速方法。實(shí)際上,上一章的代碼其實(shí)已經(jīng)隱式使用了使用這種表達(dá)式來計(jì)算網(wǎng)絡(luò)行為。
在使用方程(25)計(jì)算 $$a^l$$ 時(shí),我們計(jì)算了中間量 $$z^l \equiv w^la^{l-1} + b^l$$ 。這個(gè)量其實(shí)是非常有用的:我們稱 $$z^l$$ 為 $$l$$ 層的帶權(quán)輸入。在本章后面,我們會(huì)大量用到這個(gè)量。方程(25)有時(shí)候會(huì)寫作 $$a^l = \sigma(z^l)$$。同樣要指出的是 $$z_l$$ 的每個(gè)元素是 $$z_j^l = \sumk w{jk}^l a_k^{l-1} + b_j^l$$,其實(shí) $$z_j^l$$ 就是第 $$l$$ 層第 $$j$$ 個(gè)神經(jīng)元的激活函數(shù)帶權(quán)輸入。
反向傳播的目標(biāo)是計(jì)算代價(jià)函數(shù) $$C$$ 分別關(guān)于 $$w$$ 和 $$b$$ 的偏導(dǎo)數(shù) $$\partial C/\partial w$$ 和 $$\partial C/\partial b$$。為了讓反向傳播可行,我們需要做出關(guān)于代價(jià)函數(shù)的兩個(gè)主要假設(shè)。在給出這兩個(gè)假設(shè)之前,我們先看看具體的一個(gè)代價(jià)函數(shù)。我們會(huì)使用上一章使用的二次代價(jià)函數(shù)。按照上一節(jié)給出的表示,二次代價(jià)函數(shù)有下列形式:
http://wiki.jikexueyuan.com/project/neural-networks-and-deep-learning-zh-cn/images/8.png" alt="" />
其中 $$n$$ 是訓(xùn)練樣本的總數(shù);求和是在所有的訓(xùn)練樣本 $$x$$ 上進(jìn)行的;$$y = y(x)$$ 是對(duì)應(yīng)的目標(biāo)輸出;$$L$$ 表示網(wǎng)絡(luò)的層數(shù);$$a^L = a^L(x)$$ 是當(dāng)輸入是 $$x$$ 時(shí)的網(wǎng)絡(luò)輸出的激活值向量。
好了,為了應(yīng)用反向傳播,我們需要對(duì)代價(jià)函數(shù)做出什么樣的前提假設(shè)呢?第一個(gè)假設(shè)就是代價(jià)函數(shù)可以被寫成一個(gè) 在每個(gè)訓(xùn)練樣本 $$x$$ 上的代價(jià)函數(shù) $$C_x$$ 的均值 $$C=\frac{1}{n} \sum_x C_x$$。這是關(guān)于二次代價(jià)函數(shù)的例子,其中對(duì)每個(gè)獨(dú)立的訓(xùn)練樣本其代價(jià)是 $$C_x = \frac{1}{2} ||y-a^L||^2$$。這個(gè)假設(shè)對(duì)書中提到的其他任何一個(gè)代價(jià)函數(shù)也都是必須滿足的。
需要這個(gè)假設(shè)的原因是反向傳播實(shí)際上是對(duì)一個(gè)獨(dú)立的訓(xùn)練樣本計(jì)算了 $$\partial C_x/\partial w$$ 和 $$\partial C_x/\partial b$$。然后我們通過在所有訓(xùn)練樣本上進(jìn)行平均化獲得 $$\partial C/\partial w$$ 和 $$\partial C/\partial b$$。實(shí)際上,有了這個(gè)假設(shè),我們會(huì)認(rèn)為訓(xùn)練樣本 $$x$$ 已經(jīng)被固定住了,丟掉了其下標(biāo),將代價(jià)函數(shù) $$C_x$$ 看做 $$C$$。最終我們會(huì)把下標(biāo)加上,現(xiàn)在為了簡化表示其實(shí)沒有這個(gè)必要。
第二個(gè)假設(shè)就是代價(jià)可以寫成神經(jīng)網(wǎng)絡(luò)輸出的函數(shù):
http://wiki.jikexueyuan.com/project/neural-networks-and-deep-learning-zh-cn/images/9.png" alt="" />
例如,二次代價(jià)函數(shù)滿足這個(gè)要求,因?yàn)閷?duì)于一個(gè)單獨(dú)的訓(xùn)練樣本 $$x$$ 其二次代價(jià)函數(shù)可以寫作:
http://wiki.jikexueyuan.com/project/neural-networks-and-deep-learning-zh-cn/images/10.png" alt="" />
這是輸出的激活值的函數(shù)。當(dāng)然,這個(gè)代價(jià)函數(shù)同樣還依賴于目標(biāo)輸出 $$y$$。記住,輸入的訓(xùn)練樣本 $$x$$ 是固定的,所以輸出同樣是一個(gè)固定的參數(shù)。所以說,并不是可以隨意改變權(quán)重和偏差的,也就是說,這不是神經(jīng)網(wǎng)絡(luò)學(xué)習(xí)的對(duì)象。所以,將 $$C$$ 看成僅有輸出激活值 $$a^L$$ 的函數(shù)才是合理的,而 $$y$$ 僅僅是幫助定義函數(shù)的參數(shù)而已。
反向傳播算法基于常規(guī)的線性代數(shù)運(yùn)算——諸如向量加法,向量矩陣乘法等。但是有一個(gè)運(yùn)算不大常見。特別地,假設(shè) $$s $$和 $$t$$ 是兩個(gè)同樣維度的向量。那么我們使用 $$s\odot t$$ 來表示按元素的乘積。所以 $$s\odot t$$ 的元素就是 $$(s\odot t)_j = s_j t_j$$。給個(gè)例子,
http://wiki.jikexueyuan.com/project/neural-networks-and-deep-learning-zh-cn/images/11.png" alt="" />
這種類型的按元素乘法有時(shí)候被稱為 Hadamard 乘積或者 Schur 乘積。我們這里取前者。好的矩陣庫通常會(huì)提供 Hadamard 乘積的快速實(shí)現(xiàn),在實(shí)現(xiàn)反向傳播的時(shí)候用起來很方便。
反向傳播其實(shí)是對(duì)權(quán)重和偏差變化影響代價(jià)函數(shù)過程的理解。最終極的含義其實(shí)就是計(jì)算偏導(dǎo)數(shù) $$\partial C/\partial w_{jk}^l$$ 和 $$\partial C/\partial b_j^l$$。但是為了計(jì)算這些值,我們首先引入一個(gè)中間量,$$\delta_j^l$$,這個(gè)我們稱為在 $$l^{th}$$ 層第 $$j^{th}$$ 個(gè)神經(jīng)元上的誤差(error)。
反向傳播將給出計(jì)算誤差 $$\deltaj^l$$ 的流程,然后將其關(guān)聯(lián)到計(jì)算 $$\partial C/\partial w{jk}^l$$ 和 $$\partial C/\partial b_j^l$$ 上。
為了理解誤差是如何定義的,假設(shè)在神經(jīng)網(wǎng)絡(luò)上有一個(gè)惡魔:
http://wiki.jikexueyuan.com/project/neural-networks-and-deep-learning-zh-cn/images/12.png" alt="" />
這個(gè)小精靈在 $$l$$ 層的第 $$j^{th}$$ 個(gè)神經(jīng)元上。當(dāng)輸入進(jìn)來時(shí),精靈對(duì)神經(jīng)元的操作進(jìn)行攪局。他會(huì)增加很小的變化 $$\Delta z_j^l$$ 在神經(jīng)元的帶權(quán)輸入上,使得神經(jīng)元輸出由 $$\sigma(z_j^l)$$ 變成 $$\sigma(z_j^l + \Delta z_j^l)$$。這個(gè)變化會(huì)向網(wǎng)絡(luò)后面的層進(jìn)行傳播,最終導(dǎo)致整個(gè)代價(jià)函數(shù)產(chǎn)生 $$\frac{\partial C}{\partial z_j^l} \Delta z_j^l$$ 的改變。
現(xiàn)在,這個(gè)精靈變好了,試著幫助你來優(yōu)化代價(jià)函數(shù),他們?cè)囍业娇梢宰尨鷥r(jià)更小的 $$\Delta z_j^l$$。假設(shè) $$\frac{\partial C}{\partial z_j^l}$$ 有一個(gè)很大的值(或正或負(fù))。那么這個(gè)精靈可以降低代價(jià)通過選擇與 $$\frac{\partial C}{\partial z_j^l}$$ 相反符號(hào)的 $$\Delta z_j^l$$ 。相反,如果$$\frac{\partial C}{\partial z_j^l}$$ 接近 $$0$$,那么精靈并不能通過擾動(dòng)帶權(quán)輸入 $$z_j^l$$ 來改變太多代價(jià)函數(shù)。在小精靈看來,這時(shí)候神經(jīng)元已經(jīng)很接近最優(yōu)了。
這里需要注意的是,只有在 $$\Delta z_j^l$$ 很小的時(shí)候才能夠滿足。我們需要假設(shè)小精靈只能進(jìn)行微小的調(diào)整。
所以這里有一種啟發(fā)式的認(rèn)識(shí),$$\frac{\partial C}{\partial z_j^l}$$ 是神經(jīng)元的誤差的度量。
按照上面的描述,我們定義 $$l$$ 層的第 $$j^{th}$$ 個(gè)神經(jīng)元上的誤差 $$\delta_j^l$$ 為:
http://wiki.jikexueyuan.com/project/neural-networks-and-deep-learning-zh-cn/images/13.png" alt="" />
按照我們通常的慣例,我們使用 $$\delta^l$$ 表示關(guān)聯(lián)于 $$l$$ 層的誤差向量。反向傳播會(huì)提供給我們一種計(jì)算每層的 $$\delta^l$$ 的方法,然后將這些誤差和最終我們需要的量 $$\partial C/\partial w_{jk}^l$$ 和 $$\partial C/\partial b_j^l$$聯(lián)系起來。
你可能會(huì)想知道為何精靈在改變帶權(quán)輸入 $$z_j^l$$??隙ㄏ胂缶`改變輸出激活 $$a_j^l$$ 更加自然,然后就使用 $$\frac{\partial C}{\partial a_j^l}$$ 作為度量誤差的方法了。 實(shí)際上,如果你這樣做的話,其實(shí)和下面要討論的差不同。但是看起來,前面的方法會(huì)讓反向傳播在代數(shù)運(yùn)算上變得比較復(fù)雜。所以我們堅(jiān)持使用 $$\delta_j^l = \partial C / \partial z_j^l$$ 作為誤差的度量。
在分類問題中,誤差有時(shí)候會(huì)用作分類的錯(cuò)誤率。如果神經(jīng)網(wǎng)絡(luò)正確分類了 96.0% 的數(shù)字,那么其誤差是 4.0%。很明顯,這和我們上面提及的誤差的差別非常大了。在實(shí)際應(yīng)用中,區(qū)分這兩種含義是非常容易的。
解決方案:反向傳播基于四個(gè)基本方程。這些方程給我們一種計(jì)算誤差和代價(jià)函數(shù)梯度的方法。我列出這四個(gè)方程。但是需要注意:你不需要一下子能夠同時(shí)理解這些公式。因?yàn)檫^于龐大的期望可能會(huì)導(dǎo)致失望。實(shí)際上,反向傳播方程內(nèi)容很多,完全理解這些需要花費(fèi)充分的時(shí)間和耐心,需要一步一步地深入理解。而好的消息是,這樣的付出回報(bào)巨大。所以本節(jié)對(duì)這些內(nèi)容的討論僅僅是一個(gè)幫助你正確掌握這些公式的起步。
下面簡要介紹我們的探討這些公式的計(jì)劃:首先給出這些公式的簡短證明以解釋他們的正確性;然后以偽代碼的方式給出這些公式的算法形式,并展示這些偽代碼如何轉(zhuǎn)化成真實(shí)的可執(zhí)行的 python 代碼;在本章的最后,我們會(huì)發(fā)展處一個(gè)關(guān)于反向傳播公式含義的直覺圖景,以及人們?nèi)绾文軌驈牧汩_始發(fā)現(xiàn)這個(gè)規(guī)律。按照此法,我們會(huì)不斷地提及這四個(gè)基本方程,隨著你對(duì)這些方程理解的加深,他們會(huì)看起來更加舒服,甚至是美妙和自然的。
輸出層誤差的方程,$$\delta^L$$:每個(gè)元素定義如下:
http://wiki.jikexueyuan.com/project/neural-networks-and-deep-learning-zh-cn/images/14.png" alt="" />
這是一個(gè)非常自然的表達(dá)式。右式第一個(gè)項(xiàng) $$\partial C/\partial a_j^L$$ 表示代價(jià)隨著 $$j^{th}$$ 輸出激活值的變化而變化的速度。假如 $$C$$ 不太依賴一個(gè)特定的輸出神經(jīng)元 $$j$$,那么$$\delta_j^L$$ 就會(huì)很小,這也是我們想要的效果。右式第二項(xiàng) $$\sigma'(z_j^L)$$ 刻畫了在 $$z_j^L$$ 處激活函數(shù) $$\sigma$$ 變化的速度。
注意到在 BP1 中的每個(gè)部分都是很好計(jì)算的。特別地,我們?cè)谇跋騻鞑ビ?jì)算網(wǎng)絡(luò)行為時(shí)已經(jīng)計(jì)算過 $$z_j^L$$,這僅僅需要一點(diǎn)點(diǎn)額外工作就可以計(jì)算 $$\sigma'(z_j^L)$$。當(dāng)然 $$\partial C/\partial a_j^L$$ 依賴于代價(jià)函數(shù)的形式。然而,給定了代價(jià)函數(shù),計(jì)算$$\partial C/\partial a_j^L$$就沒有什么大問題了。例如,如果我們使用二次函數(shù),那么 $$C = \frac{1}{2} \sum_j(y_j-a_j)^2$$,所以 $$\partial C/\partial a_j^L = (a_j - y_j)$$,這其實(shí)很容易計(jì)算。
方程(BP1)對(duì) $$\delta^L$$ 來說是個(gè)按部分構(gòu)成的表達(dá)式。這是一個(gè)非常好的表達(dá)式,但不是我們期望的用矩陣表示的形式。但是,重寫方程其實(shí)很簡單,
http://wiki.jikexueyuan.com/project/neural-networks-and-deep-learning-zh-cn/images/15.png" alt="" />
這里 $$\nabla_a C$$ 被定義成一個(gè)向量,其元素師偏導(dǎo)數(shù) $$\partial C/\partial a_j^L$$。你可以將其看成 $$C$$ 關(guān)于輸出激活值的改變速度。方程(BP1)和方程(BP1a)的等價(jià)也是顯而易見的,所以現(xiàn)在開始,我們會(huì)交替地使用這兩個(gè)方程。舉個(gè)例子,在二次代價(jià)函數(shù)時(shí),我們有 $$\nabla_a C = (a^L - y)$$,所以(BP1)的整個(gè)矩陣形式就變成
http://wiki.jikexueyuan.com/project/neural-networks-and-deep-learning-zh-cn/images/16.png" alt="" />
如你所見,這個(gè)方程中的每個(gè)項(xiàng)都有一個(gè)很好的向量形式,所以也可以很方便地使用像 Numpy 這樣的矩陣庫進(jìn)行計(jì)算了。
使用下一層的誤差 $$\delta^{l+1}$$ 來表示當(dāng)前層的誤差 $$\delta_l$$:特別地,
http://wiki.jikexueyuan.com/project/neural-networks-and-deep-learning-zh-cn/images/17.png" alt="" />
其中 $$(w^{l+1})^T$$ 是 $$(l+1)^{th}$$ 權(quán)重矩陣 $$w^{l+1}$$ 的轉(zhuǎn)置。這其實(shí)可以很直覺地看做是后在 $$l^{th}$$ 層的輸出的誤差的反向傳播,給出了某種關(guān)于誤差的度量方式。然后,我們進(jìn)行 Hadamard 乘積運(yùn)算 $$\odot \sigma'(z^l)$$。這會(huì)讓誤差通過 $$l$$ 層的激活函數(shù)反向傳遞回來并給出在第 $$l$$ 層的帶權(quán)輸入的誤差 $$\delta$$。
通過組合(BP1)和(BP2),我們可以計(jì)算任何層的誤差了。首先使用(BP1)計(jì)算$$\delta^l$$,然后應(yīng)用方程(BP2)來計(jì)算$$\delta^{L-1}$$,然后不斷作用(BP2),一步一步地反向傳播完整個(gè)網(wǎng)絡(luò)。
代價(jià)函數(shù)關(guān)于網(wǎng)絡(luò)中任意偏差的改變率:就是
http://wiki.jikexueyuan.com/project/neural-networks-and-deep-learning-zh-cn/images/18.png" alt="" />
這其實(shí)是,誤差 $$\delta_j^l$$ 和偏導(dǎo)數(shù)值 $$\partial C/\partial b_j^l$$完全一致。這是很好的性質(zhì),因?yàn)?BP1)和(BP2)已經(jīng)告訴我們?nèi)绾斡?jì)算 $$\delta_j^l$$。所以就可以將(BP3)簡記為
http://wiki.jikexueyuan.com/project/neural-networks-and-deep-learning-zh-cn/images/19.png" alt="" />
其中 $$\delta$$ 和偏差 $$b$$ 都是針對(duì)同一個(gè)神經(jīng)元。
代價(jià)函數(shù)關(guān)于任何一個(gè)權(quán)重的改變率:特別地,
http://wiki.jikexueyuan.com/project/neural-networks-and-deep-learning-zh-cn/images/20.png" alt="" />
這告訴我們?nèi)绾斡?jì)算偏導(dǎo)數(shù) $$\partial C/\partial w_{jk}^l$$,其中 $$\delta^l$$ $$a^{l-1}$$ 這些量我們都已經(jīng)知道如何計(jì)算了。方程也可以寫成下面少下標(biāo)的表示:
http://wiki.jikexueyuan.com/project/neural-networks-and-deep-learning-zh-cn/images/21.png" alt="" />
其中 $$a{in}$$ 是輸出給 $$w$$ 產(chǎn)生的神經(jīng)元的輸入和 $$\delta{out}$$是來自 $$w$$ 的神經(jīng)元輸出的誤差。放大看看權(quán)重 w,還有兩個(gè)由這個(gè)鏈接相連的神經(jīng)元,我們給出一幅圖如下:
http://wiki.jikexueyuan.com/project/neural-networks-and-deep-learning-zh-cn/images/22.png" alt="" />
方程(32)的一個(gè)結(jié)論就是當(dāng)激活值很小,梯度 $$\partial C/\partial w$$ 也會(huì)變得很小。這樣,我們就說權(quán)重學(xué)習(xí)緩慢,表示在梯度下降的時(shí)候,這個(gè)權(quán)重不會(huì)改變太多。換言之,(BP4)的后果就是來自很低的激活值神經(jīng)元的權(quán)重學(xué)習(xí)會(huì)非常緩慢。
這四個(gè)公式同樣還有很多觀察。讓我們看看(BP1)中的項(xiàng) $$\sigma'(z_k^l)$$?;貞浺幌律弦徽碌?sigmoid 函數(shù)圖像,當(dāng)函數(shù)值接近 $$0$$ 或者 $$1$$ 的時(shí)候圖像非常平。這就使得在這些位置的導(dǎo)數(shù)接近于 $$0$$.所以如果輸出神經(jīng)元處于或者低激活值或者高激活值時(shí),最終層的權(quán)重學(xué)習(xí)緩慢。這樣的情形,我們常常稱輸出神經(jīng)元已經(jīng)飽和了,并且,權(quán)重學(xué)習(xí)也會(huì)終止(或者學(xué)習(xí)非常緩慢)。類似的結(jié)果對(duì)于輸出神經(jīng)元的偏差也是成立的。
針對(duì)前面的層,我們也有類似的觀點(diǎn)。特別地,注意在(BP2)中的項(xiàng) $$\sigma'(z^l)$$。這表示 $$\delta_j^l$$ 很可能變小如果神經(jīng)元已經(jīng)接近飽和。這就導(dǎo)致任何輸入進(jìn)一個(gè)飽和的神經(jīng)元的權(quán)重學(xué)習(xí)緩慢。
如果 $$(w^{l+1})^T \delta^{l+1}$$ 擁有足夠大的量能夠補(bǔ)償 $$\sigma'(z_k^l)$$ 的話,這里的推導(dǎo)就不能成立了。但是我們上面是常見的情形。
總結(jié)一下,我們已經(jīng)學(xué)習(xí)到權(quán)重學(xué)習(xí)緩慢如果輸入神經(jīng)元激活值很低,或者輸出神經(jīng)元已經(jīng)飽和了(過高或者過低的激活值)。
這些觀測其實(shí)也是不非常令人驚奇的。不過,他們幫助我們完善了關(guān)于神經(jīng)網(wǎng)絡(luò)學(xué)習(xí)的背后的思維模型。而且,我們可以將這種推斷方式進(jìn)行推廣。四個(gè)基本方程也其實(shí)對(duì)任何的激活函數(shù)都是成立的(證明中也可以看到,其實(shí)推斷本身不依賴于任何具體的代價(jià)函數(shù))所以,我們可以使用這些方程來設(shè)計(jì)有特定屬性的激活函數(shù)。我們這里給個(gè)例子,假設(shè)我們準(zhǔn)備選擇一個(gè)(non-sigmoid)的激活函數(shù) $$\sigma$$ 使得 $$\sigma'$$ 總是正數(shù)。這會(huì)防止在原始的 sigmoid 神經(jīng)元飽和時(shí)學(xué)習(xí)速度的下降的情況出現(xiàn)。在本書的后面,我們會(huì)見到這種類型的對(duì)激活函數(shù)的改變。時(shí)時(shí)回顧這四個(gè)方程可以幫助解釋為何需要有這些嘗試,以及嘗試帶來的影響。
http://wiki.jikexueyuan.com/project/neural-networks-and-deep-learning-zh-cn/images/23.png" alt="" />
另一種反向傳播方程的表示方式:我已經(jīng)給出了使用了 Hadamard 乘積的反向傳播的公式。如果你對(duì)這種特殊的乘積不熟悉,可能會(huì)有一些困惑。下面還有一種表示方式,那就是基于傳統(tǒng)的矩陣乘法,某些讀者可能會(huì)覺得很有啟發(fā)。(1) 證明 (BP1) 可以寫成
http://wiki.jikexueyuan.com/project/neural-networks-and-deep-learning-zh-cn/images/24.png" alt="" />
其中 $$\Sigma'(z^L)$$ 是一個(gè)方陣,其對(duì)角線的元素是 $$\sigma'(z_j^L)$$,其他的元素均是 $$0$$。注意,這個(gè)矩陣通過一般的矩陣乘法作用在 $$\nabla_a C$$ 上。(2) 證明(BP2) 可以寫成
http://wiki.jikexueyuan.com/project/neural-networks-and-deep-learning-zh-cn/images/25.png" alt="" />
(3) 結(jié)合(1)和(2) 證明
http://wiki.jikexueyuan.com/project/neural-networks-and-deep-learning-zh-cn/images/26.png" alt="" />
對(duì)那些習(xí)慣于這種形式的矩陣乘法的讀者,(BP1) (BP2) 應(yīng)該更加容易理解。而我們堅(jiān)持使用 Hadamard 乘積的原因在于其更快的數(shù)值實(shí)現(xiàn)。
我們現(xiàn)在證明這四個(gè)方程。所有這些都是多元微積分的鏈?zhǔn)椒▌t的推論。如果你熟悉鏈?zhǔn)椒▌t,那么我鼓勵(lì)你在讀之前自己證明一番。
這樣我們就完成了反向傳播四個(gè)基本公式的證明。證明本身看起來復(fù)雜。但是實(shí)際上就是細(xì)心地應(yīng)用鏈?zhǔn)椒▌t。我們可以將反向傳播看成是一種系統(tǒng)性地應(yīng)用多元微積分中的鏈?zhǔn)椒▌t來計(jì)算代價(jià)函數(shù)的梯度的方式。這些就是反向傳播理論上的內(nèi)容——剩下的是實(shí)現(xiàn)細(xì)節(jié)。
反向傳播方程給出了一種計(jì)算代價(jià)函數(shù)梯度的方法。讓我們顯式地用算法描述出來:
看看這個(gè)算法,你可以看到為何它被稱作反向傳播。我們從最后一層開始向后計(jì)算誤差向量 $$\delta^l$$。這看起來有點(diǎn)奇怪,為何要從后面開始。但是如果你認(rèn)真思考反向傳播的證明,這種反向移動(dòng)其實(shí)是代價(jià)函數(shù)是網(wǎng)絡(luò)輸出的函數(shù)的后果。為了理解代價(jià)隨前面層的權(quán)重和偏差變化的規(guī)律,我們需要重復(fù)作用鏈?zhǔn)椒▌t,反向地獲得需要的表達(dá)式。
正如我們上面所講的,反向傳播算法對(duì)一個(gè)訓(xùn)練樣本計(jì)算代價(jià)函數(shù)的梯度,$$C=C_x$$。在實(shí)踐中,通常將反向傳播算法和諸如隨機(jī)梯度下降這樣的學(xué)習(xí)算法進(jìn)行組合使用,我們會(huì)對(duì)許多訓(xùn)練樣本計(jì)算對(duì)應(yīng)的梯度。特別地,給定一個(gè)大小為 $$m$$ 的 minibatch,下面的算法應(yīng)用一步梯度下降學(xué)習(xí)在這個(gè) minibatch 上:
當(dāng)然,在實(shí)踐中實(shí)現(xiàn)隨機(jī)梯度下降,我們還需要一個(gè)產(chǎn)生訓(xùn)練樣本 minibatch 的循環(huán),還有就是訓(xùn)練次數(shù)的循環(huán)。這里我們先省略了。
理解了抽象的反向傳播的理論知識(shí),我們現(xiàn)在就可以學(xué)習(xí)上一章中使用的實(shí)現(xiàn)反向傳播的代碼了?;叵肷弦徽碌拇a,需要研究的是在 Network 類中的 update_mini_batch 和 backprop 方法。這些方法的代碼其實(shí)是我們上面的算法描述的直接翻版。特別地,update_mini_batch 方法通過計(jì)算當(dāng)前 mini_batch 中的訓(xùn)練樣本對(duì) Network 的權(quán)重和偏差進(jìn)行了更新:
class Network(object):
...
def update_mini_batch(self, mini_batch, eta):
"""Update the network's weights and biases by applying
gradient descent using backpropagation to a single mini batch.
The "mini_batch" is a list of tuples "(x, y)", and "eta"
is the learning rate."""
nabla_b = [np.zeros(b.shape) for b in self.biases]
nabla_w = [np.zeros(w.shape) for w in self.weights]
for x, y in mini_batch:
delta_nabla_b, delta_nabla_w = self.backprop(x, y)
nabla_b = [nb+dnb for nb, dnb in zip(nabla_b, delta_nabla_b)]
nabla_w = [nw+dnw for nw, dnw in zip(nabla_w, delta_nabla_w)]
self.weights = [w-(eta/len(mini_batch))*nw
for w, nw in zip(self.weights, nabla_w)]
self.biases = [b-(eta/len(mini_batch))*nb
for b, nb in zip(self.biases, nabla_b)]
主要工作其實(shí)是在 delta_nabla_b, delta_nabla_w = self.backprop(x, y) 這里完成的,調(diào)用了 backprop 方法計(jì)算出了偏導(dǎo)數(shù),$$\partial C_x/\partial b_j^l$$ 和 $$\partial Cx/\partial w{jk}^l$$。反向傳播方法跟上一節(jié)的算法基本一致。這里只有個(gè)小小的差異——我們使用一個(gè)略微不同的方式來索引神經(jīng)網(wǎng)絡(luò)的層。這個(gè)改變其實(shí)是為了 Python 的特性——負(fù)值索引的使用能夠讓我們從列表的最后往前遍歷,如 l[-3] 其實(shí)是列表中的倒數(shù)第三個(gè)元素。下面 backprop 的代碼,使用了一些用來計(jì)算 $$\sigma$$、導(dǎo)數(shù) $$\sigma'$$ 及代價(jià)函數(shù)的導(dǎo)數(shù)幫助函數(shù)。所以理解了這些,我們就完全可以掌握所有的代碼了。如果某些東西讓你困惑,你可能需要參考代碼的原始描述
class Network(object):
...
def backprop(self, x, y):
"""Return a tuple "(nabla_b, nabla_w)" representing the
gradient for the cost function C_x. "nabla_b" and
"nabla_w" are layer-by-layer lists of numpy arrays, similar
to "self.biases" and "self.weights"."""
nabla_b = [np.zeros(b.shape) for b in self.biases]
nabla_w = [np.zeros(w.shape) for w in self.weights]
# feedforward
activation = x
activations = [x] # list to store all the activations, layer by layer
zs = [] # list to store all the z vectors, layer by layer
for b, w in zip(self.biases, self.weights):
z = np.dot(w, activation)+b
zs.append(z)
activation = sigmoid(z)
activations.append(activation)
# backward pass
delta = self.cost_derivative(activations[-1], y) * \
sigmoid_prime(zs[-1])
nabla_b[-1] = delta
nabla_w[-1] = np.dot(delta, activations[-2].transpose())
# Note that the variable l in the loop below is used a little
# differently to the notation in Chapter 2 of the book. Here,
# l = 1 means the last layer of neurons, l = 2 is the
# second-last layer, and so on. It's a renumbering of the
# scheme in the book, used here to take advantage of the fact
# that Python can use negative indices in lists.
for l in xrange(2, self.num_layers):
z = zs[-l]
sp = sigmoid_prime(z)
delta = np.dot(self.weights[-l+1].transpose(), delta) * sp
nabla_b[-l] = delta
nabla_w[-l] = np.dot(delta, activations[-l-1].transpose())
return (nabla_b, nabla_w)
...
def cost_derivative(self, output_activations, y):
"""Return the vector of partial derivatives \partial C_x /
\partial a for the output activations."""
return (output_activations-y)
def sigmoid(z):
"""The sigmoid function."""
return 1.0/(1.0+np.exp(-z))
def sigmoid_prime(z):
"""Derivative of the sigmoid function."""
return sigmoid(z)*(1-sigmoid(z))
network.py 來實(shí)現(xiàn)這個(gè)方案。這樣做的好處其實(shí)利用到了現(xiàn)代的線性代數(shù)庫。所以,這會(huì)比在 minibatch 上進(jìn)行遍歷要運(yùn)行得更快(在我的筆記本電腦上,在 MNIST 分類問題上,我相較于上一章的實(shí)現(xiàn)獲得了 2 倍的速度提升)。在實(shí)際應(yīng)用中,所有靠譜的反向傳播的庫都是用了類似的基于矩陣或者變體的方式來實(shí)現(xiàn)的。為了回答這個(gè)問題,首先考慮另一個(gè)計(jì)算梯度的方法。就當(dāng)我們回到上世界50、60年代的神經(jīng)網(wǎng)絡(luò)研究。假設(shè)你是世界上首個(gè)考慮使用梯度下降方法學(xué)習(xí)的那位!為了讓自己的想法可行,就必須找出計(jì)算代價(jià)函數(shù)梯度的方法。想想自己學(xué)到的微積分,決定試試看鏈?zhǔn)椒▌t來計(jì)算梯度。但玩了一會(huì)后,就發(fā)現(xiàn)代數(shù)式看起來非常復(fù)雜,然后就退縮了。所以就試著找另外的方式。你決定僅僅把代價(jià)看做權(quán)重 $$C$$ 的函數(shù)。你給這些權(quán)重 $$w_1, w_2, ...$$ 進(jìn)行編號(hào),期望計(jì)算關(guān)于某個(gè)權(quán)值 $$w_j$$ 關(guān)于 $$C$$ 的導(dǎo)數(shù)。而一種近似的方法就是下面這種:
http://wiki.jikexueyuan.com/project/neural-networks-and-deep-learning-zh-cn/images/27.png" alt="" />
其中 $$\epsilon>0$$ 是一個(gè)很小的正數(shù),而 $$e_j$$ 是在第j個(gè)方向上的單位向量。換句話說,我們可以通過計(jì)算 $$w_j$$ 的兩個(gè)接近相同的點(diǎn)的值來估計(jì) $$\partial C/\partial w_j$$,然后應(yīng)用公式(46)。同樣方法也可以用來計(jì)算 $$\partial C/\partial b$$。
這個(gè)觀點(diǎn)看起來非常有希望。概念上易懂,容易實(shí)現(xiàn),使用幾行代碼就可以搞定??雌饋恚@樣的方法要比使用鏈?zhǔn)椒▌t還要有效。
然后,遺憾的是,當(dāng)你實(shí)現(xiàn)了之后,運(yùn)行起來這樣的方法非常緩慢。為了理解原因,假設(shè)我們有 $$1,000,000$$ 權(quán)重。對(duì)每個(gè)不同的權(quán)重 $$w_j$$ 我們需要計(jì)算 $$C(w+\epsilon * e_j)$$ 來計(jì)算 $$\partial C/\partial w_j$$。這意味著為了計(jì)算梯度,我們需要計(jì)算代價(jià)函數(shù) $$1, 000, 000 $$次,需要 $$1, 000, 000$$ 前向傳播(對(duì)每個(gè)樣本)。我們同樣需要計(jì)算 $$C(w)$$,總共是 $$1,000,001$$ 次。
反向傳播聰明的地方就是它確保我們可以同時(shí)計(jì)算所有的偏導(dǎo)數(shù) $$\partial C/\partial w_j$$ 使用一次前向傳播,加上一次后向傳播。粗略地說,后向傳播的計(jì)算代價(jià)和前向的一樣。*
這個(gè)說法是合理的,但需要額外的說明來澄清這一事實(shí)。在前向傳播過程中主要的計(jì)算代價(jià)消耗在權(quán)重矩陣的乘法上,而反向傳播則是計(jì)算權(quán)重矩陣的轉(zhuǎn)置矩陣。這些操作顯然有著類似的計(jì)算代價(jià)。
所以最終的計(jì)算代價(jià)大概是兩倍的前向傳播計(jì)算大家。比起直接計(jì)算導(dǎo)數(shù),顯然 反向傳播 有著更大的優(yōu)勢(shì)。所以即使 反向傳播 看起來要比 (46) 更加復(fù)雜,但實(shí)際上要更快。
這個(gè)加速在1986年首次被眾人接受,并直接導(dǎo)致神經(jīng)網(wǎng)絡(luò)可以處理的問題的擴(kuò)展。這也導(dǎo)致了大量的研究者涌向了神經(jīng)網(wǎng)絡(luò)方向。當(dāng)然,反向傳播 并不是萬能鑰匙。在 1980 年代后期,人們嘗試挑戰(zhàn)極限,尤其是嘗試使用反向傳播來訓(xùn)練深度神經(jīng)網(wǎng)絡(luò)。本書后面,我們將看到現(xiàn)代計(jì)算機(jī)和一些聰明的新想法已經(jīng)讓 反向傳播 成功地訓(xùn)練這樣的深度神經(jīng)網(wǎng)絡(luò)。
正如我所講解的,反向傳播 提出了兩個(gè)神秘的問題。首先,這個(gè)算法真正在干什么?我們已經(jīng)感受到從輸出處的錯(cuò)誤被反向傳回的圖景。但是我們能夠更深入一些,構(gòu)造出一種更加深刻的直覺來解釋所有這些矩陣和向量乘法么?第二神秘點(diǎn)就是,某人為什么能發(fā)現(xiàn)這個(gè) 反向傳播?跟著一個(gè)算法跑一遍甚至能夠理解證明算法可以運(yùn)行這是一回事。這并不真的意味著你理解了這個(gè)問題到一定程度,能夠發(fā)現(xiàn)這個(gè)算法。是否有一個(gè)推理的思路可以指引我們發(fā)現(xiàn) 反向傳播 算法?本節(jié),我們來探討一下這兩個(gè)謎題。 為了提升我們關(guān)于算法究竟做了什么的直覺,假設(shè)我們已經(jīng)對(duì) $$w{jk}^l$$ 做一點(diǎn)小小的變動(dòng) $$\Delta w{jk}^l$$:
http://wiki.jikexueyuan.com/project/neural-networks-and-deep-learning-zh-cn/images/28.png" alt="" />
這個(gè)改變會(huì)導(dǎo)致在輸出激活值上的相應(yīng)改變:
http://wiki.jikexueyuan.com/project/neural-networks-and-deep-learning-zh-cn/images/29.png" alt="" />
然后,會(huì)產(chǎn)生對(duì)下一層激活值的改變:
http://wiki.jikexueyuan.com/project/neural-networks-and-deep-learning-zh-cn/images/30.png" alt="" />
接著,這些改變都將影響到一個(gè)個(gè)下一層,到達(dá)輸出層,最終影響代價(jià)函數(shù):
http://wiki.jikexueyuan.com/project/neural-networks-and-deep-learning-zh-cn/images/31.png" alt="" />
所以代價(jià)函數(shù) $$\Delta C$$ 改變和 $$\Delta w_{jk}^l$$ 就按照下面的公式關(guān)聯(lián)起來了:
http://wiki.jikexueyuan.com/project/neural-networks-and-deep-learning-zh-cn/images/32.png" alt="" />
這給出了一種可能的計(jì)算 $$\frac{\partial C}{\partial w{jk}^l}$$ 的方法其實(shí)是細(xì)致地追蹤一個(gè) $$w{jk}^l$$ 的微小變化如何導(dǎo)致 $$C$$ 中的變化值。如果我們可以做到這點(diǎn),能夠精確地使用易于計(jì)算的量來表達(dá)每種關(guān)系,那么我們就能夠計(jì)算 $$\frac{\partial C}{\partial w_{jk}^l}$$ 了。
我們嘗試一下這個(gè)方法。$$\Delta w_{jk}^l$$ 導(dǎo)致了在 $$l^{th}$$ 層 $$j^{th}$$ 神經(jīng)元的激活值的變化 $$\Delta a_j^l$$。這個(gè)變化由下面的公式給出:
http://wiki.jikexueyuan.com/project/neural-networks-and-deep-learning-zh-cn/images/33.png" alt="" />
$$\Delta a_j^l$$ 的變化將會(huì)導(dǎo)致下一層的所有激活值的變化。我們聚焦到其中一個(gè)激活值上看看影響的情況,不妨設(shè) $$a_q^{l+1}$$,
http://wiki.jikexueyuan.com/project/neural-networks-and-deep-learning-zh-cn/images/34.png" alt="" />
實(shí)際上,這會(huì)導(dǎo)致下面的變化:
http://wiki.jikexueyuan.com/project/neural-networks-and-deep-learning-zh-cn/images/35.png" alt="" />
將其代入方程(48),我們得到:
http://wiki.jikexueyuan.com/project/neural-networks-and-deep-learning-zh-cn/images/36.png" alt="" />
當(dāng)然,這個(gè)變化又會(huì)去下一層的激活值。實(shí)際上,我們可以想象出一條從 $$w_{jk}^l$$ 到 $$C$$ 的路徑,然后每個(gè)激活值的變化會(huì)導(dǎo)致下一層的激活值的變化,最終是輸出層的代價(jià)的變化。假設(shè)激活值的序列如下 $$a_j^l, a_q^{l+1}, ..., a_n^{L-1},a_m^{L}$$,那么結(jié)果的表達(dá)式就是
http://wiki.jikexueyuan.com/project/neural-networks-and-deep-learning-zh-cn/images/37.png" alt="" />
我們已經(jīng)對(duì)每個(gè)經(jīng)過的神經(jīng)元設(shè)置了一個(gè) $$\partial a/\partial a$$ 這種形式的項(xiàng),還有輸出層的 $$\partial C/\partial am^L$$。這表示除了 $$C$$ 的改變由于網(wǎng)絡(luò)中這條路徑上激活值的變化。當(dāng)然,整個(gè)網(wǎng)絡(luò)中存在很多 $$w{jk}^l$$ 可以傳播而影響代價(jià)函數(shù)的路徑,這里我們就看其中一條。為了計(jì)算 $$C$$ 的全部改變,我們就需要對(duì)所有可能的路徑進(jìn)行求和,即,
http://wiki.jikexueyuan.com/project/neural-networks-and-deep-learning-zh-cn/images/38.png" alt="" />
這里我們對(duì)路徑中所有可能的中間神經(jīng)元選擇進(jìn)行求和。對(duì)比 (47) 我們有
http://wiki.jikexueyuan.com/project/neural-networks-and-deep-learning-zh-cn/images/39.png" alt="" />
現(xiàn)在公式(53)看起來相當(dāng)復(fù)雜。但是,這里其實(shí)有一個(gè)相當(dāng)好的直覺上的解釋。我們用這個(gè)公式計(jì)算 $$C$$ 關(guān)于網(wǎng)絡(luò)中一個(gè)權(quán)重的變化率。而這個(gè)公式告訴我們的是:兩個(gè)神經(jīng)元之間的連接其實(shí)是關(guān)聯(lián)與一個(gè)變化率因子,這僅僅是一個(gè)神經(jīng)元的激活值相對(duì)于其他神經(jīng)元的激活值的偏導(dǎo)數(shù)。從第一個(gè)權(quán)重到第一個(gè)神經(jīng)元的變化率因子是 $$\partial aj^l/\partial w{jk}^l$$。路徑的變化率因子其實(shí)就是這條路徑上的眾多因子的乘積。而整個(gè)的變化率 $$\partial C/\partial w_{jk}^l$$ 就是對(duì)于所有可能的從初始權(quán)重到最終輸出的代價(jià)函數(shù)的路徑的變化率因子的和。針對(duì)某一個(gè)路徑,這個(gè)過程解釋如下,
http://wiki.jikexueyuan.com/project/neural-networks-and-deep-learning-zh-cn/images/40.png" alt="" />
我們到現(xiàn)在所給出的東西其實(shí)是一種啟發(fā)式的觀點(diǎn),一種思考權(quán)重變化對(duì)網(wǎng)絡(luò)行為影響的方式。讓我們給出關(guān)于這個(gè)觀點(diǎn)應(yīng)用的一些流程建議。首先,你可以推導(dǎo)出公式(53)中所有單獨(dú)的的偏導(dǎo)數(shù)顯式表達(dá)式。只是一些微積分的運(yùn)算。完成這些后,你可以弄明白如何用矩陣運(yùn)算寫出對(duì)所有可能的情況的求和。這項(xiàng)工作會(huì)比較乏味,需要一些耐心,但不用太多的洞察。完成這些后,就可以盡可能地簡化了,最后你發(fā)現(xiàn),自己其實(shí)就是在做反向傳播!所以你可以將反向傳播想象成一種計(jì)算所有可能的路徑變化率的求和的方式。或者,換句話說,反向傳播就是一種巧妙地追蹤權(quán)重(和偏差)微小變化的傳播,抵達(dá)輸出層影響代價(jià)函數(shù)的技術(shù)。
現(xiàn)在我不會(huì)繼續(xù)深入下去。因?yàn)檫@項(xiàng)工作比較無聊。如果你想挑戰(zhàn)一下,可以嘗試與喜愛。即使你不去嘗試,我也希望這種思維方式可以讓你能夠更好地理解反向傳播。
那其他的一些神秘的特性呢——反向傳播如何在一開始被發(fā)現(xiàn)的?實(shí)際上,如果你跟隨我剛剛給出的觀點(diǎn),你其實(shí)是可以發(fā)現(xiàn)反向傳播的一種證明的。不幸的是,證明會(huì)比本章前面介紹的證明更長和更加的復(fù)雜。那么,前面那個(gè)簡短(卻更加神秘)的證明如何被發(fā)現(xiàn)的?當(dāng)你寫出來所有關(guān)于長證明的細(xì)節(jié)后,你會(huì)發(fā)現(xiàn)其實(shí)里面包含了一些明顯的可以進(jìn)行改進(jìn)的地方。然后你進(jìn)行一些簡化,得到稍微簡短的證明,寫下來。然后又能發(fā)現(xiàn)一些更加明顯的簡化。進(jìn)過幾次迭代證明改進(jìn)后,你會(huì)發(fā)現(xiàn)最終的簡單卻看起來奇特的證明,因?yàn)槟阋瞥撕芏鄻?gòu)造的細(xì)節(jié)了!老實(shí)告訴你,其實(shí)最早的證明的出現(xiàn)也不是太過神秘的事情。因?yàn)槟侵皇呛芏鄬?duì)簡化證明的艱辛工作的積累。