序言:現現在深度學習如日中天,CNN擅長圖像分類,RNN擅長語音識別,GAN用於生成一些有意思的圖片,YOLO、SSD等改進的算法層出不窮,又有幾我的能靜下心,仔細研讀BP神經網絡呢。筆者認爲,BP神經網絡是一切神經網絡之根本,就算談不上根本,BP神經網絡的前向傳遞,後向調參數的思想也影響了幾乎全部神經網絡模型的計算過程。鑑於此,本篇文章筆者就認真的談一談BP神經網絡,儘可能寫的言簡意賅,努力作到不誤人子弟。算法
神經網絡基本概念BP神經網絡推理 (1)前向傳遞 (2)損失函數 (3)梯度降低 (4)反向傳播BP神經網絡分類舉例 (1)數據集 (2)BP神經網絡模型的完整代碼(3)BP神經網絡分類結果
編程
神經網絡:這個名詞的解釋要分紅兩部分神經+網絡。(1)神經這個詞出如今生物學中,神經元受到刺激,電位發生變化,達到必定閾值就會將電信號繼續傳遞下去,最終傳到大腦作出反應(哈哈,筆者上高中那會兒殘存的一些記憶)。(2)網絡這個詞,不是指咱們生活中的互聯網的網絡,而是數據結構中定義的網狀結構。結合在一塊兒解釋爲,人們構建了一個模型,原理相似於神經元模型,形狀像一張網,因此起名爲神經網絡。圖1簡單展現了一張神經網絡的圖。網絡
圖1 神經網絡結構圖數據結構
深度神經網絡:神經網絡中隱藏層超過兩層的神經網絡被稱爲深度神經網絡。app
機器學習:機器學習是一種可以賦予機器學習的能力以此讓它完成直接編程沒法完成的功能的方法。但從實踐的意義上來講,機器學習是一種經過利用數據,訓練模型,而後使用模型進行預測的方法。dom
深度學習:這個名詞聽起來很高大上,讓人摸不着頭腦,可是筆者將起放開來讀,讀者就一目瞭然了。深度學習就是「基於深度神經網絡模型的機器學習」。機器學習
上邊幾個概念搞清楚,之後就不會輕易的被一些概念名詞糊弄住。函數
BP(back propagation)神經網絡是1986年由Rumelhart和McClelland提出的概念,是一種按照偏差逆向傳播算法訓練的多層前饋神經網絡。主要包含前向傳遞和後向調參兩個過程,下邊就涉及到的幾個概念進行簡要討論。學習
圖2 前向傳遞過程測試
圖2描述的是前向傳遞的過程,上圖中包含三層,分別是輸入層、隱藏層和輸出層,輸入的數據包含兩個維度,輸出數據也包含兩個維度,通常狀況下,輸出的維度就是分類的類別數。
前向傳遞到達輸出層,就計算出了模型的預測值,那麼如何計算預測值與真實值之間的偏離程度呢,就須要用到損失函數來衡量。下邊介紹幾個常見的損失函數:
0-1損失函數:若是預測值與真實值同樣,損失值爲0,相反則損失之爲1。表示成公式以下:
對值損失函數:損失值等於預測值與真實值之差的絕對值。表示成公式以下:
均方差損失函數:損失值與真實值之差取平方,再除以樣本數。表示成公式以下:
(3)梯度降低
當有了若干輸入-輸出對,也選擇了評估模型輸出結果與真實結果差值的損失函數以後,如何來調整神經網絡中的參數,來提升神經網絡的精度呢?比較經典的方法是採用梯度降低法來對神經網絡中的參數進行優化,下文簡要介紹一下梯度降低。梯度降低法的迭代公式以下(公式1):
其中和bi是要優化的神經網絡中的參數,表示損失函數,是損失函數對的偏導數,是損失函數對bi的偏導數,a學習率。
最簡單的狀況,就是輸入一個樣本,根據上邊公式調整一下參數,直到知足某種條件停止。也能夠對一批樣本進行處理,設置一個固定大小的batch_size,將batch_size個樣本的值相加取平均後,再更新參數。
經過上邊幾步的討論,第一步前向傳遞獲得模型預測結果,第二步根據預測結果計算預測偏差(經過損失函數),第三步經過梯度降低等最優化方法調整網絡中參數。當網絡中有多層的時候,如何方便的求出損失函數對每一個參數的導數呢?一個簡單有效的方法就是反向傳播。反向傳播的迭代公式以下(公式2):
公式2含義跟公式1含義基本同樣,l表示的是神經網絡中的第幾層,表示鏈接l的第j個節點到l+1層的第i個節點的權值,表示第l+1層的第i個節點的偏置項的值。
從公式2中能夠看出,只要獲得了和的值,就能夠根據梯度降低逐層更新神經網絡的權值了。爲了方便計算,引入了一個叫「殘差」的值,其定義是損失函數對l層的第i個神經元的偏導數。用公式表示爲:
根據鏈式求導法則:
是前向傳遞時候計算出來的,所以要經過公式2去逐層更新參數的重擔就落在了殘差 身上。反向調參的總體流程如圖3所示:
圖3 反向調參流程圖
文章寫到這個地方筆者也比較累了,在此再專門的捋一下BP網絡計算的思路:
▪ 給定一個樣本(x,y),首先經過前向計算,逐層計算,直到輸出。
▪ 一層一層的計算殘差.
▪ 根據殘差值計算損失值對權值的導數,而後跟新權值。
本文采用的是iris數據集,包含150個樣本。每一個樣本包含四個特徵和一個樣本的類別信息,該數據集是一個150行5列的二維表(關注公衆號,回覆「BP數據」,便可獲取訓練數據集)。
1# _*_ coding:utf-8 _*_
2#https://blog.csdn.net/li_huifei/article/details/78675032
3import math
4import random
5from sklearn.decomposition import PCA
6from sklearn.model_selection import train_test_split
7import matplotlib.pyplot as plt
8import matplotlib as mpl
9import numpy as np
10from sklearn.metrics import accuracy_score
11
12def trtype(s):#定義類別轉換函數
13 types = {'Iris-setosa': 0, 'Iris-versicolor': 1, 'Iris-virginica': 2}
14 return types[s]
15
16# data = np.loadtxt('iris.data',delimiter=',',converters={4:trtype})#讀入數據,第五列轉換爲類別012
17data = np.loadtxt('data.txt',delimiter=',',converters={4:trtype})#讀入數據,第五列轉換爲類別012
18
19x,y = np.split(data,(4,),axis=1)#切分data和label
20
21pca=PCA(n_components=2) #主成分分析
22x=pca.fit_transform(x) #爲方便繪圖,對x進行PCA降維至二維
23#劃分測試集和訓練集
24def label_tr(y):#標籤轉換,將一維標籤轉換爲三維
25 l = {0:[1,0,0],1:[0,1,0],2:[0,0,1]}
26 ys = []
27 for i in range(len(y)):
28 ys.append(l[int(y[i])])
29 return np.array(ys)
30
31def inv_label_tr(y_1d):#標籤轉換逆過程
32 y_pres = []
33 for i in range(y_1d.shape[0]):
34 for j in range(3):
35 if (y_1d[i][j]==1):
36 y_lable = j
37 y_pres.append(y_lable)
38
39 return np.array(y_pres)
40
41y = label_tr(y)
42
43#劃分數據(將數據劃分紅訓練集和測試集)
44x_train, x_test, y_train, y_test = train_test_split(x, y, random_state=1, train_size=0.6)
45
46# print y_train
47
48random.seed(0)
49
50
51def rand(a, b):#隨機數函數
52 return (b - a) * random.random() + a
53
54
55def make_matrix(m, n, fill=0.0):#矩陣生成函數
56 mat = []
57 for i in range(m):
58 mat.append([fill] * n)
59 return mat
60
61
62def sigmoid(x):#激活函數
63 return 1.0 / (1.0 + math.exp(-x))
64
65
66def sigmoid_derivative(x):#激活函數求導
67 return x * (1 - x)
68
69
70class BPNeuralNetwork:#BP神經網絡類
71 def __init__(self):#初始化
72 self.input_n = 0
73 self.hidden_n = 0
74 self.output_n = 0
75 self.input_cells = []
76 self.hidden_cells = []
77 self.output_cells = []
78 self.input_weights = []
79 self.output_weights = []
80 self.input_correction = []
81 self.output_correction = []
82
83
84 def setup(self, ni, nh, no):
85 #初始化輸入、隱層、輸出元數
86 self.input_n = ni + 1
87 self.hidden_n = nh
88 self.output_n = no
89 # 初始化神經元
90 self.input_cells = [1.0] * self.input_n
91 self.hidden_cells = [1.0] * self.hidden_n
92 self.output_cells = [1.0] * self.output_n
93 # 初始化權重矩陣
94 self.input_weights = make_matrix(self.input_n, self.hidden_n)
95 self.output_weights = make_matrix(self.hidden_n, self.output_n)
96 # 初始化權重
97 for i in range(self.input_n):
98 for h in range(self.hidden_n):
99 self.input_weights[i][h] = rand(-0.2, 0.2)
100 for h in range(self.hidden_n):
101 for o in range(self.output_n):
102 self.output_weights[h][o] = rand(-2.0, 2.0)
103 # 初始化偏置
104 self.input_correction = make_matrix(self.input_n, self.hidden_n)