這一節介紹一完整的手寫數字辨識的範例,使用Tensorflow來實現類似Lenet5的架構。除了使用MNIST數據集來做訓練與測試外,我們將訓練好的模型儲存起來,並用微軟小畫家自行手寫幾張數字來進行實際的辨識預測,最後使用Kaggle網站上的手寫數字數據進行預測,並將結果上傳至kaggle網站上打分數,得到預測的成績。
本文主要提供程式實作,不會再提到太多相關的理論,有關相關的理論,大多可以在最底下之前提過的文章或參考資料閱讀相關理論。這個程式的建立環境是python 3.5 +tensorflow1.10 win10底下使用GPU加速運算,估計跑在Linux或是純CPU運算應該也沒太大問題。
首先來回顧Lenet5的經典架構,如下<圖一>
Lenet5模型是Yann LeCun教授於1998年在論文Gradient-based learning applied to document recognition中提出的,它是第一個成功應用於數字識別問題的卷積神經網路。在MNIST數據集上,Lenet5模型可以達到大約99.2%的正確率,Lenet5模型總共有7層。
有關CNN卷積神經網路的介紹可參閱之前文章:
深度學習(2)--使用Tensorflow實作卷積神經網路(Convolutional neural network,CNN)
<圖一>Lenet5架構
第一層 卷積層(Convolution)
這一層的輸入就是原始圖像像素,Lenet5接受的輸入層大小為32x32x1。第一個卷積層filter的尺寸為5x5,深度為6,不使用zero padding,步長(Stride)為1,故這一層輸出的尺寸為32-5+1=28,深度為6。總共有5x5x1x6+6=156個參數,其中6為bias偏誤。因下一層節點矩陣有28x28x6=4704個節點,每個節點和5x5=25個節點相連,所以本層卷積層總共有4707x(25+1)=122304個連接。
第二層 池化層(Pooling)
這一層的輸入為第一層的輸出,是一28x28x6的節點矩陣,本層採用的filter為2x2,stride=2,故輸出矩陣大小為14x14x6。
第三層 卷積層(Convolution)
本層的輸入矩陣大小為14x14x6,使用的filter為5x5,深度為16,不使用Zero padding,stride=1,本層的輸出矩陣大小為10x10x6。因此本層應該有5x5x6x16+16=2416個參數,
10x10x16x(25+1)=41600個連接。
第四層 池化層(Pooling)
本層的輸入矩陣大小為10x10x16,採用filter為2x2,stride為2,本層的輸出矩陣大小為5x5x16。
第五層 卷積層(Convolution)
本層的輸入矩陣大小為5x5x16,在Lenet5模型的論文終將這一層稱為卷積層,但是因為filter大小即為5x5,所以和全連接層沒有區別,如果將5x5x16節點拉成一個向量,那麼這一層就和全連接層一樣,本層的輸出節點數為120,總共有5x5x16x120+120=48120個參數。
第六層 全連接層
本層的輸入節點數為120個,輸出節點數為84個,參數總共為120x84+84=10164個。
第七層 全連接層
本層的輸入節點數為84個,輸出節點為10個,參數總共為84x10+10=850個。
底下會使用Tensorflow來實現類似Lenet5的架構如下<圖二>
在卷積層因為使用了Zero padding所以,圖像尺寸不會縮小
在程式裡是以padding='SAME'來宣告。
conv1 = tf.nn.conv2d(input_tensor, conv1_weights, strides=[1, 1, 1, 1], padding='SAME')
<圖二>