1. 程式人生 > >“CNN使我快樂”之CNN基礎

“CNN使我快樂”之CNN基礎

本文基於coursera deeplearning.ai 第二課程《Convolutional Neural Networks》第一週,大概講一下卷積是什麼,為之後CNN的學習打一個基礎。

所有非手繪影象均來自課程,侵刪。

本人才疏學淺,如有問題歡迎禮貌指正。

謝絕任何不標註出處的轉發以及百度百家號抄襲。

作者:李皮皮


在computer vision中,深度學習已經是一個重要的工具了,其中非常常用的就是卷積神經網路,CNN。

Computer Vision 常見的用法一個是做影象分類(image classification),一個是物體識別(object detection),還有神經模式轉換(neural style transfer)。

1. 為什麼需要CNN

對於普通的深度神經網路,我們需要儲存的資料量過大過於繁雜。例如一張500*500畫素的影象,我們就需要存250000個值;如果是100張影象,就是250m個值,令人害怕。這還不說各種引數的儲存。所以我們需要一種更合理的方法來做神經網路進行影象處理。

在卷積神經網路中,引數是可以共享的(parameter sharing)。經過研究發現,如果一組引數對影象的一部分是有用的,那麼它讀另一部分也很可能有效果。

連線的稀疏性(sparsity of connections):在每一層中,每一個輸出結果的值都取決於輸入值的一小部分。這就使得每次只有一小部分會影響到某一個輸出結果值,讓整個結果更穩定。


2. 邊緣檢測(edge detection )與卷積運算

首先我們通過邊緣檢測來了解一下卷積是如何運作的。

2.1 邊緣檢測

給出一張圖片,首先我們需要分橫向和縱向對其邊緣進行檢測,如下圖所示。

2.2 二維卷積計算

然後我們來展示一下縱向邊緣檢測的計算。假設第一張圖是一個5*5*1的灰度影象(RGB影象則為5*5*3),那麼我們就有如下卷積計算。從左往右依次是影象的矩陣,過濾器也在一些科研中被稱作核。

為什麼需要過濾器呢?如下圖所示,最左邊是6*6的灰度影象,中間是一個垂直過濾器(水平過濾器是第二行是0),右邊是我們得到的矩陣。每個矩陣下面對應著其成色。過濾器可以幫我們弱化不重要的部分,強化重點部分(由亮到暗還是由暗到亮)。如果我們不需要強調其亮度的變化過程,就可以用矩陣絕對值代替。

具體的步驟如下。先在左邊選取3*3大小的小矩陣,然後將過濾器的值對應進小矩陣中,如下圖右邊所示。然後進行加權計算,得出結果為7,則輸出結構矩陣第一行第一列的值則為7.

然後將小矩陣的框向右平移一個單位,得到新的矩陣,並計算出第二個值-2:

當行挪動被遍歷一遍,就開始以1格為單位向第二行挪動。最終我們會得到一個3*3的矩陣。輸出矩陣的維度計算公式如下:

(n-f+1)*(n-f+1), 其中n是影象矩陣的邊長,f是過濾器的邊長。

在python中當然不是這麼手算的,有很多不同的計算卷積的method。比如TensorFlow的就是tf.nn.conv2d(),Keras的是Conv2D()。

這裡需要說明一下在一些數學課本中,卷積的符號表示不太一樣。通常數學課本中,卷積之前會把過濾器進行一個逆時針兩次旋轉,如下圖所示。數學概念中這樣做了旋轉其實才是真正的卷積,CS深度學習中的運算其實是叫做cross-correlation交叉相關的東西,只不過在深度學習文獻中,大家約定俗成將其稱為“卷積”。

2.3 三維/多維卷積計算

上面說的是對二維矩陣的卷積運算,但是現實中除了灰度影象,更多的是RGB影象,那麼RGB該如何表示呢?——其實很簡單,就是6*6*1的資料集變成了6*6*3。相應地,過濾器也從3*3*1變為了3*3*3。看起來就像這樣:

那麼在運算的時候呢,可以把3*3*3的過濾器考慮成一個立方體結構。這個結構中,有27個值,這27個值每次都分別要與RGB影象的對應區域做卷積,然後27個值和對應位置相乘產生的和就是輸出矩陣的第一個值。

在做完第一次過濾之後(假設它是垂直過濾),我們可能還想進行另一種過濾(假設為水平過濾)。此時我們已經得到了一個4*4*1的輸出矩陣(如上圖所示),那麼再對原矩陣進行一次運算,就會得到第二個4*4*1的矩陣。就像神經網路一樣,我們可以把這兩個輸出矩陣拼在一起,這樣又得到了一個4*4*2的矩陣,2代表我們使用了兩個過濾器。

對於多維,我們就有:(height*width*channels)卷 (f*f*channels) = (n-f+1) * (n-f+1) * filters。filters是過濾器的數量。不同的過濾器可以直接檢測RGB影象不同的特徵(不需要做灰度處理等),這就是深度學習影象處理的強大之處。

2.4 過濾器的種類

目前在計算機視覺中,採用什麼大小的過濾器,過濾器如何取值還存在很大爭議。所以不需要拘泥於上述的(-1,0,1)的3*3組合。除了上文提到的過濾器,還有如下過濾器(sobel讓我想到了saber)。可以看到他們的權重比上文提到的過濾器要大一些。

可以看到不管怎麼說,3*3都是一個過濾器常用的組合,而且一個好處就是無論圖片的解析度多高,都可以使用3*3來解決,這也使得卷積神經網路不太容易過擬合。

2.5 過濾器引數

除去給定過濾器,我們也可以將整個矩陣的值設為引數,通過反向傳播進行求解,從而得到一個很好的過濾器。如下圖所示。這樣的得到的過濾器可能不僅僅可以探測垂直、水平邊緣,甚至可以檢測帶角度的邊緣。

3. Padding

padding是構建深度學習神經網路一個非常基礎和重要的技術。什麼是padding呢?如下圖示,本來我們要計算的是一個4*4的矩陣乘一個3*3的過濾器。使用padding,給影象矩陣的四周加一圈(padding),讓它變成一個6*6的矩陣,這樣6*6卷3*3出來就是(6-3+1)*(6-3+1)還是4*4的矩陣啦~設padding的層數為p(下圖就是p=1),那麼就有新的卷積生成的矩陣維度公式:

(n+2p-f+1)*(n+2p-f+1)

為什麼需要padding呢?

(1)用來控制維度。前面提到了普通卷積計算出來的維度是(n-f+1)*(n-f+1),這意味著每次進行卷積計算,輸出矩陣的結果都會變小,幾輪下來它基本就快沒了。所以我們需要padding來控制輸出矩陣的維度。

(2)讓邊緣的畫素不被浪費。對於普通的卷積計算,影象矩陣邊上的畫素只被利用了一次,而padding可以讓其被多次利用,讓邊緣資訊不至於丟失的太厲害。

那麼我們到底需要padding多少才是合理呢?有兩種卷積方式:

(1)valid convolutions: no padding,正常卷即可

(2)same convolutions:通過padding讓input 維度和 output維度相同。那麼有:

\\n = (n + 2p -f +1) \\p = \frac{f-1}{2}

通常我們會讓f是奇數,這樣p出來就是整數,好思考一些。但這只是一個約定俗成的東西,並沒有鐵則。


4. Strided convolution

在前面卷積計算的過程時,我們是一次向右挪動一格,被稱為一格步長。其實也可以自己確定步長。這個步長就被稱為stride。例如當stride=2時,下面的計算就變成了紅圈的步驟。下移也是,s=1只下移一行,s=2就是下移兩行再進行卷積計算。

在使用strided convolution時,得出的矩陣維度就變成了:

(\frac{n+2p-f}{s}+1) * (\frac{n+2p-f}{s}+1)

如果分式不能得到整數,就進行下取整。


5. 簡單的卷積神經網路

5.1 卷積神經網路的一個卷積層

在2.3章節提到了多維RGB影象矩陣的卷及計算以及多個過濾器的卷積,這就是一層進行的工作。除此之外,在產生輸出巨震後,還要新增一個bias,形成線性的模式。在此基礎上,可以選取啟用函式對新生成的矩陣進行計算。

下圖詳細過程如下:首先得到一張RGB圖片的資訊,假設它是6*6*3的矩陣,然後我們使用兩個3*3*3的過濾器。得到了兩個4*4*1的矩陣,分別給兩個矩陣賦予bias。bias通過python的broadcasting被加入矩陣。這裡就得到了普通神經網路中z=wa+b的結構。然後使用啟用函式,這裡用的是ReLu,得到啟用矩陣a=g(z)。輸出的結果是兩個矩陣,這兩個矩陣被看做一個4*4*2的輸入進入下一層神經網路的計算。然後來看一下引數情況。首先兩個filters,每個27個值,我們有54個引數,然後加上兩個bias,56個引數。

5.2 簡單的例子

假設我們有39*49畫素的RGB圖片m張,那麼資料就是 m*39*49*3。然後用圖來表示單個圖片的神經網路:

第一層使用了10個3*3的過濾器,步長為2,沒有padding,得到了一個37*38*10的輸出值。然後第二層使用了40個4*4的過濾器,步長為2,padding為1,產生一個18*19*40的結果。第三層使用45個5*5的過濾器,步長為2,沒有padding,得到7*8*45的結果。然後將這個結果中7*8*45=2520個值平鋪成一個很長的向量,使用邏輯迴歸或者softmax(主要看你要幹啥)進行分類處理,得到最終結果。

在這樣一個例子中,使用到的超引數就巨多了。。我發現我對深度學習並不是真愛,我只是愛吳恩達。

5.3 卷積神經網路(convnext)中層的種類

(1)卷積層(Conv),就是上面提到的

(2)pooling layer(Pool)池化層,使用這種層是為了減少展示量。

池化的方式有很多,這裡拿min pooling舉例(但其實好像不太常用min, 一般都是max抓取特徵)。我們的目標是從下面4*4的矩陣中得出一個2*2的池化矩陣(差點打成痴漢矩陣。。。),min pooling就是在2*2的域裡尋找最小值,然後結果就是那個最小值。

除了min pooling,還有max pooling,average pooling。max pooling是最常用的。吳恩達說目前沒有很好地理論說明為什麼它很好用。max pooling沒有需要做調解的超參(超參包括過濾器大小,步長,哪種pooling,padding在池化層很少用),這也是它的一個優勢。常見的超參組合是f=2,s=2/f=3,s=2.

在池化層,上面提到的公式依然適用。

因為池化層沒有實際需要調節的引數,所以一般池化層會前一個卷積層合稱為一層。

(3)Fully connected layer(FC層)

在得到的三維矩陣被打成一個扁平的長向量後,我們依然可以繼續做處理。如下圖所示,將一個400*1的向量繼續用神經網路變為200*1,而這一個200*1的層被稱為FC層,其權重矩陣大小為200*400,bias為200個。

在一個CNN中,FC層可以被多次使用,一般是用在臨近輸出結果的地方,最後使用邏輯迴歸或者softmax得出最終結果。