接上一篇: 用C語言構(gòu)建一個(gè)數(shù)字識(shí)別卷積神經(jīng)網(wǎng)絡(luò)
1. 深度神經(jīng)網(wǎng)絡(luò)
按照深度學(xué)習(xí)的理論,隨著神經(jīng)網(wǎng)絡(luò)層數(shù)的增加,網(wǎng)絡(luò)擬合復(fù)雜問題的能力也會(huì)增強(qiáng),對(duì)事物特征的挖掘也會(huì)更加深入.這里嘗試構(gòu)建一個(gè)5層深度的神經(jīng)網(wǎng)絡(luò),包括兩個(gè)卷積層和兩個(gè)池化層, 其中輸出層為全連接層,如下圖示:
(如果第一層卷積用16個(gè)核,效果會(huì)更好)
程序中對(duì)應(yīng)配置說明:
conv_layer層: 為3x3的卷積層, 8個(gè)卷積核, 采用valid_padding(不填充),移動(dòng)掃描步長(zhǎng)為1.
maxpool_layer層: 采用2x2最大池化,步長(zhǎng)為2.
convA_layer層: 為3x3的卷積層, 32個(gè)卷積核, 采用valid_padding(不填充),移動(dòng)掃描步長(zhǎng)為1.
maxpoolA_layer層: 采用2x2最大池化,步長(zhǎng)為2.
輸出層output_layer: 一共10個(gè)神經(jīng)元,分別對(duì)應(yīng)0~9數(shù)字的可能性,與展平后的maxpoolA_layer層輸出進(jìn)行全連接.
卷積層的激活函數(shù)都采用func_ReLU,這樣可以很大程度上抑制神經(jīng)網(wǎng)絡(luò)的梯度爆炸和消失問題.
2. 實(shí)驗(yàn)
? 取2萬條訓(xùn)練樣本進(jìn)行訓(xùn)練,訓(xùn)練后再進(jìn)行測(cè)試,其準(zhǔn)確率可超過96%.
?3.問題和心得:
3.1 梯度爆炸和梯度消失
在運(yùn)行本文這個(gè)訓(xùn)練程序的時(shí)候,你可能會(huì)不幸踩到梯度的爆雷,提示"Gradients Explosion!? err is nan or inf!". 不過不要緊, 再來運(yùn)行一遍嘛。也可以將學(xué)習(xí)率調(diào)小一點(diǎn)。
梯度爆炸(或消失)的根本原因是反向傳播的鏈?zhǔn)絺鲗?dǎo)法則,它導(dǎo)致了梯度在反向?qū)訉觽鞑r(shí)會(huì)對(duì)后級(jí)梯度進(jìn)行放大或縮?。绻硞€(gè)節(jié)點(diǎn)上的權(quán)重梯度不幸處在一個(gè)連續(xù)放大(或連續(xù)縮小)的傳導(dǎo)路徑上,那么這個(gè)權(quán)重更新時(shí)就會(huì)被放大(或縮小)到極大(或極小)的數(shù)值從而導(dǎo)致溢出(或變成0).在這里表現(xiàn)為輸出損失值err變成NaN, 或err長(zhǎng)時(shí)間保持基本無變化.
改進(jìn): 在這個(gè)程序中梯度爆炸(或消失)的最終結(jié)果通常會(huì)體現(xiàn)在輸出層func_softmax()函數(shù)的計(jì)算中, 由于e的指數(shù)超級(jí)大(或小)而造成計(jì)算溢出.其實(shí)我們可以提前在softmax公式的分子分母上都先除以一個(gè)大數(shù)(比如e^DBL_MAX_e_EXP),以降低計(jì)算過程中間數(shù)值,而保證最后結(jié)果不變.
3.2 深度神經(jīng)網(wǎng)絡(luò)模型
深度神經(jīng)網(wǎng)絡(luò)并不是簡(jiǎn)單的堆疊網(wǎng)絡(luò)層數(shù),而是要求對(duì)每層的輸入/輸出/結(jié)構(gòu)/參數(shù)量等做合理的配置.不僅要保證層與層之間數(shù)據(jù)流的順暢,還要保證所需特征信息的充分提取和傳導(dǎo).舉個(gè)列子,如果將上面第一層和第二層卷積層的核心數(shù)量都改成16, 那么其總體效果可能還不如一個(gè)三層網(wǎng)絡(luò).如此看來, 一些經(jīng)典的神經(jīng)網(wǎng)絡(luò)模型(如LeNet-5等)都值得我們好好學(xué)習(xí).
3.3 學(xué)習(xí)率
由于我們這里采用了SGD梯度下降學(xué)習(xí)法,因此學(xué)習(xí)曲線會(huì)比較曲折, 相對(duì)batch-GD方法應(yīng)該取更小的學(xué)習(xí)率,這里可以取0.0025(或0.005). 對(duì)于大的學(xué)習(xí)率,踩到梯度雷的概率也會(huì)更大.往往大的學(xué)習(xí)率會(huì)造成輸出損失值大幅度跳動(dòng),不過令人疑惑的是其最終結(jié)果可能會(huì)更好.另外,對(duì)于層數(shù)多的神經(jīng)網(wǎng)絡(luò)也要相應(yīng)選取相對(duì)小的學(xué)習(xí)率.
? ? ? ?另外,還可以實(shí)時(shí)調(diào)整學(xué)習(xí)率,如當(dāng)發(fā)現(xiàn)輸出損失值來回跳動(dòng)時(shí)就將學(xué)習(xí)率減小一半,試驗(yàn)發(fā)現(xiàn)這樣做可以加快收斂速度。在linux下這個(gè)可以簡(jiǎn)單地用kill發(fā)信號(hào)量來實(shí)現(xiàn)。
3.4?訓(xùn)練終止條件的設(shè)置
一般對(duì)于一個(gè)新的模型一時(shí)無法知道它最終的收斂狀況。這時(shí)可以把條件設(shè)得嚴(yán)格一些,如把mean_err<=0.0005作為終止條件;或直接設(shè)定epoch的計(jì)數(shù)值,如300。在經(jīng)過一兩輪訓(xùn)練后我們就會(huì)知道模型的大概收斂值了。 另外,我們也可以用ctrl+c發(fā)個(gè)信號(hào)讓訓(xùn)練終止,但保留此時(shí)的參數(shù)值,直接進(jìn)行下一步驗(yàn)證。
4. 源代碼:
https://github.com/midaszhou/nnc 下載后編譯: make TEST_NAME=test_nnc4
(如果是用git pull更新,那么先make clean)
?文章來源地址http://www.zghlxwxcb.cn/news/detail-637398.html
參考資料:
1. ?MNIST手寫數(shù)字集 http://yann.lecun.com/exdb/mnist/
2. LeNet5 介紹: https://www.cnblogs.com/sinpoo/p/15970402.html
?文章來源:http://www.zghlxwxcb.cn/news/detail-637398.html
?
?
?
?
?
?
到了這里,關(guān)于用C語言構(gòu)建一個(gè)數(shù)字識(shí)別深度神經(jīng)網(wǎng)絡(luò)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!