BP神經網絡


代碼為MNIST數據集上運行簡單BP神經網絡的python實現。

 

 以下公式和文字來自Wanna_Go的博文 http://www.cnblogs.com/wxshi/p/6077734.html,包含詳盡的描述和推導。

BP神經網絡

單個神經元

  神經網絡是由多個“神經元”組成,單個神經元如下圖所示:

  這其實就是一個單層感知機,輸入是由ξ1 ,ξ2 ,ξ3和Θ組成的向量。其中Θ為偏置(bias),σ為激活函數(transfer function),本文采用的是sigmoid函數,功能與階梯函數(step function)相似控制設神經元的輸出,它的優點是連續可導。

是神經元的輸出,結果為

可以看得出這個“神經元”的輸入-輸出映射其實就是一個邏輯回歸,常用的激活函數還有雙曲正切函數 。

 激活函數

sigmoid:函數

取值范圍為[0,1],它的圖像如下:

求導結果為:

 

tanh函數:

 

取值范圍為[-1,1],圖像如下:

 求導數結果為。本文采用的是sigmoid函數作為激活函數。

神經網絡模型

神經網絡將許多“神經元”聯結在一起,一個神經元的輸出可以是另一個“神經元”的輸入,神經元之間的傳遞需要乘法上兩個神經元對應的權重,下圖就是一個簡單的神經網絡:

這是一個三層的神經網絡,使用圓圈來表示神經元的輸入,“+1”被稱為偏置節點,從左到右依次為輸入層、隱藏層和輸出層,從圖中可以看出,有3個輸入節點、3個隱藏節點和一個輸出單元(偏置不接受輸入)。

本例神經網絡的參數有,其中 是第l層第 j 單元與 l+1層第  \textstyle i 單元之間的聯接參數,即:節點連線的權重,本圖中 是第l+1 層第i單元的偏置項。

向前傳播

  機器學習(有監督)的任務無非是損失函數最小化,BP神經網絡的原理是前向傳播得到目標值(分類),再通過后向傳播對data loss進行優化求出參數。可見最優化部分

   \textstyle a^{(l)}_i 表示\textstyle l 層第 \textstyle i 單元激活值(輸出值)。當 \textstyle l=1 時, \textstyle a^{(1)}_i = x_i ,也就是第 \textstyle i 個輸入值。對於給定參數集 \textstyle W,b ,\textstyle h_{W,b}(x) 來表示神經網絡最后計算輸出的結果。上圖神經網絡計算步驟如下:


 可以看出,神經網絡的核心思想是這一層的輸出乘上相應的權重加上偏置,帶入激活函數后的輸出又是下一層的輸入。用 \textstyle z^{(l)}_i 表示第\textstyle l層第\textstyle i 單元輸入加權和 ,則 。使用向量化表示方法表示,上面的公式可以簡寫為:

 

這些計算步驟就是前向傳播,將計算過程進行推廣,給定第 \textstyle l 層的激活值 \textstyle a^{(l)},第 \textstyle l+1層的激活值\textstyle a^{(l+1)}的計算過程為:

 

反向傳播

在前向傳播中,我們得到了神經網絡的預測值\textstyle h_{W,b}(x),這時候可以通過反向傳播的方法計算出參數

符號定義

神經網絡21.png:第l層第j個節點的輸入。

神經網絡22.png:從第l-1層第i個節點到第l層第j個節點的權值。

神經網絡23.png:Sigmoid激活函數。

神經網絡24.png::第l層第j個節點的偏置。

神經網絡25.png::第l層第j個節點的輸出。

神經網絡26.png::輸出層第j個節點的目標值(label)。

使用梯度下降的方法求解參數,在求解的過程中需要對輸出層和隱藏層分開計算

輸出層權重計算

  給定樣本標簽神經網絡28.png和模型輸出結果神經網絡29.png,輸出層的損失函數為:

神經網絡27.png

這其實就是均方差項,訓練的目標是最小化該誤差,使用梯度下降方法進行優化,對上式子對權重W進行求導:

神經網絡31.png

,整理神經網絡32.png

其中神經網絡37.png=神經網絡36.png帶入神經網絡34.png,對sigmoid求導得:

神經網絡35.png

輸出層第k個節點的輸入神經網絡38.png等於上一層第j個節點的輸出神經網絡39.png乘上神經網絡100.png,即神經網絡38.png=神經網絡39.png神經網絡100.png,而上一層的輸出神經網絡39.png與輸出層的權重變量神經網絡100.png無關,可以看做一個常數,所以直接求導可以得到:

 

所以將神經網絡36.png=神經網絡37.png帶入式子中就得到:

神經網絡43.png

為了方便表示將上式子記作:

神經網絡44.png

其中:

 隱藏層權重計算

采用同樣方法對隱藏層的權重進行計算,與前面不同的是關於隱藏層和前一層權重的調整

神經網絡46.png

整理

神經網絡47.png

替換sigmoid函數

神經網絡48.png

對sigmoid求導

神經網絡49.png

帶入進去,使用求導的鏈式法則:

神經網絡51.png

輸出層的輸入等於上一層的輸入乘以相應的權重,即:於是得到

神經網絡54.png

進行求導(神經網絡37.png=神經網絡36.png,同樣適用於j),

神經網絡56.png

同輸出層計算的方法一樣,再次利用,j換成i,k換成j同樣成立,帶入進去:

神經網絡57.png

整理,得到:

神經網絡59.png

其中:神經網絡45.png

 

 我們還可以仿照神經網絡58.png的定義來定義一個神經網絡60.png,得到:

神經網絡61.png

其中:神經網絡70.png

 偏置調整

  從上面的計算步驟中可以看出:例如,偏置節點是不存在對應的權值參數,也就是不存在關於權值變量的偏導數。

對偏置直接求導:

神經網絡68.png

又有

神經網絡63.png

 

 得到:

神經網絡65.png,其中:神經網絡45.png

BP算法步驟

1. 隨機初始化W和b,需要注意的是,隨機初始化並是不是全部置為0,如果所有參數都是用相同的值初始化,那么所有隱藏單元最終會得到與輸入值相關、相同的函數(也就是說,對於所有 \textstyle i\textstyle W^{(1)}_{ij}都會取相同的值,那么對於任何輸入 \textstyle x 都會有: ),隨機初始化的目的是使對稱失效

2.對每個輸出節點按照這個公式計算delta:

神經網絡71.png

3.對每個隱藏節點按照這個公式計算delta:

神經網絡72.png

4.更新W和b的公式為:

神經網絡73.png

 

並更新參數神經網絡74.png,這里的η是學習率。

 

 1 # coding:utf8
 2 import cPickle
 3 import numpy as np
 4 
 5 
 6 class Network(object):
 7     def __init__(self, sizes):
 8         self.num_layers = len(sizes)
 9         self.sizes = sizes
10         self.biases = [np.random.randn(y, 1) for y in sizes[1:]]  # L(n-1)->L(n)
11         self.weights = [np.random.randn(y, x)
12                         for x, y in zip(sizes[:-1], sizes[1:])]
13 
14     def feedforward(self, a):
15         for b_, w_ in zip(self.biases, self.weights):
16             a = self.sigmoid(np.dot(w_, a)+b_)
17         return a
18 
19     def SGD(self, training_data, test_data,epochs, mini_batch_size, eta):
20         n_test = len(test_data)
21         n = len(training_data)
22         for j in xrange(epochs):
23             np.random.shuffle(training_data)  # shuffle
24             for k in xrange(0, n, mini_batch_size):
25                 mini_batch = training_data[k:k+mini_batch_size]
26                 self.update_mini_batch(mini_batch, eta)
27             print "Epoch {0}: {1} / {2}".format(
28                     j, self.evaluate(test_data), n_test)
29 
30     def update_mini_batch(self, mini_batch, eta):
31         for x, y in mini_batch:
32             delta_b, delta_w = self.backprop(x, y)
33             self.weights -= eta/len(mini_batch)*delta_w
34             self.biases -= eta/len(mini_batch)*delta_b
35 
36     def backprop(self, x, y):
37         b=np.zeros_like(self.biases)
38         w=np.zeros_like(self.weights)
39         a_ = x
40         a = [x]
41         for b_, w_ in zip(self.biases, self.weights):
42             a_ = self.sigmoid(np.dot(w_, a_)+b_)
43             a.append(a_)
44         for l in xrange(1, self.num_layers):
45             if l==1:
46                 delta= self.sigmoid_prime(a[-1])*(a[-1]-y)  # O(k)=a[-1], t(k)=y
47             else:
48                 sp = self.sigmoid_prime(a[-l])   # O(j)=a[-l]
49                 delta = np.dot(self.weights[-l+1].T, delta) * sp
50             b[-l] = delta
51             w[-l] = np.dot(delta, a[-l-1].T)
52         return (b, w)
53 
54     def evaluate(self, test_data):
55         test_results = [(np.argmax(self.feedforward(x)), y)
56                         for (x, y) in test_data]
57         return sum(int(x == y) for (x, y) in test_results)
58 
59     def sigmoid(self,z):
60         return 1.0/(1.0+np.exp(-z))
61 
62     def sigmoid_prime(self,z):
63         return z*(1-z)
64 
65 if __name__ == '__main__':
66 
67         def get_label(i):
68             c=np.zeros((10,1))
69             c[i]=1
70             return c
71 
72         def get_data(data):
73             return [np.reshape(x, (784,1)) for x in data[0]]
74 
75         f = open('mnist.pkl', 'rb')
76         training_data, validation_data, test_data = cPickle.load(f)
77         training_inputs = get_data(training_data)
78         training_label=[get_label(y_) for y_ in training_data[1]]
79         data = zip(training_inputs,training_label)
80         test_inputs = training_inputs = get_data(test_data)
81         test = zip(test_inputs,test_data[1])
82         net = Network([784, 30, 10])
83         net.SGD(data,test,20,10, 3.0,)  # 9496/10000

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM