1. 程式人生 > >吳教授的CNN課堂:基礎篇 | 卷積和池化

吳教授的CNN課堂:基礎篇 | 卷積和池化

等了一個月,吳教授的Deeplearning.ai的第四部分,也就是關於卷積神經網路(Convolutional Neural Network,簡寫CNN)的課。

作為吳教授的忠實門徒(自封),除了在課堂上受到吳教授秀恩愛暴擊外,當然也要好好做筆記。雖然之前也有過一些CNN基礎,但這次收益還是挺多的。

CNN目前主要用於?

CNN目前主要用於CV領域,也就是計算機視覺領域。

很多當前最先進的計算機視覺方面的應用,如圖片識別,物體檢測,神經風格轉換等等,都大量使用到了CNN。

而且不光是CV領域,很多CNN在CV領域應用的很多技巧,其他領域也可以從其中借鑑到很多,如自然語言處理。

為什麼要用CNN

首先,假如我們要進行一個影象識別任務?這裡就不用已經都快被玩爛了的的MNIST,用吳教授課上的SIGNS資料集(包含了用手勢表示的從0到5的圖片)。目標任務就是,給一個手勢,識別出代表數字幾。

如果是上過之前吳教授機器學習的同學的話,那麼可能會問,為什麼要用CNN呢?

何不直接像機器學習課裡面一樣,將圖片拍扁(flatten),也就是直接將(高 x 寬 x 通道(如RGB))的圖片展成一個一維向量呢。如SIGNS,本來是64x64x3的圖片,我們將它拍成1x12288的向量。

之後直接輸入全連線網路(即一般我們認為的神經網路),中間加點隱層,最後一層用softmax壓一下直接輸出結果就好了。

我們可以這樣設計網路結構,第一層12288個單元,然後中間三個隱層,分別是1028個單元、256個單元、64個單元,最後一層6個單元,也就是我們的分類數。

搭建好網路後,然後訓練。這樣子確實也可以得到還過得去的結果,大概70~80%。但是相信大家也發現了,這樣子搭建的網路需要很多很多引數,如這個例子裡面

也就是大約一千三百萬個引數。

而這個例子還只是很小的圖片,因為只有64x64大小,而現在隨意用手機拍張照片就比這大很多。處理這些圖片時,用全連線網路搭建出來的網路的引數個數,將會是一個天文數字,不光優化困難,而且效能也不怎麼樣。

而這時候,就是CNN大展神威的時候了。只需要多少引數呢?之後再揭曉揭曉。

CNN基礎:卷積層

卷積 Convolution

CNN網路最主要的計算部分就是首字母C,卷積(Convolutional)。

如下圖,這裡的一次卷積運算指的是,當我們有一個過濾器(filter),即下圖移動的方塊,將這個方塊對應要處理的輸入資料的一部分,然後位置一一對應相乘,然後把結果再相加得到一個數。

一個過濾器對一張圖片進行卷積運算時,往往要進行多次卷積運算,對一部分進行計算完之後,然後移動一點距離再計算,繼續移動,計算... 直到處理完整張圖片。

為什麼叫做過濾器呢(也有叫做kernel(核)的)?

因為我們可以把每個過濾器,當做是設定了一定條件的特徵檢測器,把不屬於檢測條件的都過濾掉。只有當前卷積的區域符合這個過濾器設定的條件時,卷積計算結果才會得到一個比較大的數。

舉個栗子,如用於檢測垂直和水平邊線的過濾器。

可以試著自己計算一下。如下圖,如果用灰度表示的話,黑的地方是255,白的地方是0。用上面的Gx來卷積下面這張圖的話,就會在中間黑白邊界獲得比較大的值。

而CNN中會有很多個過濾器,每個過濾器對圖片進行卷積後,會得到下一個結果的一個通道。CNN厲害的地方在於,過濾器的特徵並不是人為設定的,而是通過大量圖片自己訓練出來的

這樣也就增加了它的靈活性,而且因為視覺底層特徵的相容特性,因此也保證了遷移學習的可能。

步長(Stride)與填充(Padding)

上面說了卷積計算,但還有一些小的細節沒提。

如果用(f, f)的過濾器來卷積一張$(h, w)$大小的圖片,每次移動一個畫素的話,那麼得出的結果就是(h-f+1, w-f+1)的輸出結果。f是過濾器大小,h和w分別是圖片的高寬。

如果每次不止移動一個畫素,而是兩個畫素,或者是s個畫素會怎麼樣呢。

那麼結果就會變為

這個s被稱為步長。

但是如果每次這樣子進行卷積的話,會出現一個問題。只要是$f$和$s$的值比1要大的話,那麼每次卷積之後結果的長寬,要比卷積前小一些

因為這樣子的卷積,實際上每次都丟棄了一些圖片邊緣的資訊。一直這樣卷積的話,一旦卷積層過多,就會有很多資訊丟失。為了防止這種情況的發生,我們就需要對原來的圖片四周進行填充(padding)。

一般都會用“0”值來填充,填充1就代表對周圍填充一圈,如上圖。填充2就填充兩圈,填充為p就是p圈,長寬各增加2p。

有了填充之後,每次卷積後的大小會變為

此時假設卷積後高不變

那麼我們可以獲得

假設s步長為1,那麼

也就是如果過濾器的高h=5的話,那麼為了保持輸出高寬不變,那麼就需要p=2。

上面這種保持卷積前後高寬不變的填充方式叫做"Same(相同)填充"。

分數情況

之後來討論一下分數情況吧。

萬一f是4或者6這樣的數呢,那麼得到的p豈不是分數,怎麼填充。答案是,那f就不要取偶數嘛。這就是為什麼一般預設的過濾器大小都是5、7、11這樣的單數。

好的,解決了填充的情況,那麼如果輸出的

是分數怎麼辦。如h=6,f=3,p=0,s=2的情況下,按照公式計算會得到2.5。一般的處理是,只取整數部分。

而這種p=0,然後結果取整數部分的處理方式,叫做"Valid(有效)填充"。

CNN基礎:池化(Pooling)層

除了上面的卷積層,CNN裡面還有一個很重要的部分,池化層。

一般會跟在卷積層之後,主要用到的Pooling層主要由有Max PoolingAverage Pooling, 也就是最大池化和平均池化。

其實概念很簡單,最大池化就如下圖。假設有一個2x2的視窗,每次移動步長也為2,每次對窗口裡的數取最大值,然後輸出。

同樣的平均池化,則就把取最大值這個操作換成取平均值就行了。

除了上面兩種池化方式,當然還有一些其他的池化方法,如k-Max Pooling之類的,但是應用很少。在最大和平均兩個裡面,也是最大池化比較常用

池化層輸出大小的轉換也和卷積層比較類似,用

來計算,一般池化層不用填充。而且池化層沒有要需要訓練的引數。

CNN基礎:組合

有了卷積層和池化層兩大部件之後,就只剩下組合了。下圖是吳教授手繪LeNet-5網路。

結構很簡單大概是這樣子Input -> Conv1 -> Pool1 -> Conv2 -> Pool2 -> (Flatten) -> FC3 -> FC4 -> Output

Conv是卷積層,Pool是池化層,FC指的是全連線網路層(Full-Connected)。其中Flatten指的是,因為卷積網路輸出的資料形狀(3維),和緊接著的全連線網路的輸入形狀(1維)不吻合,所以需要進行一些處理。

就是之前在直接用全連線網路提到的,把卷積網路的輸出拍扁(flatten),把三維的拍成一維,之後再輸入全連線網路。

建議大家可以按照前面提到的形狀變換公式,還有吳教授的手繪圖,親自把LeNet-5過一遍,對之後程式設計CNN很有幫助的。

關於前面的引數個數的問題,用上面這個LeNet-5來處理的話

也就是大概114萬。

一下子就縮小了一個數量級,當然對於越大的圖片這個差還會更加大。

結尾

這就是吳教授CNN課堂的第一週上的內容了。這次在通道這個概念有了很多新的看法。

如果想要自己修的話,直接Coursera Deeplearning ai就能搜尋到課程。

Coursera小技巧,點選註冊,不想付錢的話,點左下角的那個小小的旁聽就好了。之後想拿證的時候再充值。

習題很簡單,這裡是我的練習解答,如有困難可以參考。 repo 作者:阪本龍一 連結:https://www.jianshu.com/p/c9a3f9ea126f 來源:簡書 簡書著作權歸作者所有,任何形式的轉載都請聯絡作者獲得授權並註明出處。