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