您現在的位置是:首頁 > 人文
從零開始構建簡單人工神經網路:1個輸入層和1個輸出層
誤差怎麼傳播
本上下篇將介紹僅使用numpy Python庫從零開始構建人工神經網路(ANN)。
上篇將介紹構建一個很簡單的ANN,只有1個輸入層和1個輸出層,沒有隱藏層。
下篇將介紹構建一個有1個輸入層、1個隱藏層和1個輸出層的ANN。
為何從零開始?
有許多深度學習庫(Keras、TensorFlow和PyTorch等)可僅用幾行程式碼構建一個神經網路。然而,如果你真想了解神經網路的底層運作,建議學習如何使用Python或任何其他程式語言從零開始為神經網路程式設計。
不妨建立某個隨機資料集:
圖1。 為簡單起見,隨機資料集帶二進位制值
上面表格有五列:Person、X1、X2、X3和Y。1表示true,0表示false。我們的任務是建立一個能夠基於X1、X2和X3的值來預測Y值的人工神經網路。
我們將建立一個有1個輸入層、1個輸出層而沒有隱藏層的人工神經網路。開始程式設計前,先不妨看看我們的神經網路在理論上將如何執行:
ANN理論
人工神經網路是一種監督式學習演算法,這意味著我們為它提供含有自變數的輸入資料和含有因變數的輸出資料。比如在該示例中,自變數是X1、X2和X3,因變數是Y。
首先,ANN進行一些隨機預測,將這些預測與正確的輸出進行比較,計算出誤差(預測值與實際值之間的差)。找出實際值與傳播值之間的差異的函式名為成本函式(cost function)。這裡的成本指誤差。我們的目標是使成本函式最小化。訓練神經網路基本上是指使成本函式最小化。下面會介紹如何執行此任務。
神經網路分兩個階段執行:前饋階段和反向傳播階段。下面詳細介紹這兩個步驟。
前饋
圖2
在ANN的前饋階段,基於輸入節點中的值和權重進行預測。如果看一下上圖中的神經網路,會看到資料集中有三個特徵:X1、X2和X3,因此第一層(又叫輸入層)中有三個節點。
神經網路的權重基本上是我們要調整的字串,以便能夠正確預測輸出。請記住,每個輸入特性只有一個權重。
以下是在ANN的前饋階段所執行的步驟:
第1步:計算輸入和權重之間的點積
輸入層中的節點透過三個權重引數與輸出層連線。在輸出層中,輸入節點中的值與對應的權重相乘並相加。最後,偏置項b新增到總和。
為什麼需要偏置項?
假設某個人有輸入值(0,0,0),輸入節點和權重的乘積之和將為零。在這種情況下,無論我們怎麼訓練演算法,輸出都將始終為零。因此,為了能夠做出預測,即使我們沒有關於該人的任何非零資訊,也需要一個偏置項。偏置項對於構建穩健的神經網路而言必不可少。
數學上,點積的總和:
X。W=x1。w1 + x2。w2 + x3。w3 + b
第2步:透過啟用函式傳遞點積(X.W)的總和
點積XW可以生成任何一組值。然而在我們的輸出中,我們有1和0形式的值。我們希望輸出有同樣的格式。為此,我們需要一個啟用函式(Activation Function),它將輸入值限制在0到1之間。因此,我們當然會使用Sigmoid啟用函式。
圖3。 Sigmoid啟用函式
輸入為0時,Sigmoid函式返回0。5。如果輸入是大正數,返回接近1的值。負輸入的情況下,Sigmoid函式輸出的值接近零。
因此,它特別適用於我們要預測機率作為輸出的模型。由於概念只存在於0到1之間,Sigmoid函式是適合我們這個問題的選擇。
上圖中z是點積X。W的總和。
數學上,Sigmoid啟用函式是:
圖4。 Sigmoid啟用函式
總結一下到目前為止所做的工作。首先,我們要找到帶權重的輸入特徵(自變數矩陣)的點積。接著,透過啟用函式傳遞點積的總和。啟用函式的結果基本上是輸入特徵的預測輸出。
反向傳播
一開始,進行任何訓練之前,神經網路進行隨機預測,這種預測當然是不正確的。
我們先讓網路做出隨機輸出預測。然後,我們將神經網路的預測輸出與實際輸出進行比較。接下來,我們更新權重和偏置,並確保預測輸出更接近實際輸出。在這個階段,我們訓練演算法。不妨看一下反向傳播階段涉及的步驟。
第1步:計算成本
此階段的第一步是找到預測成本。可以透過找到預測輸出值和實際輸出值之間的差來計算預測成本。如果差很大,成本也將很大。
我們將使用均方誤差即MSE成本函式。成本函式是找到給定輸出預測成本的函式。
圖5。 均方誤差
這裡,Yi是實際輸出值,i是預測輸出值,n是觀察次數。
第2步:使成本最小化
我們的最終目的是微調神經網路的權重,並使成本最小化。如果你觀察仔細,會了解到我們只能控制權重和偏置,其他一切不在控制範圍之內。我們無法控制輸入,無法控制點積,無法操縱Sigmoid函式。
為了使成本最小化,我們需要找到權重和偏置值,確保成本函式返回最小值。成本越小,預測就越正確。
要找到函式的最小值,我們可以使用梯度下降演算法。梯度下降可以用數學表示為:
圖6。 使用梯度下降更新權重
Error是成本函式。上面的等式告訴我們找到關於每個權重和偏置的成本函式的偏導數,然後從現有權重中減去結果以得到新的權重。
函式的導數給出了在任何給定點的斜率。為了找到成本是增加還是減少,給定權重值,我們可以找到該特定權重值的函式導數。如果成本隨重量增加而增加,導數將返回正值,然後將其從現有值中減去。
另一方面,如果成本隨重量增加而降低,將返回負值,該值將被新增到現有的權重值中,因為負負得正。
在上面公式中,a名為學習速率,乘以導數。學習速率決定了我們的演算法學習的速度。
我們需要對所有權重和偏置重複執行梯度下降操作,直到成本最小化,並且成本函式返回的值接近零。
現在是實現我們迄今為止研究的人工神經網路的時候了。我們將用Python建立一個簡單的神經網路,有1個輸入層和1個輸出層。
使用numpy實現人工神經網路
圖7
圖片來源:hackernoon。com
要採取的步驟:
1。定義自變數和因變數
2。定義超引數
3。定義啟用函式及其導數
4。訓練模型
5。做出預測
第1步:先建立自變數或輸入特徵集以及相應的因變數或標籤。
#Independent variables
input_set = np。array([[0,1,0],
[0,0,1],
[1,0,0],
[1,1,0],
[1,1,1],
[0,1,1],
[0,1,0]])#Dependent variable
labels = np。array([[1,
0,
0,
1,
1,
0,
1]])
labels = labels。reshape(7,1) #toconvert labels to vector
我們的輸入集含有七個記錄。同樣,我們還建立了一個標籤集,含有輸入集中每個記錄的對應標籤。標籤是我們希望ANN預測的值。
第2步:定義超引數。
我們將使用numpy的random。seed函式,以便在執行以下程式碼時可以獲得同樣的隨機值。
接下來,我們使用正態分佈的隨機數初始化權重。由於輸入中有三個特徵,因此我們有三個權重的向量。然後,我們使用另一個隨機數初始化偏置值。最後,我們將學習速率設定為0。05。
np。random。seed(42)
weights = np。random。rand(3,1)
bias = np。random。rand(1)
lr = 0。05 #learning rate
第3步:定義啟用函式及其導數:我們的啟用函式是Sigmoid函式。
def sigmoid(x):
return 1/(1+np。exp(-x))
現在定義計算Sigmoid函式導數的函式。
def sigmoid_derivative(x):
return sigmoid(x)*(1-sigmoid(x))
第4步:是時候訓練ANN模型了。
我們將從定義輪次(epoch)數量開始。輪次是我們想針對資料集訓練演算法的次數。我們將針對資料訓練演算法25000次,因此epoch將為25000。可以嘗試不同的數字以進一步降低成本。
for epoch in range(25000):
inputs = input_set
XW = np。dot(inputs, weights)+ bias
z = sigmoid(XW)
error = z - labels
print(error。sum())
dcost = error
dpred = sigmoid_derivative(z)
z_del = dcost * dpred
inputs = input_set。T
weights = weights - lr*np。dot(inputs, z_del)
for num in z_del:
bias = bias - lr*num
不妨瞭解每個步驟,然後進入到預測的最後一步。
我們將輸入input_set中的值儲存到input變數中,以便在每次迭代中都保留input_set的值不變。
inputs = input_set
接下來,我們找到輸入和權重的點積,併為其新增偏置。(前饋階段的第1步)
XW = np。dot(inputs, weights)+ bias
接下來,我們透過Sigmoid啟用函式傳遞點積。(前饋階段的第2步)
z = sigmoid(XW)
這就完成了演算法的前饋部分,現在是開始反向傳播的時候了。
變數z含有預測的輸出。反向傳播的第一步是找到誤差。
error = z - labels
print(error。sum())
我們知道成本函式是:
圖8
我們需要從每個權重方面求該函式的微分,這可以使用微分鏈式法則(chain rule of differentiation)來輕鬆完成。我將跳過推導部分,但如果有人感興趣,請留言。
因此,就任何權重而言,成本函式的最終導數是:
slope = input x dcost x dpred
現在,斜率可以簡化為:
dcost = error
dpred = sigmoid_derivative(z)
z_del = dcost * dpred
inputs = input_set。T
weights = weight-lr*np。dot(inputs, z_del)
我們有z_del變數,含有dcost和dpred的乘積。我們拿輸入特徵矩陣的轉置與z_del相乘,而不是遍歷每個記錄並拿輸入與對應的z_del相乘。
最後,我們將學習速率變數lr與導數相乘,以加快學習速度。
除了更新權重外,我們還要更新偏置項。
for num in z_del:
bias = bias - lr*num
一旦迴圈開始,你會看到總誤差開始減小;訓練結束時,誤差將保留為很小的值。
-0。001415035616137969
-0。0014150128584959256
-0。0014149901015685952
-0。0014149673453557714
-0。0014149445898578358
-0。00141492183507419
-0。0014148990810050437
-0。0014148763276499686
-0。0014148535750089977
-0。0014148308230825385
-0。0014148080718707524
-0。0014147853213728624
-0。0014147625715897338
-0。0014147398225201734
-0。0014147170741648386
-0。001414694326523502
-0。001414671579597255
-0。0014146488333842064
-0。0014146260878853782
-0。0014146033431002465
-0。001414580599029179
-0。0014145578556723406
-0。0014145351130293877
-0。0014145123710998
-0。0014144896298846701
-0。0014144668893831067
-0。001414444149595611
-0。0014144214105213174
-0。0014143986721605849
-0。0014143759345140276
-0。0014143531975805163
-0。001414330461361444
-0。0014143077258557749
-0。0014142849910631708
-0。00141426225698401
-0。0014142395236186895
-0。0014142167909661323
-0。001414194059027955
-0。001414171327803089
-0。001414148597290995
-0。0014141258674925626
-0。0014141031384067547
-0。0014140804100348098
-0。0014140576823759854
-0。0014140349554301636
-0。0014140122291978665
-0。001413989503678362
-0。001413966778871751
-0。001413944054778446
-0。0014139213313983257
-0。0014138986087308195
-0。0014138758867765552
-0。0014138531655347973
-0。001413830445006264
-0。0014138077251906606
-0。001413785006087985
-0。0014137622876977014
-0。0014137395700206355
-0。0014137168530558228
-0。0014136941368045382
-0。0014136714212651114
-0。0014136487064390219
-0。0014136259923249635
-0。001413603278923519
-0。0014135805662344007
-0。0014135578542581566
-0。0014135351429944293
-0。0014135124324428719
-0。0014134897226037203
-0。0014134670134771238
-0。0014134443050626295
-0。0014134215973605428
-0。0014133988903706311
第5步:作出預測
是時候作出一些預測了。先用[1,0,0]試一下:
single_pt = np。array([1,0,0])
result = sigmoid(np。dot(single_pt, weights) + bias)
print(result)
輸出:
[0。01031463]
如你所見,輸出更接近0而不是1,因此分類為0。
不妨再用[0,1,0]試一下:
single_pt = np。array([0,1,0])
result = sigmoid(np。dot(single_pt, weights) + bias)
print(result)
輸出:
[0。99440207]
如你所見,輸出更接近1而不是0,因此分類為1。
結論
我們在本文中學習瞭如何使用numpy Python庫,從零開始建立一個很簡單的人工神經網路,只有1個輸入層和1個輸出層。該ANN能夠對線性可分離資料進行分類。
如果我們有非線性可分離的資料,我們的ANN就無法對這種型別的資料進行分類。下篇將介紹如何構建這樣的ANN。
推薦文章
- 超40000名戰士陣亡,屍體橫七豎八散落一地,俄軍還能堅持多久?
在俄烏衝突中,烏克蘭一門心思搞動員,俄羅斯則是專心發展僱傭兵隊伍,大量的囚犯士兵以“僱傭方式”加入戰鬥,一定程度上當下烏軍內部主力是動員兵,而俄軍主力開始向“義務兵”轉變...
- 「寶拍」古鏡奇珍|頂級館藏頂級鑑賞系列(三)
鎏金博局紋銅鏡鎏金博局紋銅鏡 河南博物院藏極珍罕鎏金神獸博局紋鏡,古代銅鏡藝術中的名譽品種,特種工藝鏡中的奇珍,紋飾採用線雕的表現技法刻畫,鑄造精美,工藝精湛,善銅妙作...
- 有高血壓的人,喝酒對身體會產生這樣幾種影響,該不該喝你看著辦
綜上所述,通常人們所說的飲酒可以活血化瘀、軟化血管的作用不過血管受刺激擴張、血壓暫時有所下降的一種表現,但與此同時也會對血管造成損傷,且損傷後一旦引起血管病變即不可逆轉,權衡這些後果就會知道:飲酒擴張血管的作用完全可能透過加強運動等方式來替...