深度學習之人工神經網路及優化
本篇文章繼續講解深度學習的基礎知識,目錄如下:
- 人工人工神經網路簡述
- 反向傳播鏈式法則簡單理解
- 神經網路中的反向傳播
- 各類優化演算法簡述
- 總結神經網路
人工神經網路簡述
在講網路之前應該對神經元要有所理解,對於神經元的講解,請查看:神經網路(容易被忽視的基礎知識)
下面開始說神經網路。注意,當我們說N層神經網路的時候,我們沒有把輸入層算入(因為輸入層只是輸入數據)。因此,單層的神經網路就是沒有隱層的(輸入直接映射到輸出)。而對於輸出層,也和神經網路中其他層不同,輸出層的神經元一般是不會有激活函數的(或者也可以認為它們有一個線性相等的激活函數)。這是因為最後的輸出層大多用於表示分類評分值,因此是任意值的實數,然後用softmax得到分類值,或者直接某種實數值的目標數(比如在回歸中)。對於各種激活函數可以看下:神經網路(容易被忽視的基礎知識)
全連接層及其網路
對於普通神經網路,最普通的層的類型是全連接層(fully-connected layer)。全連接層中的神經元與其前後兩層的神經元是完全成對連接的,但是在同一個全連接層內的神經元之間沒有連接。下面是兩個神經網路的圖例,都使用的全連接層:
左邊是一個2層神經網路,隱層由4個神經元(也可稱為單元(unit))組成,輸出層由2個神經元組成。右邊是一個3層神經網路,兩個含4個神經元的隱層。
注意:層與層之間的神經元是全連接的,但是層內的神經元不連接。
其中,用來度量神經網路的尺寸的標準主要有兩個:一個是神經元的個數,另一個是參數的個數,用上面圖示的兩個網路舉例:
- 第一個網路有4+2=6個神經元(輸入層不算),[3x4]+[4x2]=20個權重,還有4+2=6個偏置,共26個可學習的參數。
- 第二個網路有4+4+1=9個神經元,[3x4]+[4x4]+[4x1]=32個權重,4+4+1=9個偏置,共41個可學習的參數。
值得注意的是:現代神經網路能包含約1億個參數,可由10-20層構成(這就是深度學習)。但那麼多參數是很容易學不來的,所以在卷積神經網路中,會使用參數共享和局部鏈接的方式來減少參數,效果也更加的好。更多知識,後面講卷積神經網路的時候會講到。
反向傳播鏈式法則簡單理解
首先,反向傳播的數學原理是「求導的鏈式法則」 :
設和為的可導函數,則
然後舉個簡單的例子說明鏈式求導:
我們以求e=(a+b)*(b+1)的偏導為例。它的複合關係畫出圖可以表示如下:
在圖中,引入了中間變數c,d。為了求出a=2, b=1時,e的梯度,我們可以先利用偏導數的定義求出不同層之間相鄰節點的偏導關係,如下圖所示。
利用鏈式法則我們知道:
以及。
鏈式法則在上圖中的意義是什麼呢?其實不難發現,的值等於從a到e的路徑上的偏導值的乘積,而的值等於從b到e的路徑1(b-c-e)上的偏導值的乘積加上路徑2(b-d-e)上的偏導值的乘積。也就是說,對於上層節點p和下層節點q,要求得,需要找到從q節點到p節點的所有路徑,並且對每條路徑,求得該路徑上的所有偏導數之乘積,然後將所有路徑的 「乘積」 累加起來才能得到的值。
但是,這就有一個比較大的問題,就是這樣做是十分冗餘的,很多路徑被重複訪問。比如上圖中,a-c-e和b-c-e就都走了路徑c-e。對於權值動則數萬的深度模型中的神經網路,這樣的冗餘所導致的計算量是相當大的。
同樣是利用鏈式法則,BP演算法則機智地避開了這種冗餘,它對於每一個路徑只訪問一次就能求頂點對所有下層節點的偏導值。(注意,這裡他和普通鏈式求導計算方式不同的地方)
具體做法如下:正如反向傳播(BP)演算法的名字說的那樣,BP演算法是反向(自上往下)來尋找路徑的。從最上層的節點e開始,初始值為1,以層為單位進行處理。對於e的下一層的所有子節點,將1乘以e到某個節點路徑上的偏導值,並將結果「堆放」在該子節點中。等e所在的層按照這樣傳播完畢後,第二層的每一個節點都「堆放"些值,然後我們針對每個節點,把它裡面所有「堆放」的值求和,就得到了頂點e對該節點的偏導。然後將這些第二層的節點各自作為起始頂點,初始值設為頂點e對它們的偏導值,以"層"為單位重複上述傳播過程,即可求出頂點e對每一層節點的偏導數。
加深理解做法:以上圖為例,節點c接受e發送的1*2並堆放起來,節點d接受e發送的1*3並堆放起來,至此第二層完畢,求出各節點總堆放量並繼續向下一層發送。節點c向a發送2*1並對堆放起來,節點c向b發送2*1並堆放起來,節點d向b發送3*1並堆放起來,至此第三層完畢,節點a堆放起來的量為2,節點b堆放起來的量為2*1+3*1=5, 即頂點e對b的偏導數為5.
注意:以上例子有部分參考知友回答胡逸夫:如何直觀地解釋 back propagation 演算法?
神經網路中的反向傳播
上面講述的是在簡化情況在的BP,下面講述在神經網路中的反向傳播,這裡以簡單的多層感知機為例:
如上圖,我們先定義一個三層人工神經網路,layer1至layer3分別是輸入層、隱藏層和輸出層。首先定義說明一些變數:
表示第 層的第 個神經元連接到第 層的第 個神經元的權重;
表示第 層的第 個神經元的偏置;
表示第 層的第 個神經元的輸入,即:
表示第 層的第 個神經元的輸出,即( 表示激活函數):
然後,為了簡單起見,我們定義代價函數為均方差損失函數(當然,現在很多不是用這個損失函數,為什麼?見神經網路(容易被忽視的基礎知識)):
其中, 表示輸入的樣本, 表示實際的分類, 表示預測的輸出, 表示神經網路的最大層數。將第 層第 個神經元中產生的錯誤(即實際值與預測值之間的誤差,最後一層求導之後就是實際值和預測值相減)定義為:
然後,更為了簡單來算,我們以一個輸入樣本為例進行說明,此時代價函數表示為:
- 計算最後一層神經網路產生的錯誤:
其中,表示Hadamard乘積,用於矩陣或向量之間點對點的乘法運算(注意這裡的維數應該相同),推導如下:
- 由後往前,計算每一層神經網路產生的錯誤,注意這裡是反向回傳錯誤的體現(這一步的推導最為關鍵)
所以我們得到:
這一步極為關鍵,需要前後換序、轉置等操作,進行維度的適應,當然,知友也有對這種做法的講解:維數相容原則在反向傳播的應用,可以一看!
- 然後,我們應用錯誤計算權重的梯度
所以得到:
- 最後,我們計算偏置的梯度
最終得到:
整理一下整體過程如下:
對於訓練集中的每個樣本x,設置輸入層(Input layer)對應的激活值
- 前向傳播:
- 反向傳播:
各類優化演算法簡述
隨機梯度更新:
對於普通的sgd,之前寫過,
詳見:掌握機器學習數學基礎之優化[1](重點知識)和Evan:如何理解隨機梯度下降(Stochastic gradient descent,SGD)?
主要需要注意的是,在深度學習中比較常用的是mini-batch 梯度下降
動量(Momentum)更新:
該方法可以看成是從物理角度上對於最優化問題得到的啟發。也就是物理觀點建議梯度只是影響速度,然後速度再影響位置。損失值可以理解為是山的高度(因此高度勢能是,所以有)。用隨機數字初始化參數等同於在某個位置給質點設定初始速度為0。這樣最優化過程可以看做是模擬參數向量(即質點)在地形上滾動的過程。其代碼如下:
# 動量更新
注意:在這裡引入了一個初始化為0的變數v和一個超參數mu,物理觀點建議梯度只是影響速度,然後速度再影響位置。從公式可以看出,我們通過重複地增加梯度項來構造速度,那麼隨著迭代次數的增加,速度會越來越快,這樣就能夠確保momentum技術比標準的梯度下降運行得更快;同時μ的引入,一個典型的設置是剛開始將動量設為0.5而在後面的多個周期(epoch)中慢慢提升到0.99。保證了在接近谷底時速度會慢慢下降,最終停在谷底,而不是在谷底來回震蕩。 所以,由於在公式(1)中,兩項都會發生變化,所以導致的後果就是V先增大,後減小。
Nesterov動量更新:
和上面的動量(Momentum)更新差不多,但是,不同的在於,當參數向量位於某個位置x時,觀察上面的動量更新公式可以發現,動量部分(忽視帶梯度的第二個部分)會通過mu * v稍微改變參數向量。因此,如果要計算梯度,那麼可以將未來的近似位置x + mu * v看做是「向前看」,這個點在我們一會兒要停止的位置附近。因此,計算x + mu * v的梯度而不是「舊」位置x的梯度就有意義了。
代碼實現如下:
x_ahead = x + mu * v
等價與:
v_prev = v # 存儲備份
x += -mu * v_prev + (1 + mu) * v # 位置更新變了形式
上圖對於Nesterov動量表示既然我們知道動量將會把我們帶到綠色箭頭指向的點,我們就不要在原點(紅色點)那裡計算梯度了。使用Nesterov動量,我們就在這個「向前看」的地方計算梯度,這樣的方式也使得其比動量的方式更快收斂
自適應演算法
前面的方法對學習率都是進行全局地操作,並且對所有的參數都是一樣的。而學習率調參是很耗費計算資源的過程,所以很多工作投入到發明能夠適應性地對學習率調參的方法,甚至是逐個參數適應學習率調參。很多這些方法依然需要其他的超參數設置,但是其觀點是這些方法對於更廣範圍的超參數比原始的學習率方法有更良好的表現。下面就介紹一些在實踐中可能會遇到的常用適應演算法:
Adagrad:
Adagrad是一個由Duchi等提出的適應性學習率演算法,其主要的方式是當接收到高梯度值的權重更新的效果被減弱,而接收到低梯度值的權重的更新效果將會增強。下面是實現代碼:
# 假設有梯度和參數向量x
cache += dx**2x += - learning_rate * dx / (np.sqrt(cache) + eps)這裡的變數cache的尺寸和梯度矩陣的尺寸是一樣的,還跟蹤了每個參數的梯度的平方和。這個一會兒將用來歸一化參數更新步長,歸一化是逐元素進行的。需要注意是平方根的操作非常重要,如果去掉,演算法的表現將會糟糕很多。用於平滑的式子eps(一般設為1e-4到1e-8之間)是防止出現除以0的情況。Adagrad的一個缺點是,在深度學習中單調的學習率被證明通常過於激進且過早停止學習。
RMSprop:
是一個非常高效,但沒有公開發表的適應性學習率方法。絕大部分人在他們的論文中都引用自Geoff Hinton的Coursera課程的第六課的第29頁PPT。這個方法用一種很簡單的方式修改了Adagrad方法,讓它不那麼激進,單調地降低了學習率。具體說來,就是它使用了一個梯度平方的滑動平均:
cache = decay_rate * cache + (1 - decay_rate) * dx**2
在上面的代碼中,decay_rate是一個超參數,常用的值是[0.9,0.99,0.999]。其中x+=和Adagrad中是一樣的,但是cache變數是不同的。因此,RMSProp仍然是基於梯度的大小來對每個權重的學習率進行修改,這同樣效果不錯。但是和Adagrad不同,其更新不會讓學習率單調變小。
Adam:
有點像RMSProp+momentum,效果比RMSProp稍好,而其簡化的代碼是下面這樣:
m = beta1*m + (1-beta1)*dx
注意這個更新方法看起來真的和RMSProp很像,除了使用的是平滑版的梯度m,而不是用的原始梯度向量dx。論文中推薦的參數值eps=1e-8, beta1=0.9, beta2=0.999。在實際操作中,我們推薦Adam作為默認的演算法,一般而言跑起來比RMSProp要好一點。但是也可以試試SGD+Nesterov動量。然後注意完整的Adam更新演算法也包含了一個偏置(bias)矯正機制,因為m,v兩個矩陣初始為0,在沒有完全準確更新之前存在偏差。
建議讀者可以閱讀論文查看細節。比如Adam演算法,很多細節,其論文講解的很清晰的!
下面是圖示各個優化演算法的比較:來自CS231n,本是動圖,詳見CS231n Convolutional Neural Networks for Visual Recognition
總結神經網路:
對於神經網路,現在有各種各樣的理論,下面簡略總結一下神經網路:
- 對於數據處理和初始化:預處理操作是很有必要的,特別是圖像處理的時候,使用標準差為的高斯分布來初始化權重,不用全零初始化。
- 對於神經網路的架構選擇:激活函數推薦先使用ReLU,當然,其他激活函數也需要嘗試的,神經網路不能太寬,深度要合適,適當的使用BN,Dropout等Trick
- 對於神經網路的優化:更新方法的方式屬於調參的範疇,需要經驗,對於自適應,Adam方法還是不錯的。若是自己實現反向梯度傳播,需要注意要利用小批量數據對實現進行梯度檢查。
- 最後,神經網路有各種Trick,也需要各種調參經驗,多實踐,多總結,需要我們的學習探索,加油!
資料來源:
CS231n課程
《deep learning》--Ian Goodfellow等
《機器學習》--周志華
dropout,Batch Normalization等相關論文
網上其他博文
推薦閱讀:
※使用py-faster-rcnn進行目標檢測(object detect)
※膠囊網路結構Capsule初探
※Michael Nielsen對交叉熵的解釋(三)
※ML領域的生物進化論,進化策略圖文詳解
TAG:深度學習DeepLearning | 神經網路 |