2017年7月3日 星期一

深度學習(5)--使用Tensorflow實現類AlexNet手寫數字辨識


 這一節介紹另一手寫數字辨識的範例,這次使用Tensorflow來實現類似Alexnet的架構。跟上一個範例一樣使用MNIST數據集來做訓練與測試。

    上一個範例請參閱:
深度學習(4)--使用Tensorflow實現類Lenet5手寫數字辨識


首先還是先來回顧Alexnet的經典架構,如下<圖一>
    2012年,Hinton的學生Alex Krizhevsky提出了深度卷積神經網絡模型AlexNet,它可以算是LeNet一種更深更廣的版本。AlexNet包含了幾個較新的技術點,也首次在CNN中成功應用了
ReLU,Dropout,LRN等Trick。同時AlexNet也使用了GPU進行了運算加速。
    AlexNet包含了6億三千萬個連接,6000萬個參數和65萬個神經元,擁有五個卷積層,其中3個卷積層後面連接最大池化層,最後還有3個全連接層。AlexNet以顯著的優勢贏得了競爭激烈的ILSVRC 2012比賽,Top-5的錯誤率降低至16.4%,比第二名的成績26.2%錯誤率有了巨大的提升。

<圖一>Alexnet網絡架構




AlexNet將LeNet的思想發揚光大,把CNN的基本原理應用到了很深很廣的網絡中,主要用的
新技術點如下:

(1) 成功使用了ReLU作為CNN的激活函數,並驗證其效果在較深的網絡超過了Sigmoid,成功       解決了Sigmoid在網路較深時梯度瀰散的問題。

(2) 訓練時使用Dropout隨機忽略一部分神經元,以避免過度適合(Overfiting)。在AlexNet中主
      要是最後幾個全連接層使用了Dropout。

(3) 在CNN中使用重疊的最大池化,在此之前CNN中普遍使用平均池化,AlexNet使用最大
      池化,避免平均池化的模糊化效果,並且提出讓步長(Stride)比池化核尺寸(Kernel size)小
      ,這樣池化層的輸出之間會有重疊和覆蓋,可以提升特徵的豐富性。

(4) 提出了LRN層,對局部神經元的活動創建競爭機制,使得其中響應比較大的值變得相對
      更大,並抑制其他反饋較小的神經元,增強了模型泛化能力。

(5) 使用CUDA加速深度卷積神經網路的訓練,利用GPU強大的並行計算能力,處理神經網絡
      訓練時大量的矩陣運算。AlexNet使用了兩塊GTX 580 GPU進行訓練,單個GTX 580只
      有3GB顯存,這限制了可訓練的網路的最大規模。因此作者將AlexNet分布在兩個GPU上,
      在每個GPU顯存中儲存一半的神經元參數。

(6) 數據增強,隨機從256x256的原始圖像中,擷取224x224大小的區域以及水平翻轉的鏡像,
      相當於增加了2048倍的數據量。這樣可以大大減輕過度適合,提升泛化能力。進行預測時,
      則是取圖片的四個角家中間五個位置,並進行左右翻轉,共獲得10張圖片,對他們進行
      預測,並對10次結果求取均值。同時,AlexNet論文中提到會對圖像的RGB數據進行
      PCA處理,並對主成分做一個標準差0.1的高斯擾動,增加一些雜訊,這個Trick可以讓錯
      物率再下降1%。

    整個Alexnet 有八個需要訓練參數的層,不包含池化層及LRN層,前五層為卷積層,後三
層為全連接層,如圖一所示,Alexnet最後一層是有1000類輸出的Softmax層用作分類。LRN出現在第一個及第二個卷積層後,而最大池化層出現在兩個LRN層之後及最後一個卷積層
之後。ReLU激活函數則應用在這8層每一層後面。因為Alexnet訓練時使用兩塊GPU,因此其結構圖中不少組件都被拆為了兩個部分。如果使用新的GPU有較多顯存,可以放下全部模型參數,那麼可以考慮使用一塊GPU的情形即可。

    Alexnet 每層的超參數如下圖二所示,其原本輸入的尺寸為224X224,第一個卷積層使用了
較大的卷積核尺寸11X11,步長為4,有96個卷積核,緊接著一個LRN層及一個3X3的最大
池化層,步長為2。這之後的卷積和尺寸都較小,都是5X5,或是3X3的大小,並且步長皆為1
,而最大池化層依然保持為3X3,步長為2。我們可以發現一個有意思的現象,在前幾個卷積層,雖然計算量很大,但參數量很小,都在1M左右甚至更小,只佔Alexnet總參數量很小的一部份。這就是卷積層有用的地方,可以通過較小的參數量提取有效的特徵。如果前幾層使用全連接層,那麼參數量和計算量將成為天文數字。雖然每一個卷積層佔整個網絡的參數量的1%不到,但是如果去掉任一個卷積層,都會使網絡的分類性能大幅地下降。
 

<圖二>Alexnet網絡架構及參數數量



    
我把我的source code放在底下下連結,主要有三隻檔案:

alexnet_train2.py  :用來訓練AlexNet 模型,定義各個參數,如學習率,Batch size,
     訓練週期,Cost函數,最佳化方式。訓練結果如下圖三
alexnet_inference2.py :用來定義AlexNet網絡的架構,可以參閱上圖二去做比對。只是
     原本AlexNet的輸入圖尺寸為224x224x3,我們這裡因使用MNIST資料,故輸入像素大小
     改為28x28x1,並且第一卷積層的步長從原本的4改為1,其餘後面的架構大致上都跟
     原Alenet一樣。
alexnet_eval2.py :用來評估預測模型,跟上一個Lenet範例一樣,事先將訓練好的
    model參數儲存,即可重複使用訓練好的參數做預測評估。預測結果如下圖四。


#主要參數設定
learning_rate = 0.001 #學習率
BATCH_SIZE = 100 #批次size
display_step = 10      #每隔10個batch顯示一次訓練結果
TRAINING_STEPS=1500 #總共訓練週期
# Network Parameters
n_input = 784 # MNIST data input (img shape: 28*28)
n_classes = 10 # MNIST total classes (0-9 digits)
#在全連接層使用0.5 dropout 
dropout = 0.5# Dropout, probability to keep units

# 定義損失函數及最佳化方式
 cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=pred, labels=y))
 optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(cost)

# 初始化TensorFlow持久化類
saver = tf.train.Saver()
...
print("Save model...")
#saver.save(sess, "./alexnet/alexnet_model")
saver.save(sess, os.path.join(MODEL_SAVE_PATH, MODEL_NAME))

#載入數據集的方式:
一般來說在TensorFlow裡都會用以下方式直接載入MNIST數據集,
#mnist = input_data.read_data_sets("./mnist", one_hot=True)

但是我為了更了解數據集載入的方式,以及為了能使用自己用小畫家創造的數據,所以通常
我都會改成自己定義的Load MNIST的方式,如下,先下載MNIST數據集放置目錄..\MNIST。
X_train, y_train = load_mnist('..\mnist', kind='train')

因此必須自行做資料常態化或是標準化分布,特別如果是使用Sigmoid或是Tanh激活函數,
常態化或是標準化分布後會讓數據數值靠近0,通常分布-2.0~2.0之間,做訓練時經過Sigmoid或是Tanh激活函數可以避免梯度變化不大的問題。
#常態化
mms=MinMaxScaler()
X_train=mms.fit_transform(X_train)
#標準化分布
#stdsc=StandardScaler()
#X_train=stdsc.fit_transform(X_train)
#X_test=stdsc.transform(X_test)

接著必須再將class Label做熱編碼,也就是例如標籤值為2,那麼編碼後變成[0,0,1,0,0,0,0,0,0,0]
y_train_lable = encode_labels(y_train,10)


<圖三>訓練結果

<圖四>預測數據結果




      本範例主要練習使用TensorFlow來實現Alexnet的架構,我是參考下面兩本Tensorflow的書籍自行更改調整他們的範例,也許是使用了圖像尺寸較小的MNIST數據集,並沒有對該數據集或整個模型做一些最佳化的調整,所以可以從訓練結果及預測結果看出有過度適合(Overfitting)的現象,也因此我在這次的範例中就沒有像上次自行再用小畫家產生的數據進行預測,而使用Kaggle的數據進行預測時也有過度適合(Overfitting)的現象預測的結果並不是很好,故在此就不列出相關預測結果,有興趣的人可以再自行最佳化這個模型。如果有改進的做法也歡迎分享給我。



加入阿布拉機的3D列印與機器人的FB專頁
https://www.facebook.com/arbu00/

<參考資料>
[1]書名:Tensorflow 實戰 作者:黃文堅 唐源
[2]書名:TensorFlow 技術解析與實戰 作者:李嘉璇
[3]Alexnet(ImageNet Classification with Deep Convolutional Neural Networks)


<其他相關文章>
人工神經網路(1)--使用Python實作perceptron(感知器)
人工神經網路(2)--使用Python實作後向傳遞神經網路演算法(Backprogation artificial neature network)
深度學習(1)-如何在windows安裝Theano +Keras +Tensorflow並使用GPU加速訓練神經網路
深度學習(2)--使用Tensorflow實作卷積神經網路(Convolutional neural network,CNN)
深度學習(3)--循環神經網絡(RNN, Recurrent Neural Networks)
深度學習(4)--使用Tensorflow實現類Lenet5手寫數字辨識
機器學習(1)--使用OPENCV KNN實作手寫辨識
機器學習(2)--使用OPENCV SVM實作手寫辨識
演算法(1)--蒙地卡羅法求圓周率及橢圓面積(Monte carlo)
機器學習(3)--適應線性神經元與梯度下降法(Adaline neuron and Gradient descent)
機器學習(4)--資料標準常態化與隨機梯度下降法( standardization & Stochastic Gradient descent)
機器學習(5)--邏輯斯迴歸,過度適合與正規化( Logistic regression,overfitting and regularization)
機器學習(6)--主成分分析(Principal component analysis,PCA)
機器學習(7)--利用核主成分分析(Kernel PCA)處理非線性對應
機器學習(8)--實作多層感知器(Multilayer Perceptron,MLP)手寫數字辨識