準備工作
讀懂這篇文章,需要你有以下方面的知識
- 如何求導數
- 基本的矩陣乘法
如果有下列知識就更好了
- 懂一點機器學習的知識,比如線性迴歸
- 知道什麼是 感知機(perceptron)
有任何沒看懂的部分,歡迎留言,信不信我半小時內秒回。
一個巨簡單的神經網絡(A Deadly Simple NN)
如果你對神經網絡(neural network)感興趣或者關注過相關的文章,那下圖中的這個模型想必你不會感覺很陌生。
一個人工神經網絡模型
不過這個可能對於初學者有點不太友好?那看看下面這個簡化版的
一個無隱層的神經網絡
圖裡的這些東西,咱們一個一個的捋一遍。每個藍色的圓代表一個神經元(neuron)。每個方塊代表一個運算,比如 + 代表求和。上圖中最左邊的三個神經元組成了輸入層(input layer),包含一個 h 的神經元組成了輸出層(output layer),並且這一層只有這一個神經元。
輸出層神經元的輸入值
對於生物學意義上的神經元來說,通常存在一個閾值(threshold)來使其達到興奮的狀態,也就是被激活。在我們所討論的神經網絡中,我們的神經元將會通過輸入值和激活函數(activation function)計算一個輸出值。激活函數最值得稱讚的一點就是它可以是任何類型的函數,包括但不限於躍階函數,多項式函數或者 sigmoid 函數。h 是輸出神經元的輸入值,結合激活函數,輸出神經元會輸出 f(h) 計算的結果 y,也就是整個神經網絡的輸出值。
如果你選擇 f(h) = h 作為你的激活函數,那麼你的神經網絡輸出結果將會是下圖中的這個公式,這裡 y = f(h)。
神經網絡的輸出
如果你覺得這看起來是一個線性迴歸的模型,那就對了。如果你的激活函數是連續且可導的,那麼(通常情況下)你就可以使用一個叫做 梯度下降(gradient descent) 的方法來訓練你的網絡。不過這理解起來要稍微麻煩一點,在我們深入到訓練的步驟之前,我們先來編寫一個很簡單的程序來了解神經網絡作出預測的過程。我們將使用 sigmoid 函數作為激活函數, Python 作為編程語言。預測的這個過程是一種前饋(feedforward)的計算,僅僅有這一部分的神經網絡是不能學習的(例如,通過反向傳播(backpropagation)),但我們稍後再關注訓練學習的部分。
Sigmoid 函數
import numpy as np
def sigmoid(x):
# sigmoid function
return 1/(1 + np.exp(-x))
inputs = np.array([0.7, -0.3])
weights = np.array([0.1, 0.8])
bias = -0.1
# calculate the output
output = sigmoid(np.dot(weights, inputs) + bias)
print('Output:')
print(output)
第一個單隱層神經網絡(Your First 2-Layer NN)
注:單隱層,即為包括一個隱層,一個輸出層的神經網絡,輸入層和輸出層因為是必須的,所以不計數。
現在你已經基本知道了一個神經網絡是怎麼計算預測結果的。在現實生活中,我們面臨的預測問題往往十分複雜,這樣簡單的網絡結構可能遠遠不夠。這裡我們要引入一個新的概念,隱層(hidden layer)。
一個擁有三個輸入層神經元,兩個隱層神經元和一個輸出層神經元的神經網絡
在第一部分那個簡單的網絡模型中,我們的權重(weight)是一個向量。但是對於多數神經網絡來說,其實權重將會是一個如下圖一樣的矩陣。
三個輸入層神經元和兩個隱層神經元的權重矩陣
結合第一部分的理解和上面單隱層神經網的模型,你也許已經知道怎麼通過這個模型計算 h1 的具體數值了。我們給出一個簡單的公式定義
計算隱層神經元輸入值的公式
對於我們所關注的這個單隱層模型來說,它是下面這樣的
計算隱層輸入值的矩陣乘法
注意!!:上圖中的權重下角標已經更改為矩陣的表達方式,並不是和單隱層神經網絡圖中的下角標所對應的。因為在矩陣的表達方法中,是用行/列的順序來標註的。所以如果用示意圖中的方法標註的話,會造成一些誤會。
用先前神經網絡模型圖中的下角標所標註的矩陣
記住,上圖中的這個計算過程使用的並非是矩陣使用的角標,但這個和我們上面單隱層神經網絡的示意圖中的標註是一致的。
結合上面所學的知識,我們可以快速構建一個單隱層神經網絡的前饋(即預測)過程了。我們仍然使用 sigmoid 函數作為我們的激活函數(並且在之後很長時間都會用這個函數)。
待辦事項:
- 計算隱層的輸入值
- 計算隱層的輸出值
- 計算輸出層的輸出值
- 計算輸出層的輸出值
import numpy as np
def sigmoid(x):
# sigmoid function
return 1/(1+np.exp(-x))
# 神經網絡各層神經元數量
N_input = 3
N_hidden = 2
N_output = 1
np.random.seed(42)
# Make some fake data
X = np.random.randn(4)
# 生成輸入層到隱層/隱層到輸出層權重
weights_in_hidden = np.random.normal(0, scale=0.1, size=(N_input, N_hidden))
weights_hidden_out = np.random.normal(0, scale=0.1, size=(N_hidden, N_output))
# 計算隱層的輸入值/輸出值
hidden_layer_in = np.dot(X, weights_in_hidden)
hidden_layer_out = sigmoid(hidden_layer_in)
print('Hidden-layer Output:')
print(hidden_layer_out)
# 計算輸出層的輸入值/輸出值
output_layer_in = np.dot(hidden_layer_out, weights_hidden_out)
output_layer_out = sigmoid(output_layer_in)
print('Output-layer Output:')
print(output_layer_out)
- All formulas are generated by HostMath
- Some figures are taken from the Udacity deep learning course
- 【模式識別】多層感知器 MLP
- CS224d:
TensorFlow Tutorial - CS231n Winter 2016 Lecture 4 Backpropagation, Neural Networks
閱讀更多 碼農三哥 的文章