提到人工智能算法,人工神經網絡(ANN)是一個繞不過去的話題。可是對於新手,每每容易被ANN中一堆複雜的概念公式搞得頭大,最後只能作到感性的認識,而沒法深刻的理解。正好最近筆者本人也在經歷這個痛苦的過程,本着真理越辯越明的態度,索性坐下來認真的把這些頭大的問題梳理一番,試試看能不能搞清楚ANN背後的數學原理。算法
其實ANN 的流程歸納來講倒不是很複雜,以最簡單的前饋神經網絡爲例,無非就是編程
其中四、五、6裏的內容是須要反覆迭代的(注意6是雙重循環)。網絡
在ANN的一堆操做裏,梯度降低算法是一個相對獨立的過程,不妨就讓咱們從梯度降低算法開始吧。架構
其實這個問題很是簡單,只是你們被梯度降低複雜的過程搞蒙了,忘記了它的本質。梯度降低算法自始至終都在幹一件事——就是找到函數的極值點,固然確切的說是極小值點。可是,這種方法不一樣於以往咱們在高等數學裏學到的找極值點的方法。那麼咱們首先就要問,求極值的經典方法不香嗎?框架
要回答這個問題,讓咱們先快速回顧一下在中學和大學裏學到的傳統的求極值點的方法。機器學習
對於一元函數來講,極值可能出如今一階導函數爲0的點(駐點)或是導數不存在的點。ide
例如要找到 f(x) = x^2 + 3x 的極值點
求導得 dy/dx = 2x + 3
令 dy/dx = 0
就獲得 x = -1.5 時,導函數爲0。
注意,上面找到的只是可能的極值點,也就是極值存在的必要條件。還須要驗證一下充分條件,才能肯定極值。這時,能夠判斷二階導的正負性、或是斷定一階導在可能的極值點兩邊的正負狀況。回到咱們的例子函數
當 x < -1.5 時,2x + 3 < 0
當 x > -1.5 時,2x + 3 > 0
說明函數在x = -1.5 附近先降低、後上升
該點是一個極小值點
對於二元函數,狀況更復雜一些。首先要找出該函數的駐點和偏導數不存在的點,這些點仍然只是可能的極值點。而二元函數的駐點須要同時知足兩個偏導數爲0的條件,即學習
顯然,這裏的駐點是須要解這樣一個二元方程才能求得的。對於駐點分別求出其3個二階偏導數的值,再根據一些規則才能判斷是否是極值點。人工智能
還需注意這個判斷規則是不一樣於一元函數的,由於一元函數極值的充分條件只須要考察一個二階偏導數,而這裏則須要綜合考察二元函數的3個二階偏導數,計算量明顯增大了。對於偏導數不存在的情形還須要特判。
綜合以上,咱們能夠看出使用經典方法雖然能準確的解出極值點,但當函數自變量的個數不少時,用這種方法求解極值點還真的不香。好比:
基於此,爲了找出多元函數的極值點,咱們還需另尋他法。這種方法要簡單易行,特別是要能簡單的向任意元函數推廣,並且這種方法要可以適應計算機數值計算的特色,畢竟咱們這套程序確定是要放在電腦上跑的。而這就是傳說中的梯度降低算法。
梯度的概念其實也不難,但爲了讓儘量多的人明白這一律念,咱們仍是從一元函數開始吧。不過如今咱們的目標是——用純粹數值計算的方法,從函數上的某一點出發,找到函數的極值。這裏咱們只考察極小值。
1.2.1 一元函數找極值:從枚舉試探法到梯度降低法
以函數爲例,讓咱們看看如何找到極值。
既然是從函數上的某一點出發,那麼不妨設想咱們在x = 1 的地方,這個地方是否是極小值點呢,咱們能夠試探一下。
向右走0.5,發現f(1.5) > f(1),說明這個方向是上升的方向,不該該選擇這個方向;
向左走0.5,發現f(0.5) < f(1),說明這個方向是降低的方向,選擇這個方向;
再向左走0.5,發現f(0) < f(0.5),說明這個方向是降低的方向,選擇這個方向;
再向左走0.5,發現f(-0.5) > f(0),說明這個方向是上升的方向,不該該選擇這個方向。
至此,咱們能夠將x = 0做爲極小值點。
回顧這個過程,咱們將尋找極小值點的過程抽象以下:
固然這裏還有幾點值得注意
對於第二點,咱們能夠引出梯度的定義了。
梯度是一個向量,它總指向當前函數值增加最快的方向。而它的模長則是這個最快的增加率(導數)的值。想要獲得梯度向量,也很簡單,它在x, y, z……等方向上的份量(座標)就是相應的導數值。因而咱們求導就能夠了。
對於一元函數,函數變化的方向只有兩個,咱們定義一種一維的向量來表示梯度,好比5i,-5i。i前的數爲正時,表明向量指向x軸正向;i前的數爲負時,表明向量指向x軸負向。由下圖能夠看出,按照上述定義規定的梯度向量天然的指向了函數增加的方向,是否是很神奇。
因爲梯度的方向正是函數增加最快的方向,因此梯度的逆方向就成了函數降低最快的方向。固然對於一元函數來講,沒有最快的方向的概念,由於畢竟就兩個方向而已,根本沒得比。不過有了梯度,咱們就能夠進一步簡化上述尋找極小值點的過程:
仍以函數,起始點x = 1爲例,讓咱們看看如何用梯度找到極值。
初始x = 1, 步長step = 0.5
#在咱們的例子裏,梯度的計算式爲2xi。i是指向x軸正向的單位向量
求x = 1處的梯度爲2i,梯度反方向爲-i #注意這裏咱們只關注梯度的方向,至於梯度的模長則沒必要在乎
沿此方向走一步,x新 = x舊 + step * 負梯度方向上單位向量的座標 = 1 + 0.5 * (-1) = 0.5
求x = 0.5處的梯度爲1i,梯度反方向爲-i
沿此方向再走一步,x新 = 0.5 - 0.5 * 1 = 0
求x = 0處的梯度爲0,說明到達極值點
以上就是用梯度找極小值點的過程,也就是梯度降低算法所作的事情,其實不難理解對吧。
能夠看出,相比於枚舉試探法,梯度降低法明顯智能了許多,它直接給出了正確的方向,不須要咱們一步步試探了。此外,使用梯度降低法沒必要再關注具體的函數值,只須要把注意力放在導數上,並且只關注一階導數便可。
在後面,咱們還將給上面提到的步長step換一個高大上的名字——學習率,這樣就徹底是機器學習裏的叫法了。
這裏用到梯度的時候,我進行了單位化操做,其實也能夠不進行這一步,這樣當函數變化比較劇烈的時候,移動的距離就比較多;函數變化比較平緩的時候,移動的距離就比較短。好比,在咱們這個例子裏,只需一輪迭代就能獲得結果了。
初始x = 1, 學習率step = 0.5
#在咱們的例子裏,梯度的計算式爲2xi。i是指向x軸正向的單位向量
求x = 1處的梯度爲2i,梯度反方向爲-2i #注意這裏咱們既關注梯度的方向,也關注梯度的模長
沿此方向走一步,x新 = x舊 + step * 負梯度的座標 = 1 + 0.5 * (-2) = 0
求x = 0處的梯度爲0,說明到達極值點
好了說完了梯度,對於前面第三點提到的找不到極值的情形,咱們舉兩個具體的例子
仍是函數,若是起始點選爲0.4,而學習率仍爲0.5,在採用單位化梯度向量的情形下,則沒法找到事實上的極小值點
對於這種狀況,咱們能夠經過減少學習率使結果儘量精確,例如咱們將學習率設置爲0.1,就仍然能獲得精確的結果。事實上,在實際操做中,通常也會把學習率設置爲0.1。
而對於這種有多個極值點的函數,這種方法是無法找到所有極值點的,更遑論找到全局的極值點了。這時,咱們能夠在算法里加入一些隨機性,使其有必定機率跳出可能陷入的局部極值點。
1.2.2 多元函數的梯度
前面說過梯度降低算法的好處之一在於能夠很方便的向多維推廣,如今咱們以二元函數爲例,看看梯度是如何幫助咱們找到極值點的。
此次咱們的函數變成了,起始點選擇爲(-5, -5),學習率仍設置爲0.5。如今咱們的目標是從這個點出發,找到該函數的極值點,咱們知道這個極值點應該是(0, 0)。
這裏與一元函數有幾點不一樣:
好了,如今算法開始:
起始點座標(-5,-5), 學習率step = 0.5
#在咱們的例子裏,梯度的計算式爲2xi + 2yj。i和j分別是指向x軸正向和y軸正向的單位向量
求點(-5,-5)處的梯度爲-10i-10j,負梯度爲10i+10j,寫成座標形式就是(10,10)
在點(-5,-5)處沿此梯度走一步
根據公式 向量座標 = 終點座標 - 起點座標,得終點座標 = 起點座標 + 向量座標
這裏,終點座標是(x新, y新),起點座標是(x舊, y舊) = (-5, -5)
向量座標是負梯度座標 = (10,10),再考慮學習率step,就能夠獲得
(x新, y新) = (-5,-5) + 0.5 * (10, 10) = (0, 0)
求(0, 0)處的梯度爲零向量,說明到達極值點
將上述過程抽象,咱們就獲得了梯度降低算法的所有邏輯:
咱們要找函數的極小值點(使函數取值儘量小的那一組自變量),由於,梯度的方向是函數值增加速度最快的方向,因此,沿着梯度的反方向函數值降低最快。
所以,只要沿着梯度的反方向一步步逼近就有可能找到那一組使函數取值儘量小的自變量。
如何沿着梯度的反方向一步步逼近呢?
咱們隨機指定一個起點座標(一組自變量取值),而後沿着梯度的方向求出未知的終點座標,梯度是一個向量,自己也具備座標
經過上面的迭代公式,不管是多少元的函數,它的一個個自變量們都會比較快的接近極值點(或者其近似)。這樣咱們就能夠找到一組自變量值,使得函數值儘量的小。
1.2.3 小結
若是是第一次聽到人工神經網絡這個名詞,難免會以爲比較高大上,好像咱們已經能夠模仿神祕的神經系統了。其實它只是一個數學模型而已。固然ANN的效果是使人眼前一亮的,好像計算機一會兒真的有了人的能力,能夠識人、識物。
但其實稍加抽象便能發現,這個東西無非就是個分類器,它的輸入是一張圖片,或者確切的說就是一堆表明像素點的數值,而輸出則是一個類別。
因此說白了,所謂的人工神經網絡其實就是一個超大規模的函數。
這就比如飛機和鳥兒的關係。讓飛機飛起來靠的不是依葫蘆畫瓢造一我的工鳥,而是靠流體力學中的原理創建數學模型,而後計算得出飛機的尺寸、造型,並設計相應的發動機。
盜一張老師ppt裏的圖說明問題,能夠看出ANN中的每個節點(也就是所謂的神經元)就是這樣一個簡單的線性函數模型。
固然經過激活函數咱們能夠製造一點非線性的因素,以提升模型的表達能力。這樣的話下面的神經元就表明這樣一個函數
其中,,這裏w1, w2, w3, b都是參數,x1, x2, x3是函數的輸入,也就是因變量。
經常使用的激活函數在這裏(仍然盜用老師的ppt,捂臉逃~)
以上就是所謂的人工神經元或者叫人造神經元,不少不少這樣的神經元按必定規則相連就構成了ANN,因此我才說ANN就是一個超大規模的函數而已。
是否是和你想象中的高大上的神經元截然不同,可是咱們如今所謂的人工智能其實就是這樣的數學模型而已。不管是簡單的圖像分類器仍是打敗人類的AlphaGo,都是靠這樣的數學計算算出來結果的,而不是靠什麼化腐朽爲神奇的力量。
知道了ANN的本質,如今就讓咱們看看獲得一個ANN須要怎麼作?這裏,請留意咱們會遇到不一樣功能的函數,千萬不要搞混了。
既然ANN是一個超大規模的函數,那麼首先咱們作的就是搭建起這個函數的架構,也就是設計人工神經網絡的架構。 這時這個函數就有一堆參數待定了。 接下來咱們準備一堆訓練數據訓練ANN,也就是把上面提到的待定參數都給他肯定了。 模型完成,可使用。
顯然,最關鍵的是第三步——肯定未知參數。
這裏首先解釋訓練數據,咱們知道ANN是一個分類器也是一個函數,這個函數讀取一些輸入值,通過複雜的計算後獲得輸出值,這些輸出值能夠被解釋爲類別。而訓練數據就是輸入值和最後的輸出值都已知的一組數據,換句話說就是已知一組函數的自變量和因變量的對應關係。
再說的明白點,咱們的任務就是,已知函數的架構、函數的一組輸入值和輸出值,但不知道函數的一些參數,如今要推出這些未知參數。我把這裏咱們要求出的這個函數稱之爲目標函數。因而,一言以蔽之,咱們的任務就是求出目標函數的未知參數。
爲了完成這個任務,咱們引出另外一個重要的概念——損失函數。
2.2.1 損失函數
在這裏,咱們玩一點當心機。注意了,這裏很關鍵!!!
既然咱們已知目標函數的一組輸入和輸出,而未知其參數,那麼咱們不妨將計就計將這些未知參數直接視爲因變量,而將目標函數的輸入直接代入進去,這樣咱們不就獲得了一個自變量是目標函數的全部未知參數且函數總體徹底已知的函數了嗎?
這時,若是能找到一組合適的未知參數,這個函數應該能輸出和已知輸入對應的輸出徹底一致的值。
因而咱們能夠經過做差比較定義損失函數了
上圖給出了損失函數的兩種形式(除此以外還有交叉熵損失函數等其餘類型),通常須要根據不一樣的任務類型選取適當的損失函數。爲了便於初學者理解,後文將以第二種均方偏差的形式作講解。這裏之因此出現了求和符號,是由於ANN的輸出端可能對應了不止一個函數,這些函數能夠分別表示把一張圖片分紅不一樣類別的機率。後面咱們引入一個直觀的例子,一看便知。
這裏必定要注意,損失函數看起來雖然還有目標函數的影子,但實際已經徹底不一樣了。咱們列表比較一下
目標函數 | 損失函數 | |
---|---|---|
表現形式 | f | loss |
生成方式 | 事先搭好框架,再經過訓練得出待定參數 | 將目標函數的輸出與實際值做差獲得框架,而後代入一個具體的訓練樣例(包括輸入值與標籤值) |
自變量 | ——神經網絡的輸入值(實際場合中能夠是一張圖片的全部像素值) | ——目標函數的待定參數 |
函數值(因變量)含義 | 屬於不一樣分類的機率 | 預測值與實際值的差值(越小越好) |
特色 | 咱們最終想要獲得的函數,能夠用來做圖像分類。是線性函數與非線性函數的組合,規模很大,自變量與參數都不少 | 用來求出目標函數的過渡函數。非負,最小值爲0,通常要使用梯度降低法找到極值點 |
舉個例子看看函數變異的過程吧。設原函數爲,這是一個關於的二元函數,其中a, b, c均是常數,也能夠叫待定參數。如今咱們給出一組具體的函數輸入值好比,令把它們代入函數,而且將a, b, c視爲變量,則函數變成了關於a, b, c的三元函數,記做。
綜上,求目標函數的過程,就變成了尋找損失函數極小值點的過程,而尋找極小值點不正能夠用上面介紹的梯度降低法實現嗎?
2.2.2 一個實例:關於鏈式求導和偏差反向傳播(BP)
行文至此,有關ANN的重要概念,咱們還剩下鏈式求導和偏差反向傳播(BP)沒有說起,讓咱們用一個實例融會貫通一下。
考慮下面這個簡單的ANN:
這個ANN只有4個神經元,分別是。它輸出兩個目標函數,均是輸入變量的函數,分別由神經元輸出。能夠記爲
這裏給加上帽子,表示這兩個函數(即目標函數)的函數值是預測值,區別於訓練數據給出的實際標籤值。而均是目標函數的待定參數,這裏咱們假定神經元均採用sigmoid激活函數,即,而神經元不採用激活函數。
如今定義損失函數爲
注意接下來咱們會將具體的一組輸入變量帶進去,這樣損失函數就被視做覺得自變量的多元函數(具體的自變量變化過程參見上文描述)。其中, 是中間變量,它們均是覺得自變量的多元函數。
如今只要給出一個包含輸入輸出數據的訓練樣例,損失函數就成爲不含未知參數的徹底肯定的函數。而咱們要作的就是找到這個損失函數的極小值。
按照梯度降低算法的推導,此時咱們只要按照下面的步驟就能夠找出這個極小值:
其中二、3裏的內容是須要反覆迭代的。
如今,咱們以其中的幾個參數爲例,看看在調整過程當中會遇到什麼新問題。
先試試調整吧,這時咱們須要求出損失函數對自變量的偏導數值(注意是數值,不是表達式),爲此寫出它的依賴關係:
這裏,Loss函數依賴於變量,但與無關。回想多元函數求偏導數的規則,咱們對求導時,應將視爲常數。
而依賴於變量,所以這裏應按照複合函數求導法則,即傳說中的鏈式求導法則,先讓Loss函數對變量求導,再令對求導,即:
其實從神經網絡的圖中能夠很清楚的看出求導鏈。
這裏有幾個要點:
求出損失函數對的偏導數值,咱們就能夠按照梯度降低算法推導的公式,調整這個參數了!
如今,再來看看靠前的參數是怎麼調整的,咱們以和爲例
仍是老規矩,對照神經網絡圖,先寫出它的依賴關係:
能夠看出和,分別是函數和的變量,而函數均與和有關,因此Loss函數須要對均求偏導。
依然按照鏈式求導法則對求偏導,有:
對求偏導,有:
注意紅框圈出來的部分是否是有些眼熟?
事實上,這一部分已經在調整後層參數的時候計算過了(請回看計算時的計算公式)。所以在編程時,可讓程序保存中間結果,這裏直接拿來用。
如今縱觀整個過程,咱們驚奇的發現,對於ANN,當咱們須要使用它時,是從最前面給出輸入,而後一步步日後計算得出這個龐大複雜函數的輸出的;而當咱們須要訓練它時,則是從最後面的參數開始,一步步向前求導,調整各個參數的。而且計算前面的參數時通常都會用到以前計算過的中間結果。
這樣,ANN調整參數的過程就能夠看做是一個偏差反向傳播(BP)的過程。
之因此會這樣反向傳播,是由於神經網絡中靠後的參數依賴的中間變量少、複合層數少,而靠前的參數則通過層層複合,求導鏈會拉的很長。
2.2.3 最後的一點小問題
以上咱們將求偏導的過程整個過了一遍,而求偏導只是梯度降低算法的一環。
程序跑起來以後,咱們會對每個訓練樣例,一遍遍的求偏導,直到基本上找到極小值點。
也就是說,按照梯度降低算法,每個訓練樣例都會最終給出一組參數值。
一個訓練集中顯然會有多個訓練樣例,所以最終會獲得好多組各不相同的參數值。
而ANN的訓練目標是肯定一組參數值,獲得一個有必定效果的很複雜的函數,
怎麼解決?
對每個參數,咱們能夠將不一樣訓練樣例得出的不一樣值求一個平均。也能夠構建一個更大的損失函數,即將每個訓練樣例生成的損失函數求和,而後用梯度降低算法找到這個累計損失函數的極小值點。
這樣,咱們就能經過訓練,最終肯定ANN這個大函數的全部待定參數,而後用它來作一些神奇的事情。