說明:
本系列文章翻譯斯坦福大學的課程:Convolutional Neural Networks for Visual Recognition的課程講義 原文地址:http://cs231n.github.io/。 最好有Python基礎(但不是必要的),Python的介紹見該課程的module0。
本節的code見地址:
https://github.com/anthony123/cs231n/tree/master/module1-5(working on)如果在code中發現bug或者有什么不清楚的地方,可以及時給我留言,因為code沒有經過很嚴格的測試。
課程目錄:
- 不和大腦科學類比的快速介紹
- 模擬一個神經元
- 生物學動機及連接
- 作為線性分類器的單獨神經元
- 經常使用的激活函數
- 神經網絡結構
- 層級結構
- 前向反饋計算的例子
- 表征能力
- 層數及每層大小的設置
- 總結
- 附加資源
快速介紹
介紹清楚神經網絡,而不與腦科學類比,也是可能的。在線性分類那節課中, 我們介紹了使用公式s=Wx計算不同類別的分數,其中W是一個矩陣,x是包含一張圖片所有像素的一個列向量。在CIFAR-10的例子中,x是[3072x1]的列向量,W是一個[10x3072]的矩陣,所以輸出的分數是一個10個類別分數的向量。
但是,一個簡單的神經網絡可能計算s=W2max(0,W1x),其中W1可能是[100x3072]的矩陣,它把圖像轉變為100維度的中間向量。函數max(0,-)是一個逐元素的非線性函數。對于非線性函數,我們有幾種選擇(這節課的后面會介紹),但是max函數是一個非常常用的函數,它將低于0的數值置為0。最后,W2的大小為[10x100]。所以,最終我們可以得到10個對應于類別分數的數字。我們可以注意到,非線性是計算的主要花銷。如果沒有非線性計算,那么就剩下簡單的線性計算,計算的函數也變成輸入向量的線性函數。非線性函數對最終的結果非常重要。參數W2,W1都是通過隨機梯度下降學習到的,它們的梯度值都是通過鏈式法則獲得的(使用反向傳播計算)。
一個三層的網絡可以看成是s=W3max(0,W2max(0,W1x)), 其中,所有的參數W3,W2和W1都是需要學習的參數。中間隱藏向量的大小是網絡的超參數,后面我們會講到如何設置它們。現在我們從神經元/網絡的視角來解釋這些計算。
模擬一個神經元
神經網絡領域起源于對神經生物系統的模擬,后來發現這種結構在機器學習的任務中可以達到很好的結果。我們首先介紹對這個領域有啟發的神經生物系統。
生物學動機及其連接
大腦基本的計算單元是神經元。在人類的神經元中,大概有860億個神經元。這些神經元由大概10^14 ~ 10^15個突觸連接。下面的圖顯示了一個生物的神經元(上)及其數學模型(下)。每個神經元從樹突接收信號,并沿著軸突產生輸出信號。軸突最終產生分支,并通過與其他神經元樹突的突觸進行連接。在神經元的計算模型中,沿著軸突傳播的信號(x0)與另外一個神經元樹突的突觸量(w0)進行乘法操作(w0*x0)。其中主要的思想在于突觸量(權重W)是可學習的,并且可以控制這個神經元對另外一個神經元的影響力度(及方向:興奮(正權重)和抑制(負權重))。在基本的模型中,樹突將信號放入細胞體中,并在那里進行求和操作。如果最終的和值超過一個閾值,那么神經元就會喚醒,并沿著軸突傳送神經沖動。在計算模型中,我們假設神經沖動的時間點不是非常重要,重要的是神經沖動的頻率。基于這種頻率編碼的理論,我們把神經元的激活頻率模擬成一個激活函數f, 可以用來表示沿軸突傳播的神經沖動的頻率。過去,一般選用sigmoid函數σ作為激活函數,因為它將一個實數輸入(信號求和之后)轉變為一個0到1的數值。在這節課的后面我們會講解不同的激活函數。
一個單獨神經元的前向傳導的示例代碼如下:
class Neuron(object):
# ...
def forward(inputs):
"""assume inputs and weights are 1-D numpy arrays
and bias is an number """
cell_body_sum = np.sum(inputs * self.weights) + self.bias
firing_rate = 1.0 / (1.0 + math.exp(-cell_body_sum))
# sigmoid activation function
return firing_rate
也就是說,每個神經元先對輸入及權重進行點乘操作,并加入偏置值,最后應用非線性函數(激活函數), 在上面情況下,激活函數為:
粗糙的模型
需要強調的是, 這個生物神經元的模型非常粗糙。比如,真實的神經元有不同的種類,而且不同的神經元有不同的性質。生物神經元的樹突計算是非常復雜的非線性計算。突觸也不是一個單獨的權重,而是一個復雜的非線性動態系統。很多神經系統產生神經沖動的準確時機非常重要,所以頻率編碼并不適用。由于這些及其他的簡化,所以如果你將神經網路與真實的腦神經類比的例子講給一個具有神經科學背景的人,那么你要做好準備接受他們的嘲笑。
單個神經元作為線性分類器
模擬神經元前向計算的數據公式是不是有些熟悉?在線性分類的講解中,我們知道一個神經元可以“喜歡”(在1附近激活)或者“不喜歡”(在0處激活)輸入空間的某些線性分類。所以,在神經元的輸出使用一個合適的損失函數,我們可以將一個神經元轉化成一個線性分類器。
二元softmax分類器 我們可以將
解釋為其中一種類別的概率 P(yi=1|xi;w)。那么,另外一種類別的概率為P(yi=0|xi;w) = 1 – P(yi=1|xi;w),因為兩種類別的概率之和為1。利用這種解釋,我們可以構建我們熟悉的交叉熵損失,優化它便能變成二元softmax分類器(也稱之為邏輯回歸)。因為sigmoid函數將輸出限制在0~1,所以對這個分類器的預測就是查看概率是否大于0.5。
二元SVM分類器 我們也可以將最大邊緣的鉸鏈損失放在神經元的輸出后面,并且把它訓練成一個二元SVM分類器。
正則解釋 在生物學的視角下, 在SVM/Softmax情況下的正則損失可以解釋為漸進遺忘,因為它使得每個參數更新之后,突觸權重w趨向于0。
一個單獨的神經元可以用來實現一個二元分類器(比如 二元Softmax 或者二元SVM分類器)
經常使用的激活函數
每一個激活函數(非線性函數)接收一個輸入數值,并對這個值進行某種固定的數學操作。在實踐中,你可能會遇到幾種不同的激活函數:
Sigmoid函數 Sigmoid非線性的數學公式為
其圖像如上圖所示。它接收一個實數,并把它映射到0~1范圍內。特別地,大的正數變成1,大的負數變成0。Sigmoid在過去用的非常多,因為它很好的解釋了神經元的激活頻率。從一點都沒有激活(0)到完全激活(1)。但是,現在Sigmoid函數用的很少,因為它有兩個缺點:
Sigmoid飽和容易使梯度消失。 Sigmoid的一個不好的特點在于當神經元的激活值為0或者1的附近,它的梯度就接近0。在反向傳播過程中,局部梯度將與這個門的輸出梯度相乘,所以如果局部梯度接近于0,那么就會使得整個梯度都變成0,從而使得權值不會發生改變。而且,我們也需要注意,不能使得權值的初始值過大。比如,如果初始的權重過大,那么大多數的神經元梯度都會接近0,那么整個網絡就不會學習。
Sigmoid函數不是以零為中心。 這會導致后續層也會接收到不是以零為中心的數據。這對梯度下降會有不好的影響。因為如果進入神經元的數據總是正數的話(比如,x>0 f=Wx+b),那么反向傳播過程中,權重w的梯度變得要么全是正數,要么全是負數(取決于整個f的梯度符號)。這會導致權值更新呈現出之字形。但是一旦跨批量數據相加,權重的最終更新可能會有不同的符號,這樣就可以在一定程度上解決這個問題。因此,雖然這會導致一些不方便,但是相對于上面提到的飽和激活問題,它不會產生非常嚴重的后果。
Tanh Tanh函數如上圖右所示。它把實數映射到[-1,1]。像Sigmoid函數那樣,它的激活會飽和,但是和Sigmoid函數不一樣,它的輸出是在[-1,1]范圍內。因此,在實踐中,Tanh永遠比Sigmoid函數好。其實,tanh神經元也是一個Sigmoid的一個變形,因為tanh(x) = 2σ(2x)-1.
ReLU 在最近幾年,修正線性單元非常流行。它的計算函數為f(x) = max(0,x)。下面列舉一些ReLu的優點和缺點:
(+): 實驗發現相比于Sigmoid和Tanh,它能夠加快隨機梯度下降的聚合。這被認為是由于它的線性,不飽和的形式。
(+): 相比Sigmoid和Tanh,ReLu的計算更加簡單。
(-):不幸的是,ReLU在訓練的過程中,可能會很脆弱,容易“死亡”。比如,通過ReLU神經元的大的梯度流可能永遠變成零。從而會導致部分數據在訓練的過程中丟失。如果你在訓練的過程中由于設置過高的學習速率,導致多達40%的網絡死亡,那么可以通過將學習速率降低來試著解決這個問題。
leaky ReLU 它是一個嘗試解決死亡ReLU問題的變形。當x<0時,leaky ReLU有一個小的負斜率(比如:0.01)。函數表達式為f(x) = 1(x<0)(ax) + 1(x >= 0)(x) ,其中a是一個小的常數。有些人報告說在這種形式的激活函數取得了成功,但是這個結果不總是穩定的。斜率a可以放在每個神經元的參數列表中。但是,現在跨任務的一致性還不是很清楚。
maxout 另外一種比較流行的選擇是maxout,它是ReLU和leaky ReLU的通用版。maxout神經元計算下面這個函數
我們可以發現,ReLU和Leaky ReLU 是這個函數的特殊情況(比如: 當w1,b1=0,就變成了ReLU)。所以maxout可以享受到ReLU所有的好處,而且沒有ReLU的缺點(ReLU死亡)。然而,不好的一點在于,它也使得參數的個數翻倍。
關于常見的神經元及其激活函數的討論也就結束了。最后補充一點,在一個神經網絡中,使用不同類型的神經元的做法非常少見,盡管這樣做也并沒有什么問題。
總結: “我該使用什么類型的神經元呢?” 使用ReLU,但是要小心設置學習速率并注意網絡的死亡率。如果出現了這種情況,你可以試著使用leaky ReLU或者Maxout。永遠不要使用Sigmoid.。使用Tanh,但是不要期望它會表現的比ReLU或Maxout好。
神經網絡架構
層級組織結構
作為圖結構中神經元的神經網絡 神經元可以看成是由無環圖連接的神經元的集合。也就是說,一些神經元的輸出是另外一些神經元的輸入。環形圖是不允許的,因為這會導致網絡前向傳播的無限循環。這些連接起來的神經元并不是無定形的,而是被組織成層級結構。對于普通的神經網絡來說,最常見的層級類型就是全連接層,即兩個相鄰的層之間兩兩都有連接,但是在一個層內,神經元之間沒有連接。下面是兩個全連接層網絡的例子:
命名規范 注意,當我們計算神經網絡的層數時,我們并不包括輸入層。因此,一層的神經網絡沒有隱藏層(輸入直接映射到輸出)。在那種情況下,我們可能會聽到有人稱邏輯回歸或者SVM是單層的神經網絡。你也有時候聽到別人把神經網絡稱之為人工神經網絡(Artificial Neural Network)或者 多層感知網絡(Multi-Layer Perceptrons(MLP))。很多不喜歡神經網絡與真實腦相似論斷的人傾向于把神經元稱之為單元。
輸出層 不像神經網絡其他層那樣,輸出層的神經元不包括激活函數。(或者你可以認為激活函數是單位激活函數(identity activation function))。這是因為最后的輸出函數經常用來表示類別分數(分類問題中),其中的數值為實數 ,或者是實數的目標(在回歸中)。
確定神經網絡的大小 兩個經常使用來測量神經網絡大小的度量是神經元的個數和參數的多少(更常見)。以上圖的兩個神經網絡為例
- 第一個網絡(上)有4+2個神經元(不包括輸入神經元),[3x4] + [4x2] = 20 個權重和4+2個偏置量,一共有26個可學習的參數。
- 第二個網絡(下)有4+4+1=9個神經元,[3x4]+[4x4]+[4x1]=32個權重和4+4+1=9個權重,一共有41個可學習的參數。
現代的卷積神經網絡包括1億個量級的參數,通常包括10-20層(所以稱之為深度學習)。然而,之后我們會學習到,由于參數共享,有效的連接數會遠遠大于這個量級。具體內容我們會在卷積神經網絡那節涉及。
前饋計算的例子
矩陣乘法與激活函數交替出現并重復 神經網絡被組織成層級結構的一個最基本的理由是這種結構使得利用矩陣向量操作來計算神經網絡變得簡單和有效。以上面的三層神經網絡為例,輸入是[3x1]的向量。一層的所有連接強度可以存儲在一個矩陣里面。比如,第一個隱藏層權重矩陣W1的大小是[4x3], 所有單元的偏置值在大小為[4x1]的向量b1中。每一個單獨的神經元將它的權重放在W1的某一行中。所以矩陣向量乘法np.dot(W1,x)計算這層所有神經元的激活值。類似地,W2是一個[4x4]的矩陣,它存儲著第二個隱藏層的所有連接,W3是最后一層(輸出層)的一個[1x4]的矩陣。這個三層神經網絡的整個前向傳播是簡單的三個矩陣乘法,但是和激活函數交替出現。
#一個三層神經網絡的前向傳播
f = lambda x: 1.0/(1.0+np.exp(-x)) #激活函數
x = np.random.randn(3,1) #隨機輸入向量
h1 = f(np.dot(W1, x) + b1) #計算第一個隱藏層的激活值
h2 = f(np.dot(W2, h1) + b2) #計算第二個隱藏層的激活值
out = np.dot(W3, h2) + b3 #輸出神經元
在上面的代碼中,W1,W2,W3,b1,b2,b3都是神經網絡可學習的參數。注意輸入可能不是一個單獨的向量矩陣,x也可能是訓練數據的整個批量(其中,可能每一列是一個輸入圖像),所以單個輸入都可以并發地計算。
一個全連接層的前向傳播對應于一個矩陣乘法,再加上一個偏置向量和激活函數計算
表征能力
一種觀察全連接神經網絡的視角是,把它看做是一個以權重為參數的函數群。一個自然的問題就產生了: 這個函數群的表征能力有多大?也就是說,是否存在不能用神經網絡模擬的函數?結果發現至少一個隱藏層的神經網絡是一個萬能逼近器(universal approximator)。也就是說,給出一個連續函數f(x)和一個?<0,存在一個有一個隱藏層(有一個非線性函數,比如:sigmoid)的神經網絡g(x), 使得?x, ∣ f (x) ? g(x) ∣< ?。換句話說,神經網絡可以逼近任何連續函數。
如果一個隱藏層足以逼近任何函數,那么為什么還要使用更多的層呢?答案是神經網絡是在數學上,是一個萬能逼近器,但是在實踐中,這是一個相對沒有意義的陳述。一方面,指示碰撞和(sum of indicator bumps)函數g(x) = Σi ci??(ai < x < bi), 其中參數向量a,b,c也是一個萬能逼近器,沒有人會建議我們在機器學習中使用這種函數形式。神經網絡在實踐中效果好,就是因為它簡潔表達的,平整的函數能夠非常容易地滿足我們在實踐中遇到數據的統計學特征,也非常容易使用優化算法學習(比如,梯度下降)。類似地,實踐發現,更深的網絡(多個隱藏層)比只有一個隱藏層的網絡工作地更好,盡管它們的表達能力一樣。
除此之外,實踐發現,一個三層的網絡比一個兩層的網絡效果更好,但是更深的網絡并不會使得效果更好。這和卷積神經網絡不同。實踐發現深度是一個優秀的認知系統的關鍵。
設置層的數目及它們的大小
當我們面臨一個實踐問題時,我們怎么決定使用何種架構?我們應該不使用隱藏層,使用一個隱藏層?兩個隱藏層?每一層的大小為多大?首先,當我們提高神經網絡的大小及層數,網絡的容量也會增加。也就是說,函數可表征的空間也會增加,因為神經元可以相互合作,表征出許多不同的函數。例如,假設我們有一個二維空間上的一個二元分類問題。我們可以訓練三個不同的神經網絡,每個網絡的隱藏層數不一樣。我們可以得到以下的分類器:
從上面的圖片我們可以看出,更多神經元的神經網絡能夠表征出更復雜的函數。然而,這既是一個優點(我們可以處理更加復雜的數據)也是一個缺點(容易過擬合)。當一個高容量的模型擬合數據中的噪音而不是數據內在的關系時,容易產生過擬合。例如,上圖中20個隱藏層的模型能過擬合所有的數據,但是也產生了一些分離的區域。三個隱藏層的模型只有初略分類數據的表征能力。它把數據分為兩個部分,將綠色區域的紅色點解釋為雜質。在實踐中,這可以提高在測試數據中的延展性。
基于我們上面的討論,為了防止過擬合,對于不夠復雜的數據,似乎我們應該使用更小的神經網絡。但是,這是錯誤的。在神經網絡中,我們還有很多其他的方法來阻止過擬合。在后續的課程中我們會講到(例如 L2正則化,dropout,輸入噪音等)。在實踐中,我們經常使用這些方法來避免過擬合,而不是通過減少神經元的數目。
其中背后的原因在于,小的神經網絡很難使用局部方法(如梯度下降)進行訓練。損失函數只有相對較少的局部極小值,而且很多極小值都非常容易聚合,但是結果并不好(有較高的損失值)。相反,更大的神經網絡擁有更多的局部極小值,而且這些極小值比實際的極小值更好。因為神經網絡是非凸函數,所以很難從數學的角度來分析。但是還是有一些理解這些目標函數的嘗試。例如 這篇論文: The Loss Surfaces of Multilayer Networks. 在實踐中,你會發現,一個小的神經網絡的損失值會有很大的變數。在有的情況下,你很幸運,它能聚合到一個好的地方,但是在一些情況下,你可能只能聚合到一個不好的地方。但是,如果你訓練一個大的網絡,你需要發現許多不同的解決方案,但是最終的損失的變量都會更小。也就是說,所有的解決方法都是一樣好,從而使得最終的結果更少地依賴隨機初始化。
正則強度是一個控制神經網絡過擬合的好的方案。我們來看一下不同設置所達到的結果:
所以你不應該由于害怕過擬合而使用更小的網絡。相反,你應該使用一個你能承受的計算量的大型網絡,并且使用正則技術來控制過擬合。
總結
- 我們介紹了生物神經元的及其非常粗糙的一個模型。
- 我們討論了在實踐中使用的幾種激活函數。其中ReLU是最常用的激活函數。
- 我們介紹了神經網絡, 其中神經元由全連接層連接。相鄰層的神經元兩兩連接,而每一層內的神經元則沒有連接。
- 這種層級結構使得基于矩陣乘法與激活函數交替運算的方式計算網絡參數更加有效
- 我們可以把神經網絡看成是一個萬能函數逼近器,但是我們也討論到這種性質并不能直接導致它的廣泛使用。神經網絡之所有被使用,是因為它們基于正確的,來源于實踐的,關于函數的功能性的假設。
- 我們發現更大的網絡幾乎都比更小的網絡效果更好,但是更好的網絡需要更強的正則項,否則,會導致過擬合。我們會在后面的課程中介紹更多的正則項的形式(特別是dropout)。