卷積神經網絡 Convolutional Neural Network (CNN)

李謦伊
謦伊的閱讀筆記
7 min readSep 29, 2020

自從 AlexNet 在 ImageNet LSVRC 比賽中,以懸殊的差距奪得了冠軍,開啟了 CNN 時代。接下來的ImageNet冠軍都是使用 CNN,並且層次越來越深,使得CNN 成為在影像識別分類的核心演算法模型,帶來了深度學習的大爆發

在介紹前,先來談談為何不使用多層感知機 (Multilayer Perceptron,MLP) 神經網路 (全連接層的架構) 來處理影像

原因是因為使用全連接層會有以下的問題存在

1. 輸入影像資料時,會先將所有 data 通過 Flatten 層拉成一維,也就是說輸入的影像會被 reshape 成一維的 tensor。我們認為圖片中的像素與其鄰近的像素有一定的關聯程度,或是在不同的channel之間也可能具有某些關連性。而這樣的做法會失去圖像特徵之間的空間資訊

2. 全連接層考慮的是全局的訊息,但在分類圖像中,重要的是物體本身的局部資訊

3. 對圖像做分類時,會產生大量的參數,導致計算量過高。例如,輸入一張 28x28 的灰階照片 (總共有 784個特徵),假設一層隱藏層的神經元數目為 100 個,那一層的隱藏層就需要 100*784 (weight) + 100 (bias) 個參數。而現在的照片圖像的像素都1000以上,並且是彩色圖像 (RGB),若假設隱藏層的神經元數目還是 100 個,那參數量就會有 100*1000*1000*3 + 100 這麼多!處理這麼大量的數據除了非常消耗資源外,也容易產生 overfitting 的問題

CNN 的基本架構由卷積層 (Convolution layer)、池化層 (Pooling Layer)、平坦層 (Flatten Layer)、全連接層 (Fully Connected Layer) 所組成

卷積層 Convolution layer

卷積層負責提取圖像中的局部特徵,其原理是透過許多的卷積核 (filter, kernel) 在圖片上進行滑動擷取特徵

下圖是卷積滑動的過程,左中右分別為輸入層、卷積核、輸出層

source

卷積核 (filter, kernel)

卷積核裡面的數字就是卷積層的權重,是經由神經網路訓練學習而來的。而卷積核的大小 (kernel size) 及數量 (輸出 channel) 是可以調整的超參數,通常會設定為奇數,原因有兩個:

  1. 可以保證padding 時,影像的兩邊依然相對稱
  2. 在做物件偵測時,能夠獲得中心點,可以更好的預測物件位置

輸出層為卷積運算後的結果,稱為特徵映射圖 (特徵圖,feature map)

  • 卷積運算

卷積運算的方式就是將滑動的窗口與卷積核進行點對點 (elementwise) 的相乘,再將乘完的數值相加

source
  • ž權重共享

權重共享是 CNN 裡的一個特點,可以大幅的降低參數量

權重共享是指在做卷積運算時,以同一個卷積核 (filter) 進行運算,也就是說這整張圖像都共享了這些權重

以手寫數字圖像為例,輸入一張 28x28 的灰階照片,卷積核為 3x3,假設輸出通道為 100 個,那參數計算量就變成了 100*3*3 + 100,比起使用全連接層,參數量是不是少了非常多呀~

由上面的圖可以看出在卷積運算時,就決定了輸出特徵圖的大小,那如果要改變卷積輸出 (feature map) 的大小該怎麼辦呢? 以下介紹兩個卷積層的超參數 padding, stride

Padding

Padding 就是在輸入的 feature map 外圍填充像素值,通常填入值為0,目的是為了保持 feature map 不要太小,導致失去了圖片的訊息,另一方面可以解決丟失邊緣訊息的問題。此外,Padding 也能將輸出與輸入的尺寸大小一致

下圖為 Padding=1 時,feature map 外圍的行列會先填充像素值 0 後,再開始做卷積運算

source

📚 TensorFlow 中有兩種 Padding 模式 Valid, Same,也可以自己設定 Padding 值

  • Valid: 不做任何處理,使用原始圖片
tf.keras.layers.Conv2D(filters, input_shape, kernel_size, strides ,padding=’valid’)
  • Same: 進行填充使輸出結果與輸入尺寸大小一致
tf.keras.layers.Conv2D(filters, input_shape, kernel_size, strides ,padding=’same’)
  • 自己設定: 第一個值為在 feature map高的兩側都添加了1列,第二個值為在 feature map寬的兩側都加上2行
tf.keras.layers.Conv2D(filters, input_shape, kernel_size, strides ,padding=(1, 2))

而在 Pytorch 中默認為 Valid 模式,但沒有 Same 模式,也可以自己設定 Padding 值: 第一個值為在 feature map 高的兩側添加像素值0,第二個值為在 feature map寬的兩側添加像素值0

torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride, padding)

Stride

Stride 就是指卷積運算時,滑動窗口每次滑動的行數和列數,稱之為步幅。通常默認步幅為一步,但卷積的步長可以不只是一步

下圖為默認步幅 (stride=1) 時,卷積核滑動的樣子

source

下圖為 stride=2 時,卷積核滑動的樣子

source

卷積大小的運算公式

池化層 Pooling Layer

池化層是用來大幅降低參數量級(降維)、降低過擬合問題、緩解卷積層對位置的敏感度

池化層的計算與卷積層一樣,都是透過滑動視窗框選的局部數值進行數值運算,主要分為兩種運算方式 Max pooling、Average pooling

Max pooling 就是在框選的局部數值中挑出最大值

Average pooling 則是將框選的局數數值加總做平均計算

下圖是池化層的運算方式

source

平坦層 Flatten Layer

平坦層的作用就是將卷積層與池化層輸出的特徵拉平、做維度的轉換,如此一來才能放入全連接層做分類

全連接層 Fully Connected Layer

全連接層又稱密集層 (Dense Layer),其作用是用來進行分類。將卷積層與池化層輸出的特徵輸入到全連接層,通過調整權重及偏差得到分類的結果

接下來看 CNN 的完整架構圖可以更清楚其操作流程。輸入圖片會先經過卷積層、池化層,然後在進入全連接層之前,會先通過平坦層做維度的轉換,再接上全連接層進行分類

source

以上就是 CNN 的架構啦~~下一篇會來介紹 CNN 的經典模型以及用 Pytorch 實踐 🙌

--

--