- 神經網絡簡介
- 博客主要內容
- 神經網絡框架
- 神經網絡前向傳播實例
- 神經網絡反向傳播實例
- 總結
- 引用
一.神經網絡簡介
今天,神經網絡(nerual networks)已經是一個相當大的、多學科交叉的學科領域[1]。它不能用簡單的用“一個算法”,“一個框架”,來總結它的內容。從早期神經元(neuron),到感知器(Perceptron),再到Bp神經網絡,然後到今天的深度學習(deep learning),這是它的大致的一個演變的過程。雖然不同的年代換了不同的說法,不過,大致的思想,比如前向數值傳播,反向誤差傳播等思想是大體一致的。
二.主要內容
本博客主要詳細介紹神經網絡的前向傳播和誤差的傳播過程,通過簡單的只有單層隱藏層的神經網絡,然後利用詳細的數值實例來進行演示。而且,每一個步驟,博主都提供了tensorflow[2]的實現代碼。
三.神經網絡框架
對於一個神經元有
tensorflow的代碼
def multilayer_perceptron(x , weights , bias):
layer_1 = tf.add(tf.matmul(x , weights["h1"]) , bias["b1"])
layer_1 = tf.nn.sigmoid(layer_1)
out_layer = tf.add(tf.matmul(layer_1 , weights["out"]) , bias["out"])
layer_2 = tf.nn.sigmoid(out_layer)
return layer_2
四.神經網絡前向傳播實例
(1)確定輸入數據和GD
X = [[1 , 2] , [3 , 4]]
Y = [[0 , 1] , [0 , 1]]
很明顯 batch_size = 2. 其中第一次batch_size
X1 = 1
X2 = 2
(2)初始化權重和偏執
從圖1看出 weights數目爲8 偏執爲4
weights = {
'h1': tf.Variable([[0.15 , 0.16], [0.17 , 0.18]] , name="h1"),
'out': tf.Variable([[0.15 , 0.16], [0.17 , 0.18]] , name="out")
}
biases = {
'b1': tf.Variable([0.1,0.1] , name="b1"),
'out': tf.Variable([0.1 ,.1] , name="out")
}
(3)前向傳播實例
以第一個神經元爲例:
有
有
最後,得到隱藏層 的輸出
前向傳播的 tensorflow的代碼
import tensorflow as tf
import numpy as np
x = [1 , 2]
weights = [[0.15 , 0.16] , [0.17 , 0.18]]
b = [0.1 , 0.1]
X = tf.placeholder("float" , [None , 2])
W = tf.placeholder("float" , [2 , 2])
bias = tf.placeholder("float" , [None , 2])
mid_value = tf.add(tf.matmul(X , W) , b)
result = tf.nn.sigmoid(tf.add(tf.matmul(X , W) , b))
with tf.Session() as sess:
x = np.array(x).reshape(1 , 2)
print x
b = np.array(b).reshape(1 , 2)
result , mid_value = sess.run([result , mid_value] , feed_dict={X : x , W : weights , bias : b})
print mid_value
print result
同樣的道理,我們得到輸出層的pred
(4)計算誤差
誤差函數的可選擇性很多,本示例使用的均方誤差函數(mean squared error)。
注意和平方誤差的區別,下面是平方誤差(sum-squared error)
根據均方誤差計算產生的誤差:
至此,前向傳播過程完成。
五.神經網絡反向傳播實例
知道了默認的輸出和我們期望產生的誤差,那麼我們就需要根據誤差去優化神經網路的中的參數,而誤差的傳播,參數的更新是從輸出層開始,往前進行的.這種優化方式,叫做反向傳播算法,或者誤差逆傳播算法(BackPropagation,簡稱BP)。Bp算法是神經網絡的核心部分,幾乎所有的神經網絡模型都是通過該算法或者改進算法進行訓練優化的。BP算法是基於梯度下降(gradient descent)策略,以目標的負梯度方向傳播的。
我們給定學習率爲0.5 , 有每次更新。
(1)先更新輸出層的權重(weights)
根據鏈式法則有
第一項爲對均方誤差函數求導數
第二項爲對激活函數的梯度
第三項
所以
進行更新
其他同理
(2)更新bias
根據鏈式法則有
更新
同理
(3)接下來更新隱藏層的weight
那麼有
其中對於總的誤差
有
先求cost1
(其中的有些項在之前已經求過結果了,所以直接拿過來進行計算)
再求cost2
總的
然後計算第二項有
計算第三項有
合併計算
更新
同理,其他
(4)更新隱藏層的bias
同樣根據鏈式法則有
更新
同理更新
六.總結
(1)到此,所有參數更新完畢,那麼在下一個batch[3,4],通過新的參數的前向傳播,產生的誤差爲
比第一次 0.254468的確小了,這也說明了梯度下降的有效性。
(2)我通過計算和代碼的結果是有0.01的誤差,我猜想的原因一個是我計算的錯誤,在一個是數值產生誤差。
其中的錯誤,如果你發現,請給我提示,謝謝!
(3)代碼細節
其中tensorflow中的優化方法
optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(cost)
cost定義
cost = tf.reduce_mean(tf.pow(pred - y , 2))
(4)梯度消失問題(Vanish Gradient Problem)
梯度消失問題是,在訓練的過程中,梯度會變得很小,或者梯度變成了0,以至於參數更新過於緩慢,難以訓練,這個對於過深的神經網絡是不可避免的問題。梯度消失問題是與激活函數有一定的關係,通常我們使用relu或者relu的改進版(比如prelu[3])來緩和梯度消失問題,在我們本次的實例中,我們使用的是ligistic函數,它的導數是小於1的,當然tanh也是導數1的。我們可以從之前的運算中發現,在向後傳到的過程中,都會有。
那麼對於導數小於1的,誤差向後傳到的過程中,自然會越來越小。所以,爲了解決這個問題,比如使用relu(導數爲1)代替ligistic類型的函數,也就緩和了這種問題。
七.引用
[1]周志華.《機器學習》
[2]http://tensorflow.org/
[3]Kaiming He.Delving Deep into Rectifiers: Surpassing Human-Level Performance on ImageNet Classification