卷積神經網路(CNN)介紹與實踐

致Great發表於2018-07-19

1 CNN的前生今世

1.1 大腦

作為人類,我們不斷地通過眼睛來觀察和分析周圍的世界,我們不需要刻意的“努力”思考,就可以對所看到的一切做出預測,並對它們採取行動。當我們看到某些東西時,我們會根據我們過去學到的東西來標記每個物件。為了說明這些情況,請看下面這張圖片:

資料來源:https://medium.freecodecamp.org/an-intuitive-guide-to-convolutional-neural-networks-260c2de0a050
你可能會想到“這是一個快樂的小男孩站在椅子上”。或者也許你認為他看起來像是在尖叫,即將在他面前攻擊這塊蛋糕。

這就是我們整天下意識地做的事情。我們看到事物,然後標記,進行預測和識別行為。但是我們怎麼做到這些的呢?我們怎麼能解釋我們看到的一切?

大自然花費了5億多年的時間來建立一個系統來實現這一目標。眼睛和大腦之間的合作,稱為主要視覺通路,是我們理解周圍世界的原因。

視覺通路。- 來源:https://commons.wikimedia.org/wiki/File : Human_visual_pathway.svg
雖然視力從眼睛開始,但我們所看到的實際解釋發生在大腦的初級視覺皮層中

當您看到一個物體時,您眼中的光感受器會通過視神經將訊號傳送到正在處理輸入的主視覺皮層。在初級視覺皮層,使眼睛看到的東西的感覺。

所有這一切對我們來說都很自然。我們幾乎沒有想到我們能夠識別我們生活中看到的所有物體和人物的特殊性。神經元和大腦連線的深層複雜層次結構在記憶和標記物體的過程中起著重要作用。

想想我們如何學習例如傘是什麼。或鴨子,燈,蠟燭或書。一開始,我們的父母或家人告訴我們直接環境中物體的名稱。我們通過給我們的例子瞭解到。慢慢地,但我們開始在我們的環境中越來越多地認識到某些事情。它們變得如此普遍,以至於下次我們看到它們時,我們會立即知道這個物體的名稱是什麼。他們成為我們世界的模型一部分。

1.2 卷積神經網路的歷史

與孩子學會識別物體的方式類似,我們需要在能夠概括輸入並對之前從未見過的影象進行預測之前,展示數百萬張圖片的演算法。

計算機以與我們不同的方式“看到”東西的。他們的世界只包括數字。每個影象都可以表示為二維數字陣列,稱為畫素。

但是它們以不同的方式感知影象,這一事實並不意味著我們無法訓練他們的識別模式,就像我們一樣如何識別影象。我們只需要以不同的方式思考影象是什麼。

計算機如何看到影象。- 來源:http://cs231n.github.io/classification/
為了“教會”一種演算法如何識別影象中的物件,我們使用特定型別的人工神經網路:卷積神經網路(CNN)。他們的名字源於網路中最重要的一個操作:卷積

卷積神經網路受到大腦的啟發。DH Hubel和TN Wiesel在20世紀50年代和60年代對哺乳動物大腦的研究提出了哺乳動物如何在視覺上感知世界的新模型。他們表明貓和猴的視覺皮層包括在其直接環境中專門響應神經元的神經元。

在他們的論文中,他們描述了大腦中兩種基本型別的視覺神經元細胞,每種細胞以不同的方式起作用:簡單細胞(S細胞)和複合細胞(C細胞)。

例如,當簡單單元格將基本形狀識別為固定區域和特定角度的線條時,它們就會啟用。複雜細胞具有較大的感受野,其輸出對野外的特定位置不敏感。

複雜細胞繼續對某種刺激做出反應,即使它在視網膜上的絕對位置發生變化。在這種情況下,複雜指的是更靈活。

視覺中,單個感覺神經元的感受區域是視網膜的特定區域,其中某些東西將影響該神經元的發射(即,將啟用神經元)。每個感覺神經元細胞都有相似的感受野,它們的田地覆蓋著。

神經元的感受野。- 來源:http://neuroclusterbrain.com/neuron_model.html

此外,層級【hierarchy 】的概念在大腦中起著重要作用。資訊按順序儲存在模式序列中。的新皮層,它是大腦的最外層,以分層方式儲存資訊。它儲存在皮質柱中,或者在新皮層中均勻組織的神經元分組。

1980年,一位名為Fukushima的研究員提出了一種分層神經網路模型。他稱之為新認知。該模型的靈感來自簡單和複雜細胞的概念。neocognitron能夠通過了解物體的形狀來識別模式。

後來,1998年,捲心神經網路被Bengio,Le Cun,Bottou和Haffner引入。他們的第一個卷積神經網路稱為LeNet-5,能夠對手寫數字中的數字進行分類。

LeNet-5網路 示意圖1
LeNet-5網路 示意圖2

2 卷積神經網路

卷積神經網路(Convolutional Neural Network)簡稱CNN,CNN是所有深度學習課程、書籍必教的模型,CNN在影像識別方面的為例特別強大,許多影像識別的模型也都是以CNN的架構為基礎去做延伸。另外值得一提的是CNN模型也是少數參考人的大腦視覺組織來建立的深度學習模型,學會CNN之後,對於學習其他深度學習的模型也很有幫助,本文主要講述了CNN的原理以及使用CNN來達成99%正確度的手寫字型識別。 CNN的概念圖如下:

CNN概念圖1
CNN概念圖2
CNN概念圖3
從上面三張圖片我們可以看出,CNN架構簡單來說就是:圖片經過各兩次的Convolution, Pooling, Fully Connected就是CNN的架構了,因此只要搞懂Convolution, Pooling, Fully Connected三個部分的內容就可以完全掌握了CNN!

2.1 Convolution Layer卷積層

卷積運算就是將原始圖片的與特定的Feature Detector(filter)做卷積運算(符號),卷積運算就是將下圖兩個3x3的矩陣作相乘後再相加,以下圖為例0 *0 + 0*0 + 0*1+ 0*1 + 1 *0 + 0*0 + 0*0 + 0*1 + 0*1 =0

卷積運算 1
每次移動一步,我們可以一次做完整張表的計算,如下:
卷積運算 2
下面的動圖更好地解釋了計算過程:
左:過濾器在輸入上滑動。右:結果彙總並新增到要素圖中。

中間的Feature Detector(Filter)會隨機產生好幾種(ex:16種),Feature Detector的目的就是幫助我們萃取出圖片當中的一些特徵(ex:形狀),就像人的大腦在判斷這個圖片是什麼東西也是根據形狀來推測

16種不同的Feature Detector
利用Feature Detector萃取出物體的邊界
利用Feature Detector萃取出物體的邊界
使用Relu函式去掉負值,更能淬鍊出物體的形狀
Relu函式去掉負值
淬鍊出物體的形狀1
淬鍊出物體的形狀2

我們在輸入上進行了多次卷積,其中每個操作使用不同的過濾器。這導致不同的特徵對映。最後,我們將所有這些特徵圖放在一起,作為卷積層的最終輸出。

就像任何其他神經網路一樣,我們使用啟用函式使輸出非線性。在卷積神經網路的情況下,卷積的輸出將通過啟用函式。這可能是ReLU啟用功能

其他函式

這裡還有一個概念就是步長Stride是每次卷積濾波器移動的步長。步幅大小通常為1,意味著濾鏡逐個畫素地滑動。通過增加步幅大小,您的濾波器在輸入上滑動的間隔更大,因此單元之間的重疊更少。

下面的動畫顯示步幅大小為1。

步幅為1
由於feature map的大小始終小於輸入,我們必須做一些事情來防止我們的要素圖縮小。這是我們使用填充的地方。

新增一層零值畫素以使用零環繞輸入,這樣我們的要素圖就不會縮小。除了在執行卷積後保持空間大小不變,填充還可以提高效能並確保核心和步幅大小適合輸入。

視覺化卷積層的一種好方法如下所示,最後我們以一張動圖解釋下卷積層到底做了什麼

卷積如何與K = 2濾波器一起工作,每個濾波器具有空間範圍F = 3,步幅S = 2和輸入填充P = 1. - 來源:http://cs231n.github.io/convolutional-networks/

2.2 Pooling Layer 池化層

在卷積層之後,通常在CNN層之間新增池化層。池化的功能是不斷降低維數,以減少網路中的引數和計算次數。這縮短了訓練時間並控制過度擬合

最常見的池型別是max pooling,它在每個視窗中佔用最大值。需要事先指定這些視窗大小。這會降低特徵圖的大小,同時保留重要資訊。

Max Pooling主要的好處是當圖片整個平移幾個Pixel的話對判斷上完全不會造成影響,以及有很好的抗雜訊功能。

池化層 示意圖 1
池化層 示意圖 2

2.3 Fully Connected Layer 全連線層

基本上全連線層的部分就是將之前的結果平坦化之後接到最基本的神經網路了

卷積神經網路(CNN)介紹與實踐
卷積神經網路(CNN)介紹與實踐
卷積神經網路(CNN)介紹與實踐

3 利用CNN識別MNIST手寫字型

下面這部分主要是關於如何使用tensorflow實現CNN以及手寫字型識別的應用

# CNN 程式碼
def convolutional(x,keep_prob):

    def conv2d(x,W):
        return tf.nn.conv2d(x,W,[1,1,1,1],padding='SAME')

    def max_pool_2x2(x):
        return tf.nn.max_pool(x,ksize=[1,2,2,1],strides=[1,2,2,1],padding='SAME')

    def weight_variable(shape):
        initial=tf.truncated_normal(shape,stddev=0.1)
        return tf.Variable(initial)

    def bias_variable(shape):
        initial=tf.constant(0.1,shape=shape)
        return tf.Variable(initial)

    x_image=tf.reshape(x,[-1,28,28,1])
    W_conv1=weight_variable([5,5,1,32])
    b_conv1=bias_variable([32])
    h_conv1=tf.nn.relu(conv2d(x_image,W_conv1)+b_conv1)
    h_pool1=max_pool_2x2(h_conv1)

    W_conv2 = weight_variable([5, 5, 32, 64])
    b_conv2 = bias_variable([64])
    h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)
    h_pool2 = max_pool_2x2(h_conv2)

    # full_connetion
    W_fc1=weight_variable([7*7*64,1024])
    b_fc1=bias_variable([1024])
    h_pool2_flat=tf.reshape(h_pool2,[-1,7*7*64])
    h_fc1=tf.nn.relu(tf.matmul(h_pool2_flat,W_fc1)+b_fc1)

    # dropout 隨機扔掉一些值,防止過擬合
    h_fc1_drop=tf.nn.dropout(h_fc1,keep_prob)

    W_fc2=weight_variable([1024,10])
    b_fc2=bias_variable([10])
    y=tf.nn.softmax(tf.matmul(h_fc1_drop,W_fc2)+b_fc2)

    return y,[W_conv1,b_conv1,W_conv2,b_conv2,W_fc1,b_fc1,W_fc2,b_fc2]
複製程式碼

大家稍微對tensorflow的程式碼有些基礎,理解上面這部分基本上沒有難度,並且基本也是按照我們前面概念圖中的邏輯順序實現的。

最終按照慕課網上的學習資料TensorFlow與Flask結合打造手寫體數字識別,實現了一遍CNN,比較曲折的地方是前端,以及如何將訓練的模型與flask整合,最後專案效果如下:

來源 https://github.com/yanqiangmiffy/TensorFlow-MNIST-WEBAPP
歡迎大家到GitHub fork和star,專案傳送門--->TensorFlow-MNIST-WEBAPP

4 總結

最後說自己的兩點感觸吧:

  • CNN在各種場景已經應用很成熟,網上資料特別多,原先自己也是略知一二,但是從來沒有總結整理過,還是整理完之後心裡比較踏實一些。
  • 切記理論加實踐,實現一遍更踏實。

5 參考資料

相關文章