本文基於您已經瞭解卷積神經網路的基本知識,在此之上介紹LeNet5的原理,以及利用它實現MNIST手寫數字識別。
MNIST資料集
MNIST資料集是一個手寫體資料集,資料集中每一個樣本都是一個0-9的手寫數字。該資料集由四部分組成,訓練圖片集,訓練標籤集,測試圖片集和測試標籤集。其中,訓練集中有60000個樣本,測試集中有10000個樣本。每張照片均為28*28的二值圖片,為方便儲存,官方已對圖片集進行處理,將每一張圖片變成了維度為(1,784)的向量。
LeNet-5
LeNet是一種典型的卷積神經網路的結構,由Yann LeCun發明。它的網路結構如下圖:
LeNet-5共有7層(不包含輸入),每層都包含可訓練引數。
輸入影像大小為32x32,比MNIST資料集的圖片要大一些,這麼做的原因是希望潛在的明顯特徵如筆畫斷點或角能夠出現在最高層特徵檢測子感受野(receptive field)的中心。因此在訓練整個網路之前,需要對28x28的影像加上paddings(即周圍填充0)。
C1層:該層是一個卷積層。使用6個大小為5x5的卷積核對輸入層進行卷積運算,特徵圖尺寸為32-5+1=28,因此產生6個大小為28x28的特徵圖。這麼做夠防止原影像輸入的資訊掉到卷積核邊界之外。
S2層:該層是一個池化層(pooling,也稱為下采樣層)。這裡採用max_pool(最大池化),池化的size定為2x2,池化的具體過程如下圖(圖引自cs231n)
經池化後得到6個14x14的特徵圖,作為下一層神經元的輸入。
C3層:該層仍為一個卷積層,我們選用大小為5x5的16種不同的卷積核。這裡需要注意:C3中的每個特徵圖,都是S2中的所有6個或其中幾個特徵圖進行加權組合得到的。輸出為16個10x10的特徵圖。
S4層:該層仍為一個池化層,size為2x2,仍採用max_pool。最後輸出16個5x5的特徵圖,神經元個數也減少至16x5x5=400。
C5層:該層我們繼續用5x5的卷積核對S4層的輸出進行卷積,卷積核數量增加至120。這樣C5層的輸出圖片大小為5-5+1=1。最終輸出120個1x1的特徵圖。這裡實際上是與S4全連線了,但仍將其標為卷積層,原因是如果LeNet-5的輸入圖片尺寸變大,其他保持不變,那該層特徵圖的維數也會大於1x1。
F6層:該層與C5層全連線,輸出84張特徵圖。為什麼是84?下面有論文的解釋(感謝翻譯)。
輸出層:該層與F6層全連線,輸出長度為10的張量,代表所抽取的特徵屬於哪個類別。(例如[0,0,0,1,0,0,0,0,0,0]的張量,1在index=3的位置,故該張量代表的圖片屬於第三類)
此處為論文對F6層和輸出層的解釋:
輸出層由歐式徑向基函式(Euclidean Radial Basis Function)單元組成,每類一個單元,每個有84個輸入。換句話說,每個輸出RBF單元計算輸入向量和引數向量之間的歐式距離。輸入離引數向量越遠,RBF輸出的越大。一個RBF輸出可以被理解為衡量輸入模式和與RBF相關聯類的一個模型的匹配程度的懲罰項。用概率術語來說,RBF輸出可以被理解為F6層配置空間的高斯分佈的負log-likelihood。給定一個輸入模式,損失函式應能使得F6的配置與RBF引數向量(即模式的期望分類)足夠接近。這些單元的引數是人工選取並保持固定的(至少初始時候如此)。這些引數向量的成分被設為-1或1。雖然這些引數可以以-1和1等概率的方式任選,或者構成一個糾錯碼,但是被設計成一個相應字元類的7*12大小(即84)的格式化圖片。這種表示對識別單獨的數字不是很有用,但是對識別可列印ASCII集中的字串很有用。
使用這種分佈編碼而非更常用的“1 of N”編碼用於產生輸出的另一個原因是,當類別比較大的時候,非分佈編碼的效果比較差。原因是大多數時間非分佈編碼的輸出必須為0。這使得用sigmoid單元很難實現。另一個原因是分類器不僅用於識別字母,也用於拒絕非字母。使用分佈編碼的RBF更適合該目標。因為與sigmoid不同,他們在輸入空間的較好限制的區域內興奮,而非典型模式更容易落到外邊。RBF引數向量起著F6層目標向量的角色。需要指出這些向量的成分是+1或-1,這正好在F6 sigmoid的範圍內,因此可以防止sigmoid函式飽和。實際上,+1和-1是sigmoid函式的最大彎曲的點處。這使得F6單元執行在最大非線性範圍內。必須避免sigmoid函式的飽和,因為這將會導致損失函式較慢的收斂和病態問題。
MNIST手寫體數字識別程式碼實現
基於LeNet-5的原理,我使用了TensorFlow來做了簡單實現。
Features:
- 沒有對中間的神經元使用啟用函式,僅僅對輸出層用了softmax函式,同時增加了dropout來避免過擬合。
- 使用了tensorflow的常規api和封裝好的高層api(tf.contrib)實現了兩個版本。高層api版本無法在我的渣渣GPU(GT745M,2G)上跑,而底層api可以。
- Test accuracy大概徘徊在98.2%~97.5%
程式碼在這裡。
參考資料
Gradient-Based Learning Applied to Document Recognition
CNN - TensorFlow
通俗理解卷積神經網路