BP神經網路實現(R語言+Python)
看吳恩達老師機器學習課程的反向傳播神經網路(BP-Network)一節時,網上有個《十一行Python代碼實現一個神經網路》小例子,非常小巧玲瓏,不過和吳恩達老師實現過程不太一樣(歡迎一起討論),於是又找到了一篇《R語言13行代碼實現神經網路》,正是想要的思路,和大家分享!
- 神經網路建模任務描述:
已知輸入為Input,輸出為Output,進行BP-Network建模,即權重矩陣 的求解。
- Python BP神經網路實現代碼:(一層隱藏層)
import numpy as npX = np.array([ [0,0,1],[1,1,1],[1,0,1],[0,1,1] ]) #輸入值,4*3矩陣y = np.array([[0,1,1,0]]).T #輸出值,4*1矩陣syn1 = 2*np.random.random((3,4)) - 1 # 輸入層到隱藏層的3*4 權重陣,初始值隨機產生syn2 = 2*np.random.random((4,1)) - 1 # 隱藏層到輸出層的4*1 權重陣,初始值隨機產生for j in range(20000): #迭代 a1 = 1/(1+np.exp(-np.dot(X,syn1))) #隱藏層經權重和sigmod函數轉換後的值,4*4 矩陣 a2 = 1/(1+np.exp(-np.dot(a1,syn2))) #輸出層經權重和sigmod函數轉換後的值,4*1 矩陣 error_2 = a2-y #輸出層誤差,4*1 矩陣 error_1 = np.dot(error_2,syn2.T)*(a1*(1-a1)) #隱藏層誤差,4*4 矩陣 syn2 = syn2 - np.dot(a1,error_2) #應用梯度下降法求輸出層權重陣 syn1 = syn1 - np.dot(X.T,error_1) #應用梯度下降法求隱藏層權重陣print(a2)
Python 運行結果:
[[ 3.76271664e-05] [ 9.99943981e-01] [ 9.99943983e-01] [ 5.19326828e-05]]
- R 語言 BP神經網路實現代碼:(一層隱藏層)
c <- c(0,0,1,1,1,1,1,0,1,0,1,1)x <- matrix(c,nrow = 4,ncol = 3,byrow = T) #輸入值,4*3矩陣y <- matrix(c(0,1,1,0),ncol = 1) #輸出值,4*1矩陣#set.seed(111)syn1 <- matrix(rnorm(12),nrow = 3,byrow = T) # 輸入層到隱藏層的3*4 權重陣,初始值隨機產生syn2 <- matrix(rnorm(4),nrow = 4,byrow = T) # 隱藏層到輸出層的4*1 權重陣,初始值隨機產生cost <- c(NA) #損失函數,畫圖用for (i in 1:10000){ a1 <- 1/(1+exp(-(x %*% syn1))) #隱藏層經權重和sigmod函數轉換後的值,4*4 矩陣 a2 <- 1/(1+exp(-(a1%*% syn2))) #輸出層經權重和sigmod函數轉換後的值,4*1 矩陣 error_2 <- a2 - y #輸出層誤差,4*1 矩陣 error_1 <- error_2 %*% t(syn2) * a1 * (1-a1 ) #隱藏層誤差,4*4 矩陣 syn2 <- syn2 - 0.06 * a1 %*% error_2 #應用梯度下降法求輸出層權重陣,0.06為學習率 syn1 <- syn1 - 0.06 * t(x) %*% error_1 #應用梯度下降法求隱藏層權重陣,0.06為學習率 cost[i] <- error_2 # 存儲輸出層誤差為損失函數}a1a2plot(cost)
R 語言運行結果:
> a1 [,1] [,2] [,3] [,4][1,] 0.088806742 0.071804692 0.95895670 1.334214e-02[2,] 0.002789701 0.001092767 0.99987193 8.641429e-01[3,] 0.736807129 0.817886530 0.09021681 3.025079e-05[4,] 0.074378684 0.059717055 0.97070441 1.403001e-02> a2 [,1][1,] 0.003723701[2,] 0.999205564[3,] 0.997794973[4,] 0.003076961
R 語言 損失函數迭代圖:
先讓我們來看看神經網路是怎麼回事
圖中,有四行輸入觀測變數,變數的特徵數為3,即 :
> x [,1] [,2] [,3][1,] 0 0 1[2,] 1 1 1[3,] 1 0 1[4,] 0 1 1
輸出變數為 :
> y [,1][1,] 0[2,] 1[3,] 1[4,] 0
該網路共有三層,第一層 層為輸入層,即 ;第二層 層為隱藏層;第三層 層為輸出層。
網路最上層的兩個值為1的圈為偏置單元,所謂偏置單元,可以這樣理解:
比如擬合一個線性模型 ,此時為了表示成與 向量或矩陣同維度的形式,輸入矩陣 實際為[1, ]的形式,而這個1就是偏置單元。
- 下面來看看前向傳播的概念:
第一層為輸入層,不做處理,上標 j = 0為層數;
第二層有3個單元(先不考慮偏置單元),這裡以其中某一單元為例,注意這裡為單獨的一個單元,相當於網路圖中藍色箭頭指向的單元, 為輸入經過了權重 的變換;(一定要搞清楚這裡矩陣相乘的維度)
對於第二層的所有單元,有:
這裡矩陣的維度發生了變化 , 代表從 層映射到第 層時的權重矩陣,其維度為以要映射層的單元數量為行數,以前一層的單元數加一(加一為偏置單元)為列數的矩陣。例如本例中的尺寸為3*4。
就是如下代碼部分:
a1 <- 1/(1+exp(-(x %*% syn1))) #隱藏層經權重和sigmod函數轉換後的值,4*4 矩陣a2 <- 1/(1+exp(-(a1%*% syn2))) #輸出層經權重和sigmod函數轉換後的值,4*1 矩陣
函數為將連續值轉換成 區間的值,具有如下形狀:
函數公式:
函數的導數公式:
因此,注意求 時是矩陣之間的乘(Python中是np.dot乘,R中是%*%乘),而 函數變換是對矩陣 中各個數值的變換,在程序里就是矩陣中各個元素與實數的乘(*乘)!
以上即為前向傳播的概念,其實就是兩個步驟,一步是輸入乘以權重矩陣,並經過sigmod函數變化後作為下一層的輸入,直到得到最後一層的 ,即輸出值。
- 再來看一下反向傳播的概念:
圖中,我們從最後一層,即輸出層計算輸出誤差 ,從輸出層向左看,即下一層是隱藏層 層,而 層的誤差 可以看成是前一層誤差 的函數(反向傳播即指的是誤差的反向函數),之前計算的權重陣 依然是此處的權重陣,不過在此基礎上另加了一項 的導數( ),即:
# T是轉置的意思,此處*是數值直接相乘的意思;
代碼部分為:
error_2 <- a2 - y #輸出層誤差,4*1 矩陣error_1 <- error_2 %*% t(syn2) * a1 * (1-a1 ) #隱藏層誤差,4*4 矩陣
如果有多個隱藏層同樣求法(公式此處不做證明),注意輸入沒有誤差。
由此,我們求出了除了輸入層以後的各層誤差(各層誤差與各層的 同維度),那麼求這個誤差有什麼用呢?下面就是神經網路迭代使損失函數最小的關鍵環節:
我們先寫梯度下降函數:
# 為損失函數,可以簡單理解為模型輸出與實際輸出的差值; 為學習率;
即,我們想要損失函數最小時的 ,那我們就沿著損失函數對 求偏導的方向來更新 ,學習率可以嘗試著選取(文章 開 頭的程序里選的0.06)。
而經數學推導 有:
代碼部分:
syn2 <- syn2 - 0.06 * a1 %*% error_2 #應用梯度下降法求輸出層權重陣,0.06為學習率syn1 <- syn1 - 0.06 * t(x) %*% error_1 #應用梯度下降法求隱藏層權重陣,0.06為學習率
這樣利用前面由前向傳播求出的 ,由反向傳播求出的 ,我們就可以應用梯度下降演算法來更新 ( 陣的初始值可取一個(-1,1)之間的數)了!
讓我們來重新看一下文章開頭部分的代碼,是不是有一種恍然大明白的感覺!現在快動手來嘗試一下吧~~
(如有疏漏,歡迎指正!)
推薦閱讀:
※模型監控構建方案
※My First Machine Learning Study Notes
※Accuracy,Precision, Recall, F-score,以及ROC曲線的總結
※深度模型訓練時間預估