天天看點

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

先向各位小夥伴道歉,文中可能會出現許多錯别字,表達不清楚,病句,标點符号使用不當,圖檔難看且潦草的情況,必須誠懇地向大家表示:湊合看吧,還能咬我咋的...

        在之前的文章中,有提到過,所謂的 AI 技術,本質上是一種資料處理處理技術,它的強大來自于兩方面:1.網際網路的發展帶來的海量資料資訊  2.計算機深度學習算法的快速發展。 是以說 AI 其實并沒有什麼神秘,隻是在算法上更為複雜。要想了解這一點,我們要從一個問題說起:找資料的規律...

        如果你是一名上過大學的人,有幾個數學上的方法你應該不太陌生:線性拟合,多項式拟合,最小二乘法...如果這個你都不知道的話,我建議你現在 假裝明白 ,然後往下看,應該不難。

        先看一下下面這組資料:

x y
1
1 2
2 9
3 28
4 65
5 126
6 217
7 344
8 513
9 730

        這裡沒什麼好說的,這個表是一個 x 與 y 的對應關系,我們現在的目标比較明确,找到x與y的對應關系,也就是求y=f(x)的關系式。

第 1 部分  傳統數學方法回顧

        這部分内容就很簡單了,關鍵記住一個名詞 ——  一通(tòng)操作 ...

方法一:線性拟合

        我們知道,在大多數情況下,當我們拿來一組資料,進行拟合時,首先想到的肯定是線性拟合,因為其方法簡單暴力直接有效,往往很快就能得到一個差不多的結論。雖然不是很精确,但是有句名言說得好,要啥自行車?直接來看結果。

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

        關于線性拟合在數學上的方法,這裡就不講了,随便找本教材應該就有,我相信看到上面的圖,你應該已經了解了。總之就是經過 一通操作 ,得到線性關系。我這裡并沒有用數學方法親自去進行計算和拟合關系式,而是用了一種很高端的工具,叫 Excel ... 以示說明,領會精神即可。

        紅色虛線為拟合線,藍色實線為實際點的連線,可以看到,利用線性拟合,得到的結果是 y = 75.4x - 135.8 這樣一個數學關系,很顯然,它的效果不是他别理想,可以看到,誤差還是不小的。

方法二:多項式拟合

        這個的思路也比較直接,其實就是假設  

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

 , 比如我們要拟合一個2次的多項式,就可以假設

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

 。同樣的,3次方的關系就是

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

 。應該是很好了解吧······

        跟剛才一樣,又是一通操作,拟合的方法我不就不贅述了,直接用我們的高端工具 Excel 來完成這個工作。效果如下:

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡
一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

        可以看到,二次拟合的效果比線性拟合的結果要更接近于真實的結果,而三次曲線就是真實的關系(當然大多數實際情況下并不是嚴格對應)。

        通常利用更高階的多項式,得到的結果就更加接近于實際的資料。

方法三:其他

        最小二乘法,指數拟合,對數拟合,根據資料的不同,用不同的方法來進行拟合得到接近真實情況的數學關系。差別就是利用不同的 一通操作 ... 但是無論是哪一種,解決的數學問題相對來說比較有限,并不能準确拟合出很複雜的數學關系。

        如果利用邏輯回歸、貝葉斯、決策樹、KNN、套袋法等等,也能夠解決很多很複雜的數學問題,但這又是另外一個很大的領域,不過建議有機會還是要把這些基礎打好,但是這篇部落格中,我們不探讨,完全不熟悉也沒關系,隻要知道這些都是傳統的資料處理方法就好。

第 2 部分  現代技術中的難題

        下面我們來思考一個 重!要!問!題!:别人爸爸 跟 你爸爸 的不同之處,在數學上的表達是怎麼樣的 ?

        多麼深奧的問題,也許你覺得這是一個顯而易見的問題,你爸爸就是你爸爸,他爸爸就是他爸爸。這點我十分相信,雖然你不知道如何去回答這個問題,但是你這輩子應該是沒喊錯過你父親... 可是問題來了,你怎麼讓計算機去熟練的分辨出兩個人誰是誰?這就必須要依賴數學了...

        是以回到問題中來:别人爸爸 跟 你爸爸 的不同之處,在數學上的表達是怎麼樣的 ?你可能要打我了。但是先别急,先來分析分析。首先,必須明搞明白一件事,這個世界上的事情可以分為兩種,可歸納的問題 與 不可歸納的問題。

        首先什麼是不可歸納的問題,舉個例子,你不能用一套完美的數學公式去表達 所有的質數 , 因為目前的研究表明,還沒有什麼方法是能夠表達質數的,也就是說,質數的出現,本身不具備嚴格的數學規律,是以無法歸納。

        可歸納問題就比較好了解了,一隻貓 和 一隻狗 出現在你的面前時 ,你能夠清晰地将他們進行分辨,這說明在貓和狗之間,确實存在着不同,雖然你很難說清楚它們的不同到底是什麼,但是可以知道,這背後是可以通過一套數學表達來完成的,隻是很複雜而已。理論上來講,凡是人類能夠掌握的事情,比如再怎麼複雜的語言,人類的快速分辨物體的視覺,複雜的邏輯思考,都是可以用數學來表達的可歸納問題。我們人類之是以能夠快速地對這些複雜的問題進行快速地反應,得益于我們的大腦内部複雜的神經網絡構造。當我們不經意間看到一些物體時,大腦其實是在高速的進行計算,我們天生擁有這種能力,以至于我們根本沒有察覺。多麼神奇,可以說我們每個人其實都是超級算法工程師...

        對比第一部分的那個表格,和如何分辨爸爸的問題,可以得到結論是,這是同一個層次的問題:可歸納數學問題,隻是用到的方法不同,複雜度不同而已。都可以用公式來表達:

        問題一: x 與 y 的對應關系  y = f(x)

        問題二:你爸爸 = f (你爸爸的特征)

        這當然是一個複雜的問題,因為首先需要将人的特征轉化為數字資訊,比如圖像(圖像本質上就是二位的數組),然後根據不同人的特征,對應的不同人的代号,來拟合一個複雜的,一一對應的函數關系,就是現在技術中的一個難題。解決的方法就是 AI :神經網絡。

         是以所謂的 AI 技術 ,說到底 是找規律的問題,是拟合複雜函數的問題,是資料處理的問題。

         下面将通過執行個體,來給大家搭建一個最簡單的神經網絡:Bp神經網絡,來了解 AI 。

第 3 部分  最簡單的神經網絡Bp神經網絡

1.Bp 神經網絡的簡單了解

        這裡要從名字開始說起了,首先從名稱中可以看出,Bp神經網絡可以分為兩個部分,bp和神經網絡。

        bp是 Back Propagation 的簡寫 ,意思是反向傳播。而神經網絡,聽着高大上,其實就是一類相對複雜的計算網絡。舉個簡單的例子來說明一下,什麼是網絡。

        看這樣一個問題,假如我手裡有一筆錢,N個億吧(既然是假設那就不怕吹牛逼),我把它分别投給5個公司,分别占比 M1,M2,M3,M4,M5(M1到M5均為百分比 %)。而每個公司的回報率是不一樣的,分别為 A1, A2, A3, A4, A5,(A1到A5也均為百分比 %)那麼我的收益應該是多少?這個問題看起來應該是夠簡單了,你可能提筆就能搞定  收益 = N*M1*A1 + N*M2*A2+N*M3*A3+N*M4*A4+N*M5*A5 。這個完全沒錯,但是展現不出水準,我們可以把它轉化成一個網絡模型來進行說明。如下圖:

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

        圖有點醜,領會精神,領會精神。上面的問題是不是莫名其妙的就被整理成了一個三層的網絡,N1到N5表示每個公司獲得的錢,R表示最終的收益。R = N*M1*A1 + N*M2*A2+N*M3*A3+N*M4*A4+N*M5*A5 。我們可以把 N 作為輸入層 ,R作為輸出層,N1到N5則整體作為隐藏層,共三層。而M1到M5則可以了解為輸入層到隐藏層的權重,A1到A5為隐藏層到輸出層的權重。

        這裡提到了四個重要的概念 輸入層(input) , 隐藏層 (hidden),輸出層(output)和權重(weight) 。而所有的網絡都可以了解為由這三層和各層之間的權重組成的網絡,隻是隐藏層的層數和節點數會多很多。

        輸入層:資訊的輸入端,上圖中 輸入層 隻有 1 個節點(一個圈圈),實際的網絡中可能有很多個

        隐藏層:資訊的處理端,用于模拟一個計算的過程,上圖中,隐藏層隻有一層,節點數為 5 個。

        輸出層:資訊的輸出端,也就是我們要的結果,上圖中,R 就是輸出層的唯一一個節點,實際上可能有很多個輸出節點。

        權重:連接配接每層資訊之間的參數,上圖中隻是通過乘機的方式來展現。

        在上面的網絡中,我們的計算過程比較直接,用每一層的數值乘以對應的權重。這一過程中,權重是恒定的,設定好的,是以,是将 輸入層N 的 資訊 ,單向傳播到 輸出層R 的過程,并沒有反向傳播資訊,是以它不是神經網絡,隻是一個普通的網絡。

        而神經網絡是一個資訊可以反向傳播的網絡,而最早的Bp網絡就是這一思想的展現。先不急着看Bp網絡的結構,看到這兒你可能會好奇,反向傳播是什麼意思。再來舉一個通俗的例子,猜數字:

        當我提前設定一個數值 50,讓你來猜,我會告訴你猜的數字是高了還是低了。你每次猜的數字相當于一次資訊正向傳播給我的結果,而我給你的提示就是反向傳播的資訊,往複多次,你就可以猜到我設定的數值 50 。 這就是典型的反向傳播,即根據輸出的結果來反向的調整模型,隻是在實際應用中的Bp網絡更為複雜和數學,但是思想很類似。

2.Bp 神經網絡的結構與數學原理(可以不細看)

        此節的内容 極!其!重!要!但是要涉及到一些數學,是以我盡量用人話去跟大家細細解釋,并且結合執行個體來給大家進行一下分析。

        如果你不想看太多的推導和數學,那麼隻需要大概了解 Bp 網絡的運作思想就好:我們知道,一個函數是由自變量x和決定它的參數θ組成。比如 y=ax + b 中,a,b為函數的固定參數 θ ,x為自變量。那麼對于任意一個函數我們可以把它寫成 y = f(θ,x)的形式,這裡的 θ 代表所有參數的集合[

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

,

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

,

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

,...],x代表所有自變量的集合[

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

,

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

,

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

,...]。而 Bp 網絡的運作流程就是根據已有的 x 與 y 來不停的疊代反推出參數 θ 的過程,這一過程結合了最小二乘法與梯度下降等特殊的計算技巧。這一節看到這兒就基本上可以了,但是如果還想繼續深入了解,可以跟着思路,往下接着看。

       事實上,這些内容已經被各路神仙們寫爛了,因為 Bp網絡對于 AI 技術來說,實在太基礎,太重要,但是由于在實際學習中,我也遇到過一些困難,現在根據我的學習過程和了解過程,還是要再拿出來寫一遍。大神們勿噴···

         還是老樣子,先來看一個問題,找到下列資料中,y 與 x1,x2,x3的關系,即 y = f(x1,x2,x3)的數學表達式。 

表 3.1

x1 x2 x3 y
1 1 2 2
1 2 3 6
2 1 6 12
5 2 5 50
8 3 4 96
7 7 4 196
7 7 7 343
13 8 3 312
6 10 11 660
13 17
14 7 12 1176

        這裡一共是 11 組資料(資料量很少),很明顯 y 是關于 x1,x2,x3 的三元函數,通常情況下,想要通過一套固定的套路來拟合出一個三元函數的關系式,是一件很複雜的事。而實際問題中的參數往往不止三個,可能成千上百,也就是說 決定 y 的參數會有很多,這樣的問題更是複雜的很,用正常的方法去拟合,幾乎不可能,那麼換一種思路,用 Bp神經網絡的方法來試一下。

        根據上表給出的條件和問題,我們先來分析一下。首先,我們的輸入資訊是 3 個參數,x1,x2,x3 。輸出結果是 1 個數 y 。那麼可以畫一個這樣的關系網路圖(直接手畫了,湊合看吧···):

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

        在這個網絡中,輸入層(input )有三個節點(因為有三個參數),隐藏層(hidden )先不表示,輸出層(output )有1個節點(因為我們要的結果隻有一個 y )。那麼關鍵的問題來了,如何進行這一通操作,它的結構究竟是怎樣的?

     2.1 正向傳播

        正向傳播就是讓資訊從輸入層進入網絡,依次經過每一層的計算,得到最終輸出層結果的過程。

        我直接把設計好的結構圖給大家畫出來,然後再一點一點地解釋。結構如下:

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

        看到這兒你可能會有點懵,不過不要緊,一步一步來分析。先來看網絡的結構,輸入層(input )沒有變,還是三個節點。輸出層(input )也沒有變。重點看隐藏層(hidden ),就是圖中紅色虛線框起的部分,這裡我設計了一個隐藏層為兩層的網絡,hidden_1和hidden_2 ,每層的節點為 2 個,至于為什麼是兩層,節點數為什麼是 2 兩個 ,這裡你隻需要知道,實驗證明,解決這個問題,這樣的網絡就夠用了。具體的一會兒講。

        關鍵看一下連線代表的意義,和計算過程。可以從圖上看到,每層的節點都與下一層的每個節點有一一對應的連線,每條連線代表一個權重,這裡你可以把它了解為資訊傳輸的一條通路,但是每條路的寬度是不一樣的,每條通路的寬度由該通道的參數,也就是該通路的權重來決定。為了說明這個問題,拿一個節點的計算過程來進行說明,看下圖:

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

        這上上圖中的一部分,輸入層(input )與 第一層隐藏層(hidden )的第一個節點

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

的連接配接關系。根據上邊的圖你可能自然的會想到:  

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

 。如果你這麼想,那就說明你已經開竅了,不過實際過程要複雜一些。我們可以把

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

這個節點看做是一個有輸入,有輸出的節點,我們規定輸入為

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

, 輸出為

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

,則真實的過程如下:

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

        計算的方法我直接寫到圖裡了,字兒醜,但是應該能看清楚···解釋一下,

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

就是x1,x2,x3與各自權重乘積的和,但是為什麼非要搞一個 sigmoid() ,這是什麼鬼? 其實最早人們在設計網絡的時候,是沒有這個過程的,統統使用線性的連接配接來搭建網絡,但是線性函數沒有上界,經常會造成一個節點處的數字變得很大很大,難以計算,也就無法得到一個可以用的網絡。是以人們後來對節點上的資料進行了一個操作,利用sigmoid()函數來處理,使資料被限定在一定範圍内。此外sigmoid函數的圖像是一個非線性的曲線,是以,能夠更好的逼近非線性的關系,因為絕大多數情況下,實際的關系是非線性的。sigmoid在這裡被稱為 激勵函數 ,這是神經網絡中的一個非常重要的基本概念。下面來具體說一下什麼是 sigmoid() 函數。

        不作太具體的分析,直接看公式和圖像:

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡
一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

        圖像來自百度百科,可以看到sigmoid函數能夠将函數限制在 0到1 的範圍之内。

        這裡還要進行一下說明,sigmoid 是最早使用的激勵函數,實際上還有更多種類的激勵函數 ,比如 Relu ,tanh 等等,性質和表達式各有不同,以後再說,這裡先用 sigmoid 來說明。

        如果說看到這兒,你對 激勵函數 這個概念還是不太懂的話 ,沒關系,可以假裝自己明白了,你就知道這個東西很有用,裡面必有道道就行了,以後慢慢體會,慢慢了解,就行了。接着往下看。

        剛剛解釋了一個節點的計算過程,那麼其他節點也就可以舉一反三,一一計算出來。現在我們來簡化一下網絡。我們可以把x1,x2,x3作為一個向量 [x1,x2,x3] ,權重矩陣 u 也作為一個 3x2 的矩陣 ,w 作為一個 2x2 的矩陣 ,v作為一個 2x1 的矩陣,三個矩陣如下:

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

         可以看到這三個矩陣與網絡中的結構圖中是一一對應的。下面我們把隐藏層與輸出層也寫成矩陣的形式:

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

        可以看到這兩層隐藏層(hidden)的輸入Hi 與 Ho 均為 1x2 的矩陣,輸出層(output )為 1x1 的矩陣。下面就可以把網絡簡化為下面的結構:

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

        根據我們剛才講過的每個節點的計算方法,以及我們簡化後的網絡,則可以将整個計算過程等效的化為以下幾個矩陣相城的步驟(矩陣相乘是怎麼會回事,請複習線性代數...):

        注意:下式中,除sigmoid代表激勵函數以外,其餘各個符号都代表一個矩陣(或者向量),而非常數,乘積符号“ x ”代表正常的矩陣乘法計算。

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

                     ※ 由于矩陣 x 次元為 1*3 ,u 次元為 3*2 ,是以自然得到次元為1*2的矩陣(或者向量) 

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

      ※ 次元不變

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

                 ※ (1*2) x (2*2) →(1*2) 括号内為各矩陣次元

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

      ※ 次元不變

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

                     ※ (1*2) x (2*1) →(1*1)  括号内為各矩陣次元

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

        注意:細心的小夥伴應該發現公式中出現了幾個之前沒有提到的符号 

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

 。它們也各自代表一個矩陣,它們的概念為門檻值,通常用符号b來表示。門檻值的意義是,每個節點本身就具有的一個數值,設定門檻值能夠使網絡更快更真實的去逼近一個真實的關系。

        以上這個過程,就是該網絡的資訊進行了一次 正向傳播 。

     2.2 反向傳播

        那麼有正向傳播,就必須得有反向傳播,下面來講一下 反向傳播 的過程。首先明确一點,反向傳播的資訊是什麼,不賣關子,直接給答案,反向傳播的資訊是誤差,也就是 輸出層(output )的結果 與 輸入資訊 x 對應的真實結果 之間的差距(表達能力比較差,畫個圖說明...)。

         拿出上文的資料表中的第一組資料  x1 = 1,x2=1,x3=2,y=2 為例。

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

        假設我們将資訊x1,x2,x3 輸入給網絡,得到的結果為 

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

 = 8 ,而我們知道真實的 y 值為 2,是以此時的誤差為 |

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

-y|  ,也就是 6 。 真實結果與計算結果的誤差被稱作 損失 loss , loss = |

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

 - y|  記作 損失函數 。這裡有提到了一個很重要的概念,損失函數,其實在剛才的例子中,損失函數 loss = |

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

 - y|  隻是衡量誤差大小的一種方式,稱作L1損失(先知道就行了),在實際搭建的網絡中,更多的用到的損失函數為 均方差損失,和交叉熵損失。原則是分類問題用交叉熵,回歸問題用均方差,綜合問題用綜合損失,特殊問題用特殊損失···以後慢慢說吧,因為損失函數是一個超級龐大的問題。

        總之我們先知道,損失函數 loss 是一個關于 網絡輸出結果 

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

 與真實結果 y 的,具有極小值的函數 。那麼我們就可以知道,如果一個網絡的計算結果 

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

 與 真是結果 y 之間的損失總是很小,那麼就可以說明這個網絡非常的逼近真實的關系。是以我們現在的目的,就是不斷地通過調整權重u,w,v(也就是網絡的參數)來使網絡計算的結果 

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

 盡可能的接近真實結果 y ,也就等價于是損失函數盡量變小。那麼如何調整u,w,v 的大小,才能使損失函數不斷地變小呢?這理又要說到一個新的概念:梯度下降法 。

        梯度下降法 是一個很重要很重要的計算方法,要說明這個方法的原理,就又涉及到另外一個問題:邏輯回歸。為了簡化學習的過程,不展開講,大家可以自己去搜一下邏輯回歸,學習一下。特别提醒一下,邏輯回歸是算法工程師必須掌握的内容,因為它對于 AI 來說是一個很重要的基礎。下面隻用一個圖(圖檔來自百度)進行一個簡單地說明。

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

        假設上圖中的曲線就是損失函數的圖像,它存在一個最小值。梯度是一個利用求導得到的數值,可以了解為參數的變化量。從幾何意義上來看,梯度代表一個損失函數增加最快的方向,反之,沿着相反的方向就可以不斷地使損失逼近最小值,也就是使網絡逼近真實的關系。

        那麼反向傳播的過程就可以了解為,根據 損失loss ,來反向計算出每個參數(如 

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

 ,

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

 等)的梯度 d(

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

) ,d(

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

) ....等等,再将原來的參數分别加上自己對應的梯度,就完成了一次反向傳播。

        來看看 損失loss 如何完成一次反向傳播,這裡再定義一些變量

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

 , 

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

 和

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

 。注意:它們都代表矩陣(向量),而非一個數值。它們分别代表第一層,第二層隐藏層,以及輸出層每個神經元節點反向輸出的值。

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

 分别代表權值矩陣與門檻值矩陣對應的梯度矩陣,用符号 

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

 代表損失,

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

來表示sigmoid函數的導數。這裡隻簡單的說一下計算公式,推導過程後邊講。

        計算梯度,注意:下式中未标紅的都代表一個矩陣(或者向量),标紅符号的代表一個常數。

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡
一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡
一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡
一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡
一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡
一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡
一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡
一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡
一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

        更新權值與門檻值

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡
一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡
一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡
一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡
一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡
一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

        ※ 公式中的 乘号 “ x ”表示正常的矩陣乘積運算,運算後會發生次元的變化。 符号 “ · ” 表示按位乘積,運算後次元不變。

        以上就是一次完整的反向傳播過程,需要說明的是,上式當中用到了一個符号 

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

 ,這又是一個重要的概念,學習率,一個小于1的實數,它的大小會影響網絡學習的速率以及準确度。可以把它了解為梯度下降時的步長。

        反向傳播過程實際上還是有點複雜的,下面我來簡單說一下為什麼梯度是這樣求的。

        我們知道,整個網絡可以簡化成一個函數 

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

,也就是說這個函數的表達式,主要由各個參數 

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

 來決定,而現在為了确定網絡的參數,則可以把

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

 作為函數的自變量,而x作為參數,對 

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

 求偏導    

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

 ,這個偏導的結果就是該參數

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

 對應的梯度,這個思想實際上來自于最小二乘法,反正求完就是上邊式子中的結果,這裡不再進行推導。

     2.3 網絡的訓練

        通過一次正向傳播,和一次反向傳播,我們就可以将網絡的參數更新一次,所謂訓練網絡,就是讓正向傳播和反向傳播不斷的往複進行,不斷地更新網絡的參數,最終使網絡能夠逼近真實的關系。

        理論上,隻要網絡的層數足夠深,節點數足夠多,可以逼近任何一個函數關系。但是這比較考驗你的電腦性能,事實上,利用 Bp 網絡,能夠處理的資料其實還是有限的,比如 Bp 網絡在圖像資料的識别和分類問題中的表現是很有限的。但是這并不影響 Bp 網絡是一種高明的政策,它的出現也為後來的 AI 技術做了重要的鋪墊。

3.Bp 神經網絡的代碼實作

        回到 表 3.1 中的資料,将用 python 來實作一個 Bp 網絡 ,對資料的關系建立一個網絡模型。

        這裡有幾點需要說明,首先在資料進入網絡之前,要先進行歸一化處理,即将資料除以一個數,使它們的值都小于 1 ,這樣做的目的是避免梯度爆炸。其次為了更好、更快的收斂得到準确的模型,這裡采用了對資料進行特征化的處理。最後,這段代碼中用到的激勵函數是Relu,并非我們之前所講的 sigmoid ,因為Relu的計算速度更快,更容易收斂。

        這裡有幾個參數和數組需要說明,其中 p_s 中的數組代表 表 3.1 中 11組資料的 [x1,x2,x3] ,t_s代表對應的 y 。p_t 與t_t用來存放測試網絡訓練效果的 測試資料集 。我們用p_s與t_s來訓練 Bp 網絡 ,用 p_t 與 t_t 來檢驗訓練的效果。表 3.1 的資料中,y 與 x1,x2,x3 的對應關系實際上是 y = x1 * x2 * x3 。

        代碼如下:

import time
from numpy import *


######## 資料集 ########

p_s = [[1,1,2],[1,2,3],[2,1,6],[5,2,5],[8,3,4],[7,7,4],[7,7,7],[13,8,3],[6,10,11],[13,0,17],[14,7,12]]              # 用來訓練的資料集 x
t_s = [[2],[6],[12],[50],[96],[196],[343],[312],[660],[0],[1176]]   # 用來訓練的資料集 y

p_t = [[6,9,1017],[2,3,4],[5,9,10]]      # 用來測試的資料集 x_test    
t_t = [[54918],[24],[450]]               # 用來測試的資料集 對應的實際結果 y_test                                                                        

######## 超參數設定 ########

n_epoch = 20000             # 訓練次數

HNum = 2;                   # 各層隐藏層節點數

HCNum = 2;                  # 隐藏層層數

AFKind = 3;                 # 激勵函數種類
emax = 0.01;                # 最大允許均方差根
LearnRate = 0.01;           # 學習率

######## 中間變量設定 ########
TNum = 7;                   # 特征層節點數 (特征數)

SNum = len(p_s);            # 樣本數

INum = len(p_s[0]);         # 輸入層節點數(每組資料的次元)
ONum = len(t_s[0]);         # 輸出層節點數(結果的次元)
StudyTime = 0;              # 學習次數
KtoOne = 0.0;               # 歸一化系數
e = 0.0;                    # 均方差跟

######################################################### 主要矩陣設定 ######################################################

I = zeros(INum);

Ti = zeros(TNum);
To = zeros(TNum);

Hi = zeros((HCNum,HNum));
Ho = zeros((HCNum,HNum));

Oi = zeros(ONum);
Oo = zeros(ONum);

Teacher = zeros(ONum);

u = 0.2*ones((TNum,HNum))                  # 初始化 權值矩陣u
w = 0.2*ones(((HCNum-1,HNum,HNum)))        # 初始化 權值矩陣w
v = 0.2*ones((HNum,ONum))                  # 初始化 權值矩陣v

dw = zeros((HCNum-1,HNum,HNum))

Hb = zeros((HCNum,HNum));
Ob = zeros(ONum);

He = zeros((HCNum,HNum));
Oe = zeros(ONum);

p_s = array(p_s)
t_s = array(t_s)
p_t = array(p_t)

################################# 時間參數 #########################################

time_start = 0.0
time_gyuyihua = 0.0
time_nnff = 0.0
time_nnbp = 0.0
time_begin = 0.0

time_start2 = 0.0

time_nnff1 = 0.0
time_nnff2 = 0.0
time_nnbp_v = 0.0
time_nnbp_w = 0.0
time_nnbp_u = 0.0
time_nnbp_b = 0.0



######################################################### 方法 #######################################################

def Calcu_KtoOne(p,t):                         # 确定歸一化系數
	p_max = p.max();
	t_max = t.max();
	return max(p_max,t_max);
	
def trait(p):                                  # 特征化
	t = zeros((p.shape[0],TNum));
	for i in range(0,p.shape[0],1):
		t[i,0] = p[i,0]*p[i,1]*p[i,2]
		t[i,1] = p[i,0]*p[i,1]
		t[i,2] = p[i,0]*p[i,2]
		t[i,3] = p[i,1]*p[i,2]
		t[i,4] = p[i,0]
		t[i,5] = p[i,1]
		t[i,6] = p[i,2]
	
	return t
	
def AF(p,kind):   # 激勵函數
	t = []
	if kind == 1:   # sigmoid
		pass
	elif kind == 2:   # tanh
		pass
	elif kind == 3:    # ReLU

		return where(p<0,0,p)
	else:
		pass


		
def dAF(p,kind):   # 激勵函數導數
	t = []
	if kind == 1:   # sigmoid
		pass
	elif kind == 2:   # tanh
		pass
	elif kind == 3:    # ReLU
		
		return where(p<0,0,1) 
	else:
		pass

		
		
def nnff(p,t):
	pass
	
def nnbp(p,t):
	pass
	

def train(p,t):                                # 訓練
	
	global e
	global v
	global w
	global dw
	global u	
	global I 
	global Ti 
	global To 
	global Hi 
	global Ho 
	global Oi 
	global Oo 
	global Teacher 
	global Hb 
	global Ob 
	global He 
	global Oe
	global StudyTime
	global KtoOne
	
	global time_start
	global time_gyuyihua
	global time_nnff
	global time_nnbp	
	global time_start2
	global time_nnff1
	global time_nnff2
	global time_nnbp_v
	global time_nnbp_w
	global time_nnbp_u
	global time_nnbp_b
	
	
	time_start = time.clock()
	
	
	e = 0.0
	p = trait(p)
		
	KtoOne = Calcu_KtoOne(p,t)
	
	time_gyuyihua += (time.clock()-time_start)
	
	time_start = time.clock()
		
	for isamp in range(0,SNum,1):
		To = p[isamp]/KtoOne
		Teacher = t[isamp]/KtoOne
		
		
		################ 前向 nnff #############################
			
		time_start2 = time.clock()
		######## 計算各層隐藏層輸入輸出 Hi Ho ########
		
		for k in range(0,HCNum,1):
			if k == 0:
				Hi[k] = dot(To,u)
				Ho[k] = AF(add(Hi[k],Hb[k]),AFKind)
			else:
				Hi[k] = dot(Ho[k-1],w[k-1])
				Ho[k] = AF(add(Hi[k],Hb[k]),AFKind)
		
		
		time_nnff1 += (time.clock()-time_start2)	
		time_start2 = time.clock()
		
		########   計算輸出層輸入輸出 Oi Oo    ########
		Oi = dot(Ho[HCNum-1],v)
		Oo = AF(add(Oi,Ob),AFKind)
		
		
		time_nnff2 += (time.clock()-time_start2)	
		time_start2 = time.clock()	
		time_nnff += (time.clock()-time_start)	
		time_start = time.clock()
				
		################ 反向 nnbp #############################
		
		######## 反向更新 v ############
		
		Oe = subtract(Teacher,Oo)
		Oe = multiply(Oe,dAF(add(Oi,Ob),AFKind))
						
		e += sum(multiply(Oe,Oe))
		
		
		
		#### v 梯度 ####		
		
		dv = dot(array([Oe]),array([Ho[HCNum-1]])).transpose()			  # v 的梯度

		v = add(v,dv*LearnRate)    # 更新 v
		
		time_nnbp_v += (time.clock()-time_start2)
	
		time_start2 = time.clock()
		
		######## 反向更新 w #############
		He = zeros((HCNum,HNum))
	
		for c in range(HCNum-2,-1,-1):
			if c == HCNum-2:
				He[c+1] = dot(v,Oe)
				He[c+1] = multiply(He[c+1],dAF(add(Hi[c+1],Hb[c+1]),AFKind))
				
				
				#dw[c] = dot(array([He[c+1]]),array([Ho[c]]).transpose())
				dw[c] = dot(array([Ho[c]]).transpose(),array([He[c+1]]))
				#dw[c] = dw[c].transpose()  #@@@@@@ 若結果不理想,可嘗試用此條語句
				
				w[c] = add(w[c],LearnRate*dw[c])
				
		
				
			else:
				He[c+1] = dot(w[c+1],He[c+2])
				He[c+1] = multiply(He[c+1],dAF(add(Hi[c+1],Hb[c+1]),AFKind))
				
				dw[c] = dot(array([Ho[c]]).transpose(),array([He[c+1]]))	
				
				w[c] = add(w[c],LearnRate*dw[c])

		time_nnbp_w += (time.clock()-time_start2)
	
		time_start2 = time.clock()
		
		######## 反向更新 u #############
		
		He[0] = dot(w[0],He[1])
		He[0] = multiply(He[0],dAF(add(Hi[0],Hb[0]),AFKind))
				
				
		du = dot(array([To]).transpose(),array([He[0]]))
				
		u = add(u,du)
		
		time_nnbp_u += (time.clock()-time_start2)
	
		time_start2 = time.clock()
		
		######### 更新門檻值 b ############
		
		Ob = Ob + Oe*LearnRate
				
		Hb = Hb + He*LearnRate
		
		time_nnbp += (time.clock()-time_start)
	
		time_start = time.clock()
		
		time_nnbp_b += (time.clock()-time_start2)
	
		time_start2 = time.clock()
	
	e = sqrt(e)

	
def predict(p):
				
	p = trait(p)
	p = p/KtoOne
	p_result = zeros((p.shape[0],1))

	for isamp in range(0,p.shape[0],1):
		for k in range(0,HCNum,1):
			if k == 0:
				Hi[k] = dot(p[isamp],u)
				Ho[k] = AF(add(Hi[k],Hb[k]),AFKind)
			else:
				Hi[k] = dot(Ho[k-1],w[k-1])
				Ho[k] = AF(add(Hi[k],Hb[k]),AFKind)
			
			
		########   計算輸出層輸入輸出 Oi Oo    ########
		Oi = dot(Ho[HCNum-1],v)
		Oo = AF(add(Oi,Ob),AFKind)
		Oo = Oo*KtoOne
		p_result[isamp] = Oo
	return p_result

	
time_begin = time.clock()

for i in range(1,n_epoch,1):
	if i%1000 == 0:
		print('已訓練 %d 千次 ,誤差均方差 %f'%((i/1000),e))
	train(p_s,t_s)
print('訓練完成,共訓練 %d 次,誤差均方差 %f'%(i,e))

print('共耗時: ',time.clock()-time_begin)

print()
		
result = predict(p_t)

print('模型預測結果 : ')
for i in result:
	print('%.2f'%i)
		
print('\n實際結果 : ')	
for i in t_t:
	print(i)
		
           

        運作代碼後,得到的結果如下圖:

一、最簡單的神經網絡--Bp神經網絡第 3 部分  最簡單的神經網絡Bp神經網絡

        可以看到,經過訓練後,該 Bp 網絡确實從原始資料中學到了特征 , 并且較為準确地對測試資料進行了推測。

        此外還要說明,此段代碼曆史較為悠久,是以很多地方寫的很不規範(很多地方保持了C的習慣···實際上是多餘的),符号使用的也比較混亂(但是實在懶得整理),僅拿來供大家參考和了解,望小夥伴們見諒。

4.Bp 神經網絡的經驗總結

        以上内容對 Bp 網絡的基本用法和數學關系 進行了講解。下面有幾個重要的知識點,需要特别指出:

        a.對于一個神經網絡來說,更寬更深的網絡,能夠學到更加複雜的特征,其能夠解決的問題也就越複雜,但是其計算過程也越繁瑣,參數越多,越容易出現過拟合的情況(過拟合即網絡過度學習了資料的特征,将噪聲也同時考慮到了網絡中,造成網絡隻在訓練集上表現良好,而無法泛化到其他資料上,說白了就是這個網絡已經學傻了...),是以要根據資料的實際情況來設計網絡的層數,節點數,激勵函數類型 以及 學習率。

        b.對于一個神經網絡來說,用來訓練神經網絡的資料集的品質,很大程度上決定了網絡的預測效果。資料越豐富,神經網絡越能夠貼近實際關系,泛化能力越強。

        c.Bp神經網絡是差別于傳統資料處理的一種方法,其特點在于尋找資料之間的相關性,并非嚴格地數學關系,是以是一種有效但是并非嚴格地網絡。對于實際問題的處理非常有用,但不能作為嚴謹數學計算的方法。

        Bp網絡的出現,為後來的 AI 技術提供了理論基礎,無論是 AlphaGo ,計算機視覺,還是自然語言處理等複雜問題,都可以了解為這一結構的更新和變種(不過更新幅度有點大,變化樣式有點多···)。是以這一對于這一網絡的了解,大家應該親自寫寫代碼,多看一看大神們寫的推導過程,深入了解。

繼續閱讀