神經網絡篇——從代碼出發理解BP神經網絡

2021-01-07 神經網絡研究所

一提到反向傳播算法,我們就不自覺的想到隨機梯度下降、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日凌晨。祝各位讀者,元旦快樂!!!

公眾號「神經網絡研究所」

公眾號發送「BP神經網絡圖書」,即可獲取電子版圖書。

公眾號發送「BP源碼」,即可獲取完整版源碼。

相關焦點

  • 神經網絡篇——用TensorFlow2.0框架實現BP網絡
    那這個感知器模型和BP網絡有什麼關係呢?在我們所看到的BP網絡的結構圖中,其實是被簡化了的,下面小編畫了一個邏輯更清晰一點的圖:這樣我們就可以看出來,其實BP網絡是由一個一個的感知器組成,也就構成了一個真正的神經網絡,自然就能理解為什麼要使用激活函數了。接下來我們來看一下TensorFlow實現BP神經網絡到底有多簡單!
  • BP神經網絡算法與實踐
    (點擊上方公眾號,可快速關注)來源: CodeMealscnblogs.com/fengfenggirl/p/bp_network.html
  • AI從入門到放棄:BP神經網絡算法推導及代碼實現筆記
    導數符號不變,讓神經網絡訓練容易收斂。這裡只說我們用到的激活函數:求一下它的導數把,因為後面講bp算法會直接套用它:先祭出大殺器,高中數學之複合函數求導法則:它的導數圖像:▌五. 沙漠中心的風暴:BP(Back Propagation)算法1.
  • BP神經網絡
    其實在其他領域也是一樣,隨著神經網絡學習資料庫的範圍變大,學習程度的深入,使得神經網絡在更多領域得到運用,神經網絡正在成為一種有效的工具。由於財務風險預警的複雜性以及對決策的重要影響,國內外有大量的研究預測工作,採用各種方法來優化財務風險預警模型。
  • 個人對神經網絡的理解(前饋神經網絡)
    神經網絡的發展還是挺快的,市面上的神經網絡種類已經發展得挺豐富了,比如卷積神經網絡(CNN),循環神經網絡(RNN),長短期記憶網絡(LSTM)等等。本文僅介紹一下筆者對於最簡單的神經網絡中前饋神經網絡的部分的理解,想必其中有許多謬誤,歡迎大家指正。
  • 前饋神經網絡和BP算法簡單教程
    吳立德老師親自講解前饋神經網絡和BP算法,讓初學者對基礎更加了解,對以後網絡的改建和創新打下基礎,值得好好學習!
  • 人工神經網絡
    例如,當我們拿出小米手機跟小愛同學進行聊天,小愛同學會識別你的話並進行分析來理解你的意思,以給你最貼心的反饋回復。當然人工智慧的概念在實際中其實是相當廣泛,人工智慧能發展到今天,它需要硬體、數據、運算、算法四個方面來支撐的。而小創君今天分享的人工神經網絡其實就是早期的機器學習算法。
  • 「人工神經網絡」人工神經網絡之BP算法
    人工神經網絡(Artificial Neural Network,ANN)是在受到了生物學的啟發後創建的,在某種程度上它是對生物大腦的一種模擬。人們仿照生物神經網絡的結構,使用簡單運算單元模擬神經元,並將大量運算單元按某種形式密集連接,便構成了人工神經網絡。結構如圖:人工神經網絡(ANN)模型帶有權重值(w1,w2,...
  • ICLR 2020 | 神經正切,5行代碼打造無限寬的神經網絡模型
    近年來,該領域取得進展的一個關鍵理論觀點是:增加 DNN 的寬度會帶來更有規律的行為,並使這些行為更易於理解。最近的許多結果表明,能夠變得無限寬的DNN聚合到另一種更簡單的模型類別上的過程,稱為高斯過程。在這一限制下,複雜的現象(如貝葉斯推理或卷積神經網絡的梯度下降動力學)可以歸結為簡單的線性代數方程。這些無限寬網絡的一些思路,也被頻繁地擴展到有限的網絡上。
  • 理解LSTM神經網絡
    為了更便於大家理解,我會在其中加入一些我個人的理解。所以,我以字體顏色區分二者:遞歸神經網絡人類不會從每一時刻都開始思考。就像你閱讀這篇文章,你會基於之前已理解的內容理解當前的內容。你不會把所有東西都丟掉,然後重新開始思考。
  • 如何教神經網絡玩 21 點遊戲(附代碼)?
    一個簡單神經網絡的視覺缺陷在我們開始訓練之前,讓我們退一步,快速討論一下在這種情況下使用神經網絡的優缺點。神經網絡是高度靈活的算法——像軟粘土一樣,神經網絡調整自己,以適應數據的輪廓。第一行(第 1 行)創建一個順序型神經網絡,它是神經網絡層的線性序列。第一行之後的代碼逐個地向我們的模型中添加層。最後,對於最後一層,我們需要選擇一個激活函數。這將神經網絡的原始輸出轉換成我們可以解釋的東西。在最後一層需要注意兩件事。首先,它只包含一個神經元,因為我們正在預測兩種可能的結果(二分類問題)。
  • R 語言機器學習—快速實現BP神經網絡
    BP神經網絡(BPNN)的全稱是:誤差反向傳播神經網絡(Error back propagation training neural network
  • 神經網絡的BP算法學習
    有了上面的基礎後,就可以看看幾種常見的神經網絡的推導1)普通的神經網絡將其中的函數塊都變為節點,一個典型的seq2seq網絡就如下圖所示:具體的代碼參見:http://git.oschina.net/bamuyy/lstm/blob/master/lstm.py?
  • 理解神經網絡中的Dropout
    dropout是指在深度學習網絡的訓練過程中,對於神經網絡單元,按照一定的概率將其暫時從網絡中丟棄。注意是暫時,對於隨機梯度下降來說,由於是隨機丟棄,故而每一個mini-batch都在訓練不同的網絡。
  • 三步教你搭建給黑白照片上色的神經網絡 !(附代碼)
    進入正題~以下內容編譯自FloydHub官方博客:我將分三個步驟展示如何打造你自己的著色神經網絡。第一部分介紹核心邏輯。我們將用40行代碼來構建一個簡單的神經網絡,叫做「Alpha」版本著色機器人。這個代碼裡沒有太多技巧,但是有助於熟悉語法。
  • 如何用30行JavaScript代碼編寫神經網絡異或運算器
    近日,編程學習平臺 Scrimba 聯合創始人 Per Harald Borgen 在 Medium 上發文介紹了一種僅用 30 行 JavaScript 代碼就創建出了一個神經網絡的教程,而且使用的工具也只有 Node.js、Synaptic.js 和瀏覽器而已。另外,作者還做了一個交互式 Scrimba 教程,也許能幫你理解其中的複雜概念。
  • 前饋神經網絡——深度學習之神經網絡核心原理與算法
    因上幾次讀者反映,公式代碼有亂碼和不規整的問題,小編有改善喲,這篇文章開始親們會看到效果的喲~Feedforward Neural Network網絡結構(一般分兩種)BP網絡是所有的神經網絡中結構最為簡單的一種網絡。一般我們習慣把網絡畫成左邊輸入右邊輸出層的結構。
  • 30行代碼,帶你分分鐘創建神經網絡!(附工具&教程)
    本文含大量代碼,如需原文請從文末來源連結獲取。自己搭建神經網絡太複雜?。在本篇文章中,你將學到://karpathy.github.io/neuralnets/)神經網絡和深度學習-作者:Michael Nielsen(http://neuralnetworksanddeeplearning.com/chap1.html)用代碼搭建神經網絡現在,你應該已經對神經網絡有了基礎概念,那就讓我們進入代碼部分吧
  • 【神經網絡】神經網絡簡介
    這種網絡依靠系統的複雜程度,通過調整內部大量節點之間相互連接的關係,從而達到處理信息的目的。剛剛入門神經網絡,往往會對眾多的神經網絡架構感到困惑,神經網絡看起來複雜多樣,但是這麼多架構無非也就是三類:前饋式網絡、反饋式網絡、圖網絡。
  • 實戰|手把手入門神經網絡,74行代碼實現手寫數字識別
    因此,本文直接用Michael Nielsen先生的代碼作為例子,給大家展現神經網絡分析的普遍過程:導入數據,訓練模型,優化模型,啟發式理解等。本文假設大家已經了解python的基本語法,並在自己機器上運行過簡單python腳本。