自己寫一個卷積神經(jīng)網(wǎng)絡(luò)

姓名 郭宇

學(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)整等等。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容