姓名 郭宇
學(xué)號 16130130299
轉(zhuǎn)載自
【深度學(xué)習(xí)系列?自己手寫一個卷積神經(jīng)網(wǎng)絡(luò)】
http://m.toutiaocdn.net/group/6491421372814721549/?iid=18102364373&app=news_article&tt_from=android_share&utm_medium=toutiao_android&utm_campaign=client_share
【嵌牛導(dǎo)讀】如何自己寫一個卷積神經(jīng)網(wǎng)絡(luò)以及掌握一些技巧
【嵌牛鼻子】人工智能 機器學(xué)習(xí)
【嵌牛提問】怎樣進一步理解卷積神經(jīng)網(wǎng)絡(luò)
【嵌牛正文】卷積神經(jīng)網(wǎng)絡(luò)的前向傳播
首先我們來看一個最簡單的卷積神經(jīng)網(wǎng)絡(luò):
1.輸入層---->卷積層
以上一節(jié)的例子為例,輸入是一個4*4 的image,經(jīng)過兩個2*2的卷積核進行卷積運算后,變成兩個3*3的feature_map
以卷積核filter1為例(stride = 1 ):
計算第一個卷積層神經(jīng)元o11的輸入:
神經(jīng)元o11的輸出:(此處使用Relu激活函數(shù))
其他神經(jīng)元計算方式相同
2.卷積層---->池化層
計算池化層m11 的輸入(取窗口為 2 * 2),池化層沒有激活函數(shù)
3.池化層---->全連接層
池化層的輸出到flatten層把所有元素“拍平”,然后到全連接層。
4.全連接層---->輸出層
全連接層到輸出層就是正常的神經(jīng)元與神經(jīng)元之間的鄰接相連,通過softmax函數(shù)計算后輸出到output,得到不同類別的概率值,輸出概率值最大的即為該圖片的類別。
卷積神經(jīng)網(wǎng)絡(luò)的反向傳播
傳統(tǒng)的神經(jīng)網(wǎng)絡(luò)是全連接形式的,如果進行反向傳播,只需要由下一層對前一層不斷的求偏導(dǎo),即求鏈?zhǔn)狡珜?dǎo)就可以求出每一層的誤差敏感項,然后求出權(quán)重和偏置項的梯度,即可更新權(quán)重。而卷積神經(jīng)網(wǎng)絡(luò)有兩個特殊的層:卷積層和池化層。池化層輸出時不需要經(jīng)過激活函數(shù),是一個滑動窗口的最大值,一個常數(shù),那么它的偏導(dǎo)是1。池化層相當(dāng)于對上層圖片做了一個壓縮,這個反向求誤差敏感項時與傳統(tǒng)的反向傳播方式不同。從卷積后的feature_map反向傳播到前一層時,由于前向傳播時是通過卷積核做卷積運算得到的feature_map,所以反向傳播與傳統(tǒng)的也不一樣,需要更新卷積核的參數(shù)。下面我們介紹一下池化層和卷積層是如何做反向傳播的。
在介紹之前,首先回顧一下傳統(tǒng)的反向傳播方法:
卷積層的反向傳播
由前向傳播可得:
首先計算輸入層的誤差項δ11:
觀察一下上面幾個式子的規(guī)律,歸納一下,可以得到如下表達式:
此時我們的誤差敏感矩陣就求完了,得到誤差敏感矩陣后,即可求權(quán)重的梯度。
推論出權(quán)重的梯度:
誤差項的梯度:
可以看出,偏置項的偏導(dǎo)等于這一層所有誤差敏感項之和。得到了權(quán)重和偏置項的梯度后,就可以根據(jù)梯度下降法更新權(quán)重和梯度了。
池化層的反向傳播
池化層的反向傳播就比較好求了,看著下面的圖,左邊是上一層的輸出,也就是卷積層的輸出feature_map,右邊是池化層的輸入,還是先根據(jù)前向傳播,把式子都寫出來,方便計算:
這樣就求出了池化層的誤差敏感項矩陣。同理可以求出每個神經(jīng)元的梯度并更新權(quán)重。
手寫一個卷積神經(jīng)網(wǎng)絡(luò)
1.定義一個卷積層
首先我們通過ConvLayer來實現(xiàn)一個卷積層,定義卷積層的超參數(shù)
其中calculate_output_size用來計算通過卷積運算后輸出的feature_map大小
2.構(gòu)造一個激活函數(shù)
此處用的是RELU激活函數(shù),因此我們在activators.py里定義,forward是前向計算,backforward是計算公式的導(dǎo)數(shù):
其他常見的激活函數(shù)我們也可以放到activators里,如sigmoid函數(shù),我們可以做如下定義:
如果我們需要自動以其他的激活函數(shù),都可以在activator.py定義一個類即可。
3.定義一個類,保存卷積層的參數(shù)和梯度
4.卷積層的前向傳播
1).獲取卷積區(qū)域
2).進行卷積運算
3).增加zero_padding
4).進行前向傳播
其中element_wise_op函數(shù)是將每個組的元素對應(yīng)相乘
5.卷積層的反向傳播
1).將誤差傳遞到上一層
2).保存?zhèn)鬟f到上一層的sensitivity map的數(shù)組
3).計算代碼梯度
4).按照梯度下降法更新參數(shù)
6.MaxPooling層的訓(xùn)練
1).定義MaxPooling類
2).前向傳播計算
3).反向傳播計算
完整代碼請見:cnn.py(https://github.com/huxiaoman7/PaddlePaddle_code/blob/master/1.mnist/cnn.py)
最后,我們用之前的4 * 4的image數(shù)據(jù)檢驗一下通過一次卷積神經(jīng)網(wǎng)絡(luò)進行前向傳播和反向傳播后的輸出結(jié)果:
運行一下:
運行結(jié)果:
總結(jié)
本文主要講解了卷積神經(jīng)網(wǎng)絡(luò)中反向傳播的一些技巧,包括卷積層和池化層的反向傳播與傳統(tǒng)的反向傳播的區(qū)別,并實現(xiàn)了一個完整的CNN,后續(xù)大家可以自己修改一些代碼,譬如當(dāng)水平滑動長度與垂直滑動長度不同時需要怎么調(diào)整等等。