全連接神經(jīng)網(wǎng)絡(luò)之反向傳播算法原理推導(dǎo)

簡(jiǎn)介

在上一篇文章《手寫一個(gè)全連接神經(jīng)網(wǎng)絡(luò)用于MNIST數(shù)據(jù)集》中蔗彤,我們使用少于100行代碼實(shí)現(xiàn)了一個(gè)3層的全連接網(wǎng)絡(luò),并且在MNIST數(shù)據(jù)集上取得了95%以上的準(zhǔn)確率载庭。相信讀過這篇文章的讀者對(duì)全連接網(wǎng)絡(luò)如何使用梯度下降算法來學(xué)習(xí)自身的權(quán)值和偏置的原理已經(jīng)有所了解(如果你沒讀過,建議先看一下再閱讀本文)歇僧。但是上篇文章留下了一個(gè)問題筛峭,就是我們沒有討論如何計(jì)算損失函數(shù)的梯度宛徊,在本文中,我會(huì)詳細(xì)解釋如何計(jì)算這些梯度夜只。

本文會(huì)涉及到較多的數(shù)學(xué)公式垒在,要求讀者了解微積分的基本知識(shí),尤其是鏈?zhǔn)椒▌t扔亥。


反向傳播概覽

先引用一下維基百科中對(duì)于反向傳播的定義:

反向傳播(英語:Backpropagation场躯,縮寫為BP)是“誤差反向傳播”的簡(jiǎn)稱,是一種與最優(yōu)化方法(如梯度下降法)結(jié)合使用的旅挤,用來訓(xùn)練人工神經(jīng)網(wǎng)絡(luò)的常見方法踢关。該方法對(duì)網(wǎng)絡(luò)中所有權(quán)重計(jì)算損失函數(shù)的梯度。這個(gè)梯度會(huì)反饋給最優(yōu)化方法粘茄,用來更新權(quán)值以最小化損失函數(shù)签舞。

反向傳播的核心是對(duì)損失函數(shù)C關(guān)于任何權(quán)重w(或偏置b)的偏導(dǎo)數(shù)\partial C/\partial w(或\partial C / \partial b)的表達(dá)式。這個(gè)表達(dá)式告訴我們?cè)诟淖儥?quán)重和偏置時(shí)柒瓣,損失函數(shù)變化的快慢儒搭。由于C是一個(gè)疊加了多種運(yùn)算的多元函數(shù),所以對(duì)網(wǎng)絡(luò)的某一層的某一個(gè)權(quán)重w_i的偏導(dǎo)數(shù)可能會(huì)變得很復(fù)雜芙贫,不過這也讓我們直觀的看到了某一個(gè)權(quán)重w_i的變化究竟會(huì)如何改變網(wǎng)絡(luò)的行為搂鲫。


神經(jīng)網(wǎng)絡(luò)參數(shù)的表示

通過上一篇文章,我們知道神經(jīng)網(wǎng)絡(luò)是由多個(gè)S型神經(jīng)元構(gòu)成的屹培,每個(gè)S型神經(jīng)元有輸入x默穴,權(quán)重w怔檩,偏置b,以及輸出z蓄诽。那么當(dāng)它們組合在一起形成復(fù)雜的神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu)的時(shí)候薛训,參數(shù)會(huì)變得異常的多。這個(gè)時(shí)候我們需要先約定一下如何來表示這些參數(shù)仑氛,以便數(shù)學(xué)描述和基于矩陣的運(yùn)算乙埃。先以一個(gè)簡(jiǎn)單的神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu)為例:


可以看到上述網(wǎng)絡(luò)一共有3層,第一層是輸入層锯岖,第二層是隱層介袜,第三層是輸出層。接下來我會(huì)在這張圖上標(biāo)注權(quán)重w出吹,偏置b遇伞,激活值a等參數(shù),并且會(huì)引入若干個(gè)符號(hào)來表示這些參數(shù)捶牢。

w_{jk}^l表示從(l-1)^{th}層的k^{th}個(gè)神經(jīng)元到l^{th}層的j^{th}個(gè)神經(jīng)元上的權(quán)重鸠珠。這個(gè)表示看起來有點(diǎn)奇怪,也不容易理解秋麸,因?yàn)檫@個(gè)表達(dá)式里面雖然帶有一個(gè)l渐排,但是實(shí)際上它表示的是第l-1層到第l層的之間的權(quán)重關(guān)系。以上圖的藍(lán)色箭頭所指的線段為例灸蟆,w_{24}^3代表的含義是驯耻,第2層的第4個(gè)神經(jīng)元到第3層的第2個(gè)神經(jīng)元之間的權(quán)重。

其實(shí)如果你仔細(xì)看過上一篇文章中的代碼炒考,你會(huì)發(fā)現(xiàn)權(quán)重向量w和偏置向量b只是第二層和第三層才會(huì)有可缚,而輸入層是沒有這些參數(shù)的。在上圖中斋枢,我們是用帶箭頭的線段來表示的權(quán)重城看,故w^l代表的并不是第l層指出去的線段,而指的是第l-1層指向它的線段杏慰,這個(gè)有點(diǎn)違反直覺,但是接下來你會(huì)看到這么做的好處炼鞠。

b_j^l表示在第l^{th}層的第j^{th}個(gè)神經(jīng)元的偏置缘滥,如上圖b^2_{3}表示第2層的第3個(gè)神經(jīng)元上的偏置。
a_j^l表示在第l^{th}層的第j^{th}個(gè)神經(jīng)元的激活值谒主,如上圖a^2_{4}代表第2層的第4個(gè)神經(jīng)元上的激活值朝扼。

有了這些表示,l^{th}層的第j^{th}個(gè)神經(jīng)元的激活值a^l_{j}就和(l-1)^{th}層的激活值a^{l-1}通過方程關(guān)聯(lián)起來了:

其中求和是在(l-1)^{th}層的全部k個(gè)神經(jīng)元之間進(jìn)行的霎肯。為了用矩陣的形式重寫這個(gè)表達(dá)式擎颖,我們對(duì)每一層l都定義了一個(gè)權(quán)重矩陣w^l榛斯。權(quán)重矩陣w^l的元素是連接到第l層的神經(jīng)元的權(quán)重(即指向第l層神經(jīng)元的全部箭頭)。同理搂捧,對(duì)每一層定義一個(gè)偏置向量b^l驮俗,向量中的每一個(gè)元素就是b^l_k。最后定義每一層的激活向量a^l允跑,向量中的每個(gè)元素是a^l_j王凑。
也許你還不明白這個(gè)怎么計(jì)算的,讓我以上圖的a^2_4來描述一下它的計(jì)算過程聋丝。我用橙色的線段來代表所有指向第2層第4個(gè)神經(jīng)元的權(quán)重索烹,可以看到一共有3條線段指向了它,其代表的權(quán)重分別是w^2_{41}弱睦,w^2_{42}百姓,w^2_{43},由于這是第一層况木,故它的激活向量就是輸入向量x垒拢,b_4^2代表的是這個(gè)神經(jīng)元的偏置值,那么完整的計(jì)算過程描述如下:
a^2_4 = \sigma (w^2_{41}*a^1_1 + w^2_{42}*a^1_2 + w^2_{43}*a^1_3 + b_4^2)

上面的公式(1)還是太麻煩了焦读,我們注意到(1)式中的參數(shù)w子库、ab其實(shí)都是向量矗晃,故我們可以將其改寫成矩陣形式仑嗅,如下:

這個(gè)式子看著更加簡(jiǎn)潔,它描述了第l層的激活值a^l與第l-1層的激活值a^{l-1}之間的關(guān)系张症。我們只需要將本層的權(quán)重矩陣作用在上一層的激活向量上仓技,然后加上本層的偏置向量,最后通過\sigma函數(shù)俗他,便得到了本層的激活向量脖捻。
如果將(2)式寫的更詳細(xì)一點(diǎn),其實(shí)我們是先得到了中間量z^l = w^l a^{l-1} + b^l兆衅,然后通過\sigma函數(shù)地沮。我們稱z^l為第l層神經(jīng)元的帶權(quán)輸入。故為了本文后面描述方便羡亩,我們也會(huì)將(2)式寫成以下形式:

注意z^l是一個(gè)向量摩疑,代表了第l層的帶權(quán)輸入。它的每一個(gè)元素是z^l_j = \sum_k w_{jk}^l a_k^{l-1} + b_j^l畏铆,其中z^l_j就是第l層的第j個(gè)神經(jīng)元的激活函數(shù)的帶權(quán)輸入雷袋。

注意,在本文中辞居,只帶了上標(biāo)而沒有帶下標(biāo)的表達(dá)式楷怒,都是指的向量蛋勺。


損失函數(shù)

還記得我們?cè)谏弦黄恼轮校褂昧司讲顡p失函數(shù)鸠删,定義如下:

其中n是訓(xùn)練樣本的總數(shù)抱完,求和運(yùn)算遍歷了每個(gè)訓(xùn)練樣本xy(x)是每個(gè)樣本對(duì)應(yīng)的標(biāo)簽冶共,L代表網(wǎng)絡(luò)的層數(shù)乾蛤,a^L代表的是輸入為x時(shí)網(wǎng)絡(luò)輸出的激活向量(在MNIST任務(wù)中,輸出是一個(gè)10維的向量)捅僵。
在上式中家卖,對(duì)于一個(gè)特定的輸入樣本集xny(x)都是固定的庙楚,所以我們可以將C看做是a^L的函數(shù)上荡。
本文將會(huì)繼續(xù)使用此損失函數(shù)來描述如何進(jìn)行反向傳播算法的應(yīng)用。


Hadamard乘積

反向傳播算法基于常規(guī)的線性代數(shù)運(yùn)算 —— 諸如向量加法馒闷,向量矩陣乘法等酪捡。但是有一個(gè)運(yùn)算不大常?。特別地纳账,假設(shè)st是兩個(gè)同樣維度的向量逛薇。那么我們使用s ⊙ t來表示按元素的乘積。所以s ⊙ t的元素就是(s ⊙ t)_j = s_jt_j疏虫。舉個(gè)例子如下:

這種類型的按元素乘法有時(shí)候被稱為Hadamard乘積永罚,具體定義可以參考百度百科


反向傳播

定義神經(jīng)元誤差

反向傳播其實(shí)是對(duì)權(quán)重和偏置變化影響損失函數(shù)過程的理解卧秘,最終的目的就是計(jì)算偏導(dǎo)數(shù)\partial C/ \partial w^l_{jk }\partial C / \partial b^l_j呢袱。為了計(jì)算這些值,我們首先引入一個(gè)中間量\delta ^l_j翅敌,我們稱之為在第l^{th}層的第j^{th}個(gè)神經(jīng)元上的誤差羞福。

為了理解誤差是如何定義的,假設(shè)在神經(jīng)網(wǎng)絡(luò)上有一個(gè)調(diào)皮?:


這個(gè)調(diào)皮鬼在第l層的第j^{th}個(gè)神經(jīng)元上蚯涮。當(dāng)輸入進(jìn)來的時(shí)候治专,這個(gè)調(diào)皮鬼對(duì)這個(gè)輸入增加了很小的變化\Delta z^l_j,使得神經(jīng)元輸出由原本的\sigma (z^l_j)變成了\sigma (z^l_j + \Delta z^l_j)遭顶。這個(gè)變化會(huì)依次向網(wǎng)絡(luò)后面的層進(jìn)行傳播看靠,最終導(dǎo)致整個(gè)損失函數(shù)產(chǎn)生\frac {\partial C }{\partial z^l_j} \Delta z^l_j的變化(具體可以參考全微分的定義)。
現(xiàn)在加入這個(gè)調(diào)皮鬼改邪歸正了液肌,并且試著幫你優(yōu)化損失函數(shù),它試著找到可以讓損失函數(shù)更小的\Delta z^l_j鸥滨。假設(shè)\frac {\partial C}{\partial z^l_j}有一個(gè)很大的值嗦哆,或正或負(fù)谤祖。那么這個(gè)調(diào)皮鬼可以通過選擇適當(dāng)?shù)?img class="math-inline" src="https://math.jianshu.com/math?formula=%5CDelta%20z%5El_j" alt="\Delta z^l_j" mathimg="1">來降低損失函數(shù)的值。相反老速,如果\frac {\partial C}{\partial z^l_j}接近0粥喜,那么無論怎么調(diào)整\Delta z^l_j都不能改善太多損失函數(shù)的值。因此橘券,在調(diào)皮鬼看來额湘,這時(shí)神經(jīng)元已經(jīng)接近最優(yōu)了。所以這里有一種啟發(fā)式的認(rèn)識(shí)旁舰,\frac {\partial C}{\partial z^l_j}可以認(rèn)為是神經(jīng)元誤差的度量锋华。

按照上面的描述,我們定義第l層的第j^{th}個(gè)神經(jīng)元上的誤差\delta ^l_j為:
\delta ^l_j = \frac {\partial C}{\partial z^l_j} \tag 5

反向傳播的四個(gè)方程

反向傳播基于4個(gè)基本方程箭窜,這些方程指明了計(jì)算誤差\delta ^l和損失函數(shù)梯度的方法毯焕。先列舉出來:

1. 輸出層誤差的方程

結(jié)合(3)式,我們簡(jiǎn)單證明一下第一個(gè)方程:

因?yàn)樯鲜街械那蠛褪窃谳敵鰧拥乃?img class="math-inline" src="https://math.jianshu.com/math?formula=k" alt="k" mathimg="1">個(gè)神經(jīng)元上運(yùn)行的磺樱,由于這里是求損失函數(shù)C對(duì)第L層的第j個(gè)神經(jīng)元的輸出激活值求導(dǎo)纳猫,故當(dāng)k \ne j時(shí), \partial a^L_k / \partial z^L_j都為0竹捉。

上式右邊第一個(gè)項(xiàng)\partial C / \partial a^L_j表示損失函數(shù)C隨著j^{th}輸出激活值的變化而變化的速度芜辕。假如C不依賴特定的神經(jīng)元j,那么\delta ^L_j就會(huì)比較小块差,這也是我們期望的效果侵续。右邊第二項(xiàng)\delta ' (z^L_j)表達(dá)的是在激活函數(shù)\sigmaz^L_j處的變化速度。
對(duì)于第一項(xiàng)\partial C / \partial a^L_j憾儒,它依賴特定的損失函數(shù)C的形式询兴,如果我們使用均方差損失函數(shù),那么其實(shí)很容易就可以算出來起趾,如下:

如果我們令\nabla _aC代表損失函數(shù)C對(duì)激活值向量a的偏導(dǎo)數(shù)向量诗舰,那么(6)式可以被寫成矩陣的形式:

(7)式就是反向傳播4個(gè)方程中的第一個(gè)方程。對(duì)于均方差損失函數(shù)训裆,\nabla _aC = (a^L - y)眶根,所以(7)式可以寫成如下形式:

寫成上述向量的形式是為了方便使用numpy之類的庫進(jìn)行矩陣計(jì)算。

2. 使用下一層的誤差\delta ^{l+1}來更新當(dāng)前層的誤差\delta ^{l}

第一個(gè)方程描述了輸出層的誤差\delta ^L边琉,那么如何求得前一層的誤差\delta ^{L-1}呢属百?我們還是可以從(5)式出發(fā),對(duì)其運(yùn)用鏈?zhǔn)椒▌t变姨,如下:

又根據(jù)上文族扰,我們知道z^l_j = \sum_k w_{jk}^l a_k^{l-1} + b_j^la^l= \sigma(z^l),因此可以得到:

上式對(duì)z^l_j微分的結(jié)果如下:

將式(11)帶入式子(9)得:

將式(12)寫成向量的形式渔呵,得到第二個(gè)方程:

其中(w^{l+1})^T代表第(l+1)^{th}層的權(quán)重矩陣的轉(zhuǎn)置怒竿。這個(gè)公式看起來挺復(fù)雜,但是每一項(xiàng)都有具體的意義扩氢。假如第(l+1)^{th}層的誤差是\delta ^{l+1}耕驰,當(dāng)我們使用同一層的轉(zhuǎn)置權(quán)重矩陣(w^{l+1})^T去乘以它時(shí),直觀感覺可以認(rèn)為它是沿著網(wǎng)絡(luò)反向地移動(dòng)誤差录豺,這給了我們度量在第l^{th}層輸出的誤差方法(還記得上文朦肘,我們使用帶箭頭的線段來表明權(quán)重么,這里這么做双饥,相當(dāng)于把第l層第j個(gè)神經(jīng)元指向第l+1層的所有神經(jīng)元的箭頭線段全部逆向了)媒抠。
接著我們進(jìn)行Hadamard乘積運(yùn)算,這會(huì)讓誤差通過第l層的激活函數(shù)反向傳遞回來兢哭,并給出在第l層的帶權(quán)輸入誤差\delta领舰。

我估計(jì)你看到這里會(huì)很懵逼,我當(dāng)時(shí)學(xué)習(xí)的時(shí)候也是非常迷惑迟螺,感覺腦子一團(tuán)糟冲秽,不過我將會(huì)以第二層第4個(gè)神經(jīng)元的誤差\delta ^2_4為例,來展示誤差的反向傳播過程矩父,根據(jù)式(12)锉桑,可以得出以下計(jì)算過程:

下面用圖例展示了誤差是如何從第三層的神經(jīng)元反向傳播到第二層的:

其實(shí)這個(gè)也很符合直覺,因?yàn)榈?層第4個(gè)神經(jīng)元連接到了第3層的全部神經(jīng)元窍株,故誤差反向傳播的時(shí)候民轴,應(yīng)該是與其連接的所有神經(jīng)元的誤差之和傳遞給此神經(jīng)元。

有了前兩個(gè)方程之后球订,我們就可以計(jì)算任何層的誤差\delta ^L后裸。首先使用方程(7)計(jì)算當(dāng)前層誤差\delta ^L,然后使用式(13)來計(jì)算得到\delta ^{L-1}冒滩,以此類推微驶,直到反向傳播完整個(gè)網(wǎng)絡(luò)。

3. 損失函數(shù)關(guān)于任意偏置b^l_j的變化率

由上面內(nèi)容可知开睡,z^l_j = \sum_k w_{jk}^l a_k^{l-1} + b_j^l因苹,z^l_j對(duì)b^l_j求偏導(dǎo)得\frac {\partial z^l_j}{\partial b^l_j} = 1。則有:

故可知篇恒,誤差\delta ^l_j和偏導(dǎo)數(shù)\partial C / \partial b^l_j完全一致扶檐。
寫成向量的形式如下:

其中\delta和偏置b都是針對(duì)同一個(gè)神經(jīng)元。

4. 損失函數(shù)對(duì)于任意一個(gè)權(quán)重的變化率

由上面內(nèi)容可知胁艰,z^l_j = \sum_k w_{jk}^l a_k^{l-1} + b_j^l款筑,z^l_j對(duì)w^l_{jk}求偏導(dǎo)得\frac {\partial z^l_j}{\partial w^l_{jk}} = a^{l-1}_k智蝠。又:

上式可以簡(jiǎn)化成更少下標(biāo)的表示:

其中a_{in}是上一層的激活輸出向量,\delta _{out}是當(dāng)前層的誤差奈梳,可以使用下圖來描述:


上圖說明寻咒,當(dāng)上一層的激活值a_{in}很小的時(shí)候,梯度\partial C / \partial w也會(huì)很小颈嚼,這意味著在梯度下降算法過程中,這個(gè)權(quán)重不會(huì)改變很多饭寺。這樣導(dǎo)致的問題就是來自較低激活值的神經(jīng)元的權(quán)重學(xué)習(xí)會(huì)非常緩慢阻课。
另外觀察一下前兩個(gè)方程,可以看到它們的表達(dá)式中都包含\sigma ' (z^l_k)艰匙,即要計(jì)算\sigma函數(shù)的導(dǎo)數(shù)限煞。回憶一下上一篇文章中Sigmoid函數(shù)的圖像员凝,可以看到署驻,當(dāng)輸入非常大或者非常小的時(shí)候,\sigma函數(shù)變得非常平坦健霹,即導(dǎo)數(shù)趨近于0旺上,這會(huì)導(dǎo)致梯度消失的問題,后面會(huì)專門寫文章討論糖埋。
總結(jié)一下宣吱,如果輸入神經(jīng)元激活值很低,或者神經(jīng)元輸出已經(jīng)飽和了瞳别,那么權(quán)重學(xué)習(xí)的過程會(huì)很慢征候。

反向傳播的算法流程

反向傳播的4個(gè)方程給出了一種計(jì)算損失函數(shù)梯度的方法,下面用算法描述出來:

  1. 輸入x祟敛,為輸入層設(shè)置對(duì)應(yīng)的激活值a^1疤坝。
  2. 前向傳播: 對(duì)每一層l=2,3,4,...,L,計(jì)算相應(yīng)的權(quán)重輸入z^L = w^la^l + b^la^l = \sigma (z^l)馆铁。
  3. 輸出層的誤差\delta ^L: 計(jì)算向量\delta ^L = \nabla C \ ⊙ \ \sigma ' (z^L)
  4. 誤差反向傳播:對(duì)于每一層l=L-1,L-2,...,2跑揉,計(jì)算\delta^l = ((w^{l+1})^T \delta ^{l+1}) ⊙ \sigma ' (z^L)
  5. 輸出: 損失函數(shù)的梯度分別由\frac {\partial C}{\partial w^l_{ji}} = a^{l-1}_k \delta ^L_j\frac {\partial C}{\partial b^l_j} = \delta ^L_j得出。

很多人在一開始學(xué)習(xí)的時(shí)候叼架,分不清梯度下降和反向傳播之間的關(guān)系畔裕,我最開始也是。不過從上面的流程中應(yīng)該可以了解一點(diǎn)乖订。梯度下降法是一種優(yōu)化算法扮饶,中心思想是沿著目標(biāo)函數(shù)梯度的方向更新參數(shù)值以希望達(dá)到目標(biāo)函數(shù)最小(或最大)乍构。而這個(gè)算法中需要計(jì)算目標(biāo)函數(shù)的梯度甜无,那么反向傳播就是在深度學(xué)習(xí)中計(jì)算梯度的一種方式扛点。

代碼解析

這里只列舉了代碼中反向傳播部分,若需完整代碼岂丘,請(qǐng)?jiān)?a target="_blank">https://github.com/HeartbreakSurvivor/FCN下載陵究。
我對(duì)代碼中關(guān)鍵步驟,都添加了詳細(xì)的注釋奥帘,讀者再對(duì)著文章內(nèi)容铜邮,應(yīng)該能夠看明白。

def update_mini_batch(self, mini_batch, eta):
    """
    通過小批量隨機(jī)梯度下降以及反向傳播來更新神經(jīng)網(wǎng)絡(luò)的權(quán)重和偏置向量
    :param mini_batch: 隨機(jī)選擇的小批量
    :param eta: 學(xué)習(xí)率
    """
    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:
        # 反向傳播算法寨蹋,運(yùn)用鏈?zhǔn)椒▌t求得對(duì)b和w的偏導(dǎo)
        delta_nabla_b, delta_nabla_w = self.backprop(x, y)
        # 對(duì)小批量訓(xùn)練數(shù)據(jù)集中的每一個(gè)求得的偏導(dǎo)數(shù)進(jìn)行累加
        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)]

    # 使用梯度下降得出的規(guī)則來更新權(quán)重和偏置向量
    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)]

def backprop(self, x, y):
    """
    反向傳播算法松蒜,計(jì)算損失對(duì)w和b的梯度
    :param x: 訓(xùn)練數(shù)據(jù)x
    :param y: 訓(xùn)練數(shù)據(jù)x對(duì)應(yīng)的標(biāo)簽
    :return: 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]
    # 前向傳播,計(jì)算網(wǎng)絡(luò)的輸出
    activation = x
    # 一層一層存儲(chǔ)全部激活值的列表
    activations = [x]
    # 一層一層第存儲(chǔ)全部的z向量已旧,即帶權(quán)輸入
    zs = []
    for b, w in zip(self._biases, self._weights):
        # 利用 z = wt*x+b 依次計(jì)算網(wǎng)絡(luò)的輸出
        z = np.dot(w, activation) + b
        zs.append(z)
        # 將每個(gè)神經(jīng)元的輸出z通過激活函數(shù)sigmoid
        activation = sigmoid(z)
        # 將激活值放入列表中暫存
        activations.append(activation)
    # 反向傳播過程

    # 首先計(jì)算輸出層的誤差delta L
    delta = self.cost_derivative(activations[-1], y) * sigmoid_prime(zs[-1])
    # 反向存儲(chǔ) 損失函數(shù)C對(duì)b的偏導(dǎo)數(shù)
    nabla_b[-1] = delta
    # 反向存儲(chǔ) 損失函數(shù)C對(duì)w的偏導(dǎo)數(shù)
    nabla_w[-1] = np.dot(delta, activations[-2].transpose())
    # 從第二層開始秸苗,依次計(jì)算每一層的神經(jīng)元的偏導(dǎo)數(shù) 
    for l in range(2, self._num_layers):
        z = zs[-l]
        sp = sigmoid_prime(z)
        # 更新得到前一層的誤差delta
        delta = np.dot(self._weights[-l + 1].transpose(), delta) * sp
        # 保存損失喊出C對(duì)b的偏導(dǎo)數(shù),它就等于誤差delta
        nabla_b[-l] = delta
        # 根據(jù)第4個(gè)方程运褪,計(jì)算損失函數(shù)C對(duì)w的偏導(dǎo)數(shù)
        nabla_w[-l] = np.dot(delta, activations[-l - 1].transpose())
    # 返回每一層神經(jīng)元的對(duì)b和w的偏導(dǎo)數(shù) 
    return (nabla_b, nabla_w)

參考

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末惊楼,一起剝皮案震驚了整個(gè)濱河市秸讹,隨后出現(xiàn)的幾起案子嗦枢,更是在濱河造成了極大的恐慌文虏,老刑警劉巖年鸳,帶你破解...
    沈念sama閱讀 216,324評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異膳算,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)机隙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門有鹿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來葱跋,“玉大人娱俺,你說我怎么就攤上這事∧砸纾” “怎么了屑彻?”我有些...
    開封第一講書人閱讀 162,328評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長违寿。 經(jīng)常有香客問我,道長掂咒,這世上最難降的妖魔是什么绍刮? 我笑而不...
    開封第一講書人閱讀 58,147評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮挨摸,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘油坝。我一直安慰自己刨裆,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,160評(píng)論 6 388
  • 文/花漫 我一把揭開白布帆啃。 她就那樣靜靜地躺著,像睡著了一般窍帝。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上疯坤,一...
    開封第一講書人閱讀 51,115評(píng)論 1 296
  • 那天菌瘫,我揣著相機(jī)與錄音布卡,去河邊找鬼忿等。 笑死栖忠,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的贸街。 我是一名探鬼主播庵寞,決...
    沈念sama閱讀 40,025評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼薛匪!你這毒婦竟也來了皇帮?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,867評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤蛋辈,失蹤者是張志新(化名)和其女友劉穎属拾,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體冷溶,經(jīng)...
    沈念sama閱讀 45,307評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡渐白,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,528評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了逞频。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片纯衍。...
    茶點(diǎn)故事閱讀 39,688評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖苗胀,靈堂內(nèi)的尸體忽然破棺而出襟诸,到底是詐尸還是另有隱情瓦堵,我是刑警寧澤,帶...
    沈念sama閱讀 35,409評(píng)論 5 343
  • 正文 年R本政府宣布歌亲,位于F島的核電站菇用,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏陷揪。R本人自食惡果不足惜惋鸥,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,001評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望悍缠。 院中可真熱鬧卦绣,春花似錦、人聲如沸飞蚓。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,657評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽趴拧。三九已至蜗搔,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間八堡,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,811評(píng)論 1 268
  • 我被黑心中介騙來泰國打工聘芜, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留兄渺,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,685評(píng)論 2 368
  • 正文 我出身青樓汰现,卻偏偏與公主長得像挂谍,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子瞎饲,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,573評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容