神經網路篇——從程式碼出發理解BP神經網路
一提到反向傳播演算法,我們就不自覺的想到隨機梯度下降、sigmoid啟用函式和最讓人頭大的反向傳播法則的推導,即便是把反向傳播神經網路的原理學了一遍,也還是一頭霧水,在這裡推薦一本小編認為把BP神經網路講的最通透的教材《Python神經網路程式設計》。下面小編將以程式碼的方式帶著大家一步一步實現BP神經網路,並且還會再用框架的方式實現BP網路,用來和原始碼作比較,認識一下TensorFlow2.0的強大。
我們首先要理清建立BP神經網路的目的,其次,確定BP神經網路的結構,簡單地以一個輸入層,一個隱藏層,一個輸出層為例,我們來思考一下寫程式碼的思路,然後一步一步實現。
在這裡,我們建立BP神經網路的目的是為了做預測,我們這裡用700條MG時間序列資料作為訓練資料,輸入維度是10,輸出為1,為了方便,我們設定一個隱藏層,這個隱藏層包含10個節點,所以我們的BP神經網路的結構就是[10,10,1]。接下來,開始思考一下流程:
1、讀取資料,將資料分為訓練集和測試集,注意這裡的資料預設都是np.array()的格式。
2、初始化BP網路,主要是確定網路結構,輸入層、隱藏層、輸出層個數,以及隨機初始化相互連線的權值
3、呼叫訓練方法,傳入資料進行訓練
-
-
前向傳播
-
反向傳播
-
儲存模型進行測試
-
裡面還有很多細節,我們邊寫邊完善,整個程式的框架已經很明確了。從第一步開始,讀取資料,第一步中需要注意的是,讀取的資料最好進行歸一化處理,一方面,這樣做有助於提高預測精度,另一方面,如果使用sigmoid作為啟用函式的話,它的輸出是在[0,1]之間的,如果資料不進行歸一化,不在[0,1]區間的數是沒有辦法預測的。這裡我們直接呼叫sklearn中的最大最小歸一化的方法就可以,為了方便讀者理解程式碼,我們將import緊挨著程式碼:
#防止資料用科學計數法輸出
np.set_printoptions(suppress=True)
#讀取資料
way1 = 'Traindata11.csv'
data = np.array(pd.DataFrame(pd.read_csv(way1)))
# 歸一化所有資料
from sklearn.preprocessing import MinMaxScaler
format_minmax = MinMaxScaler()
data = format_minmax.fit_transform(data)
x = data[:,:-1] #需要訓練的資料
y = data[:,-1] #label,標籤
#初始化BP網路
#訓練網路
第二步,我們要初始化網路,確定網路的結構:
def __init__(self, ni, nh, no):
"""
構造神經網路
:param ni:輸入單元數量
:param nh:隱藏單元數量
:param no:輸出單元數量
"""
self.ni = ni + 1 # +1 是為了偏置節點
self.nh = nh
self.no = no
# 啟用值(輸出值)
self.ai = [1.0] * self.ni #這裡會生成一個1*ni維,數值全為1的列表
self.ah = [1.0] * self.nh
self.ao = [1.0] * self.no
# 權重矩陣
self.wi = np.random.randn(self.ni, self.nh) #輸入層到隱藏層
self.wo = np.random.randn(self.nh, self.no) # 隱藏層到輸出層
# 記錄權重矩陣的上次梯度
self.ci = np.zeros([self.ni, self.nh])
self.co = np.zeros([self.nh, self.no])
第三步開始訓練並儲存模型:
def train(self,train,lable,max_iterations=1000, N=0.5, M=0.1):
"""
訓練
:param train:訓練集
:param lable:標籤
:param max_iterations:最大迭代次數
:param N:本次學習率
:param M:上次學習率
"""
for i in range(max_iterations): #迭代最大訓練次數(epoch)
for j in range(len(train)): #訓練集
inputs = train[j] #輸入向量
targets = lable[j] #目標值
self.forword_propagation(inputs) #前向傳播訓練
error = self.back_propagation(targets, N, M) #反向傳播訓練,傳入lable
if i % 50 == 0: #每50次輸出一次誤差(loss),loss函式為mse
print('Combined error', error)
winame = 'wi.npy'
woname = 'wo.npy'
np.save(winame, self.wi)
np.save(woname, self.wo)
接下來我們就要實現前向傳播和反向傳播的方法了,我們按照順序從前向傳播開始,前向傳播用到了sigmoid作為啟用函式,所以我們把sigmoid函式也一併列出:
def sigmoid(self,x):
"""
sigmoid 函式,1/(1+e^-x)
:param x:
:return:
"""
return 1.0 / (1.0 + math.exp(-x))
def forword_propagation(self, inputs):
"""
前向傳播進行分類
:param inputs:輸入
:return:類別
"""
if len(inputs) != self.ni - 1: #檢查輸入資料的維度是否和宣告的一致
print('輸入維度有誤,請重新檢查輸入')
for i in range(self.ni - 1): #按順序將n維的input對映到n個輸入節點上
self.ai[i] = inputs[i]
for j in range(self.nh): #遍歷隱藏層節點,每個隱藏層節點的值為n個輸入節點*對應權值(輸入層和隱藏層)的和
sum = 0.0
for i in range(self.ni):
sum += (self.ai[i] * self.wi[i][j])
self.ah[j] = self.sigmoid(sum) #將節點值經過sigmoid函式啟用後,變為[0,1]之間的值
for k in range(self.no): #遍歷輸出層節點,每個輸出層節點的值為n個隱藏層節點*對應權值(隱藏層和輸出層)的和
sum = 0.0
for j in range(self.nh):
sum += (self.ah[j] * self.wo[j][k])
self.ao[k] = self.sigmoid(sum) ##將節點值經過sigmoid函式啟用後,變為[0,1]之間的值
return self.ao #返回輸出層的值
接下來是反向傳播,反向傳播中需要對sigmoid進行求導,為了方便我們直接寫出sigmoid的求導結果,另外這裡的誤差函式(loss)選擇mse:
def dsigmoid(self,y):
"""
sigmoid 函式的導數
:param y:
:return:
"""
return y * (1 - y)
def back_propagation(self, targets, N, M):
"""
反向傳播演算法
:param targets: 例項的類別
:param N: 本次學習率
:param M: 上次學習率
:return: 最終的誤差平方和的一半
"""
# 計算輸出層 deltas,求導數
# dE/dw[j][k] = (t[k] - ao[k]) * s'( SUM( w[j][k]*ah[j] ) ) * ah[j]
output_deltas = [0.0] * self.no #初始化輸出層列表為0
for k in range(self.no):
error = targets[k] - self.ao[k] #計算輸出層誤差
output_deltas[k] = error * self.dsigmoid(self.ao[k]) #計算每一個節點對誤差的影響大小,佔比越大,影響越大
# 根據delta更新隱藏層和輸出層之間的權值
for j in range(self.nh):
for k in range(self.no):
# output_deltas[k] * self.ah[j] 才是 dError/dweight[j][k]
change = output_deltas[k] * self.ah[j] #根據比例計算需要調整的值
self.wo[j][k] += N * change + M * self.co[j][k] #調整權值,調整方法有很多,例如隨機梯度下降,這裡只是簡單寫了一下
self.co[j][k] = change #儲存調整的梯度
# 計算隱藏層 deltas
hidden_deltas = [0.0] * self.nh
for j in range(self.nh):
error = 0.0
for k in range(self.no):
error += output_deltas[k] * self.wo[j][k]
hidden_deltas[j] = error * self.dsigmoid(self.ah[j])
# 更新輸入層權值
for i in range(self.ni):
for j in range(self.nh):
change = hidden_deltas[j] * self.ai[i]
# print 'activation',self.ai[i],'synapse',i,j,'change',change
self.wi[i][j] += N * change + M * self.ci[i][j]
self.ci[i][j] = change
# 計算MSE
error = 0.0
for k in range(len(targets)):
error += (targets[k] - self.ao[k]) ** 2
error = error/len(y)
return error
到這裡就差不多實現了一個最簡單的BP神經網路,不過小編強烈反對用這個程式碼來進行實戰,這個程式碼只適用於理解BP神經網路。在下一篇中,我將用Tensorflow框架和Pytorch框架來實現一個通用的BP神經網路,並且解答一下為什麼要使用啟用函式。
不知不覺,2021年到來了,馬上天就要亮了,這一篇是小編的第一篇公眾號,僅以此銘記2021.1.1日凌晨。祝各位讀者,元旦快樂!!!
歡迎關注公眾號“NNResearch”
公眾號傳送“BP神經網路圖書”,即可獲取電子版圖書。
公眾號傳送“BP原始碼”,即可獲取完整版原始碼。
相關文章
- BP神經網路流程圖神經網路流程圖
- 資料探勘---BP神經網路神經網路
- 構建兩層以上BP神經網路(python程式碼)神經網路Python
- python對BP神經網路實現Python神經網路
- 聊聊從腦神經到神經網路神經網路
- Andrew BP 神經網路詳細推導神經網路
- 【神經網路篇】--RNN遞迴神經網路初始與詳解神經網路RNN遞迴
- 【深度學習篇】--神經網路中的卷積神經網路深度學習神經網路卷積
- 神經網路:numpy實現神經網路框架神經網路框架
- 神經網路神經網路
- 3.2 神經網路的通俗理解神經網路
- Tensorflow系列專題(四):神經網路篇之前饋神經網路綜述神經網路
- MATLAB人工神經網路ANN程式碼Matlab神經網路
- LSTM神經網路神經網路
- 8、神經網路神經網路
- 圖神經網路GNN 庫,液體神經網路LNN/LFM神經網路GNN
- 深入淺出圖神經網路 GCN程式碼實戰神經網路GC
- 神經網路之卷積篇:詳解經典網路(Classic networks)神經網路卷積
- 神經網路最佳化篇:如何理解 dropout(Understanding Dropout)神經網路
- 神經網路的發展史神經網路
- 【深度學習基礎-08】神經網路演算法(Neural Network)上--BP神經網路例子計算說明深度學習神經網路演算法
- 人工神經網路(ANN)神經網路
- 卷積神經網路卷積神經網路
- 迴圈神經網路神經網路
- 神經網路(neural networks)神經網路
- 生成型神經網路神經網路
- 神經網路中間層輸出神經網路
- 《TensorFlow2.0》前饋神經網路和 BP 演算法神經網路演算法
- 【深度學習基礎-07】神經網路演算法(Neural Network)上--BP神經網路基礎理論深度學習神經網路演算法
- 卷積神經網路學習筆記——Siamese networks(孿生神經網路)卷積神經網路筆記
- 神經網路初始化神經網路
- 卷積神經網路概述卷積神經網路
- 解密卷積神經網路!解密卷積神經網路
- MXNET:多層神經網路神經網路
- 淺析模糊神經網路神經網路
- 白話深度神經網路神經網路
- 5.2.1 卷積神經網路卷積神經網路
- 迴圈神經網路(RNN)神經網路RNN