機器學習入門(05)— 使用 NumPy 實現 3 層簡單神經網絡

我們以圖 3-15 的3 層神經網絡爲對象,實現從輸入到輸出的(前向)處理。在代碼實現方面,使用上一節介紹的 NumPy 多維數組。

3 層神經網絡

1. 符號定義

符號定義

2. 各層之間信號傳遞

從輸入層到第 1 層的 第1 個神經元的信號傳遞過程,如圖 3-17 所示。
輸入層到 1 層傳遞
圖 3-17 中增加了表示偏置的神經元 “1”。請注意,偏置的右下角的索引號只有一個。這是因爲前一層的偏置神經元(神經元“1”)只有一個。

神經元關係
矩陣表示
用代碼實現上述過程:

In [1]: import numpy as np

In [2]: X = np.array([1.0, 0.5])

In [3]: W1 = np.array([[0.1, 0.3, 0.5], [0.2, 0.4, 0.6]])

In [5]: B1 = np.array([0.1, 0.2, 0.3])

In [6]: A1 = np.dot(X, W1) + B1

In [7]: A1
Out[7]: array([0.3, 0.7, 1.1])

In [8]: 

我們觀察第1 層中激活函數的計算過程。如果把這個計算過程用圖來表示的話,則如圖 3-18 所示。

如圖3-18 所示,隱藏層的加權和(加權信號和偏置的總和)用 a 表示,被激活函數轉換後的信號用 z 表示。此外,圖中 h() 表示激活函數,這裏我們使用的是sigmoid 函數。代碼如下所示。

輸入層到第1層信號傳遞

In [8]: def sigmoid(x):
   ...:     return 1/(1+np.exp(-x))
   ...:     

In [12]: Z1 = sigmoid(A1)

In [13]: Z1
Out[13]: array([0.57444252, 0.66818777, 0.75026011])

下面,我們來實現第 1 層到第 2 層的信號傳遞(圖3-19)
第 1 層到第 2 層傳遞

In [14]: W2 = np.array([[0.1, 0.4], [0.2, 0.5], [0.3, 0.6]])

In [15]: B2 = np.array([0.1, 0.2])

In [16]: A2 = np.dot(Z1, W2) + B2 

In [17]: Z2 = sigmoid(A2)

In [18]: Z2
Out[18]: array([0.62624937, 0.7710107 ])

In [19]: 

最後是第 2 層到輸出層的信號傳遞(圖 3-20)。輸出層的實現也和之前的實現基本相同。不過,最後的激活函數和之前的隱藏層有所不同。

第 2 層到輸出層信號傳遞

In [18]: def identity_function(x):
   ...:     return x
In [19]: 
In [20]: W3 = np.array([[0.1, 0.3], [0.2, 0.4]])

In [21]: B3 = np.array([0.1, 0.2])

In [22]: Z3 = np.dot(Z2, W3) + B3

In [23]: Z3
Out[23]: array([0.31682708, 0.69627909])

In [24]: Y = identify_function(Z3)

In [25]: Y
Out[25]: array([0.31682708, 0.69627909])

In [26]: 

這裏我們定義了 identity_function() 函數(也稱爲“恆等函數”),並將其作爲輸出層的激活函數。恆等函數會將輸入按原樣輸出,因此,這個例子中沒有必要特意定義identity_function() 。這裏這樣實現只是爲了和之前的流程保持統一。

另外,圖 3-20 中,輸出層的激活函數用 σ() 表示,不同於隱藏層的激活函數 h()σ 讀作 sigma )。

輸出層所用的激活函數,要根據求解問題的性質決定。一般地,

  • 迴歸問題可以使用恆等函數;
  • 二元分類問題可以使用 sigmoid 函數;
  • 多元分類問題可以使用 softmax 函數;

3. 代碼實現總結

import numpy as np

network = {}

def sigmoid(x):
    return 1/(1+np.exp(-x))

def identity_function(x):
    return x

def init_work():
    network["W1"] = np.array([[0.1, 0.3, 0.5], [0.2, 0.4, 0.6]])
    network["b1"] = np.array([0.1, 0.2, 0.3])
    network["W2"] = np.array([[0.1, 0.4], [0.2, 0.5], [0.3, 0.6]])
    network["b2"] = np.array([0.1, 0.2])
    network["W3"] = np.array([[0.1, 0.3], [0.2, 0.4]])
    network["b3"] = np.array([0.1, 0.2])

    return network

def forward(nt, x):
    W1, W2, W3 = nt["W1"], nt["W2"], nt["W3"]
    b1, b2, b3 = nt["b1"], nt["b2"], nt["b3"]

    a1 = np.dot(x, W1) + b1
    z1 = sigmoid(a1)

    a2 = np.dot(z1, W2) + b2
    z2 = sigmoid(a2)

    a3 = np.dot(z2, W3) + b3
    y = identity_function(a3)

    return y

network = init_work()
x = np.array([1.0, 0.5])
y = forward(network, x)
print("y is {}".format(y))	# y is [0.31682708 0.69627909]
  • init_network() 函數會進行權重和偏置的初始化,並將它們保存在字典變量 network中。這個字典變量 network 中保存了每一層所需的參數(權重和偏置)。
  • forward() 函數中則封裝了將輸入信號轉換爲輸出信號的處理過程。

forward (前向)一詞,它表示的是從輸入到輸出方向的傳遞處理。與之對應的backward 表示從輸出到輸入方向的處理。

參考:《深度學習入門:基於Python的理論與實現》

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章