深度学习(神经网络) —— BP神经网络原理推导及python实现
深度學習(神經網絡) —— BP神經網絡原理推導及python實現
- 摘要
- (一)BP神經網絡簡介
- 1、神經網絡權值調整的一般形式為:
- 2、BP神經網絡中關于學習信號的求取方法:
- (二)BP神經網絡原理推導
- 1、變量說明
- 2、BP算法推導
- (三)BP神經網絡python實現
- 1、模型所需傳參介紹
- 2、模型具有的主要方法和屬性
- 3、python代碼
- 4、代碼運行結果
摘要
本文首先介紹了BP神經網絡求取學習信號的方法,其次對BP神經網絡在原理上進行了推導,最后在python上進行編程實現,并將其封裝,方便讀者直接調用。
(一)BP神經網絡簡介
BP神經網絡是整個神經網絡體系中的精華,與一般神經網絡相比,它調整權值方式為從最后一層開始逐層調整,通過多次迭代,使得代價函數降低至可接受范圍。因此,這就是BP神經網絡的來源(Back Propagation,誤差反向傳播)。
1、神經網絡權值調整的一般形式為:
(1)其中 η為學習率,可以理解為每次權值調整的步長
(2)其中δ為學習信號,可以理解為每次權值調整的方向,實際上為一個梯度向量。
由上式也可以發現不同神經網絡的差異主要體現在學習信號上的差異。
2、BP神經網絡中關于學習信號的求取方法:
假設一個神經網絡共n層
上式為求取最后一層,即輸出層的學習信號,其中t為期望輸出,y為模型輸出,f(x)為激活函數(對激活函數不了解的可自行先百度或查看我的其他文章)。
上式為求取除最后一層以外其他層的學習信號,i+1表示第i層后面的一層,可以發現求取第i層學習信號時,需要先求取出第i+1層的學習信號,這也是誤差反向傳播的來源。
具體BP神經網絡的學習信號推導過程見以下的原理推導,推導過程有點小復雜,即使不看,根據以上的結論也可以編寫自己的BP神經網絡程序了。
(二)BP神經網絡原理推導
1、變量說明
(1)以三層感知器構成的神經網絡為例(實際為兩層神經網絡)。
(2)定義各層的輸入和輸出:
輸入向量
隱含層輸出向量
輸出層輸出向量
期望輸出向量
(3)定義權值矩陣:
輸入層到隱含層的權值矩陣
隱含層到輸出層的權值矩陣
(4)設定激活函數
2、BP算法推導
(1)構建計算輸出層輸出的函數
(2)構建計算隱含層輸出的函數
(3)定義代價函數
(4)式9中x與d分別為輸入與對應的期望輸出,皆為已知,所以代價函數則為兩個權值矩陣的函數,為了使代價函數減小,權值的調整應往負梯度方向調整,如下:(η為學習率,可以理解為往負梯度方向改變的步長)
(5)將式10和式11按鏈式求導法則進行展開:
(6)對輸出層和隱含層各定義一個誤差信號(本質上為負梯度):
(7)將式14和式15代入式12和式13,得:
(8)求解輸出層和隱含層的學習信號(需結合式1和式3):
(9)計算式18和19中的偏導:
(10)將式20和式21帶回式18和19:
(11)將式22)和式23帶回式16和17,得:
(12)將三層感知器推廣到任意層數神經網絡:
假設神經網絡共n層。
(三)BP神經網絡python實現
如果讀者想自己動手在python上實現BP神經網絡的話,可以根據文章給出的關于學習信號的求取方法進行編程,本文給出了自己的實現代碼,且將其封裝成一個類,基本上的屬性和方法都具有,通用性較強,讀者既可調用其來訓練自己的模型,也可以參考其架構自行編寫代碼。
1、模型所需傳參介紹
layer 為神經網絡各層神經元的個數,包括輸出層神經元個數,傳參形式以列表傳入; activate:為各層的激活函數,傳參形式為字符串或列表,若傳入一個字符串,則各層激活函數相同,若傳入一個列表,則列表元素代表各層激活函數可傳參數有:(1)sigmoid:S型函數(2)tanh:雙曲正弦函數(3)relu:max(0,x)函數(4)purline:線性函數(5)softsign:平滑函數lr:學習率,默認為0.01 epoch:最大迭代次數 默認為1e42、模型具有的主要方法和屬性
fit(X,Y):模型擬合方法 predict(X):輸出預測方法 predict_label(X):分類標簽輸出預測方法 activate:激活函數列表 W:權值列表3、python代碼
import numpy as np import time class Cyrus_BP(object):"""layer 為神經網絡各層神經元的個數,包括輸出層神經元個數,傳參形式以列表傳入;activate:為各層的激活函數,傳參形式為字符串或列表,若傳入一個字符串,則各層激活函數相同,若傳入一個列表,則列表元素代表各層激活函數可傳參數有:(1)sigmoid:S型函數(2)tanh:雙曲正弦函數(3)relu:max(0,x)函數(4)purline:線性函數(5)softsign:平滑函數lr:學習率,默認為0.01epoch:最大迭代次數 默認為1e4該模型具有的主要方法和屬性如下:fit(X,Y):模型擬合方法predict(X):輸出預測方法predict_label(X):分類標簽輸出預測方法activate:激活函數列表W:權值列表"""def __init__(self,layer,**kargs):self.layer = np.array(layer).reshape(1,-1)if 'activate' in kargs.keys():if str(type(kargs["activate"])) == "<class 'str'>": self.activate = [kargs["activate"]]*int(len(layer))else:self.activate = kargs["activate"]else:self.activate = ["sigmoid"]*int(len(layer))self.diff_activate = []if 'lr' in kargs.keys():self.lr = kargs["lr"]else:self.lr = 0.01if 'epoch' in kargs.keys():self.epoch = kargs["epoch"]else:self.epoch = int(1e4)self.X = Noneself.Y = Noneself.W = Noneself.output = []self.delta = []self.sum_input = []# 1、選擇激活函數def activation_func(self):temp_func = []for i in range(len(self.activate)):if self.activate[i] == "sigmoid":temp_func.append(lambda x:1/(1+np.exp(-x)))self.diff_activate.append(lambda x:(1/(1+np.exp(-x)))*(1-(1/(1+np.exp(-x)))))if self.activate[i] == "tanh":temp_func.append(lambda x:(np.exp(x)-np.exp(-x))/(np.exp(x)+np.exp(-x)))self.diff_activate.append(lambda x:((-np.exp(x) + np.exp(-x))*(np.exp(x) - np.exp(-x))/(np.exp(x) + np.exp(-x))**2 + 1))if self.activate[i] == "softsign":temp_func.append(lambda x:x/(1+np.abs(x)))self.diff_activate.append(lambda x:1/((1+x/np.abs(x)*x)**2))if self.activate[i] == "relu":temp_func.append(lambda x:(x+np.abs(x))/(2*np.abs(x))*x)self.diff_activate.append(lambda x:(x+np.abs(x))/(2*np.abs(x)))if self.activate[i] == "purline":temp_func.append(lambda x:x)self.diff_activate.append(lambda x:1+x-x)self.activate = temp_func# 2、權值初始化函數def init_w(self):self.W = []for i in range(self.layer.shape[1]):if i == 0:w = np.random.random([self.X.shape[1]+1,self.layer[0,i]])*2-1else:w = np.random.random([self.layer[0,i-1]+1,self.layer[0,i]])*2-1self.W.append(w)# 3、權值調整函數def update_w(self):# 1 計算各層輸出值self.output = []self.sum_input = []for i in range(self.layer.shape[1]):if i == 0:temp = np.dot(np.hstack((np.ones((self.X.shape[0],1)),self.X)),self.W[i])self.sum_input.append(temp)self.output.append(self.activate[i](temp))else:temp = np.dot(np.hstack((np.ones((self.output[i-1].shape[0],1)),self.output[i-1])),self.W[i])self.sum_input.append(temp)self.output.append(self.activate[i](temp))# 2 求每層的學習信號self.delta = [0 for i in range(len(self.output))]for i in range(len(self.output)):if i == 0:self.delta [-i-1] = ((self.Y-self.output[-i-1])*self.diff_activate[-i-1](self.sum_input[-i-1]))else:self.delta [-i-1] = ((self.delta[-i].dot(self.W[-i][1:,:].T))*self.diff_activate[-i-1](self.sum_input[-i-1]))# 3 更新權值for i in range(len(self.W)):if i == 0 :self.W[i] += self.lr * np.hstack((np.ones((self.X.shape[0],1)),self.X)).T.dot(self.delta[i])else:self.W[i] += self.lr * np.hstack((np.ones((self.output[i-1].shape[0],1)),self.output[i-1])).T.dot(self.delta[i])def fit(self,X,Y):self.X = np.array(X)self.Y = np.array(Y)# 1 權值初始化self.init_w()# 2 選擇激活函數self.activation_func()# 3 更新權值start_time = time.time()for i in range(int(self.epoch)):self.update_w()end_time = time.time()if end_time - start_time >= 5:print("Epoch%d:"%(i+1),np.mean(np.square(self.Y-self.output[-1])))print("\n")start_time = time.time()def predict(self,x):x = np.array(x)result = []for i in range(self.layer.shape[1]):if i == 0:result.append(self.activate[i](np.dot(np.hstack((np.ones((x.shape[0],1)),x)),self.W[i])))else:result.append(self.activate[i](np.dot(np.hstack((np.ones((result[i-1].shape[0],1)),result[i-1])),self.W[i])))return result[-1]def predict_label(self,x):x = np.array(x)result = []for i in range(self.layer.shape[1]):if i == 0:result.append(self.activate[i](np.dot(np.hstack((np.ones((x.shape[0],1)),x)),self.W[i])))else:result.append(self.activate[i](np.dot(np.hstack((np.ones((result[i-1].shape[0],1)),result[i-1])),self.W[i])))result = result[-1] return np.array([result[i].argmax() for i in range(result.shape[0])]).reshape(-1,1)if __name__ == "__main__":bp = Cyrus_BP([50,10,3],lr=0.01,epoch = 2e5,activate = ["softsign","softsign","softsign"])from sklearn.datasets import load_irisfrom sklearn.metrics import accuracy_scoredata = load_iris()X = data["data"]Y = data["target"]import pandas as pd# 用神經網絡進行分類時,需把輸出先進行獨熱編碼Y1 = pd.get_dummies(Y1) # 進行獨熱編碼或將期望輸出轉換為啞變量bp.fit(X,Y1)Y_pre = bp.predict_label(X)print("準確率為:",accuracy_score(Y,Y_pre))4、代碼運行結果
Epoch9314: 0.02853577904298399Epoch19691: 0.02145897246261971Epoch31495: 0.01784770845276102Epoch42539: 0.01415043927077651Epoch53434: 0.015407038745481208Epoch64893: 0.016390764988851683Epoch76186: 0.015016316993973523Epoch86931: 0.013693150044879728Epoch97390: 0.013706384360315056Epoch108511: 0.012193768543380657Epoch118993: 0.010314480349340294Epoch128337: 0.009862103298377766Epoch138193: 0.01057658278951552Epoch147889: 0.009652582210903272Epoch157632: 0.009137051214565095Epoch165815: 0.009407398018203143Epoch175037: 0.009429640020604707Epoch185229: 0.00991562156191445Epoch194220: 0.009801710064963167 準確率為: 0.9933333333333333可見模型訓練結果還是不錯的
by CyrusMay 2020 05 11
晚風吻盡 荷花葉
任我醉倒在池邊
等你清楚看見我的美
月光曬干眼淚
——五月天(擁抱)——
總結
以上是生活随笔為你收集整理的深度学习(神经网络) —— BP神经网络原理推导及python实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 机器学习 回归篇(1)——多元线性回归
- 下一篇: 机器学习 集成学习篇——python实现