中文字幕精品亚洲无线码二区,国产黄a三级三级三级看三级,亚洲七七久久桃花影院,丰满少妇被猛烈进入,国产小视频在线观看网站

手算神經網絡BP傳播算法(fa)

雖然說是手算,但是我還是會(hui)寫一點 C# 代碼,避(bi)免敲壞了計(ji)(ji)算器。我和大家保證,整個(ge)手算過程(cheng)中,最(zui)終的(de)計(ji)(ji)算結(jie)果(guo)只需要用到初高(gao)中知(zhi)識(shi)。推導過程(cheng)會(hui)用到部分高(gao)數的(de)知(zhi)識(shi)。我盡量(liang)將用到的(de)知(zhi)識(shi)點全列(lie)舉出來,本文(wen)對學(xue)渣友好(hao),期望(wang)能夠拿(na)出紙筆和 VisualStudio 的(de)伙伴閱讀完本文(wen)能夠真的(de)理解神經(jing)網絡(luo)BP傳播算法是如(ru)何計(ji)(ji)算的(de)

看了(le)(le)一(yi)下時(shi)間,今年(nian)(nian)確實(shi)(shi) 2025 年(nian)(nian),而不(bu)是(shi)(shi) 2015 年(nian)(nian)。在 2025 時(shi)還在聊(liao)BP 算(suan)(suan)法(fa)(fa)實(shi)(shi)在有點一(yi)言難盡(jin)(jin)。我(wo)在 10 多年(nian)(nian)前(qian)嘗試(shi)寫(xie)過貼近(jin)的(de)(de)(de)(de)(de)(de)程(cheng)序,當時(shi)寫(xie)的(de)(de)(de)(de)(de)(de)時(shi)候有一(yi)些概念(nian)沒有理(li)解(jie)(jie)(jie),但(dan)代(dai)碼(ma)(ma)(ma)是(shi)(shi)寫(xie)了(le)(le)也能(neng)(neng)跑(pao),甚至于在當時(shi)世界上(shang)最(zui)快的(de)(de)(de)(de)(de)(de)超級計(ji)算(suan)(suan)機跑(pao)了(le)(le)我(wo)的(de)(de)(de)(de)(de)(de)代(dai)碼(ma)(ma)(ma)。但(dan)不(bu)能(neng)(neng)理(li)解(jie)(jie)(jie)的(de)(de)(de)(de)(de)(de)部分就(jiu)是(shi)(shi)不(bu)能(neng)(neng)理(li)解(jie)(jie)(jie)。最(zui)近(jin)在散步(bu)(bu)的(de)(de)(de)(de)(de)(de)時(shi)候,我(wo)的(de)(de)(de)(de)(de)(de)伙伴 和(he)我(wo)說(shuo)明白(bai)了(le)(le)求偏導的(de)(de)(de)(de)(de)(de)數學意義。我(wo)當初高數學了(le)(le)3年(nian)(nian),別人(ren)都是(shi)(shi)只學一(yi)年(nian)(nian)(因為(wei)我(wo)不(bu)斷掛(gua)科(ke)),那會以(yi)為(wei)偏導沒有什(shen)么(me),于是(shi)(shi)缺了(le)(le)一(yi)個(ge)知(zhi)(zhi)識點,導致我(wo)對(dui) BP 的(de)(de)(de)(de)(de)(de)部分理(li)解(jie)(jie)(jie)錯誤。盡(jin)(jin)管代(dai)碼(ma)(ma)(ma)能(neng)(neng)跑(pao),也能(neng)(neng)符合預(yu)期進行訓練,但(dan)里(li)面(mian)關(guan)于傳播算(suan)(suan)法(fa)(fa)中,如(ru)何計(ji)算(suan)(suan)各個(ge)權(quan)重參數的(de)(de)(de)(de)(de)(de)過程(cheng)我(wo)是(shi)(shi)不(bu)能(neng)(neng)全說(shuo)明白(bai)的(de)(de)(de)(de)(de)(de)。我(wo)最(zui)近(jin)理(li)解(jie)(jie)(jie)了(le)(le)偏導的(de)(de)(de)(de)(de)(de)數學意義之后,再到知(zhi)(zhi)乎上(shang)閱讀(du)了(le)(le) 通俗理(li)解(jie)(jie)(jie)神(shen)經(jing)網絡(luo)BP傳播算(suan)(suan)法(fa)(fa)( ) 文章(zhang),嘗試(shi)按照(zhao)知(zhi)(zhi)乎文章(zhang)的(de)(de)(de)(de)(de)(de)給定的(de)(de)(de)(de)(de)(de)內(nei)容(rong)和(he)方法(fa)(fa),自己(ji)(ji)手算(suan)(suan)了(le)(le)一(yi)遍,我(wo)就(jiu)完全理(li)解(jie)(jie)(jie)了(le)(le)之前(qian)我(wo)所寫(xie)的(de)(de)(de)(de)(de)(de)代(dai)碼(ma)(ma)(ma)了(le)(le)。擔(dan)心本(ben)(ben)金魚會忘了(le)(le)之前(qian)的(de)(de)(de)(de)(de)(de)想法(fa)(fa),或者擔(dan)心下次(ci)和(he)伙伴聊(liao)天(tian)的(de)(de)(de)(de)(de)(de)時(shi)候又說(shuo)錯了(le)(le),我(wo)就(jiu)編寫(xie)了(le)(le)本(ben)(ben)文。可以(yi)認(ren)為(wei)本(ben)(ben)文沒有給出比 通俗理(li)解(jie)(jie)(jie)神(shen)經(jing)網絡(luo)BP傳播算(suan)(suan)法(fa)(fa)( ) 文章(zhang)更多的(de)(de)(de)(de)(de)(de)內(nei)容(rong),只是(shi)(shi)按照(zhao)我(wo)自己(ji)(ji)的(de)(de)(de)(de)(de)(de)方式一(yi)步(bu)(bu)步(bu)(bu)推導和(he)計(ji)算(suan)(suan)。閱讀(du)完本(ben)(ben)文,預(yu)期大家能(neng)(neng)夠對(dui)神(shen)經(jing)網絡(luo)有了(le)(le)更明了(le)(le)的(de)(de)(de)(de)(de)(de)理(li)解(jie)(jie)(jie)。如(ru)果大家還是(shi)(shi)在迷(mi)迷(mi)糊糊地訓練人(ren)工(gong)智能(neng)(neng)做(zuo)玄(xuan)學的(de)(de)(de)(de)(de)(de)活,那閱讀(du)本(ben)(ben)文可以(yi)讓(rang)大家能(neng)(neng)夠稍微有點落地的(de)(de)(de)(de)(de)(de)感覺,至少大概知(zhi)(zhi)道簡單的(de)(de)(de)(de)(de)(de) BP 神(shen)經(jing)網絡(luo)是(shi)(shi)如(ru)何工(gong)作(zuo)起來(lai)的(de)(de)(de)(de)(de)(de)

我努力(li)讓大家盡量少知識地開局(ju)

開始之前,期望(wang)大(da)家(jia)已經聽說過(guo)一些神(shen)經網(wang)絡(luo)的(de)(de)概念。這里只要求(qiu)聽說過(guo),不解其中的(de)(de)內容也(ye)沒(mei)關系(xi),有部分概念我沒(mei)提到的(de)(de),也(ye)許大(da)家(jia)看完(wan)了自然就能明(ming)白,或閱讀完(wan)本文(wen)之后(hou)再繼(ji)續在網(wang)上(shang)搜(sou)關鍵詞繼(ji)續了解。期望(wang)聽說過(guo)的(de)(de)概念有:神(shen)經網(wang)絡(luo)、圖論、矩陣(zhen)、激活函(han)數、損(sun)失函(han)數、權重

神經網絡可以理解圖(tu)(tu)(tu)論上的(de)(de)(de)一(yi)(yi)張(zhang)圖(tu)(tu)(tu),盡(jin)管在(zai)幾乎所有的(de)(de)(de)科普文(wen)(wen)章中,都會(hui)使(shi)用(yong)(yong)到(dao)矩(ju)(ju)陣,但從原理上說都是圖(tu)(tu)(tu)論的(de)(de)(de)一(yi)(yi)張(zhang)圖(tu)(tu)(tu)。經費有限,有了節省矩(ju)(ju)陣的(de)(de)(de)出場費,本文(wen)(wen)就(jiu)不帶入矩(ju)(ju)陣的(de)(de)(de)內容了,直(zhi)接平鋪進行(xing)計算。本文(wen)(wen)也不會(hui)用(yong)(yong)到(dao)多少(shao)圖(tu)(tu)(tu)論的(de)(de)(de)知識,只(zhi)是用(yong)(yong)了一(yi)(yi)點(dian)圖(tu)(tu)(tu)論上的(de)(de)(de)概念。本文(wen)(wen)介紹的(de)(de)(de)手算的(de)(de)(de)神經網絡是一(yi)(yi)個簡單的(de)(de)(de)有向圖(tu)(tu)(tu),只(zhi)有5個點(dian)。即使(shi)沒有了解過圖(tu)(tu)(tu)論的(de)(de)(de)伙伴(ban),也許通過示意圖(tu)(tu)(tu)也能夠看懂(dong)

本(ben)文的(de)(de)(de)(de)(de)手算(suan)內容是假定(ding)咱就(jiu)是一(yi)個無情(qing)的(de)(de)(de)(de)(de)計算(suan)機(ji),正(zheng)在被(bei)訓練(lian)的(de)(de)(de)(de)(de)人(ren)工智能(neng)。咱的(de)(de)(de)(de)(de)需(xu)要計算(suan)出圖(tu)上(shang)(圖(tu)論的(de)(de)(de)(de)(de)圖(tu))的(de)(de)(de)(de)(de)各個點的(de)(de)(de)(de)(de)權重。為了(le)讓人(ren)類更方便理(li)解,以下(xia)圖(tu)中,我給(gei)定(ding)了(le)明確的(de)(de)(de)(de)(de)數值。假定(ding)輸入是兩(liang)個數字,期望經過咱訓練(lian)出來的(de)(de)(de)(de)(de)神經網絡(luo)之(zhi)后(hou),能(neng)夠獲取符合(he)預期的(de)(de)(de)(de)(de)輸出數字。這樣的(de)(de)(de)(de)(de)模擬情(qing)況,就(jiu)能(neng)夠覆蓋(gai)非常(chang)多的(de)(de)(de)(de)(de)情(qing)況了(le)。也許有伙伴(ban)此時還會有一(yi)些疑惑(huo),沒(mei)關系,先帶(dai)著(zhu)疑惑(huo)看下(xia)去吧,我也不能(neng)一(yi)口氣全交(jiao)代清(qing)楚情(qing)況

以下是(shi)咱的(de)神經網絡圖(圖論(lun)的(de)圖)的(de)示意圖

其中(zhong) a 和 b 兩個(ge)(ge)點負(fu)(fu)責(ze)輸入,e點負(fu)(fu)責(ze)輸出(chu)。各個(ge)(ge)點之間(jian)的(de)(de)(de)連接存在權重,其示意圖如下(xia)(xia),下(xia)(xia)圖的(de)(de)(de) wxx 表示的(de)(de)(de)就(jiu)是(shi)各個(ge)(ge)邊的(de)(de)(de)權重。寫成 wxx 的(de)(de)(de)形式其實(shi)就(jiu)是(shi)在隱含矩陣(zhen)的(de)(de)(de)概念(nian)了,只是(shi)咱本(ben)文這(zhe)里不需(xu)要請(qing)出(chu)矩陣(zhen)而已,如果真套上(shang)矩陣(zhen)的(de)(de)(de)話(hua),這(zhe)里的(de)(de)(de)權重就(jiu)是(shi) w行列的(de)(de)(de)表示法(fa)(fa),即 w21 就(jiu)是(shi)表示第2行第1列的(de)(de)(de)值(zhi)。這(zhe)也是(shi)一個(ge)(ge)習(xi)慣表示方(fang)法(fa)(fa)

假定有輸入源 x0=0.35 x1=0.9 , 期望的輸出是 \(y_{out}=0.5\)。這就是一組訓練值,當然了,在實際的神經網絡訓練里面,肯定會給許多組訓練值的。只是現在換成人類手算,需要降低難度,就只要求訓練這一組數據。假定沒有神經網絡,就是一個正常人類在拿到 x0=0.35 x1=0.9的輸入,要求寫出一個函數,讓這個函數能夠根據此輸入計算出 \(y_{out}=0.5\) 的值,估計也沒那么簡單(禁止直接寫 \(f(x0,x1)=0.5\) 這樣的(de)拖出去打靶的(de)函(han)數)

為了更加方便大家理解,這里先給各個權重添加隨機的初始值。初始值很多時候真的是隨機給的,依靠的是訓練過程中不斷算法修改參數,從而訓練出一個可用的神經網絡。咱現在這個神經網絡只是期望訓練出當拿到 x0=0.35 x1=0.9 的輸入時,能夠返回 \(y_{out}=0.5\) 的(de)(de)輸出。標記了添加了隨機權重初始(shi)值的(de)(de)示意圖如下

好的,勤奮的伙伴可以開始拿出紙筆,在紙上畫出以上示意圖內容了。云程序猿們沒有紙筆那就進入幻想模式,我不會讓大家不至于說沒紙筆就看不下去的
對于一個正常的神經網絡來說,每個點就是一個神經元,神經元里面包含了激活函數。在本文這里選定的 \(f(x)\) 激(ji)活函數的定(ding)義如(ru)下

世(shi)界上的激(ji)活(huo)函數有許許多(duo)多(duo),沒(mei)有說一定要用(yong)哪(na)個激(ji)活(huo)函數,大家也可(ke)以在閱讀完(wan)本(ben)文之后,自己嘗試(shi)其他的激(ji)活(huo)函數

在本文的 BP 神經網絡里面,是取所有的輸入乘以各自的權重之和,進入激活函數計算,從而得到輸出。我將取所有的輸入乘以各自的權重之和記為 \(z_n\),將經過激活函數之后的輸出記為\(y_n\) ,其示意圖如下

也許大家看到這里開始有疑惑了,憑什么神經網絡是這樣子的。沒為什么,最簡單的神經網絡只需要一個神經元即可,但一個神經元能做的事情就太弱了。雖然本文的圖(圖論的圖)有5個點,但實際上 a 和 b 點都是在接收輸入,實際參與計算只有三個點,相對來說已經足夠簡化了。在閱讀完本文之后,大家也可以試試玩玩更多點和更多層的神經網絡,只不過這時候就需要多寫寫代碼啦,全靠手算可有點難哦
 似乎現在(zai)這(zhe)個示意圖(tu)看(kan)起來就有(you)些復雜了,但(dan)相信(xin)如果是一步步看(kan)下來的(de)伙伴,自然能夠很(hen)快(kuai)理解示意圖(tu)的(de)內容了

寫到這里,咱(zan)距離(li)整個簡(jian)單 BP 神經網(wang)絡就只剩下 損失(shi)函數(shu)(Loss Function)的定(ding)義了。簡(jian)單說明損失(shi)函數(shu)就是(shi)用(yong)來度(du)量神經網(wang)絡輸出的值(zhi)與(yu)預期期望值(zhi)的差異程度(du)的函數(shu)

損失函數要能反饋結果和預期的距離,且還要能夠求導有意義。一聽到反饋結果和預期的距離,大家可能想到的就是直接減就可以了,如這樣的一個函數\(C=y_2-y_{out}\),但在后續步驟里一求導就約分沒了,算出來的\(C^{'}=1\),自然就無法繼續進行下去了。那求差的平方呢,如\(C=(y_2-y_{out})^2\)呢?這個就好多了,加上平方也不用去煩惱絕對值的問題了,那自然就求結果和預期的差的平方好了。試試看求導的結果 \(C^{'}=2y_2-2y_{out}\),這一求(qiu)導發現約分(fen)出(chu)了(le)2的(de)值,那索性(xing)繼續乘以(yi)二分(fen)之一好(hao)了(le),這樣求(qiu)導返(fan)回(hui)結果(guo)剛好(hao)就是(shi)(shi)簡(jian)單的(de)減(jian)法,計算(suan)機看了(le)非常開森。于(yu)是(shi)(shi)決定出(chu)來的(de)損失函數定義如下(xia)

看(kan)到這里(li)相信(xin)大家也感受到了照現在的(de)(de)(de)人類的(de)(de)(de)數學能(neng)(neng)力還不能(neng)(neng)讓大家隨意寫一個函(han)(han)數,就能(neng)(neng)獲取(qu)預期(qi)(qi)的(de)(de)(de)結果。在本文的(de)(de)(de)手算過程(cheng)中,也許大家也就能(neng)(neng)夠(gou)理解神經網絡的(de)(de)(de)能(neng)(neng)力邊(bian)界。所(suo)使用的(de)(de)(de)各(ge)個函(han)(han)數都有一些原因(yin),不一定是期(qi)(qi)望獲取(qu)咋(za)樣的(de)(de)(de)結果就能(neng)(neng)用對應(ying)的(de)(de)(de)函(han)(han)數,還需要(yao)所(suo)使用的(de)(de)(de)函(han)(han)數剛好(hao)從數學上(shang)能(neng)(neng)夠(gou)幫助后(hou)續的(de)(de)(de)計算

如此(ci)咱的所(suo)有內容就(jiu)都定義完成(cheng)了。為了防(fang)止大家忘記現在的狀態,我再次放入當前的示(shi)意(yi)圖,咱接下來就(jiu)按(an)照這個(ge)意(yi)義圖開(kai)始將(jiang)自己當成(cheng)一個(ge)神經網絡,進行手算過程

拿出紙筆的(de)(de)(de)伙伴(ban)可以(yi)將上(shang)述的(de)(de)(de)示意圖抄在(zai)草(cao)稿紙上(shang),咱現在(zai)就來(lai)開始(shi)第一(yi)輪(lun)的(de)(de)(de)計算(suan)(suan)過程。打開了 VisualStudio 的(de)(de)(de)伙伴(ban),還請創建好控(kong)制臺(tai)項目,開始(shi)記(ji)錄一(yi)些代碼,先是一(yi)些初始(shi)化的(de)(de)(de)變量(liang)或常量(liang)的(de)(de)(de)值(zhi)(zhi)。為了確保讓大(da)家能夠校驗自(zi)己(ji)的(de)(de)(de)計算(suan)(suan)結果(guo)內容,我這里的(de)(de)(de)代碼就寫固定(ding)值(zhi)(zhi),而(er)不是使用隨機(ji)數,這樣也好方(fang)便紙筆手算(suan)(suan)的(de)(de)(de)伙伴(ban)對比計算(suan)(suan)差異

const double x0 = 0.35;
const double x1 = 0.9;

const double y_out = 0.5;

var a = x0;
var b = x1;

var w11 = 0.1;
var w12 = 0.8;

var w21 = 0.4;
var w22 = 0.6;

var w31 = 0.3;
var w32 = 0.9;

var count = 0;

看到以(yi)上的(de)代碼,也(ye)許有伙伴(ban)有疑惑,以(yi)上代碼中的(de) y_out 是不(bu)(bu)是不(bu)(bu)符合 C# 代碼規(gui)范?我(wo)這里是借用(yong) Latex 的(de)表示,表示 y_out 常量,按照 Latex 寫法就是 y_out 啦。因此就不(bu)(bu)要將其改成 yOut 或 YOut 哦

來進行一步步的計算過程,求 \(z_0\) 的值

對應的代碼實現如下

var z0 = w11 * a + w12 * b;

這個過程看起來十分簡單,就是將所有進入 c 點的輸入乘以對應的權重返回的和。同理繼續計算d點的\(z_1\)的值

對應的代碼如下

var z1 = w21 * a + w22 * b;

分別讓 \(z_0\)\(z_1\) 經過 \(f(x)\) 激活函數,可分別得到 \(y_0\)\(y_1\) 的值

也許大家用計算器算出來的小數點精度有些差異,但只要前面幾位差不多就可以,對于神經網絡來說不用太精確
對(dui)應的代碼如下,封裝(zhuang)了 F 函數

double F(double x)
{
    return 1.0 / (1 + Math.Pow(Math.E, -x));
}
var y0 = F(z0);
var y1 = F(z1);

繼續計算 \(z_2\) 的值

對應的代碼如下

var z2 = w31 * y0 + w32 * y1;

\(z_2\) 經過激活函數,可得到\(y_2\)的值

對應的代碼如下

var y2 = F(z2);

此時可見這一輪的輸出\(y_2\)距離預期的\(y_{out}\)還有點距離。具體(ti)度量(liang)的距離有多大,那(nei)就要經過損失函數計算看

對應的代碼如下

var c = C(y2);
static double C(double y2)
{
    return 1.0 / 2 * Math.Pow((y2 - y_out), 2);
}

完成了第一輪計算,接下來就是進行第一輪訓練,進行 BP 的傳播算法。此時在推導計算過程,就需要用到偏導的知識了。其中包括了偏導的鏈式計算和對函數求導的知識。借用從 //www.ywjunkang.com/awei040519/articles/18529084 博客的(de)(de)(de)一(yi)張圖來說明偏導在(zai)(zai)這里(li)(li)的(de)(de)(de)意義(yi)。在(zai)(zai)這里(li)(li)的(de)(de)(de)意義(yi)就(jiu)是假定輸(shu)入到(dao)輸(shu)出中(zhong)間經過(guo)的(de)(de)(de)神(shen)經網絡(luo)的(de)(de)(de)某些權重變量(liang)(liang)計算之后,能夠(gou)獲取預期的(de)(de)(de)輸(shu)出內容,求(qiu)解神(shen)經網絡(luo)中(zhong)的(de)(de)(de)權重變量(liang)(liang)的(de)(de)(de)值(zhi)。這個(ge)求(qiu)解過(guo)程有解,即(ji)是求(qiu)讓(rang)損失函數(shu)快速到(dao)達一(yi)個(ge)極(ji)小(xiao)點。在(zai)(zai)偏導意義(yi)里(li)(li)面,極(ji)大和(he)極(ji)小(xiao)這些極(ji)值(zhi)是相(xiang)同的(de)(de)(de),從極(ji)大到(dao)極(ji)小(xiao)的(de)(de)(de)轉換只需乘以(yi)負一(yi)即(ji)可(ke)

沒(mei)有(you)(you)經過損失函數(shu)可不(bu)可以(yi)?可以(yi)的(de)(de)(de)(de),但(dan)是(shi)存(cun)在的(de)(de)(de)(de)問(wen)題是(shi),如(ru)果不(bu)用隨機數(shu)隨便亂碰(peng),那怎么能(neng)(neng)夠知(zhi)道各(ge)個(ge)權(quan)重(zhong)(zhong)應(ying)(ying)該(gai)如(ru)何調,應(ying)(ying)該(gai)是(shi)朝著加(jia)(jia)號(hao)方向(xiang)(xiang)調還是(shi)減號(hao)方向(xiang)(xiang)調好呢。假(jia)定咱(zan)有(you)(you)無窮的(de)(de)(de)(de)計(ji)算(suan)時(shi)間,那就不(bu)停各(ge)個(ge)參數(shu)加(jia)(jia)0.00001或0或-0.00001給他全遍歷即可,這(zhe)(zhe)樣(yang)自(zi)然(ran)能(neng)(neng)夠獲取很(不(bu)敢說(shuo)最(zui)哈)優(you)解(jie)。但(dan)大家肯(ken)定也(ye)看出來問(wen)題,這(zhe)(zhe)樣(yang)的(de)(de)(de)(de)做法需要大量(liang)的(de)(de)(de)(de)時(shi)間,且隨著圖(圖論(lun)的(de)(de)(de)(de)圖)上(shang)(shang)的(de)(de)(de)(de)點(dian)越多,這(zhe)(zhe)個(ge)計(ji)算(suan)時(shi)間就會越長,且是(shi)排列組合的(de)(de)(de)(de)快速(su)(su)加(jia)(jia)長,也(ye)許此時(shi)只有(you)(you)量(liang)子計(ji)算(suan)機才能(neng)(neng)計(ji)算(suan)了(le)。聰明的(de)(de)(de)(de)數(shu)學家想到(dao)了(le)利(li)用數(shu)學上(shang)(shang)的(de)(de)(de)(de)偏導工具,協助(zhu)更快速(su)(su)求較(jiao)優(you)解(jie)的(de)(de)(de)(de)權(quan)重(zhong)(zhong)數(shu)值解(jie)。如(ru)上(shang)(shang)圖所(suo)示(shi),利(li)用偏導數(shu)協助(zhu)求某一個(ge)切面上(shang)(shang)的(de)(de)(de)(de)函數(shu)導數(shu)的(de)(de)(de)(de)極(ji)值方向(xiang)(xiang)從(cong)而讓權(quan)重(zhong)(zhong)的(de)(de)(de)(de)修改能(neng)(neng)夠更快到(dao)達較(jiao)優(you)解(jie),如(ru)從(cong) 拷貝(bei)的(de)(de)(de)(de)動圖所(suo)示(shi)

讀過高(gao)數的(de)(de)伙伴也許(xu)有(you)(you)疑惑,由于偏導只是(shi)求一(yi)個切面(mian)方(fang)向上(shang)的(de)(de),而整個網絡是(shi)依(yi)靠多(duo)個權重(zhong)一(yi)起(qi)工作的(de)(de),那是(shi)否會導致畫出來的(de)(de)函數圖實際上(shang)有(you)(you)多(duo)個極(ji)值呢?沒錯,這(zhe)就是(shi)局部(bu)最(zui)優解陷阱。好在本文這(zhe)里足(zu)夠(gou)簡單,還不會踩到(dao)這(zhe)個坑。進入局部(bu)最(zui)優解陷阱時(shi),也許(xu)經過了很多(duo)輪的(de)(de)訓練,其輸(shu)出也不能達到(dao)預(yu)期,這(zhe)時(shi)候就是(shi)大佬們常說的(de)(de)煉(lian)丹(dan)結果是(shi)廢丹(dan)了,需要重(zhong)新修改權重(zhong)為隨機數重(zhong)新煉(lian)丹(dan)

求出(chu)來各個(ge)(ge)權(quan)重(zhong)(zhong)對應偏(pian)導數(shu)(shu)值(zhi)之后,就可以更(geng)新(xin)(xin)各個(ge)(ge)權(quan)重(zhong)(zhong)的(de)值(zhi),進(jin)行下一(yi)輪(lun)計算(suan)。下一(yi)輪(lun)計算(suan)結果輸出(chu)之后,再(zai)經(jing)過損(sun)失(shi)函數(shu)(shu)判(pan)斷是否(fou)結果已經(jing)接近了。如果不接近,則(ze)再(zai)次求各個(ge)(ge)權(quan)重(zhong)(zhong)對應偏(pian)導數(shu)(shu)值(zhi),用各個(ge)(ge)權(quan)重(zhong)(zhong)對應偏(pian)導數(shu)(shu)值(zhi)更(geng)新(xin)(xin)各個(ge)(ge)權(quan)重(zhong)(zhong)的(de)值(zhi),再(zai)進(jin)行下一(yi)輪(lun)計算(suan)。這樣的(de)過程就是簡化后的(de) BP 神(shen)經(jing)網絡訓練的(de)過程。其計算(suan)方(fang)式(shi)如下,以下列舉的(de)公式(shi)中帶(dai)“’”的(de)部分(fen)表(biao)示更(geng)新(xin)(xin)之后的(de)權(quan)重(zhong)(zhong)的(de)值(zhi)

通過(guo)以上公式不難看(kan)出(chu),其中的核心點(dian)就(jiu)是在于如(ru)何求偏(pian)導。只要(yao)求出(chu)偏(pian)導了(le),那(nei)自然就(jiu)有了(le)更新權重的數值的方法了(le)

開始(shi)求(qiu)偏導準備來(lai)修(xiu)改(gai)權重參數(shu)。開始(shi)之前先簡單介(jie)(jie)紹鏈式(shi)法則的(de)(de)計(ji)(ji)算(suan)方式(shi)。在本(ben)文(wen)(wen)用(yong)到的(de)(de)偏導知識(shi)部(bu)分非(fei)常少,本(ben)文(wen)(wen)也只介(jie)(jie)紹本(ben)文(wen)(wen)需要用(yong)到的(de)(de)部(bu)分知識(shi)。假(jia)定有(you)一個(ge)(ge)參數(shu) x 計(ji)(ji)算(suan)出(chu)了(le) y 的(de)(de)過程中(zhong),經過了(le)兩個(ge)(ge)步(bu)驟,先經過了(le) g 函數(shu),求(qiu)出(chu)了(le) t 結(jie)(jie)果(guo)。再(zai)將 t 結(jie)(jie)果(guo)傳入 f 函數(shu),從而計(ji)(ji)算(suan)出(chu) y 結(jie)(jie)果(guo)。此時求(qiu)x的(de)(de)偏導則可用(yong)以(yi)下的(de)(de)公式(shi)

可(ke)以(yi)看(kan)(kan)到(dao),此時將計(ji)算(suan)拆分為兩(liang)步(bu),先求t的偏導(dao),再求x的偏導(dao)。如此過程恰好就可(ke)以(yi)用在神經網絡(luo)上,逐層逐個求偏導(dao),且剛好可(ke)以(yi)實(shi)現(xian)累加的過程。當(dang)然,本文(wen)為了(le)簡單(dan)起見,不會減(jian)少(shao)計(ji)算(suan)過程,沒有將計(ji)算(suan)過的值(zhi)緩存起來省略(lve)重(zhong)(zhong)新計(ji)算(suan)的過程,但相信大家(jia)看(kan)(kan)到(dao)后(hou)面一眼(yan)就看(kan)(kan)出來重(zhong)(zhong)復部分很簡單(dan)就可(ke)以(yi)省略(lve)重(zhong)(zhong)復計(ji)算(suan)

如求w31的偏(pian)(pian)導(dao)(dao),就可以從y2到z2再到w31這樣一步步求偏(pian)(pian)導(dao)(dao)做乘法,如以下(xia)示意圖所(suo)示

如此(ci)即可得(de)出(chu)以下(xia)公式

這個過程(cheng)里面(mian),各(ge)個步驟都是一個簡(jian)單(dan)的(de)(de)確(que)定的(de)(de)函(han)數,求(qiu)(qiu)偏導過程(cheng)也就很(hen)簡(jian)單(dan)了。不需要說整(zheng)個一路(lu)將 w31帶(dai)入(ru)到(dao)最(zui)終計(ji)(ji)算式里面(mian)。大家(jia)如(ru)果(guo)好奇真的(de)(de)一路(lu)將w31帶(dai)入(ru)表(biao)達(da)式里面(mian),最(zui)終損(sun)失(shi)函(han)數C有(you)多(duo)長,且求(qiu)(qiu)導稍微困(kun)難。通(tong)過鏈式的(de)(de)方式可以(yi)進行一級級的(de)(de)計(ji)(ji)算,整(zheng)體(ti)復雜度也能(neng)夠降低(di)

接下來咱來開始一步步求這個(ge)偏導的內容

相(xiang)信(xin)大(da)家的求導知識還(huan)沒忘記,求導數學意(yi)義上就是求速(su)率(lv)。如對于常量(liang)函(han)數,如 y=5 的函(han)數,其速(su)率(lv)就是平的,如下(xia)圖所示,自然求出來的導數就是 0 的值

求偏導的話,只要對求偏導的變量當成變量,其他當成常量計算。這也就是為什么求出來的式子里面 \(1/2 y_{out}^2\) 會是0的(de)值(zhi)的(de)原因。那對(dui)于一次(ci)函數(shu)(shu)呢,如y=2x 函數(shu)(shu)呢,其導數(shu)(shu)反映的(de)速率(lv)就剛好是變量前面的(de)系數(shu)(shu)了。如下圖所示(shi)

于是就有

那平方(fang)(fang)呢?平方(fang)(fang)的話,可以認為速率需要乘以變量自身(shen),幾倍方(fang)(fang)就是幾倍速率

于是就有

回顧一(yi)下(xia),整條式子算起來就(jiu)是

是不(bu)是看到這里(li)感覺損失函(han)數確(que)實(shi)不(bu)是隨便選的,剛好這個函(han)數能夠非(fei)常好的適(shi)應求(qiu)導(dao)的結果。求(qiu)導(dao)結果里(li)面非(fei)常方便進行計(ji)算,計(ji)算機看了非(fei)常開森,因為求(qiu)導(dao)結果是兩個已(yi)經(jing)計(ji)算出(chu)結果的值(zhi),而且只(zhi)做減法。在(zai)第一輪訓(xun)練結果里(li)面,相信大家(jia)能夠直接口算結果

看吧,沒(mei)騙大家,只有過程推導用到(dao)了一點(dian)高(gao)數的知識(shi),最(zui)終(zhong)計算都(dou)是小(xiao)學(xue)到(dao)高(gao)中(zhong)的知識(shi),且大部分都(dou)是小(xiao)學(xue)知識(shi)

希望看(kan)到這里的大家會(hui)有很多(duo)信心,接下(xia)來開始(shi)解下(xia)一(yi)個偏導內容,這是最難的一(yi)個部分了

激(ji)活函(han)數求(qiu)導過程如下(xia),咱選用的(de)(de)激(ji)活函(han)數都是現(xian)成的(de)(de),有很多(duo)大(da)佬幫(bang)忙求(qiu)導過了的(de)(de)函(han)數的(de)(de)。如果大(da)家感覺這(zhe)個過程有點難,那也(ye)可以(yi)跳過,直接看(kan)求(qiu)導結果就可以(yi)了

可以看到激活函數求導(dao)結果也是(shi)(shi)非常開森的(de)計(ji)算,直接就是(shi)(shi) fx·(1-fx) 的(de)值,計(ji)算非常簡單。試試代入公(gong)式

看起來這也是(shi)非(fei)常簡單(dan)的小(xiao)學數學就能完(wan)成(cheng)計(ji)(ji)算結果(guo)(guo),雖然(ran)本次計(ji)(ji)算過程有點難,但結果(guo)(guo)卻是(shi)簡單(dan)的。也依然(ran)是(shi)計(ji)(ji)算機非(fei)常開森的計(ji)(ji)算表(biao)達式,都(dou)是(shi)已(yi)知的變量的基(ji)礎加減(jian)乘除計(ji)(ji)算

最后(hou)一步(bu)的求導(dao)就特別簡單啦

因為只對w31求偏導,于是(shi) w32 就(jiu)可以視為常量。本身(shen)y0和y1就(jiu)是(shi)被(bei)視為常量,直接 w32 乘以 y1就(jiu)算(suan)出0的(de)值。而y0作(zuo)為w31的(de)系(xi)數,求導結果就(jiu)是(shi)y0了(le)(le)。這個過(guo)程看起來很解壓。好了(le)(le),各個式子就(jiu)在這里求完了(le)(le),將其(qi)組合(he)起來

換成代碼(ma)的話,其實現如下

var dc_dw31 = (y2 - y_out) * (y2 * (1 - y2)) * y0;

不知道大家這一步求出來的結果是否和我(wo)的接近呢

第一(yi)步(bu)的(de)求偏導計算咱(zan)(zan)算了很久,后續的(de)步(bu)驟(zou)咱(zan)(zan)就能快非常多了。如對w32求偏導,可以看到(dao)只有(you)最后一(yi)條(tiao)式子有(you)所不同

代碼實現如下

var dc_dw32 = (y2 - y_out) * (y2 * (1 - y2)) * y1;

從這(zhe)里也(ye)(ye)可以看到(dao)(dao)對 w31 和 w32 求偏(pian)導,也(ye)(ye)只(zhi)有最后一個乘數不相同而已(yi)。對于程序(xu)猿來說(shuo),看到(dao)(dao)有很多相同的(de)代碼,本(ben)能地自然就會去想(xiang)優(you)化,這(zhe)是非常正(zheng)確(que)的(de),那(nei)就作為課后作業給(gei)到(dao)(dao)大(da)家(jia)去優(you)化啦

下一(yi)步嘗試求(qiu)w11的(de)偏導,這一(yi)次(ci)鏈(lian)式過(guo)程就(jiu)稍微長了一(yi)些了,如以下示意圖

有示意圖(tu),相(xiang)信大家(jia)很(hen)容(rong)易就(jiu)知(zhi)道了上面(mian)這條表(biao)達式是(shi)如(ru)何(he)寫出(chu)來的(de)(de)(de)。核心關鍵點就(jiu)是(shi)倒(dao)推(tui),看看w11在哪一級表(biao)達式中,然(ran)后(hou)再繼續(xu)往上找(zhao),直到能(neng)到達C損失函數里(li)去。這個(ge)過(guo)程就(jiu)類似于(yu)已知(zhi)樹(shu)(圖(tu)論的(de)(de)(de)樹(shu))進行(xing)求(qiu)到根的(de)(de)(de)路徑的(de)(de)(de)過(guo)程。求(qiu)導(dao)數的(de)(de)(de)前面(mian)兩(liang)項咱已經在w32求(qiu)偏導(dao)中計算過(guo)了,其(qi)結果如(ru)下

接下來(lai)的各項的求導過程(cheng)如下

將幾個表(biao)達式合起來,即可計(ji)算結果

表達式雖然(ran)長,但拆(chai)開看(kan)卻非常清晰,如下圖所示(shi)

以(yi)上的各(ge)個變量(liang)參(can)數都(dou)是已(yi)經計(ji)算(suan)出結果(guo)(guo)的,其整個表達式最終結果(guo)(guo)也是非常簡單的小學計(ji)算(suan)題。計(ji)算(suan)結果(guo)(guo)是 0.000929 的值

寫成代碼如下

var dc_dw11 = (y2 - y_out) * (y2 * (1 - y2)) * w31 * (y0 * (1 - y0)) * a;

同理來求 w12 的偏導,接近(jin)和 w11 相同,其(qi)差(cha)別只(zhi)有最后的一步計(ji)算。如(ru)下示(shi)意(yi)圖所示(shi)

可見計算公式為

對應的代碼實現如下

var dc_dw12 = (y2 - y_out) * (y2 * (1 - y2)) * w31 * (y0 * (1 - y0)) * b;

同理也可(ke)以(yi)繼續(xu)求w21的偏(pian)導

通過以上示意圖可知

各自代入可得

對應的代碼如下

var dc_dw21 = (y2 - y_out) * (y2 * (1 - y2)) * w32 * (y1 * (1 - y1)) * a;

按照以上(shang)求偏導方式,可得(de)

對應的代碼如下

var dc_dw22 = (y2 - y_out) * (y2 * (1 - y2)) * w32 * (y1 * (1 - y1)) * b;

最后(hou)將各個權重(zhong)減去(qu)對應的(de)偏導,更(geng)新(xin)之后(hou)的(de)權重(zhong)我給它上面多標(biao)了一瞥

對應的代碼如下

w31 = w31 - dc_dw31;
w32 = w32 - dc_dw32;

w11 = w11 - dc_dw11;
w12 = w12 - dc_dw12;

w21 = w21 - dc_dw21;
w22 = w22 - dc_dw22;

按照更新的值(zhi)再跑一(yi)遍計(ji)算(suan)(suan),可(ke)得(de)到y2輸出為 0.6820 的值(zhi),求損失(shi)函數為 0.0165 的值(zhi),可(ke)以看出比原來的第(di)一(yi)遍計(ji)算(suan)(suan)得(de)到的 0.0181 更小,證明更加貼近。好在我(wo)過程中順(shun)帶編寫了代碼(ma),可(ke)以愉快地讓(rang)計(ji)算(suan)(suan)機幫我(wo)跑個100次,跑了100次之后的各個值(zhi)如(ru)下

w11=0.099497286575324431
w12=0.79870730833654868
w21=0.35650028026826369
w22=0.48814357783267731
w31=-0.30047225429264057
w32=0.32533602822418006
y2=0.50076396515258481
c=2.9182137718196697E-07

可見(jian)看(kan)到(dao)此時(shi)輸(shu)出(chu)的 y2 已(yi)經(jing)非常(chang)貼近預期的輸(shu)出(chu)了。于是大家可以開森地認為(wei)咱手(shou)算訓練(lian)出(chu)一個能(neng)夠當輸(shu)入為(wei) x0=0.35 x1=0.9時(shi),獲(huo)得0.5輸(shu)出(chu)值的簡(jian)單BP神經(jing)網絡啦(la)

相信看了整個過程的(de)大家也能(neng)感(gan)受出來,本文選用(yong)的(de)例子中所涉及(ji)的(de)計算是(shi)非(fei)常(chang)簡單的(de)。再回頭看看總的(de)代(dai)碼,可見實現(xian)代(dai)碼量(liang)是(shi)非(fei)常(chang)少的(de)

const double x0 = 0.35;
const double x1 = 0.9;

const double y_out = 0.5;

var a = x0;
var b = x1;

var w11 = 0.1;
var w12 = 0.8;

var w21 = 0.4;
var w22 = 0.6;

var w31 = 0.3;
var w32 = 0.9;

var count = 0;

while (true)
{
    var z0 = w11 * a + w12 * b;
    var z1 = w21 * a + w22 * b;

    var y0 = F(z0);
    var y1 = F(z1);

    var z2 = w31 * y0 + w32 * y1;

    var y2 = F(z2);

    var c = C(y2);

    if (c < 0.0000001)
    {
        break;
    }

    var dc_dw31 = (y2 - y_out) * (y2 * (1 - y2)) * y0;
    var dc_dw32 = (y2 - y_out) * (y2 * (1 - y2)) * y1;

    var dc_dw11 = (y2 - y_out) * (y2 * (1 - y2)) * w31 * (y0 * (1 - y0)) * a;
    var dc_dw12 = (y2 - y_out) * (y2 * (1 - y2)) * w31 * (y0 * (1 - y0)) * b;

    var dc_dw21 = (y2 - y_out) * (y2 * (1 - y2)) * w32 * (y1 * (1 - y1)) * a;
    var dc_dw22 = (y2 - y_out) * (y2 * (1 - y2)) * w32 * (y1 * (1 - y1)) * b;

    w31 = w31 - dc_dw31;
    w32 = w32 - dc_dw32;

    w11 = w11 - dc_dw11;
    w12 = w12 - dc_dw12;

    w21 = w21 - dc_dw21;
    w22 = w22 - dc_dw22;

    count++;
}

Console.WriteLine("Hello, World!");

double F(double x)
{
    return 1.0 / (1 + Math.Pow(Math.E, -x));
}

static double C(double y2)
{
    return 1.0 / 2 * Math.Pow((y2 - y_out), 2);
}

也許(xu)此時(shi)有人會(hui)說(shuo),明明我看(kan)到的(de)py代(dai)(dai)碼量(liang)(liang)更少(shao),為什么換(huan)成(cheng)C#的(de)代(dai)(dai)碼量(liang)(liang)就(jiu)這么多(duo)了?別急,大(da)家試(shi)(shi)試(shi)(shi)看(kan)回(hui)憶一下上文(wen)布置的(de)課后作業。之所以網(wang)上看(kan)到的(de)很(hen)多(duo)py實現(xian)的(de)版本的(de)代(dai)(dai)碼量(liang)(liang)少(shao),是因(yin)為使用了本文(wen)沒有付(fu)出場費的(de)矩陣來(lai)幫忙計算,許(xu)多(duo)重(zhong)復(fu)(fu)的(de)計算邏(luo)輯被封(feng)裝起來(lai)了。試(shi)(shi)試(shi)(shi)看(kan)給以上的(de)代(dai)(dai)碼進(jin)行(xing)(xing)優化,將(jiang)重(zhong)復(fu)(fu)的(de)計算進(jin)行(xing)(xing)合并(bing),將(jiang)重(zhong)復(fu)(fu)的(de)結構(gou)進(jin)行(xing)(xing)抽象,很(hen)好,此時(shi)相(xiang)信(xin)大(da)家一和py代(dai)(dai)碼進(jin)行(xing)(xing)對比就(jiu)會(hui)發(fa)現(xian)接近相(xiang)同啦

本文代碼放在(zai) 和(he) 上,可以(yi)使(shi)用如(ru)下命令(ling)行(xing)拉取(qu)代碼。我整個代碼倉(cang)庫比較(jiao)(jiao)龐大,使(shi)用以(yi)下命令(ling)行(xing)可以(yi)進行(xing)部(bu)分拉取(qu),拉取(qu)速(su)度比較(jiao)(jiao)快

先創(chuang)建(jian)一(yi)個空文件(jian)夾,接著使用(yong)命(ming)(ming)(ming)令(ling)(ling)行 cd 命(ming)(ming)(ming)令(ling)(ling)進(jin)入(ru)此空文件(jian)夾,在(zai)命(ming)(ming)(ming)令(ling)(ling)行里面(mian)輸入(ru)以下代(dai)碼(ma),即可獲取到(dao)本文的代(dai)碼(ma)

git init
git remote add origin //gitee.com/lindexi/lindexi_gd.git
git pull origin 3621fbea66658c99f11ed4faa28aa60bb5ac4466

以(yi)上(shang)使用的(de)是國內的(de) gitee 的(de)源(yuan)(yuan),如果 gitee 不能訪問,請(qing)替換為 github 的(de)源(yuan)(yuan)。請(qing)在命(ming)令行(xing)繼(ji)續輸入以(yi)下(xia)代(dai)(dai)碼(ma),將 gitee 源(yuan)(yuan)換成 github 源(yuan)(yuan)進(jin)行(xing)拉取代(dai)(dai)碼(ma)。如果依然拉取不到(dao)代(dai)(dai)碼(ma),可以(yi)發郵件向我要代(dai)(dai)碼(ma)

git remote remove origin
git remote add origin //github.com/lindexi/lindexi_gd.git
git pull origin 3621fbea66658c99f11ed4faa28aa60bb5ac4466

獲取代碼之后,進入 Bp/DewhigarjejelDaykogiqem 文件夾,即可獲取到源代碼

更(geng)多技術博客,請參閱

posted @ 2025-08-31 21:19  lindexi  閱讀(1797)  評論(6)    收藏  舉報