深度学习系列:全连接神经网络和BP算法
前言
注:以后我的文章會寫在個人博客網站上,本站文章也已被搬運。本文地址:
https://xiaodongfan.com/%E6%B7%B1%E5%BA%A6%E5%AD%A6%E4%B9%A0%E7%B3%BB%E5%88%97-%E4%BA%8C-%EF%BC%9A%E5%85%A8%E8%BF%9E%E6%8E%A5%E7%A5%9E%E7%BB%8F%E7%BD%91%E7%BB%9C%E5%92%8CBP%E7%AE%97%E6%B3%95.html
上篇介紹了深度學習框架pytorch的安裝以及神經網絡的基本單元:感知機。本文將介紹全連接神經網絡(FCNet)的結構和訓練方法,全連接神經網絡是一種典型的前饋網絡。感知機解決不了非線性分類問題,但是多層神經元疊加在一起理論上可以擬合任意的非線性連續函數映射。
全連接網絡
全連接網絡是一種前饋網絡,由輸入層、輸出層和若干個隱層組成。如下圖所示,輸入層由ddd個神經元組成,用于輸入樣本的各個特征值;網絡可以存在若干個隱層,每個隱層的神經元個數也是不確定的;輸出層由lll個神經元組成,lll就是最后要分類的類別數。因此神經網絡由很多層構成。
神經元之間的連接方式為:同一層之間的神經元沒有連接關系,每一層的神經元和下一層的所有神經元連接。每兩個連接的神經元之間都有一個連接權重,這里記第iii個神經元和下一層第jjj個神經元的權重為ωij\omega_{ij}ωij?。
以上圖中只有一個隱層的神經網絡為例,隱層的第hhh個神經元的輸入可以表示為:
αh=∑i=1dvihxi\alpha_h = \sum_{i=1}^d v_{ih}x_i αh?=i=1∑d?vih?xi?
其輸出則是輸入經過激活函數fff作用在輸入上,這里取激活函數為Sigmoid函數:
sigmoid(x)=11+e?xsigmoid(x) = \frac{1}{1+e^{-x}} sigmoid(x)=1+e?x1?
之前我們使用的是階躍函數,Sigmoid也是一個非線性函數,它有一個很好的性質就是它的導數可以用自己本身來表示:
y′=y(1?y)y'=y(1-y) y′=y(1?y)
階躍函數和Sigmoid的函數圖如下:
這樣全連接網絡的輸出計算也就是前向傳播的過程為:首先通過輸入層計算得到第一個隱層的輸出,第iii個神經元至第hhh個神經元的計算公式為:
output=f(∑i=1dvihxi)output = f( \sum_{i=1}^d v_{ih}x_i) output=f(i=1∑d?vih?xi?)
然后通過第一個隱層計算下一個隱層的值,最后傳播到輸出層,最后得到神經網絡的輸出y^=(y^1,y^2,...,y^l)\mathbf {\hat y}=(\hat y_1, \hat y_2, ... ,\hat y_l)y^?=(y^?1?,y^?2?,...,y^?l?)
神經網絡訓練 BP算法
對上面介紹的神經網絡應該怎么訓練呢?應該怎么找到最適合一個數據集分類的各個神經元之間連接的權重ωij\omega_{ij}ωij?呢?反向傳播算法(Back Propagation)提供了解決方法。
訓練的思路同樣是梯度下降算法,我們定義一個損失函數LLL,通過朝著損失函數下降最快的方向也就是梯度方向去調整我們的權重系數。損失函數可以為均方誤差:
E=12∑j=1m(y^j?yj)2E=\frac{1}{2} \sum_{j=1}^m (\hat y_j - y_j)^2 E=21?j=1∑m?(y^?j??yj?)2
接下來的問題就是求損失函數EEE對需要訓練的權重系數的梯度?E?ωij\frac {\partial E}{\partial \omega_{ij}}?ωij??E?。
輸出層權重訓練
首先從隱層至輸出層的連接權重ωhj\omega _{hj}ωhj?為例進行推導。這個求梯度的過程就是鏈式求導法則,首先我們分析一下ωhj\omega_ {hj}ωhj?是如何影響到我們的損失函數EEE的,ωhj\omega_ {hj}ωhj?首先影響了第jjj個輸出層神經元的輸入值βj\beta_jβj?,然后進而通過激勵函數Sigmoid影響到其輸出值y^j\hat y_jy^?j?,然后影響到EEE。
這個求導過程為:
?E?ωhj=?E?y^j×?y^j?βj×?βj?ωhj\frac {\partial E}{\partial \omega_{hj}} = \frac {\partial E}{\partial {\hat y_j}} \times \frac{\partial {\hat y_j}}{\partial \beta_j} \times \frac{\partial \beta_j}{\partial \omega_{hj}} ?ωhj??E?=?y^?j??E?×?βj??y^?j??×?ωhj??βj??
我們分別來分析這三項:
第一項:
將上面EEE的表達式代入?E?y^j\frac {\partial E}{\partial {\hat y_j}}?y^?j??E?:
?E?y^j=?y^j12∑j=1m(y^j?yj)2=?(yj?y^j)\frac {\partial E}{\partial {\hat y_j}} = \frac{\partial}{{\hat y_j}} \frac{1}{2} \sum_{j=1}^m (\hat y_j - y_j)^2 = -(y_j - \hat y_j) ?y^?j??E?=y^?j???21?j=1∑m?(y^?j??yj?)2=?(yj??y^?j?)
第二項:
這一項是神經元輸出對輸入求導,實際上就是Sigmoid求導:
?y^j?βj=yj(1?yj)\frac{\partial {\hat y_j}}{\partial \beta_j} = y_j(1-y_j) ?βj??y^?j??=yj?(1?yj?)
第三項:
這一項是神經元的輸入對權重求導,實際上就等于上一個神經元的值bhb_hbh?:
?βj?ωhj=bh\frac{\partial \beta_j}{\partial \omega_{hj}} = b_h ?ωhj??βj??=bh?
所以根據梯度下降規則更新權重過程為:
ωhj←ωhj?η?E?ωhj\omega_{hj} \gets \omega_{hj} - \eta \frac {\partial E}{\partial \omega_{hj}} ωhj?←ωhj??η?ωhj??E?
=ωji+η(yj?y^j)yj(1?yj)bh=ηδjbh=\omega_ji + \eta (y_j - \hat y_j) y_j(1-y_j) b_h = \eta \delta_j b_h =ωj?i+η(yj??y^?j?)yj?(1?yj?)bh?=ηδj?bh?
上式中的δj\delta_jδj?我們定義為:
δj=(yj?y^j)yj(1?yj)\delta_j = (y_j - \hat y_j) y_j(1-y_j) δj?=(yj??y^?j?)yj?(1?yj?)
隱層權重訓練
隱層神經元權系數vihv_{ih}vih?首先影響bhb_hbh?神經元的輸入αh\alpha_hαh?,進而影響輸出。
?E?vih=?E?bh×?bh?αh=∑j=1l?E?βj×?βj?bh×bh(1?bh)\frac{\partial E}{\partial{v_{ih}}} = \frac{\partial E}{\partial b_h} \times \frac{\partial b_h}{\partial \alpha_h} = \sum_{j=1}^l \frac{\partial E}{\partial \beta_j} \times \frac{\partial \beta_j}{\partial b_h} \times b_h(1-b_h) ?vih??E?=?bh??E?×?αh??bh??=j=1∑l??βj??E?×?bh??βj??×bh?(1?bh?)
=bh(1?bh)∑j=1lωhjδj=b_h(1-b_h) \sum_{j=1}^l \omega_{hj} \delta_j =bh?(1?bh?)j=1∑l?ωhj?δj?
至此,我們求出了損失函數對輸出層權重系數的梯度和對隱層權重系數的梯度,然后就可以根據梯度下降算法對我們的網絡進行訓練了。
反向傳播算法原理比較簡單,推到起來由于標號復雜顯得繁瑣,后面我們訓練網絡不怎么關心反向傳播的內部求解過程,因為pytorch提供了自動求導的功能,這一點讓使用者著重于自己的網絡結構構建和參數調節,十分方便!!
花這么大功夫敲公式推導BP算法只是為了讓讀者對訓練的過程有個清楚的理解,接下來在pytorch中實戰一個簡單的全連接網絡。
Pytorch 全連接網絡實現
Pytorch 上手非常容易,這里有個翻譯版的60min入門:https://www.jianshu.com/p/889dbc684622
使用的數據集為Mnist手寫數字,訓練集有60000個樣本,測試集有10000個樣本,首先我們建立一個工程并下載數據集如下:
torch里面有MNIST數據集,所以直接調用datasets.MNIST下載就行了,然后將得到的數據集用DataLoader類裝起來,這個對象參數中的batch_size為每一批的樣本個數,也就是訓練時一次性裝載進內存的數據,shuffle是將數據集順序打亂的操作。
這段代碼的運行輸出:
可以看到打印出的Tensor是四維的一個數組,以后我們進入神經網絡的都是一個四維的Tensor,第一維為batch_size,后面三維為圖像的CWH,也就是顏色通道數和圖像的長寬。MNIST是黑白的數據集,所以顏色通道為1,彩圖為3.
裝載完數據就可以進行神經網絡的構建了。
不熟悉pytorch建議先看看上面的教程,上手很快,這個框架也給了我們很多便利,搭建神經網絡十分簡單。
上述代碼搭建的是一個最簡單的三層的全連接網絡,輸入層神經元為28*28也就是每張圖的像素個數,有一個隱層為100個神經元,輸出層為10個神經元對應10類數字。代碼注釋比較詳細,這里不細說。
最后訓練的結果:
這里可以看到,經過10輪的訓練之后,網絡對測試集的準確率達到了0.92,這還僅僅是一個最簡單的三層全連接網絡!!可見神經網絡的強大。
這里要注意的就是,網絡的訓練都是前幾輪損失函數值下降的很快,準確率上升也快,后面損失函數就不怎么下降了,這也意味著我們的模型正在逐漸收斂。由于網絡簡單且圖片較小,網絡的訓練很快,特別是使用GPU的話。
我這里20輪訓練之后,準確率達到了94%,但是一直訓練下去的話會發現網絡準確率不再上升,這是因為網絡的結構本身比較簡單,學習能力有限,之后我們會使用卷積神經網絡對這個數據集進行分類,能夠達到更高的準確率。
總結
本篇主要介紹了全連接神經網絡的基本結構以及著名的反向傳播算法(BP)的原理推導,最后使用pytorch實現了一個最簡單的全連接神經網絡對MNIST手寫數據集進行分類,實例中的代碼已經上傳至github:https://github.com/Fanxiaodon/nn/tree/master/FCNetMnist
全連接神經網絡存在一些缺陷,后面我們會提到,下篇介紹卷積神經網絡CNN,CNN相比全連接網絡有一些較大的優點,廣泛應用于圖像處理。
本文中的理論推導部分參考:周志華-《機器學習》
總結
以上是生活随笔為你收集整理的深度学习系列:全连接神经网络和BP算法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 高度坍塌的几种解决方法
- 下一篇: SequoiaDB分布式数据库2022.