誤差反向傳播算法(BP)
一、神經網絡基本概念
二、神經元模型
神經元細胞示意圖
1. 單個神經元
1> 感知器模型
2> 輸入與輸出
3> 激活函數
Sigmoid(x)=1+e−x1
Sigmoid′(x)=Sigmoid(x)∗(1−Sigmoid(x))
2. 單個神經元的學習
1> 識別
3. 多層神經元模型
三、誤差反向傳播算法(BP)
1. 算法的推導
符號說明:
X
: 輸入向量
- Ytrue: 輸入向量
X
對應的真實結果
- Ypred: 根據輸入向量
X
預測的結果
Yi
: 向量的某個分量
h_in
: 隱藏層輸入
h_out
: 隱藏層輸出(經過激活函數處理)
h_w
: 隱藏層權重矩陣
output_in
: 輸出層輸入
output_out
: 輸出層輸出(經過激活函數處理)
output_w
: 輸出層權重矩陣
1> 輸出層權重偏導
已知對於某個訓練樣例 d 的誤差函數:
Error=21∗i∈output∑(Yitrue−Yipred)2
可得,總誤差函數對輸出層權重 w35 的偏導數:
∂w35∂E=∂output5_out∂E∗∂output5_in∂output5_out∗∂w35∂output5_in
各項展開得:
∂output5_out∂E=−(Y5true−output5_out)
∂output5_in∂output5_out=Sigmoid(output5_in)∗(1−Sigmoid(output5_in))
output5_in = h3_out * w_{35} + h4_out * w_{45}
∂w35∂output_in=h3_out
最終偏導爲:
∂w35∂E=−(Y5true−output5_out)∗Sigmoid(output5_in)∗(1−Sigmoid(output5_in))∗h3_out
2> 隱藏層權重偏導
總體上,隱藏層權重偏導公式如下:
∂w13∂E=∂h3_out∂E∗∂h3_in∂h3_out∗∂w13∂h3_in
展開,得:
∂w13∂E=∂h3_out∂E∗Sigmoid(h3_in)∗(1−Sigmoid(h3_in))∗x1
仔細分析,我們只需對權重 w13 直接影響的節點求導即可:
∂h3_out∂E=i∈Downstream(h3)∑∂outputi_out∂E∗∂outputi_in∂outputi_out∗∂h3_out∂outputi_in
各項展開得:
∂h3_out∂E=i∈Downstream(h3)∑−(Yitrue−outputi_out)∗Sigmoid(outputi_in)∗(1−Sigmoid(outputi_in))∗w3i
3. 訓練
1> 調整單個權重 w。我們追求誤差減小,故,有以下公式:
w35=w35−Δw35
定義學習速率:r
w35=w35−r∗∂w35∂E
輸出層權重調整:
w35=w35+r∗(Y5true−output5_out)∗Sigmoid(output5_in)∗(1−Sigmoid(output5_in))∗h3_out
w45=w45+r∗(Y5true−output5_out)∗Sigmoid(output5_in)∗(1−Sigmoid(output5_in))∗h4_out
w36=w36+r∗(Y6true−output6_out)∗Sigmoid(output6_in)∗(1−Sigmoid(output6_in))∗h3_out
w46=w46+r∗(Y6true−output6_out)∗Sigmoid(output6_in)∗(1−Sigmoid(output6_in))∗h4_out
利用矩陣運算簡化
ow+=r∗(Y5true−Y5predY6true−Y6pred)⋅Sigmoid′(output5_inoutput6_in)×(h3_outh4_out)
繼續化簡(默認向量爲列向量):
ow+=r∗(Ytrue−Ypred)⋅Sigmoid′(output_in)×h_out.T
令:
output_errors=(Ytrue−Ypred)
則:
hw+=r∗(output_errors⋅Sigmoid′(output_in))×h_out.T
隱藏層權重調整:
w13=w13+r∗Sigmoid′(h3_in)∗x1∗i∈Downstream(h3)∑(Yitrue−outputi_out)∗Sigmoid′(outputi_in)∗w3i
w23=w23+r∗Sigmoid′(h3_in)∗x2∗i∈Downstream(h3)∑(Yitrue−outputi_out)∗Sigmoid′(outputi_in)∗w3i
w14=w14+r∗Sigmoid′(h4_in)∗x1∗i∈Downstream(h4)∑(Yitrue−outputi_out)∗Sigmoid′(outputi_in)∗w4i
w24=w24+r∗Sigmoid′(h4_in)∗x2∗i∈Downstream(h4)∑(Yitrue−outputi_out)∗Sigmoid′(outputi_in)∗w4i
利用矩陣簡化:
hwij+=r∗Sigmoid′(hj_inhj_in)⋅(x1x2)×k∈Downstream(hj)∑(Yktrue−Ykpred)⋅Sigmoid′(outputk_in)×wjk
令(默認向量爲列向量):
hidden_errors=output_w.T×((Yktrue−Ykpred)⋅Sigmoid′(output_in))
帶入得(默認向量爲列向量):
hw+=r∗(hidden_errors⋅Sigmoid′(h_in))×X.T
2> 隨機梯度下降
- 對訓練樣本中的每一個數據,進行一次訓練
- 對整個樣本進行多次(例如:100次)訓練
4. 編碼
import numpy as np
def activate(x):
return 1/(1+np.exp(-x))
def activate_de(x):
return activate(x)*(1-activate(x))
class NeutualNetWork:
def __init__(self):
self.hw=np.random.normal(np.zeros((2,2)))
self.ow=np.random.normal(np.zeros((2,2)))
self.r=0.1
self.epoch=100
def prdict(self,x):
x=np.array(x,ndmin=2).T
h_in=np.dot(self.hw,x)
h_out = activate(h_in)
output_in=np.dot(self.ow,h_out)
output_out=activate(output_in)
return output_out
def train(self,x_data,ytrue_data):
for i in range(self.epoch):
for data in zip(x_data,ytrue_data):
self.train_once(data[0],data[1])
def train_once(self,x,ytrue):
'''
:param x: 輸入行向量
:param ytrue: 輸出行向量
:return:
'''
x = np.array(x, ndmin=2).T
ytrue = np.array(ytrue, ndmin=2).T
h_in=np.dot(self.hw,x)
h_out=activate(h_in)
output_in=np.dot(self.ow,h_out)
output_out=activate(output_in)
output_errors=ytrue-output_out
cal_tmp=output_errors*activate_de(output_in)
self.ow+=self.r*np.dot(cal_tmp,h_out.T)
hidden_errors=np.dot(self.ow.T,cal_tmp)
self.hw+=self.r*np.dot(hidden_errors*activate_de(h_in),x.T)
in_data = [
[165, 55],
[160, 53],
[175, 55],
[163, 55],
[173, 49],
[163, 56],
[180, 77],
[155, 54],
[176, 79],
[161, 49],
[180, 60],
[168, 57],
[172, 69],
[166, 50],
[172, 90],
[163, 51],
[175, 70],
[164, 53],
[160, 45],
[160, 56],
[182, 70],
[180, 74],
[185, 73],
[165, 55],
[185, 75]
]
out_data = [
[1,0],
[0,1],
[1, 0],
[0, 1],
[1, 0],
[0, 1],
[1, 0],
[0, 1],
[1, 0],
[0, 1],
[1, 0],
[0, 1],
[1, 0],
[0, 1],
[1, 0],
[0, 1],
[1, 0],
[0, 1],
[1, 0],
[0, 1],
[1, 0],
[0, 1],
[1, 0],
[0, 1],
[1, 0],
[0, 1],
[1, 0],
[0, 1],
[1, 0],
[0, 1]
]
in_test=[
[165, 55],
[160, 53],
[175, 55],
[163, 55],
[173, 49]
]
out_test=[
[0,1],
[0, 1],
[1, 0],
[0, 1],
[1, 0],
]
nn = NeutualNetWork()
nn.train(in_data,out_data)
for test in zip(in_test,out_test):
ypred=nn.prdict(test[0])
print("in:",test[0],"yture:",test[1])
print("predit:",ypred)
這串代碼可以直接運行
五、 算法優化
1. 指定網絡結構
可隨意指定:輸入層,隱藏層,輸出層的神經元個數
2. 存儲當前神經網絡的訓練數據
將神經網絡結構,包括:學習速率,訓練次數和所有權重矩陣存成文件,以便以後可以不必訓練,加載數據後可直接進行預測。