作者:Adi Chris
機器之心編譯
參與:朱乾樹、劉曉坤
機器學習工程師 Adi Chris 最近學習完吳恩達在 Coursera 上的最新課程后,決定寫篇博客來記錄下自己對這一領域的理解。他建議通過這種方式有效地深入理解一個學習主題。除此之外,也希望這篇博客可以幫助到那些有意入坑的朋友。
言歸正傳。在我正式介紹深度學習是什么東西之前,我想先引入一個簡單的例子,借以幫助我們理解為什么需要深度神經網絡。
同時,本文附有使用深度神經網絡模型求解異或(XOR)問題的代碼,發布在 GitHub 上。
GitHub 地址:https://github.com/chrisbangun/medium-post/tree/master/Perceptron-to-DNN
何為異或問題?對于給定的兩個二進制輸入,我們通過異或邏輯門得到一個預測輸出,這一過程即為異或問題。注意,輸入不相等時輸出為 1,否則為 0。表 1 展示了異或函數的所有可能的輸出結果:
那么現在我們就畫出數據分布圖來探究它的本質。
def plot_data(data, labels):
'''
argument:
data: np.array containing the input value
labels: 1d numpy array containing the expected label
'''
positives = data[labels == 1, :]
negatives = data[labels == 0, :]
plt.scatter(positives[:, 0], positives[:, 1],
color='red', marker='+', s=200)
plt.scatter(negatives[:, 0], negatives[:, 1],
color='blue', marker='_', s=200)
positives = np.array([[1, 0], [0, 1]])
negatives = np.array([[0, 0], [1, 1]])
data = np.concatenate([positives, negatives])
labels = np.array([1, 1, 0, 0])
plot_data(data, labels)
看到上圖后,我們或許會反思,這真的是一個簡單問題么?
如你所見,我們的數據并非線性可分的,因此,一些常用的線性模型,例如 logistic 回歸可能就不太適合分類我們的數據了。為了給你一個更直觀的理解,我用一個簡單的線性模型畫出了如下圖的決策邊界。
微調 logistic 回歸模型構造決策邊界
上面的圖清楚的告訴我們,我們需要一個更好的分類器來分離非線性數據。SVM 結合它的核心技巧就是一個不錯的選擇。但是,在本文中,我們打算重新構建一個神經網絡而非 SVM,并帶你領略下神經網絡解決異或問題的風采。
神經網絡就是就是找到一個可以模擬人腦工作行為的表現良好的近似函數。圖 1 對人類神經元與人工智能網絡作了類比。
圖 1:(a)人腦神經元結構(b)從生理神經網絡類比得出的人工智能網絡—圖片摘自 cs231n.github.io
你不需要了解太多生物學知識,我會從高度形象的角度來解釋人體神經元如何處理信息。
人體的神經元通過樹突接受信號。這些信息或信號隨后被傳遞到腦細胞或細胞體。在細胞體內部,所有的信息將被加工生成一個輸出。當該輸出結果達到某一閾值時,神經元就會興奮,并通過軸突傳遞信息,然后通過突觸傳遞到其他相連的神經元。神經元間傳輸的信號量取決于連接的強度。
前面提到的整個流程某種程度上適用于人工智能網絡。你可以把樹突想象成人工智能網絡中基于突觸感知器的被賦予了權重的輸入。然后,該輸入在人工智能網絡的『細胞體』中相加。如果得出的輸出值大于閾值單元,那么神經元就會『興奮』,并將輸出傳遞到其它神經元。
這樣你就可以理解人工智能網絡就是借鑒基本的生物神經元工作原理建模的吧。
為了了解神經網絡是如何工作的,我們先來看看一個叫感知機的簡單的人工神經網絡。
對我而言,感知機是我見過的機器學習中最優雅的算法之一。它于 1950 年代被提出,盡管很簡單,但它可以說是很多重要的機器學習算法的起點了,例如 logistic 回歸、支持向量機甚至深度神經網絡。
那么感知機怎么工作昵?我們以圖 2 展開討論。
圖 2:感知機
圖 2 展示了給定三個輸入 x_1、x_2 和 x_3 以及一個可以計算輸出值的神經元的感知機算法。Rosenblatt 通過引入權重的概念介紹這一簡單的規則,用于生成輸出值。權重通常是表示輸入對應于輸出的重要性的實數。上圖中的神經元將會得到兩個可能的結果,0 或 1,是由每個輸入的加權和 ∑wjxj 決定的大于或小于閾值的結果。因此,感知機的主要思想就是去學到一些可以決定神經元興奮還是抑制的與輸入特征相乘的權重 w。我們可以寫出一個如下的數學表達式:
我們現在可以做兩件事來修改上述公式:第一,我們把權重相加操作轉變成兩個向量的點乘。
w (權重) 和 x (輸入), 其中 w?x ≡ ∑wjxj。接下來,我們可以把閾值移到不等式的另一端并取個新變量名為偏置 b,b 恒等于閾值的負數。通過這些改動,感知機公式重寫如下:
現在我們把這些公式套進我們的感知機架構,這樣就有了如下所示的完整的單層感知機架構:
圖 3:單層感知機架構
通常情況下,單層感知機模型都會使用階躍函數作為激活函數將結果轉化成 0 或 1,因此將輸入歸到 0 或 1 類。如圖 4 所示,負數的輸出為 0,正數的輸出為 1。
圖 4:階躍函數的圖示
對于輸入數據線性可分的分類任務,階躍函數十分有用。但是,由于我們的目的是找到一個用于分離非線性數據的分類器,單層感知機與階躍函數就毫無意義了。稍后幾節,我們將會看到使用非線性激活函數的多層感知機網絡模型。
關于我們為什么不用使用階躍函數,這里有兩個主要原因:
1. 目前,結合反向傳播使用梯度下降算法是訓練一個多層神經網絡的有效方法之一(我們稍后會簡短的介紹一下)。反向傳播的必要條件是使用的激活函數必須可微。然而階躍函數在 x=0 處不可導,且其它位置導數均為 0。如此一來就無法運用梯度下降法更新權重了。
2. 回想下,神經網絡的主要目的就是學習到使預測盡可能接近真實值的權重和偏置。為了達到這一目的,如同很多優化問題,我們希望對權重或偏置上作一個小的改變,在網絡輸出中只產生一個相對小的變化。而這是一個僅能生成 0 或 1 的函數難以企及的。
激活函數是神經網絡的一個重要組成部分。一般來說,我們最少有三個需要激活函數的理由:
它幫助神經元學習和理解一些非常復雜的東西。
它們為網絡引入非線性屬性
我們希望對權重或偏差上作一個小的改變,以便在網絡輸出中只產生一個相對小的變化。
我們已經看到以階躍函數作激活函數的例子,然而,在這一節,我們將要探討一些深度學習中常用的非線性激活函數。順便提一下,若要深入了解激活函數,包括每一個激活函數的利弊,你可以參考 Avinash Sharma 和 Karpathy 寫的文章。
Avinash Sharma :https://medium.com/the-theory-of-everything/understanding-activation-functions-in-neural-networks-9491262884e0
Karpathy:https://medium.com/@karpathy/yes-you-should-understand-backprop-e2f06eab496b
sigmoid 函數,也即 logistic 函數,對于任意輸入,它的輸出范圍都是 (0,1)。公式如下:
sigmoid 的數學公式
圖 5:sigmoid 函數圖
圖 5 畫出了 sigmoid 函數的圖形。如你所見,它很像平滑版的階躍函數。但是,sigmoid 有很多好處,例如:
1. 它是非線性的
2. 不同于二值化輸出,sigmoid 可以輸入 0 到 1 之間的任意值。對,跟你猜的一樣,這可以用來表示概率值。
3. 與 2 相關,sigmoid 的輸出值在一個范圍內,這意味著它不會輸出無窮大的數。
但是,sigmoid 激活函數并不完美:
梯度消失。如前面的圖片所示,當輸入值 z 趨近負無窮時,sigmoid 函數的輸出幾乎為 0 . 相反,當輸入 z 趨近正無窮時,輸出值幾乎為 1 . 那么這意味著什么?
在這兩個極端情況下,對應的梯度很小,甚至消失了。梯度消失在深度學習中是一個十分重要的問題,我們在深度網絡中加了很多層這樣的非線性激活函數,這樣的話,即使第一層的參數有很大的變化,也不會對輸出有太大的影響。換句話講,就是網絡不再學習了,通常訓練模型的過程會變得越來越慢,尤其是使用梯度下降算法時。
sigmoid 的另一個弊端就是實際運用中指數運算開銷太大。盡管有人說,與矩陣乘法或卷積相比,激活函數在深度網絡的計算是非常小的一部分,所以這可能不會成為一個大問題。不過,我認為這值得一提。
Tanh 或雙曲正切是另一個深度神經網絡中常用的激活函數。類似于 sigmoid 函數,它也將輸入轉化到良好的輸出范圍內。具體點說就是對于任意輸入,tanh 將會產生一個介于 -1 與 1 之間的值。
Tanh 函數的數學公式
圖 6:tanh 函數圖
如前面提及的,tanh 激活函數有點像 sigmoid 函數。非線性且輸出在某一范圍,此處為 (-1, 1)。不必意外,它也有跟 sigmoid 一樣的缺點。從數學表達式就可以看出來,它也有梯度消失的問題,以及也需要進行開銷巨大的指數運算。
終于講到了 Relu,人們起初并不覺得它的效果會好過 sigmoid 和 tanh。但是,實戰中它確實做到了。事實上,cs231n 課程甚至指出,應該默認使用 Relu 函數。
ReLU 從數學表達式來看,運算十分高效。對于某一輸入,當它小于 0 時,輸出為 0,否則不變。下面是 ReLU 的函數表達式。
圖 7:ReLU 函數圖
那么你可能會問,「它是線性函數吧?為何我們說它是非線性函數?」
在線代中,線性函數就是兩個向量空間進行向量加和標量乘的映射。
給定上面的定義,我們知道 max(0, x) 是一個分段線性函數。之所以說是分段線性,是因為它在 (?∞, 0] 或 [0,+∞) 上符合線性函數的定義。但是在整個定義域上并不滿足線性函數的定義。例如f(?1) + f(1) ≠f (0)
所以 Relu 就是一個非線性激活函數且有良好的數學性質,并且比 sigmoid 和 tanh 都運算得快。除此以外,Relu 還因避免了梯度消失問題而聞名。然而,ReLU 有一個致命缺點,叫「ReLU 壞死」。ReLu 壞死是指網絡中的神經元由于無法在正向傳播中起作用而永久死亡的現象。
更確切地說,當神經元在向前傳遞中激活函數輸出為零時,就會出現這個問題,導致它的權值將得到零梯度。因此,當我們進行反向傳播時,神經元的權重將永遠不會被更新,而特定的神經元將永遠不會被激活。
還有件事值得一提。你可能注意到,不像 sigmoid 和 tanh,Relu 并未限定輸出范圍。這通常會成為一個很大的問題,它可能在另一個深度學習模型如遞歸神經網絡(RNN)中成為麻煩。具體而言,由 ReLU 生成的無界值可能使 RNN 內的計算在沒有合理的權重的情況下發生數值爆炸。因此反向傳播期間權重在錯誤方向上的輕微變化都會在正向傳遞過程中顯著放大激活值,如此一來學習過程可能就非常不穩定。我會嘗試在下一篇博客文章中詳細介紹這一點。
圖 8:多層感知機
圖 8 所示架構叫多層感知機(MLP)。從名字我們就可以推知,我們只是簡單地堆積多層感知機而已。上圖是一個三層感知機模型:一個輸入層、一個隱藏層,以及一個輸出層。然而,在深度學習或神經網絡領域,人們并不叫它三層神經網絡。通常,我們只統計隱藏層或其加上輸出層的層數,因此,上圖的網絡也叫兩層神經網絡。隱藏層并不單單指輸入層或輸出層。現在,如你所猜,所謂的深度學習,就意味著有更多的隱藏層。
那么神經網絡如何進行預測昵?
當所有的輸入通過所有隱藏層到輸出層后,神經網絡就會產生一個預測。這一過程叫前饋。如圖 8 所示,網絡接受輸入 X,然后計算激活函數并逐層傳遞,直到輸出。在監督任務中,對于此類分類任務,我們通常在輸出層使用一個 sigmoid 函數,以便將預測值轉化為概率值。在圖 8 中,我們可以看到輸出值為 0.24,由于它小于 0.5,我們可以說預測值 y_hat 為 0 .
跟一般的分類任務一樣,我們有一個代價函數,用于評估我們的模型擬合真實標簽的程度。事實上,訓練神經網絡可以簡單地看作盡可能最小化代價函數的過程。我們可以定義如下的代價函數:
均方誤差
所以我們的目的就是找到最佳 w 和 b,使代價函數 J 盡可能的小。為了達到這一目的,我們得靠兩大重要的算法,梯度下降和反向傳播。
對那些已經接觸過機器學習的人來說,你們已經很熟悉梯度下降法了。訓練神經網絡與訓練任何其它使用梯度下降法的機器學習模型沒有多大區別。唯一明顯的區別是網絡中的非線性效應使得我們的代價函數非凸。
為了幫助你理解,我們假設有一個如下圖 9 所示的凸代價函數:
圖 9:梯度下降法圖解
上表中,水平坐標表示參數空間,權重和偏置,代價函數 J(w, b) 就是水平軸上面的拋物面。圖中的紅色圓圈代表初始權重 w 和 b 對應的代價。為了最小化這一代價,我們需要走到這個拋物面底。那么問題來了,我們怎么知道沿哪個方向走昵?是參數變大的方向還是變小的方向?我們可以做一個隨機搜索,但這顯然耗時且開銷過大。
通過處理可學習的權重和偏置可以找到最佳方向。微積分告訴我們,在給定的點上,梯度方向就會指向函數值改變最快的方向。因此,我們將使用代價函數對權重和偏置的梯度。
現在,我們簡單地看看圖 10 所示的代價-權重變化。
圖 10:梯度的形象化表示
圖 10 描繪了代價函數對應權重的函數值。你可以把圖上的黑色圓看作初始代價。考慮到函數或變量的梯度可負可正可 0。負梯度意味著該線反向傾斜,反之亦然。現在,我們的目的是最小化代價函數,我們就必須沿著梯度的反方向更新權重。這一更新過程可以用以下公式表示:
圖 11:梯度下降法的參數更新
其中α是步長或學習率,我們將它與可學習參數 w 的偏微分相乘。所以α有啥用昵?
梯度告訴我們哪個方向函數值改變的最快,但是它并未告訴我們應該沿這一方向跨多大步。我們需要一個超參數去控制步長的大小,例如,我們沿某一方向該移動多遠,這就是 α 存在的意義。選取正確的學習率十分重要,因為它對兩方面有很大的影響:算法的學習速度和我們是否收斂到局部極小值。實際運用中,你可能會運用一個自適應學習率算法,例如動量算法、RMSProp、Adam 等等。AYLIEN 的一個大佬寫了一篇關于學習率算法的很棒的文章(如下參考第一篇)。
我們在前一節講述了梯度下降算法,它是深度學習的學習問題的一個優化算法。考慮到我們需要計算關于可學習參數 w 和 b 的偏微分才能使用梯度下降法。換句話說,我們需要計算 w 和 b 的偏微分。
但是,如果我們仔細看看代價函數 J,下圖 12 所示,就會發現 J 和 w 、 b 并沒有直接關系。
圖 12:均方誤差
只有從得到 y_hat 的輸出層追溯到輸入層,我們才會發現 J 與 w 、b 的間接關系,如下圖 13 所示:
圖 13:反向傳播圖解
你現在應該明白,為了得到代價函數的參數關于 w 和 b 的梯度,我們需要計算所有參數的偏微分,例如前面層的*a* (激活函數) 和 *z* (線性運算: wx + b),這就是反向傳播存在的意義。反向傳播其實就是反復運用微積分的鏈式法則,這可能是神經網絡中最有效的計算可學習參數梯度的方法了。
接下來,我手把手帶你算一下代價函數對第二層神經網絡權重 w2 的梯度,簡單起見,我們使用圖 8 的結構,一個包含三個神經元的隱藏層。
為了得到 y_hat 對 z2 的變化率,我們需要對 sigmoid 激活函數的 z 求微分。
一旦我們得到 J 對 W2 的偏導值,就可以使用圖 11 中的公式更新 W2 的值。
我們通常對所有可學習參數重復這一過程,直到得到盡可能小的代價函數值。
不錯!我想我們已經了解了如何構建一個神經網絡模型甚至深度學習模型的所有知識,這些知識將幫助我們解決異或問題。
寫這篇博客時,我順便搭了一個簡單的單隱藏層神經網絡模型。圖 14 是我使用的樣例網絡。我畫出了一些由我的模型生成的不同數量的神經元的決策邊界。如你后面將看到的,包含更多的神經元會使網絡模型變得更加復雜,從而創造一個更復雜的決策邊界。
圖 14:3 隱藏神經元的兩層神經網絡
圖 15:由一個包含多個神經元(2 個、3 個、4 個)的隱藏層生成的決策邊界
但是,到底怎樣才是最佳選擇?包含更多的神經元還是更多的隱藏層?
理論上講,網絡深的主要好處就是可以表示更復雜的函數。具體而言,通過使用更深層次的網絡結構,我們可以學習許多不同抽象層次的特征,例如,從邊緣(較底層)到非常復雜的特征(較深層)。
然而,實際中使用深度網絡并非總是有用。我們訓練深度網絡時最常遇到的就是梯度消失問題:一個非常深的網絡通常會發生某個梯度迅速變為零的狀況,因此使得梯度下降非常緩慢。
再具體點說,使用梯度下降時,因為反向傳播是從輸出層傳播到輸入層,而從輸入到輸出的每一步都是權重矩陣的相乘,因此梯度可能呈指數衰減到 0,某些情況下甚至會發生梯度爆炸。
為了結束這篇冗長的博文,簡要總結的要點如下:
神經網絡直觀地引入了可以用來解決一個復雜的非線性可分的數據的非線性模型。
感知機算法為之后的很多高級機器學習甚至是深度學習算法提供了思路。
深度學習直觀上就是使用很多隱藏層來搭建一個網絡,當然有很多版本,例如卷積網絡、循環網絡等。
激活函數是神經網絡中的重要一環,你必須理解。
目前反向傳播搭配梯度下降法是訓練神經網絡的最佳方案。
使用更多的隱藏層并不一定能提高我們的模型的表現。事實上,深度網絡飽受梯度消失之苦。
原文鏈接:https://becominghuman.ai/from-perceptron-to-deep-neural-nets-504b8ff616e