簡單解釋神經(jīng)網(wǎng)絡是如何工作的,以及如何在Python中從頭實現(xiàn)一個。
這句話可能會讓你大吃一驚:神經(jīng)網(wǎng)絡并沒有那么復雜!“神經(jīng)網(wǎng)絡”這個詞經(jīng)常被用作流行語,但實際上它們往往比人們想象的要簡單得多。
這篇文章是完全針對初學者準備的,我們假設你沒有任何機器學習的知識。我們將了解神經(jīng)網(wǎng)絡如何工作,同時在Python中從零開始實現(xiàn)一個。
讓我們開始吧!
1. 構建塊:神經(jīng)元
首先,我們必需討論神經(jīng)元,神經(jīng)網(wǎng)絡的基本單位。一個經(jīng)元接受輸入,對它們進行一些數(shù)學運算,然后產(chǎn)生一個輸出。這里是一個2輸入神經(jīng)元的樣子:

這里發(fā)生了三件事。首先,每個輸入被乘以一個權重:

接下來,將所有加權后的輸入與一個偏差b相加:

最后,總和被傳入一個激活函數(shù):

激活函數(shù)用于將一個無界輸入轉(zhuǎn)換為一個具有良好的、可預測形式的輸出。一個常用的激活函數(shù)是sigmoid函數(shù):

sigmoid函數(shù)只輸出(0,1)范圍內(nèi)的數(shù)字。你可以認為它是把(−∞,+∞) 壓縮到(0,1)——大負數(shù)變成~0,大正數(shù)變成~1。
一個簡單的例子
假設我們有一個使用sigmoid激活函數(shù)的2輸入神經(jīng)元,并帶有以下參數(shù):

w =[0,1]就是向量形式的w1 =0,w2 =1。現(xiàn)在,我們給這個神經(jīng)元提供一個x=[2,3]的輸入 。我們用點積來寫得更簡潔一些:

給定輸入x=[2,3] ,神經(jīng)元會輸出0.999。就是這樣!這個將輸入向前傳遞以獲得輸出的過程稱為前饋。
編寫一個神經(jīng)元
是時候?qū)崿F(xiàn)一個神經(jīng)元了!我們將使用NumPy,一個流行而強大的Python計算庫,來幫助我們處理數(shù)學運算:

認出這些數(shù)了嗎?這就是我們剛才舉的例子!我們得到了相同的答案0.999。
2. 將神經(jīng)元組合成一個神經(jīng)網(wǎng)絡
一個神經(jīng)網(wǎng)絡只不過是一群連接在一起的神經(jīng)元。下面是一個簡單的神經(jīng)網(wǎng)絡的樣子:

這個網(wǎng)絡有2個輸入,一個帶有2個神經(jīng)元(h1和h2)的隱藏層,一個帶有1個神經(jīng)元(σ1)的輸出層。注意σ1的輸入是來自h1和h2的輸出——這就是一個網(wǎng)絡的組成。
隱藏層是在輸入(第一個)層和輸出(最后一個)層之間的任何層。可以有多個隱藏層!
一個例子:前饋
我們來使用上圖所示的網(wǎng)絡,假設所有的神經(jīng)元都具有相同的權重w=[0,1] ,相同的偏差b= 0,以及相同的sigmoid激活函數(shù)。讓h1、h2、σ1表示它們所表示的神經(jīng)元的輸出。
如果我們傳入輸入x=[2,3] 會發(fā)生什么?

該神經(jīng)網(wǎng)絡對輸入x=[2,3] 的輸出為0.7216。很簡單,對吧?
一個神經(jīng)網(wǎng)絡可以有任意數(shù)量的層,每個層可以包含任意數(shù)量的神經(jīng)元。其基本思想是相同的: 通過網(wǎng)絡中的神經(jīng)元向前反饋輸入以便最終得到輸出。為了簡單起見,我們將在本文的其余部分繼續(xù)使用上面所示的網(wǎng)絡。
編寫一個神經(jīng)網(wǎng)絡: 前饋
我們來實現(xiàn)我們神經(jīng)網(wǎng)絡的前饋。這里是該網(wǎng)絡的圖片,再次供參考:


我們又得到了0.7216 !看起來它可以工作。
3.訓練神經(jīng)網(wǎng)絡,第1部分
假設我們有以下測量值:

我們來訓練我們的網(wǎng)絡,并根據(jù)一個人的體重和身高來預測他的性別:

我們將用0表示男性,用1表示女性,我們還將對數(shù)據(jù)進行移位,使其更容易使用:

我隨意選擇了移位量(135和66)來使數(shù)字看起來漂亮一些。一般情況下,你應該使用平均值來移位。
損失
在訓練我們的網(wǎng)絡之前,我們首先需要一種方法來量化它做得有多“好”,這樣它就可以嘗試做得“更好”。這種方法就是損失。
我們將使用均方誤差(MSE)損失:

讓我們來分解一下:
- n是樣本的個數(shù),這里是4 (Alice、 Bob、 Charlie、 Diana)。
- y表示要預測的變量,即性別。
- ytrue是變量(“正確答案”)的真值。例如,對于Alice來說,ytrue是1(女性)。
- ypred是變量的預測值。它是我們網(wǎng)絡的輸出。
(ytrue - ypred)2稱為平方誤差。我們損失函數(shù)只是取所有平方誤差的平均值(因此得名均方誤差)。我們的預測越好,我們的損失就會越低!
更好的預測=更低的損失。
訓練一個網(wǎng)絡=盡量減少它的損失。
一個損失計算例子
假設我們的網(wǎng)絡總是輸出0,換句話說,它確信所有的人類都是男性。那我們的損失是多少?

代碼: 均方誤差損失
下面是一些計算損失的代碼:

如果你不理解這段代碼的工作原理,請閱讀NumPy數(shù)組操作快速入門。
好了。開始!
4.訓練神經(jīng)網(wǎng)絡,第2部分
我們現(xiàn)在有了一個明確的目標: 最小化神經(jīng)網(wǎng)絡的損失。我們知道我們可以改變網(wǎng)絡的權重和偏差來影響它的預測,但我們?nèi)绾尾拍芤砸环N減少損失的方式做到這一點呢?
本節(jié)使用了一些多變量微積分。如果你對微積分不熟悉,你可以跳過數(shù)學部分。
為了簡單起見,假設我們的數(shù)據(jù)集中只有Alice:

那么均方誤差損失就是Alice的平方誤差:

另一種考慮損失的方法是將損失看作是一個權重和偏差的函數(shù)。我們來標記我們的網(wǎng)絡中的每個權重和偏差:

然后,我們可以將損失寫成一個多元函數(shù):

假設我們想調(diào)整w1。如果我們改變w1,損失L將如何變化? 偏導數(shù)∂L/∂w1可以回答這個問題。我們?nèi)绾斡嬎闼?
這就是數(shù)學開始變得更加復雜的地方。不要氣餒!我建議你帶一支筆和一張紙來跟著計算,它們可以幫助你理解。
首先,我們用∂ypred/∂w1來重寫偏導數(shù)代替:

由于我們上邊計算出了L=(1-ypred)2,因此,我們可以計算∂L/∂ypred:

現(xiàn)在,讓我們算出∂ypred/∂w1的值。就像之前一樣,假設h1、 h2 、σ1是它們所代表的神經(jīng)元的輸出。那么

由于w1只影響h1(不影響h2),因此,我們可以寫

我們對∂h1/∂w1做相同的事情:

這里的x1 是體重 , x2是身高。現(xiàn)在已經(jīng)是我們第二次看到f'(x)(sigmoid函數(shù)的推導式)了!我們對它進行推導:

我們稍后將使用f'(x)這個漂亮的形式。
我們完成了!我們已經(jīng)將∂L/∂w1分解成了幾個我們可以計算的部分:

這種通過逆向運行計算偏導數(shù)的系統(tǒng)稱為反向傳播,或者“backprop”。
哦。這里有很多符號——如果你仍然有點困惑,也沒關系。讓我們舉一個例子來實際看一下!
例子: 計算偏導數(shù)
我們將繼續(xù)假設我們的數(shù)據(jù)集中只有Alice:

我們初始化所有的權重為1,所有的偏差為0。如果我們執(zhí)行一個前饋通過網(wǎng)絡,我們得到:

該網(wǎng)絡輸出 ypred =0.524,這并沒有特別偏向男性(0)或女性(1)。我們來計算∂L/∂w1:

提醒: 我們在前面為我們的 sigmoid函數(shù)推導出了f'(x) = f(x) * (1 - f(x))。
我們做到了!這告訴我們,如果我們增加w1,L就會相應地增加一點點。
訓練:隨機梯度下降法
我們現(xiàn)在有了訓練神經(jīng)網(wǎng)絡所需的所有工具! 我們將使用一種稱為隨機梯度下降(SGD)的優(yōu)化算法,它告訴我們?nèi)绾胃淖儥嘀睾推钜宰钚』瘬p失。它基本上就是這個更新方程:

η是一個稱為學習率的常數(shù),它控制我們訓練的速度。我們所做的就是從w1中減去η∂L/∂w1:
- 如果∂L/∂w1是正數(shù),w1會減小,從而使得L也減小。
- 如果∂L/∂w1 是負數(shù),w1會增加,從而使得L也減小。
如果我們對網(wǎng)絡中的每一個權重和偏差都這樣做,損失就會慢慢減小,我們的網(wǎng)絡就會改善。
我們的訓練過程如下:
- 從數(shù)據(jù)集中選擇一個樣本。這就是稱其為隨機梯度下降的原因——我們一次只對一個樣本進行操作。
- 計算所有關于權重或偏差的損失的偏導數(shù)(例如∂L/∂w1、∂L/∂w2等等)。
- 使用更新方程來更新每個權重和偏差。
- 回到步驟1。
讓我們實際看一下!
代碼: 一個完整的神經(jīng)網(wǎng)絡
終于是時候?qū)崿F(xiàn)一個完整的神經(jīng)網(wǎng)絡了:





你可以自己運行/測試這段代碼(https://repl.it/@vzhou842/An-Introduction-to-Neural-Networks )。你也可以在Github上找到它。(https://github.com/vzhou842/neural-network-from-scratch )
隨著網(wǎng)絡的學習,我們的損失逐漸減小:

我們現(xiàn)在可以用這個網(wǎng)絡來預測性別:

現(xiàn)在怎么辦?
你成功了!現(xiàn)在來快速回顧一下我們所做的:
- 介紹了神經(jīng)元——神經(jīng)網(wǎng)絡的構建塊。
- 在我們的神經(jīng)元中使用了sigmoid激活函數(shù)。
- 看到了神經(jīng)網(wǎng)絡只是連接在一起的神經(jīng)元。
- 創(chuàng)建了一個帶有體重和身高的數(shù)據(jù)集,并將其作為輸入(或特征),性別作為輸出(或標簽)。
- 學習了損失函數(shù)和均方誤差(MSE)損失。
- 意識到訓練一個網(wǎng)絡只是最小化它的損失。
- 使用反向傳播計算偏導數(shù)。
- 利用隨機梯度下降法(SGD)對網(wǎng)絡進行訓練。
還有很多事情要做:
- 使用合適的機器學習庫(如Tensorflow、Keras和PyTorch)來測試更大/更好的神經(jīng)網(wǎng)絡。
- 使用Keras構建你的第一個神經(jīng)網(wǎng)絡。
- 在你的瀏覽器中修補一個神經(jīng)網(wǎng)絡。
- 發(fā)現(xiàn)除了sigmoid之外的其它激活函數(shù),如Softmax。
- 發(fā)現(xiàn)除了SGD之外的其它優(yōu)化器。
- 閱讀我的《卷積神經(jīng)網(wǎng)絡(CNNs)介紹》。CNNs給計算機視覺領域帶來了革命性的變化,其功能非常強大。
- 閱讀我的《遞歸神經(jīng)網(wǎng)絡(RNNs)介紹》。RNNs經(jīng)常用于自然語言處理(NLP)。
我可能會在將來寫這些主題或類似的主題,所以如果你想獲得關于新文章的通知,請訂閱我吧。
感謝閱讀!
英文原文:https://victorzhou.com/blog/intro-to-neural-networks/ 譯者:Nothing