BP神經網絡

序言:現現在深度學習如日中天,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神經網絡推理

BP(back propagation)神經網絡是1986年由Rumelhart和McClelland提出的概念,是一種按照偏差逆向傳播算法訓練的多層前饋神經網絡。主要包含前向傳遞和後向調參兩個過程,下邊就涉及到的幾個概念進行簡要討論。學習

(1)前向傳遞

 

圖2 前向傳遞過程測試

       圖2描述的是前向傳遞的過程,上圖中包含三層,分別是輸入層、隱藏層和輸出層,輸入的數據包含兩個維度,輸出數據也包含兩個維度,通常狀況下,輸出的維度就是分類的類別數。

(2)損失函數

前向傳遞到達輸出層,就計算出了模型的預測值,那麼如何計算預測值與真實值之間的偏離程度呢,就須要用到損失函數來衡量。下邊介紹幾個常見的損失函數:
       0-1損失函數:若是預測值與真實值同樣,損失值爲0,相反則損失之爲1。表示成公式以下:

對值損失函數:損失值等於預測值與真實值之差的絕對值。表示成公式以下:

       均方差損失函數:損失值與真實值之差取平方,再除以樣本數。表示成公式以下:

(3)梯度降低

當有了若干輸入-輸出對,也選擇了評估模型輸出結果與真實結果差值的損失函數以後,如何來調整神經網絡中的參數,來提升神經網絡的精度呢?比較經典的方法是採用梯度降低法來對神經網絡中的參數進行優化,下文簡要介紹一下梯度降低。梯度降低法的迭代公式以下(公式1):

其中和bi是要優化的神經網絡中的參數,表示損失函數,是損失函數對的偏導數,是損失函數對bi的偏導數,a學習率。

   最簡單的狀況,就是輸入一個樣本,根據上邊公式調整一下參數,直到知足某種條件停止。也能夠對一批樣本進行處理,設置一個固定大小的batch_size,將batch_size個樣本的值相加取平均後,再更新參數。

(4)反向傳播

經過上邊幾步的討論,第一步前向傳遞獲得模型預測結果,第二步根據預測結果計算預測偏差(經過損失函數),第三步經過梯度降低等最優化方法調整網絡中參數。當網絡中有多層的時候,如何方便的求出損失函數對每一個參數的導數呢?一個簡單有效的方法就是反向傳播。反向傳播的迭代公式以下(公式2):

公式2含義跟公式1含義基本同樣,l表示的是神經網絡中的第幾層,表示鏈接l的第j個節點到l+1層的第i個節點的權值,表示第l+1層的第i個節點的偏置項的值。

從公式2中能夠看出,只要獲得了的值,就能夠根據梯度降低逐層更新神經網絡的權值了。爲了方便計算,引入了一個叫「殘差」的值,其定義是損失函數對l層的第i個神經元的偏導數。用公式表示爲:

根據鏈式求導法則:

        是前向傳遞時候計算出來的,所以要經過公式2去逐層更新參數的重擔就落在了殘差 身上。反向調參的總體流程如圖3所示:

圖3 反向調參流程圖

文章寫到這個地方筆者也比較累了,在此再專門的捋一下BP網絡計算的思路:
▪ 給定一個樣本(x,y),首先經過前向計算,逐層計算,直到輸出。
▪ 一層一層的計算殘差.
▪ 根據殘差值計算損失值對權值的導數,而後跟新權值。

BP神經網絡分類舉例

(1)數據集

本文采用的是iris數據集,包含150個樣本。每一個樣本包含四個特徵和一個樣本的類別信息,該數據集是一個150行5列的二維表(關注公衆號,回覆「BP數據」,便可獲取訓練數據集)。

(2)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)
105        self.output_correction = make_matrix(self.hidden_n, self.output_n)
106
107
108    def predict(self, inputs):  #inputs是x的一個值
109        # 激活輸入層
110        for i in range(self.input_n - 1):
111            self.input_cells[i] = inputs[i]
112        # 激活隱層
113        for j in range(self.hidden_n):
114            total = 0.0
115            for i in range(self.input_n):
116                total += self.input_cells[i] * self.input_weights[i][j]
117            self.hidden_cells[j] = sigmoid(total)
118        # 激活輸出層
119        for k in range(self.output_n):
120            total = 0.0
121            for j in range(self.hidden_n):
122                total += self.hidden_cells[j] * self.output_weights[j][k]
123            self.output_cells[k] = sigmoid(total)
124        return self.output_cells[:]
125
126
127    def back_propagate(self, case, label, learn, correct):
128        # 反向傳播
129        self.predict(case)
130        # print self.predict(case)
131        # 求輸出偏差
132        output_deltas = [0.0] * self.output_n
133        for o in range(self.output_n):
134            error = label[o] - self.output_cells[o]
135            output_deltas[o] = sigmoid_derivative(self.output_cells[o]) * error
136        # print output_deltas[0]
137        # 求隱層偏差
138        hidden_deltas = [0.0] * self.hidden_n
139        for h in range(self.hidden_n):
140            error = 0.0
141            for o in range(self.output_n):
142                error += output_deltas[o] * self.output_weights[h][o]
143            hidden_deltas[h] = sigmoid_derivative(self.hidden_cells[h]) * error
144        # 更新輸出權重
145        for h in range(self.hidden_n):
146            for o in range(self.output_n):
147                change = output_deltas[o] * self.hidden_cells[h]
148                self.output_weights[h][o] += learn * change + correct * self.output_correction[h][o]
149                self.output_correction[h][o] = change
150        # 更新輸入權重
151        for i in range(self.input_n):
152            for h in range(self.hidden_n):
153                change = hidden_deltas[h] * self.input_cells[i]
154                self.input_weights[i][h] += learn * change + correct * self.input_correction[i][h]
155                self.input_correction[i][h] = change
156        # 求全局偏差
157        error = 0.0
158        for o in range(len(label)):
159            error += 0.5 * (label[o] - self.output_cells[o]) ** 2
160        return error
161
162
163    def train(self, cases, labels, limit=10000, learn=0.05, correct=0.1):
164        #訓練神經網絡
165        for j in range(limit):
166            error = 0.0
167            for i in range(len(cases)):
168                label = labels[i]
169                case = cases[i]
170                error += self.back_propagate(case, label, learn, correct)
171
172    def fit(self,x_test):#離散預測函數用於輸出數據
173        y_pre_1d = []
174        for case in x_test:
175            y_pred = self.predict(case)
176            for i in range(len(y_pred)):
177                if (y_pred[i] == max(y_pred)):
178                    y_pred[i] = 1
179                else: y_pred[i] = 0
180            y_pre_1d.append(y_pred)
181        return inv_label_tr(np.array(y_pre_1d))
182
183
184    def fit2(self,x_test):#連續預測函數用於畫圖
185        y_pre_1d = []
186        for case in x_test:
187            w = np.array([0,1,2])
188            y_pred = self.predict(case)
189            y_pre_1d.append(np.array(y_pred).dot(w.T))
190        return np.array(y_pre_1d)
191
192
193if __name__ == '__main__':#主函數
194    nn = BPNeuralNetwork()
195    nn.setup(2, 5, 3)#初始化
196    # nn.train(x_train, y_train, 100000, 0.05, 0.1)#訓練 
197    nn.train(x_train, y_train, 100, 0.05, 0.1)#訓練 
198
199    y_pre_1d = nn.fit(x_test)#測試
200    y_test_1d = inv_label_tr(y_test)
201    print accuracy_score(y_pre_1d,y_test_1d)#打印測試精度
202
203    #畫圖
204    mpl.rcParams['font.sans-serif'] = [u'SimHei']
205    mpl.rcParams['axes.unicode_minus'] = False
206    cm_light = mpl.colors.ListedColormap(['#FFA0A0', '#A0FFA0', '#A0A0FF'])
207    cm_dark = mpl.colors.ListedColormap(['#AAAAFF', '#FFAAAA','#AAFFAA'])
208
209    x1_min, x1_max = x[:, 0].min(), x[:, 0].max()  # 第0列的範圍
210    x2_min, x2_max = x[:, 1].min(), x[:, 1].max()  # 第1列的範圍
211    x1, x2 = np.mgrid[x1_min:x1_max:200j, x2_min:x2_max:200j] # 生成網格採樣點
212
213    grid_test = np.stack((x1.flat, x2.flat), axis=1)  # 測試點
214    grid_hat = nn.fit2(grid_test)#預測結果
215    grid_hat = grid_hat.reshape(x1.shape)  # 使之與輸入的形狀相同
216    plt.pcolormesh(x1, x2, grid_hat, cmap=cm_light)
217    plt.scatter(x[:, 0], x[:, 1], c=y, edgecolors='k', s=50, cmap=cm_dark)
218    # plt.title(u'BPNN二特徵分類', fontsize=15)
219    plt.title(u'BPNNClassfy', fontsize=15)
220    plt.show()
221print grid_hat.shape

(3)BP神經網絡分類結果

爲了方便做圖,對數據集的維度進行了降維處理,先採用PCA(主成分分析法)將訓練數據降爲二維,而後採用BP網絡進行分類,分類結果以下圖所示:

圖4 BP神經網絡分類效果圖

從圖4清晰看出,總體的分類效果還算不錯,截至當前,機器學習經典分類器已經介紹了兩個,後續會陸續的推出SVM、貝葉斯、決策樹、隨機森林等經典算法,小夥伴們多多支持。

 

相關文章
相關標籤/搜索