本文相關(guān)代碼可以從Backpropagation下載
在上一篇文章小白也能看懂的BP反向傳播算法之Towards-Backpropagation,我們學(xué)習(xí)了如何利用函數(shù)的微分來更新變量值,是函數(shù)值發(fā)生相應(yīng)的變化!
例如,對于函數(shù)

我們想要更新變量a,b的值使f的值增加,就可以根據(jù)以下公式來更新

實際上這就是反向傳播的最基本的思想!我們試想假設(shè)f函數(shù)是一個代價函數(shù),神經(jīng)網(wǎng)絡(luò)的訓(xùn)練就是將代價函數(shù)的值變小,那么就是問題就變成了,對于一個代價函數(shù)f,我們將改變f的變量,使其f能減小,而f不就是關(guān)于每個神經(jīng)元權(quán)重和偏置的函數(shù)么,f = f(w,b)。只不過是代價函數(shù)的變量更多,函數(shù)形式更復(fù)雜,更新起來相對復(fù)雜,這個我們將在后面詳細(xì)介紹!但其實反向傳播的基本思想就是根據(jù)微分去更新!
接下來,我們就將問題慢慢復(fù)雜化,一步一步接近最終的神經(jīng)網(wǎng)絡(luò)中的反向傳播!
前文中,我們利用的是一個神經(jīng)元,這里我們講問題變復(fù)雜,變成兩個神經(jīng)元,并且是有嵌套關(guān)系的兩個神經(jīng)元!如下圖:

,將輸入值相加然后輸出到第二個神經(jīng)元,同時第二個神經(jīng)元還接受輸入c,并將兩個值相乘,最后輸出!
這個簡單網(wǎng)絡(luò)的正向傳播很容易寫出來:
def product(x, y):
return x * y
def addition(x, y):
return x + y
def forward(a, b, c):
d = addition(a, b)
return product(d, c)
print(forward(5, -6, 7))
Our aim is still the same as was in last post viz;we want to manipulate the values of our inputs a,b,c in such a way that the value of output fincreases.
現(xiàn)在開始我們的訓(xùn)練吧!
目標(biāo)和之前一樣,就是改變輸入的a,b,c三個值,使函數(shù)f的值增加!之后我們就會發(fā)現(xiàn),在這個過程中,我們會慢慢接觸到反向傳播的核心思想!
previous post.
初看上去,這個網(wǎng)絡(luò)似乎比之前的要復(fù)雜,但依照我們前一篇文章提出的思路!我們先看函數(shù)f,函數(shù)f是一個關(guān)于輸入a,b,c的函數(shù),想要讓函數(shù)f的值增加,直接微分即可,然后加上步長與微分的乘積,如下:

所以,核心問題在此就變成怎么求解函數(shù)f關(guān)于a,b,c的微分!
我們不能向之前一個神經(jīng)元那樣直接計算,因為此處的神經(jīng)元是相互嵌套的。我們將函數(shù)f反著往回寫!
首先,與函數(shù)f直接關(guān)聯(lián)的神經(jīng)元,就是接受兩個輸入,一個來自第一個神經(jīng)元的,一個來自輸入c,我們把第一個神經(jīng)元的輸出記作d,那么函數(shù)f就可以寫成

然后我們繼續(xù)反著往前推,對于d,其實就是第一個神經(jīng)元的輸出,也就是可以直接寫成:

這樣我們就反向的把函數(shù)f簡化成了兩個函數(shù):

熟悉微積分的朋友應(yīng)該就知道,我們在此可以利用函數(shù)求微分的鏈?zhǔn)椒▌t。

分別求微分之后,如下:


求微分

現(xiàn)在我們有四個微分的值:

我們的目標(biāo)是求取這三個微分的值:

Backpropagation
這個時候,就輪到鏈?zhǔn)椒▌t出場了!
鏈?zhǔn)椒▌t其實就是:

如我們所見,鏈?zhǔn)椒▌t有點代數(shù)的特點;因為萊布尼茲的導(dǎo)數(shù)符號表明兩個分式中的du可以消掉,所以這個公式很好記憶。如果我們將導(dǎo)數(shù)看作變化率的話,直觀上也很容易理解:
如果y的變化速度是u的a倍,u的變化速度是x的b倍,那么y的變化速度是x的ab倍。
或者用日常用語來說,如果車的速度是自行車的兩倍,自行車的速度是步行的四倍,那么車的速度是步行的2?4=8倍。
所以此處我們對a,b應(yīng)用鏈?zhǔn)椒▌t,就能求取出微分:


所以最后求出微分就是:

根據(jù)以上求出的微分,我們就能很好的寫出變量的更新規(guī)則:

我們用python實現(xiàn)上面的更新的過程:
def product(x, y):
return x * y
def addition(x, y):
return x + y
def forward(a, b, c):
d = addition(a, b)
return product(d, c)
print(forward(5, -6, 7))# output -7
def update(a, b, c):
d = addition(a, b)
h = 0.01
derivative_f_d = c
derivative_f_c = d
derivative_d_a = 1
derivative_d_b = 1
derivative_f_a = derivative_f_d * derivative_d_a
derivative_f_b = derivative_f_d * derivative_d_b
a = a + h * derivative_f_a
b = b + h * derivative_f_b
c = c + h * derivative_f_c
d = addition(a, b)
return product(d, c)
print(update(5, -6, 7))# output -6.0113999999999965
可以看到更新之后的輸出確實增大了!說明我們現(xiàn)在已經(jīng)可以實現(xiàn)嵌套神經(jīng)元的變量參數(shù)的更新了!離真正的反向傳播的又近了一步!
Why did it work?
接下來,我們深入整個更新的過程,一步步分析看看究竟更新的本質(zhì)是什么。首先,我們從輸入到輸出,分析一遍,前向傳播,輸入值為a=5,b=-6,c=7,很容易發(fā)現(xiàn),第一個神經(jīng)元的輸出為d為1,然后第二個神經(jīng)元輸出為-7,所以最后結(jié)果就是-7!這就是此網(wǎng)絡(luò)前向傳播的過程!
然后我們開始反向傳播,從輸出開始分析,我們現(xiàn)在的目標(biāo)是將輸出的值增大,輸出值是由-1*7得到的,現(xiàn)在要增加輸出值,我們先不看微分,顯然就是增加-1,減少7,這樣就能使他們的乘積變大!我們再來計算微分,微分結(jié)果就是增加d的值,減少c的值。我們繼續(xù)反向推理,這里d的值又是有a,b的值決定的!我們現(xiàn)在的目標(biāo)又變成了
對于第一個神經(jīng)元,減少輸出值,那么很顯然,只要減少a和b的值就行了,我們運(yùn)用鏈?zhǔn)椒▌t求取a,b的微分,也能得到相同的結(jié)果!
我們可以看到,當(dāng)我們反向傳播的時候,一個神經(jīng)元的輸入會變成上一個神經(jīng)元的輸出,然后他們之間相互影響,從而使傳播下去!
我們倒著從輸出分析到輸入的過程就是反向傳播的過程!我們通過計算微分可以從輸出到輸入更新變量的值,以使得輸出朝著我們期待的方向的變化!
待續(xù)
本文就在這里結(jié)束了!本文將前文的更新變量的算法擴(kuò)展到嵌套的多個神經(jīng)元中,并應(yīng)用到了鏈?zhǔn)椒▌t求微分!而且在這個過程中,其實我們已經(jīng)逐漸接觸到反向傳播的基本思想!
下一篇文章小白也能看懂的BP反向傳播算法之Let's practice Backpropagation,我們會將算法應(yīng)用到一個標(biāo)準(zhǔn)的神經(jīng)網(wǎng)絡(luò)中,讓我們看看真正的反向傳播算法是什么樣的!
本文相關(guān)代碼可以從Backpropagation下載