bp神經網絡
BP(back propagation,反向傳播)神經網絡(neural network),通常指具有三層網絡結構的淺層神經網絡。神經網絡由一個個神經元(Neuron)組成,神經元由輸入、計算、輸出單元組成。
對應上圖輸入爲和截距,輸出爲:
其中w表示權重值,函數f爲激活函數,有如下激活函數:
對應圖像爲:
一個三層的神經網絡結構圖:
相關參數說明
- 網絡層數,三層網絡,第層記爲
- 分別爲輸入層,隱藏層,輸出層
- 權重,其中表示層的第個神經元與層的第個神經元的參數,如表示1層第1個神經元與2層第2個神經元的連接參數
- 偏置表示第層的第i個神經元的偏置項,如表示2層第2個神經元的偏置項
- 表示層第個神經元的輸入
- 表示層第個神經元的輸出
- 表示層的神經元個數,如表示3層有2個神經元
參數計算關係如下:
即每個神經元的輸入爲上一層所有神經元輸出的加權求和,神經元輸入值經過激活函數處理後得到神經元輸出。
損失函數
對於每個訓練樣本,損失函數爲:
表示最後一層輸出層的輸出值與實際值的歐式距離,結果是一個向量,向量維度等於輸出層神經元數量。
爲得到損失函數最小值,首先對參數進行初始化,初始化爲一個接近0的隨機值。再利用前向傳播得到預測值,從而計算損失值。此時需要利用損失函數調整參數,可使用梯度下降法,梯度下降公式爲:
其中偏導部分:
由於每兩層之間有參數矩陣,考慮到預測值在最後一層輸出層,可以先求解,推導如下:
其中等於:
即對可導,可以使用鏈式法則求導:
反向傳播算法的思路爲,對於給定訓練數據,通過前向傳播算法計算每個神經元的輸出值,當所有神經元的輸出都計算完成後,對每個神經元計算殘差,如第層的第i個神經元的殘差表示爲,該殘差表示該神經元對最終殘差的影響,最後一層的殘差公式爲:
將代入,得出:
其中可以通過前向傳播得到,需要求解,可以推導倒數第二層殘差與最後一層殘差的關係:
即
推導到一般情況:
python實例
# 代碼來自《Python機器學習算法》一書
def bp_train(feature, label, n_hidden, maxCycle, alpha, n_output):
'''計算隱含層的輸入
input: feature(mat):特徵
label(mat):標籤
n_hidden(int):隱含層的節點個數
maxCycle(int):最大的迭代次數
alpha(float):學習率
n_output(int):輸出層的節點個數
output: w0(mat):輸入層到隱含層之間的權重
b0(mat):輸入層到隱含層之間的偏置
w1(mat):隱含層到輸出層之間的權重
b1(mat):隱含層到輸出層之間的偏置
'''
m, n = np.shape(feature)
# 1、初始化
w0 = np.mat(np.random.rand(n, n_hidden))
w0 = w0 * (8.0 * sqrt(6) / sqrt(n + n_hidden)) - \
np.mat(np.ones((n, n_hidden))) * \
(4.0 * sqrt(6) / sqrt(n + n_hidden))
b0 = np.mat(np.random.rand(1, n_hidden))
b0 = b0 * (8.0 * sqrt(6) / sqrt(n + n_hidden)) - \
np.mat(np.ones((1, n_hidden))) * \
(4.0 * sqrt(6) / sqrt(n + n_hidden))
w1 = np.mat(np.random.rand(n_hidden, n_output))
w1 = w1 * (8.0 * sqrt(6) / sqrt(n_hidden + n_output)) - \
np.mat(np.ones((n_hidden, n_output))) * \
(4.0 * sqrt(6) / sqrt(n_hidden + n_output))
b1 = np.mat(np.random.rand(1, n_output))
b1 = b1 * (8.0 * sqrt(6) / sqrt(n_hidden + n_output)) - \
np.mat(np.ones((1, n_output))) * \
(4.0 * sqrt(6) / sqrt(n_hidden + n_output))
# 2、訓練
i = 0
while i <= maxCycle:
# 2.1、信號正向傳播
# 2.1.1、計算隱含層的輸入
hidden_input = hidden_in(feature, w0, b0) # mXn_hidden
# 2.1.2、計算隱含層的輸出
hidden_output = hidden_out(hidden_input)
# 2.1.3、計算輸出層的輸入
output_in = predict_in(hidden_output, w1, b1) # mXn_output
# 2.1.4、計算輸出層的輸出
output_out = predict_out(output_in)
# 2.2、誤差的反向傳播
# 2.2.1、隱含層到輸出層之間的殘差
delta_output = -np.multiply((label - output_out), partial_sig(output_in))
# 2.2.2、輸入層到隱含層之間的殘差
delta_hidden = np.multiply((delta_output * w1.T), partial_sig(hidden_input))
# 2.3、 修正權重和偏置
w1 = w1 - alpha * (hidden_output.T * delta_output)
b1 = b1 - alpha * np.sum(delta_output, axis=0) * (1.0 / m)
w0 = w0 - alpha * (feature.T * delta_hidden)
b0 = b0 - alpha * np.sum(delta_hidden, axis=0) * (1.0 / m)
if i % 100 == 0:
print "\t-------- iter: ", i, \
" ,cost: ", (1.0/2) * get_cost(get_predict(feature, w0, w1, b0, b1) - label)
i += 1
return w0, w1, b0, b1
(1)初始化參數
-
樣本特徵數
n=2
-
隱藏層節點數
n_hidden=20
-
輸出層節點數(分類數量)
n_output=2
-
構成
2*20*2
的三層神經網絡結構 -
輸入層到隱藏層的權重
w0 = np.mat(np.random.rand(n, n_hidden))
,即2*20
個 -
輸入層到隱藏層的偏置
b0 = np.mat(np.random.rand(1, n_hidden))
,即20
個 -
隱藏層到輸出層的權重
w1 = np.mat(np.random.rand(n_hidden, n_output))
,即20*2
個 -
隱藏層到輸出層的偏置
b1 = np.mat(np.random.rand(1, n_output))
,即2
個
可以利用更科學的隨機算法,得到隨機化的w0,b0,w1,b1
(2)正向傳播
# 2.1.1、計算隱含層的輸入
hidden_input = hidden_in(feature, w0, b0) # mXn_hidden
# 2.1.2、計算隱含層的輸出
hidden_output = hidden_out(hidden_input)
# 2.1.3、計算輸出層的輸入
output_in = predict_in(hidden_output, w1, b1) # mXn_output
# 2.1.4、計算輸出層的輸出
output_out = predict_out(output_in)
hidden_in
方法計算隱藏層的輸入值,對應公式:
def hidden_in(feature, w0, b0):
'''計算隱含層的輸入
input: feature(mat):特徵
w0(mat):輸入層到隱含層之間的權重
b0(mat):輸入層到隱含層之間的偏置
output: hidden_in(mat):隱含層的輸入
'''
m = np.shape(feature)[0]
hidden_in = feature * w0
for i in xrange(m):
hidden_in[i, ] += b0
return hidden_in
hidden_out
方法計算隱藏層的輸出,對應公式:
def hidden_out(hidden_in):
'''隱含層的輸出
input: hidden_in(mat):隱含層的輸入
output: hidden_output(mat):隱含層的輸出
'''
hidden_output = sig(hidden_in)
return hidden_output;
predict_in
方法等同於hidden_in
,predict_out
方法等同於hidden_out
。
(3)反向傳播
# 2.2.1、隱含層到輸出層之間的殘差
delta_output = -np.multiply((label - output_out), partial_sig(output_in))
# 2.2.2、輸入層到隱含層之間的殘差
delta_hidden = np.multiply((delta_output * w1.T), partial_sig(hidden_input))
partial_sig
方法計算輸入值的偏導值,delta_output
對應最後一層的殘差公式:
delta_hidden
對應一般情況的殘差公式:
def partial_sig(x):
'''Sigmoid導函數的值
input: x(mat/float):自變量,可以是矩陣或者是任意實數
output: out(mat/float):Sigmoid導函數的值
'''
m, n = np.shape(x)
out = np.mat(np.zeros((m, n)))
for i in xrange(m):
for j in xrange(n):
out[i, j] = sig(x[i, j]) * (1 - sig(x[i, j]))
return out
(4)更新權重和偏置
w1 = w1 - alpha * (hidden_output.T * delta_output)
b1 = b1 - alpha * np.sum(delta_output, axis=0) * (1.0 / m)
w0 = w0 - alpha * (feature.T * delta_hidden)
b0 = b0 - alpha * np.sum(delta_hidden, axis=0) * (1.0 / m)
對應公式:
(5)預測
def get_predict(feature, w0, w1, b0, b1):
'''計算最終的預測
input: feature(mat):特徵
w0(mat):輸入層到隱含層之間的權重
b0(mat):輸入層到隱含層之間的偏置
w1(mat):隱含層到輸出層之間的權重
b1(mat):隱含層到輸出層之間的偏置
output: 預測值
'''
return predict_out(predict_in(hidden_out(hidden_in(feature, w0, b0)), w1, b1))
傳入訓練完成的參數,計算測試樣本在輸出層每個神經元的輸出值,選取最大值的神經元作爲分類結果。