【機器學習基礎】卷積神經網路(CNN)基礎

Uniqe 發表於 2021-11-25
Machine Learning 神經網路

最近幾天陸續補充了一些“線性迴歸”部分內容,這節繼續機器學習基礎部分,這節主要對CNN的基礎進行整理,僅限於基礎原理的瞭解,更復雜的內容和實踐放在以後再進行總結。


卷積神經網路的基本原理 

  前面對全連線神經網路和深度學習進行了簡要的介紹,這一節主要對卷積神經網路的基本原理進行學習和總結。

  所謂卷積,就是通過一種數學變換的方式來對特徵進行提取,通常用於圖片識別中。

  既然全連線的神經網路可以用於圖片識別,那麼為什麼還要用卷積神經網路呢?

0.使用卷積神經網路的理由

(1)首先來看下面一張圖片:

【機器學習基礎】卷積神經網路(CNN)基礎

  在這個圖片當中,鳥嘴是一個很明顯的特徵,當我們做影像識別時,當識別到有“鳥嘴”這樣的特徵時,可以具有很高的確定性認為圖片是一個鳥類。

  那麼,在提取特徵的過程中,有時就沒有必要去看完整張圖片,只需要一小部分就能識別出一定具有代表的特徵。

  因此,使用卷積就可以使某一個特定的神經元(在這裡,這個神經元可能就是用來識別“鳥嘴”的)僅僅處理帶有該特徵的部分圖片就可以了,而不必去看整張圖片

【機器學習基礎】卷積神經網路(CNN)基礎

   那麼這樣就會使得這個神經元具有更少的引數(因為不用再跟圖片的每一維輸入都連線起來)。

(2)再來看下面一組圖片:

【機器學習基礎】卷積神經網路(CNN)基礎

 上面兩張圖片都是鳥類,而不同的是,兩隻鳥的“鳥嘴”的位置不同,但在普通的神經網路中,需要有兩個神經元,一個去識別左上角的“鳥嘴”,另一個去識別中間的“鳥嘴”:

【機器學習基礎】卷積神經網路(CNN)基礎

  但其實這兩個“鳥嘴”的形狀是一樣的,這樣相當於上面兩個神經元是在做同一件事情

  而在卷積神經網路中,這兩個神經元可以共用一套引數,用來做同一件事情

(3)對樣本進行子取樣,往往不會影響圖片的識別。

  如下面一張圖:

【機器學習基礎】卷積神經網路(CNN)基礎

  假設把一張圖片當做一個矩陣的話,取矩陣的奇數行和奇數列,可看做是對圖片的一種縮放,而這種縮放往往不會影響識別效果。

  卷積神經網路中就可以對圖片進行縮放,是圖片變小,從而減少模型的引數。

1.卷積神經網路的基本結構

  卷積神經網路的基本結構如圖所示:

【機器學習基礎】卷積神經網路(CNN)基礎

  從右到左,輸入一張圖片→卷積層→max pooling(池化層)→卷積層→max pooling(池化層)→......→展開→全連線神經網路→輸出。

  中間的卷積層和池化層可以重複多次。後面會一一介紹每一層是如何工作的。

  對於第0部分的三個功能:

  (1)某個神經元只需偵測某一部分的圖片,來識別某種特徵這個工作是在卷積層內完成的。

  (2)具有相同功能的神經元共用一套引數,這個工作也是在卷積層內完成的。

  (3)通過縮小圖片,來減少模型的引數,這個工作是在池化層中完成的。

  稍後會解釋上面三個部分是如何進行的。

1.1.卷積層的工作原理

  假設有一張6*6的黑白圖片,如圖所示:

【機器學習基礎】卷積神經網路(CNN)基礎

  首先圖片經過卷積層,卷積層有一組filter每個filter用來抓取圖片中的某一種特徵,如圖所示:

【機器學習基礎】卷積神經網路(CNN)基礎

  假設filter是3*3的矩陣,每個filter有9個引數,而這些引數就是通過訓練學習得到的,這裡假設我們已經學習得到了上面一組引數的值。

  因此也就說明了問題(1)中,每一個filter只偵測圖片中的很小一部分資料。

  那麼每個filter是如何去抓取特徵的呢?也就是(1)中使某一個神經元只偵測一部分圖片就能提取某一種特徵的問題。

  首先看filter1,filter大小為3*3,那麼相當於這個filter1依次從左到右去覆蓋整張圖片,然後與覆蓋區域做內積,如圖所示:

【機器學習基礎】卷積神經網路(CNN)基礎

  首先從左上角開始,覆蓋圖片左上角3*3的區域,計算結果得到3,然後向右移動,這裡移動的步長稱之為stride當stride為1時,即一次移動一格,為2時,一次移動兩格,如圖所示:

【機器學習基礎】卷積神經網路(CNN)基礎

  移動之後再次用圖片被覆蓋的區域與filter做內積,得到第二個值:

【機器學習基礎】卷積神經網路(CNN)基礎

  依次進行移動和計算,當移到最右邊盡頭時,則從下一行開始繼續移動,最終得到如圖所示矩陣:

【機器學習基礎】卷積神經網路(CNN)基礎

  通過觀察這個filter1可以看出,filter1的對角矩陣全為1其他為-1那麼對於圖片中對角為1的部分,與filter1做內積後的值就會很大(例子中等於3),其他的則會很小。

  因此filter1是一種用於偵測對角都為1的圖片這種屬性,在圖片中可以看到,坐上角和右下角都具有這種特徵。

  所以這也就說明了(2)中的問題,一個filter的一組引數,可以偵測到圖片中兩個位置的相同屬性。

  接下來是第二個filter,filter2,那麼filter2與圖片的計算方式一模一樣,如圖所示:

【機器學習基礎】卷積神經網路(CNN)基礎

  其他的filter也是如此,依次計算,然後把每個filter處理結果放在一起,如圖所示:

【機器學習基礎】卷積神經網路(CNN)基礎

  那麼相當於一個紅色方框現在是由2個值來描述的,最終得到的是2個4*4的圖片,稱之為“feature map”。

  上面是對於一張黑白的圖片進行一次卷積(convolution)的過程,那麼對於彩色的圖片是怎樣處理的呢?

  彩色圖片通常是由“RGB”組成,分別表示紅色、綠色和藍色,那麼就相當於有三個部分的組成,如圖所示:

【機器學習基礎】卷積神經網路(CNN)基礎  這三個層稱之為“通道”(channel),那麼利用卷積處理這種圖片時,filter也應該是三層,即3*3*3的,是帶有深度的,長下面這個樣子:

【機器學習基礎】卷積神經網路(CNN)基礎

  相當於每個filter具有27個引數

卷積與全連線網路的關係

  其實卷積就是一種特殊形式的全連線網路,還是假設是上面那張6*6的圖片,如下是全連線的網路結構:

【機器學習基礎】卷積神經網路(CNN)基礎

  把圖片進行拉直展開,但在卷積中,這個網路有些連線的地方被切斷了,只有一部分輸入與神經元相連線。下面進行解釋:

  正如上面的卷積過程,如下是其中的一步,如圖所示:

【機器學習基礎】卷積神經網路(CNN)基礎

  那麼這個步驟我們可以想象成是這樣子的:

【機器學習基礎】卷積神經網路(CNN)基礎

  左邊把圖片的36個數值拉直,然後,對於filter1所覆蓋的區域為左上角,那麼元素對應的位置為1、2、3、7、8、9、13、14、15

  然後這9個數值,依次經過各自的weight相乘再相加,得到第一個值3,這裡的weight就是對應的filter中各個位置的值,圖中weight線的顏色與filter中圓圈顏色一一對應

  到這裡就很清楚的看出卷積與全連線之間的關係,相當於簡化了全連線神經網路,從而使得引數量更少

  然後filter開始向右移動一格(stride=1,上面計算過程的第二個方框,元素依次為2、3、4、8、9、10、14、15、16),與filter做inner product,得到結果-1,對應到全連線網路中如圖所示:

【機器學習基礎】卷積神經網路(CNN)基礎

  依舊是每個元素的weight與輸入輸出連線,顏色對應的filter圓圈與weight的顏色一致。

  從上面的圖可以看出,兩個神經元(3和-1)都是通過filter1作為weight與輸入進行連線的,也就是說,這兩個神經元是共用同一組引數,這樣,在上面減少引數的基礎上,使得模型的引數更少了

  上述過程就是卷積層的工作過程,主要用於圖片中特徵的抓取,完成第0節內容的前兩個。

1.2池化層的工作原理

  池化層的作用上面說了,就是為了圖片的縮放,那麼池化層是如何進行縮放的呢?

  其實池化層的原理很簡單,這裡以max-pooling為例,經過卷積層之後的圖片變為4*4大小的圖片,有2個filter,也就是兩張4*4的圖片:

【機器學習基礎】卷積神經網路(CNN)基礎

  池化就是將上面得到的資料進行分組,如圖所示:

【機器學習基礎】卷積神經網路(CNN)基礎

  如圖示中的分組方法,這種分組方法可以是任意的,也可以三個一組等等,然後取每個組中的最大值:

【機器學習基礎】卷積神經網路(CNN)基礎

  那麼原來4*4的圖片經過maxpooling之後就縮小為2*2的圖片了,當然這裡也不一定非要取最大值,也可以取平均,或者又取平均又取最大值等。

  那麼上面的過程總結一下就可以用如下圖進行概括:

 【機器學習基礎】卷積神經網路(CNN)基礎

  這就是池化層的工作原理,比較簡單。

1.3Flatten和全連線層

  接下來就來到了flatten和全連線層了,flatten的作用就是把上面得到的兩個2*2的image拉直展開,然後再丟進全連線網路中計算就可以了,這個跟前面全連線神經網路的方法一樣,如圖所示:

【機器學習基礎】卷積神經網路(CNN)基礎

  這裡就不再詳細贅述了。那麼整個網路就是利用梯度下降的方法進行訓練的,所有的引數被一起學習得到。

2.使用Keras對CNN的簡單實現

  這裡還是使用keras對CNN的建模過程進行一個簡單的實現,首先先來看一下keras分別新增摺積層和池化層的過程:

【機器學習基礎】卷積神經網路(CNN)基礎

  如圖中所示,首先要匯入Convolution2D(後來這個介面會改成Conv2D)和Maxpooling2D。

  然後與之前神經網路中一樣,不過是把“Dense”換成了上面兩個方法,其中Convolution2D中,25表示filter的數量,3,3表示filter的尺寸,input_shape為輸入圖片的大小,28*28為圖片大小,1表示黑白圖片,3則表示彩圖“RGB”

  Maxpooling2D中只有分組的形狀,即2*2大小的。

  接下來就是根據設計的網路的形狀,重複上面兩個步驟,完成卷積和池化。如圖所示:

【機器學習基礎】卷積神經網路(CNN)基礎

  圖中黑色的方框為程式碼的實現內容,在keras1.0和2.0中可能有些差異;

  黃色的框中是輸入和輸出的尺寸大小,可以看到,輸入為28*28的圖片,經過25個3*3的filter組成的第一個卷積層之後,變成了25*26*26的尺寸

  然後經過第一個2*2的池化層,縮小後的輸出尺寸大小為25*13*13

  然後經過第二個由50個3*3的filter之後,輸出變為50*11*11

  之後經過第二個2*2的池化層後,縮小後的輸出尺寸變為50*5*5(這裡由於輸入為基數,最後一格就忽略掉了)。

  而在卷積層中,filter的引數數量是在變化的,在第一個卷積層的引數為3*3=9個,這個比較好理解;

  而在第二個卷積層中,引數就變成了225個,這是因為上一層的輸出為25*13*13大小的圖片,這時是帶有channel的(就相當於一開始輸入為RGB時,通道數為3)當使用3*3的filter進行處理時,需要帶有深度25,因此每個filter的引數數量為25*3*3=225。

  然後就是經過Faltten和fully-connection了,這個與之前的神經網路一致:

【機器學習基礎】卷積神經網路(CNN)基礎

  然後就可以對模型進行訓練了。這裡要注意的是,這裡的輸入跟全連線有所不同,要把輸入圖片資料轉化為(28,28,1)的格式。完整程式碼如下:

from sklearn.datasets import fetch_openml
from sklearn.preprocessing import OneHotEncoder
from sklearn.model_selection import train_test_split
import numpy as np
from keras import Sequential
from keras.layers import Dense
from keras.layers import Activation
from keras.layers import Convolution2D, MaxPooling2D, Flatten

data_x, data_y = fetch_openml('mnist_784', version=1, return_X_y=True)

x = []
for i in range(len(data_x)):
    tmp = data_x.iloc[i, :].tolist()
    tmp = np.array(tmp).reshape((28, 28, 1))
    x.append(tmp)
x = np.array(x)

one_hot = OneHotEncoder()
data_y = one_hot.fit_transform(np.array(data_y).reshape(data_y.shape[0], 1)).toarray()
train_x, test_x, train_y, test_y = train_test_split(x, data_y)

model2 = Sequential()

model2.add(Convolution2D(25, 3, 3, input_shape=(28, 28, 1)))

model2.add(MaxPooling2D((2, 2)))

model2.add(Convolution2D(50, 3, 3))

model2.add(MaxPooling2D((2, 2)))

model2.add(Flatten())
model2.add(Dense(units=100))
model2.add(Activation('relu'))
model2.add(Dense(units=10))

model2.add(Activation('softmax'))

model2.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])

model2.fit(train_x, train_y, batch_size=300, epochs=20)

最後的輸出如下:

【機器學習基礎】卷積神經網路(CNN)基礎

3.CNN都學到了啥?

  通過CNN的原理我們大致知道,CNN的卷積是不斷提取特徵的過程,池化是對圖片的縮放,那麼究竟CNN學習到了什麼呢?如下面一張圖:

【機器學習基礎】卷積神經網路(CNN)基礎

  給機器一張圖片,那麼對人來說,這張圖片是一雙鞋,而對機器來說,它可能認為是是美洲獅,因為圖中的鞋標有一隻美洲獅。

  因此,我們想要知道CNN究竟學習到了啥,下面介紹幾種方法來檢視CNN都在偵測什麼特徵的方法。

3.1 直接檢視filter

  前面我們說到,filter就是為了抓取某一種特徵的,那麼我們是不是可以看一下這些filter分別都是偵測什麼樣的特徵的。

  根據CNN的原理,隨著網路越來越靠近輸出層,那麼這一層所學習到的東西就越來越抽象,不太容易觀察。因此,我們選取第一個卷積層的filters來看一下。

  對於一個訓練好的模型,將第一個卷積層的filters單獨拿出來,並畫出來,如圖所示:

【機器學習基礎】卷積神經網路(CNN)基礎

  上面一共96個filter,每個filter的大小為11*11,從filter我們可以看出,上面幾排的filter主要是偵測形狀特徵的,下面幾排的filter主要是偵測色彩特徵的。

  我們也可以通過單獨看一個filter,然後把圖片依次輸入的CNN中,看哪些圖片經過這個filter後的輸出(Activate)最大,如下圖所示:

【機器學習基礎】卷積神經網路(CNN)基礎

  白色的框表示filter,這裡白色的框看著很大,主要是因為這個filter比較靠後,也就是它所看到的是前面經過縮小後的輸入,因此框就會變得很大。

  第一排的圖片中的框是一個filter1,可以看到,這個filter對於臉部的偵測比較強;

  第二排的框是另一個filter2,可以看到filter2偵測的主要是洞狀排列的特徵;

  第三排的filter3則是偵測紅色的特徵;

  以此類推...

3.2 特徵的視覺化

  這種方法是檢視特徵的,也就是說使用反摺積、反池化的方法,來視覺化輸入影像的啟用特徵。

  還用原理部分那個CNN結構的例子,如下圖左邊的結構:

【機器學習基礎】卷積神經網路(CNN)基礎                           【機器學習基礎】卷積神經網路(CNN)基礎

  在第二個卷積層中,假設第k個filter,它與輸入作用以後得到的結果如上圖中右側,每一個元素aij,然後把aij相加,即為ak,即:

【機器學習基礎】卷積神經網路(CNN)基礎

  那麼現在我們想要通過輸入x使得ak最大,也就是找一張圖片x,使得ak的輸出最大,即:

【機器學習基礎】卷積神經網路(CNN)基礎

這裡就要利用gradient ascent的方法去找這個最大值了,即求:

【機器學習基礎】卷積神經網路(CNN)基礎

  就相當於原先經過卷積、池化過程,現在要將x當做未知量,反過來求反池化、反摺積去求解出一個使得ak最大的x注意這裡x並不是真正的圖片了,相當於是通過反池化和反摺積所得到的的帶有一些特徵的影像);

  具體原因就在於反池化和反摺積的求解過程,無法還原為原先的圖片,這裡暫不過多介紹如何反池化和反摺積的原理,後續再補充。

  那麼經過上面的步驟,還原得到的x的結果如圖所示:

【機器學習基礎】卷積神經網路(CNN)基礎

   一共50個filter,這裡取前12個,每個圖片的意思代表1個filter所還原得到的圖片x,也就是說,比如第一張圖片,將其作為input丟進上面那個網路後,其輸出與第一個filter作用後得到的ak最大。

  仔細觀察一下上面的圖,還是有一定的規律可循的。

  同時我們也可以去檢視fully-connection部分的神經元,原理跟上面一樣,不過再求解釋時又多了一層反向傳播的過程,如圖:

【機器學習基礎】卷積神經網路(CNN)基礎

  當然也可以去拿輸出層的神經元,比如識別結果為0,輸出層在第0維值就很大,然後一樣根據上面的原理得到的結果如圖:

【機器學習基礎】卷積神經網路(CNN)基礎

  會發現得到的結果什麼也看不到,但是當把某張圖片再次輸入進網路之後,得到的確實是對應的結果。

  這也就說明了深度學習很容易被欺騙,但從側面也反映出了,深度學習確實學習到了某些特徵,並非僅僅簡單“記住”資料,也說明深度學習的“玄學”性,難以解釋

  當然,在上面的求解過程中,我們可以適當加一些限制,比如正則化:

【機器學習基礎】卷積神經網路(CNN)基礎

  那麼得到的結果如圖:

【機器學習基礎】卷積神經網路(CNN)基礎

  發現結果稍微清晰了一些,有些能夠看到一些筆畫。

  那麼正則化的目的是在保證y越大越高的同時,也要使得xij(圖片中的每一個pixel)越小越好,也就是說對於圖片顯示(白色的是筆畫,黑色的是空白)時,儘可能使空白減少,能連的連起來。所以效果會好些。

3.3 微分

  對於一張圖片的識別,我們可以計算類別y對影像畫素pixel的微分的值:

【機器學習基礎】卷積神經網路(CNN)基礎

  通過改變畫素xij,來看這個畫素對識別的影響是否重要,也就是說,當xij稍微做一下改變,對識別的結果影響有多大,用這樣的方法可以得到如下的結果:

【機器學習基礎】卷積神經網路(CNN)基礎

  白色區域表示對識別影響較為重要的pixel,可以大概看到一些形狀。那這樣做有什麼意義呢?

  有時當我們從網上爬取圖片進行建模後,發現對馬的識別率很高,但對其他的識別一般,這是因為可能關於“馬”的圖片都包含“horse”字樣的標籤,機器真正識別到的是“horse”的標籤,而並非知道馬長什麼樣子。

  同樣的道理,我們可以通過蓋住圖片的一部分,去看看蓋住的部分結果的影響有多大,比如:

【機器學習基礎】卷積神經網路(CNN)基礎

  圖中灰色的區域是被蓋住的,不斷移動灰色的區域,看對結果的影響有多大,那麼可以獲取到下面一樣的熱力圖:

【機器學習基礎】卷積神經網路(CNN)基礎

  圖中顏色越淺表示對辨識的結果影響越大,越不能辨別出是什麼,可以看到,第一張當蓋住狗的臉的時候,很難分辨出狗;

  第二張圖片當蓋住輪胎部分的時候,就很難辨別出輪胎;

  第三張圖片當蓋住狗的身子的部分,就很難辨別出狗了。

  更多有關CNN視覺化的內容,可搜尋一些有關部落格進行學習:https://blog.csdn.net/xys430381_1/article/details/90413169

4.關於CNN一些有趣的應用

  根據上面的理論,我們可以通過修改某個filter的引數,去還原出一張另類的圖片,比較有趣的應用有deep dream和風格遷移,如下圖(圖片來源於網路):

【機器學習基礎】卷積神經網路(CNN)基礎

這裡就暫時不具體介紹原理了,後面會找一些開源的專案去玩。

 

參考資料:臺大李宏毅《機器學習-卷積神經網路》


 

上面是對CNN進行的一個初步的介紹,後面會對深度學習部分進行系統的學習和整理,這裡主要是對原理有個初步的認識,因此很多都是概念性的東西,後續會進一步新增補充。