1. 程式人生 > >cs231n-(7)卷積神經網路:架構,卷積層/池化層

cs231n-(7)卷積神經網路:架構,卷積層/池化層

卷積神經網路和普通神經網路非常類似。卷積神經網路由神經元組成,每個神經元包含權重weight和諞置bias;它接收上一層輸入,和權重相乘,通常再經過一個非線性函式(可選)輸出。整個網路擬合一個可微分的score function:從原始影象到每類別得分。在最後一層(全連線層)包含一個loss function(例如SVM/Softmax),常規神經網路用到的技巧,卷積神經網路通常也適用。

架構總覽

上一節用到的網路是全連線網路,它接收一個向量輸入,得到每個類別的得分。全卷積網路不太適用於影象,在CIFAR-10中,影象大小是32x32x3,所以第一層網路的每個神經元將會有32*32*3=3072個權重;當輸入影象變大後,權重數量會以乘積形式增長;神經元的數量不止一個,這麼多的權重,將會導致過擬合。

3維神經元。影象由三個維度組成:width、height、channel,因此“層”也是對應三維:width、height、depth,這裡的depth是啟用函式的維度,不是神經網路的depth。

卷積神經網路和全連線網路的不同在於,卷積神經網路只是用全一層的部分輸出作為一個神經元的輸入,這樣可以大大減少權重個數。下面是視覺化的一個對比:
cs231n08_01.jpeg

左邊是3層的全連線網路。右邊是卷積神經網路,把神經元按照三維來組織的。

常用的層

卷積神經網路由層構成,每層有簡單的介面:把輸入的三維資料轉換為輸出的三維資料,通常使用可微函式或者不用引數。

卷積網路由一系列的層構成,資料在層之間流動。常用到的層包括:卷基層Convolutional Layer、池化層Pooling Layer、全連線層Fully-Connected Layer

以一個分類CIFAR-10影象的卷積網路為例,網路結構[INPUT-CONV-RELU-POOL-FC],具體如下:

  • INPUT[32x32x3],資料為原始畫素值,高寬都為32,三通道RGB。

  • CONV layer,卷積層計算物件連線到輸入層神經元的輸出,每次計算都是權重和區域性輸入的點乘。如果使用12個濾波器(核),輸出為[32x32x12]。

  • RELU layer,ReLU是逐元素操作(elementwise),使用函式max(0,x),經過ReLU後,輸出大小不會變,還是[32x32x3]。

  • POOL layer,池化層是下采樣操作(在寬weight和高height緯度上),這樣輸出會變小為[16x16x12],但是depth不變。

  • FC layer全連線層將會計算每類別對應的得分,輸出大小為[1x1x10],代表10類每個類別的得分。全連線顧名思義,這一層的每個神經元和上一層的每個神經元之間都有連線。

通過上面的網路,把原始畫素值通過不同的層,最終得到每個類別的得分。上面的層中,卷積層和全連線層有引數,池化層沒有傳引數,訓練是訓練有引數的層。

總結:

  • 卷積網路最簡單的結構就是一系列的層的連線,把輸入的影象轉換為輸出。
  • 有不同型別的層,最常用的有CONV/FC/RELU/POOL。
  • 每個層都是接收三維資料,之後通過一個可微函式轉換成一個三維輸出。
  • 層可以包含引數,也可以不包含。
  • 層可以包含超引數,也可以不包含。

cs231n08_02.jpeg

上圖就是一個卷積網路的視覺化,因為對三維資料難以視覺化,對三維資料通過行來切片平鋪展示,最後一層是對應每類的得分。這個網路是tiny VGG NET。

下面詳細介紹每種類別的層的結構。

卷積層

卷積層是卷積網路的核心,大部分的計算量都在這個層。

概述

不考慮和大腦、神經元做對比,卷積層引數包含要學習引數的一個集合。每個濾波器引數長度和寬度比較小,但是深度和輸入資料保持一致。在前向傳播過程中,把卷積核沿著輸入資料在寬和高上滑動,把對應的資料和卷積核做內積運算;隨著卷積核的滑動,可以得到一個2維的啟用圖(activation map),啟用圖的值是卷積核在不同空間位置的響應。直觀上看,網路會讓卷積核學到“對某些特定物體或顏色產生啟用”。假設我們有一個卷積核的集合,每個卷積核都會生成一個2維啟用圖,多個卷積核就可以在深度方向上得到輸出。

大腦角度,從大腦角度看,每個3維輸出可以看做一個神經元的輸出,每個神經元只是觀察到了輸入資料的一部分,在空間上和左右兩邊的神經元進行引數共享。

區域性連線,每個神經元只跟前一層輸入的一個區域性區域相連線;這個區域性區域大型是一個超引數,叫做感受視野receptive field,其大小就是卷積核大小,其深度和輸入資料深度一致。

例如,對於RGB CIFAR-10的影象,如果感受視野(卷積核/濾波器)大小為5x5,那麼權重大小為[5x5x3],總共有引數5*5*3+1=76個(加上一個bias)。

如果輸入資料大小為[16x16x20],感受視野(卷積核)3x3,那麼權重為[3x3x20]。

cs231n08_03.jpeg
左圖是32x32x3(CIFAR-10)的一個輸入,卷積核只是連線到輸入的區域性部分,但是擴充套件到輸入的整個深度。右邊是一個神經元,它計算輸入資料和權重的內積,再加上一個bias;隨後經過一個非線性函式。

空間安排,前面已經解釋了輸入資料如何跟輸出進行連線,但是還沒討論神經元的數量以及它們之間如何排列,這裡需要用到三個超引數:深度depth,步長stride,零填充zero-padding

1、輸出的深度對應卷積核的個數,不同的卷積核查找輸入中不同的物體。例如,輸入是原始影象,那麼深度方向上不同神經元可能被顏色、邊緣、特定形狀所啟用。沿著深度方向上排列的叫做深度列depth column

2、步長是卷積核滑動的距離,例如stride=1表示滑動一個畫素;stride=2卷積核會滑動2個畫素,這樣得到的輸出width和height會比輸入小。

3、有時候,在輸入的邊緣上填充0會給計算帶來方便,這種操作叫做零填充zero-padding。零填充的大小也是一個超引數,其大小會影響輸出在空間上的大小(常常用來填充,使得輸入和輸入的width和height大小一致)

計算輸出在空間的大小,輸入的size為W,卷積核size為F,步長為S,零填充為P,那麼輸出的size為(W - F + 2P)/ S + 1。例如輸入為7x7,卷積核3x3,零填充為0,步長為1,那麼輸入大小為5x5;如果步長為2,那麼輸出大小為3x3。

cs231n08_04.jpeg
上圖是沿著某一維度的例子,輸入是7x7,卷積核是3x3(最右邊),bias為零;左邊stride=1,中間stride=2。注意(W - F + 2P)/ S一點要可以整除。

權重在同一個輸入的啟用圖上,是共享的。

零填充的使用:上面的例子中,輸出的size比輸入小,如果使用零填充P = (F - 1)/2,那麼輸出和輸出size大小將一致。

步長的限制:超引數有一些限制。例如,W = 10, P = 10, F = 3,那麼步長S = 2就不合適,因為(W - F + 2P)/S + 1 = (10 − 3 + 0) / 2 + 1 = 4.5,不是整數,這將導致神經元不能整齊滑過輸入資料。這樣的引數被認為是無效的。卷積網路庫可能會報異常,或者通過零填充/裁剪來使大小合理。

實際例子:AlexNet輸入大小為[227x227x3],第一個卷積層F=11,S=4,P=0,(227-11)/4+1=55,第一個卷積層depth**K=96**,所有共有96個卷積核,每個卷積核[11x11x3]。

引數共享,引數共享可以減少引數個數。以AlexNet第一個卷積層為例,共有神經元55*55*96=290,400,如果不適用引數共享,每個神經元有11*11*3=363個權重和1個bias,共有引數290400*364=105,705,600 個。

可以基於幾個假設來減少引數:如果計算位置(x,y)處的某一特徵的卷積核,應該可以計算不同位置(x2,y2)處的相同特徵,所以可以使用同一個卷積核。即可以在深度方向上做一個2維切片(depth slice),每個切片使用相同權重。這樣AlexNet第一層就有96*11*11*3=34,848個權重和96個bias。在反向傳播時,要計算每個神經元都權重的梯度,這樣要在一個深度切片上進行累加,更新時,單獨更新每一個深度切片對應的權重。

注意,如果在一個深度切片上使用相同的權重,那麼前向傳播就是輸入資料和權重的卷積運算(卷積層名字的由來),這也是為什麼稱權重為濾波器或卷積核。

cs231n08_05.jpeg

上圖是AlexNet第一個卷積層權重[11x11x3]的視覺化,對應96個不同卷積核,每個權重用來計算[55x55]個神經元。注意到引數共享是合理的:如果檢測某一位置水平方向邊界很重要,那麼也應該適用於其他地方,因為具有平移不變性。因此沒有必要再學習一個檢測水平邊界的卷積核了。

有時引數共享假設並沒有意義。例如輸入影象有明確的中心結構,這時我們希望在不同位置學習到不同特徵。一個典型的例子就是人臉檢測,人臉就位於影象中心位置,其他位置可能學到眼睛或頭髮特徵;這種情況,就需要放鬆引數共享的限制,稱這樣的層叫做區域性連線層Locallly-Connected Layer

Numpy example,下面使用Numpy一個具體例子來說明,假設Numpy陣列為X

  • 在深度上的某一列位置(x,y),表示為X[x,y,:]
  • 在深度d上的一個切片,表示為X[:,:,d]

假設輸入X的形狀X.shape:(11,11,4)。零填充P=0,濾波器核F=5,步長S=2,輸出size為(11-5)/2+1=4,輸出用V來表示:

  • V[0,0,0] = np.sum(X[:5,:5,:] * W0) + b0
  • V[1,0,0] = np.sum(X[2:7,:5,:] * W0) + b0
  • V[2,0,0] = np.sum(X[4:9,:5,:] * W0) + b0
  • V[3,0,0] = np.sum(X[6:11,:5,:] * W0) + b0

其中,*表示逐個元素相乘,W0表示權重,b0表示偏置bias,W0大小W0.shape:(5,5,4),5表示卷積核大小,4表示深度。計算在同一個深度切片時,使用的是同一個權重和bias,這就是引數共享。第二個特徵圖計算:

  • V[0,0,1] = np.sum(X[:5,:5,:] * W1) + b1
  • V[1,0,1] = np.sum(X[2:7,:5,:] * W1) + b1
  • V[2,0,1] = np.sum(X[4:9,:5,:] * W1) + b1
  • V[3,0,1] = np.sum(X[6:11,:5,:] * W1) + b1
  • V[0,1,1] = np.sum(X[:5,2:7,:] * W1) + b1
  • V[2,3,1] = np.sum(X[4:9,6:11,:] * W1) + b1

上面是計算第二個特徵圖的過程。計算特徵圖後,往往跟著非線性操作例如ReLU,這裡沒有展示。

總結

  • 輸入資料size:W1×H1×D1
  • 需要使用的超引數:
    1、卷積核個數K
    2、卷積核大小F
    3、步長S
    4、零填充大小P
  • 輸出大小size為W2×H2×D2,其中
    W2=(W1F+2P)/S+1
    H2=(H1F+2P)/S+1
    D2=K
  • 使用超引數共享,每個濾波器權重個數FFD1,共有權重(FFD1)K個,偏置K個。

  • 輸出中,在深度的第d個切片上(size為W2×H2),其結果是第d個卷積核與輸入卷積的結果,卷積步長為S

超引數的設定,習慣為F=3,S=1,P=1

卷積例子
因為3維資料難以視覺化,下面圖中,每一行是深度上的一個切片,輸入時藍色,權重是紅色,輸出是綠色。輸入sizeW1=5,H1=5,D1=3,卷積層引數K=2,F=3,S=2,P=1,即有2個3×3的卷積核,步長為2,零填充為P=1。下面是動態示意圖:

cs231n08_06.gif

以矩陣乘積方式實現
卷積操作是輸入的區域性區域和卷積核的點乘,可以利用這一點用一個大矩陣相乘來實現:
1、使用im2col操作,把輸入的區域性區域當做一列,展開為一個大矩陣。例如輸入[227x227x3],卷積核[11x11x3],步長為4;從輸入中取出[11x11x3]大小的塊展開為一個列向量,列向量大小為11*11*3=363。沿著步長為4來重複進行這個操作,在width和height方向分別迭代(227-11)/4+1=55次,共進行55*55=3025次。這樣展開後矩陣X_col的size大小為[363x3025],每一列是區域性視野展開後的資料。注意區域性視野有重疊,因此展開後的列可能會有重複。
2、卷積核的權重展開為行。例如96個[11x11x3]的卷積核,展開後的權重矩陣W_row大小為[96x363]。
3、卷積的結果為上面兩個矩陣相乘np.dot(W_row,X_col),相當於卷積核和感受視野的點乘。上面的例子中,得到結果為[96x3025]。
4、把得到的結果重新排列,正確的size為[55x55x96]。

這個方法的缺點是佔用了過多記憶體,因為X_col中的資料有重複;優點是可以高效實用矩陣乘法(使用BLAS介面)。這個思想同樣適用於pooling操作。

反向傳播
卷積反向傳播同樣是卷積操作(對於資料和權重都是,但是在空間反轉)。

1x1卷積
論文Network in Network首次發明了1x1卷積,訊號處理背景的人可能疑惑。通常訊號是2維資料,1x1卷積沒有意義(只是縮放)。但是在卷積網路中,資料是3維的,濾波器深度和輸入資料深度相同。例如輸入[32x32x3],使用1x1卷積,是3維的點乘。

擴展卷積
Fisher Yu and Vladlen Kultun的論文引入了另外一個超引數叫做擴張dilation。前面我們討論的卷積核是連續的,同樣卷積核之間也可以有間隔。例如size為3的卷積核計算輸入為xw[0]*x[0] + w[1]*x[1] + w[2]*x[2],這是dilation為0的情況;如果dilation為1,那麼計算為w[0]*x[0] + w[1]*x[2] + w[2]*x[4]。擴張卷積核正常卷積結合非常有用,例如可以在很少的層中匯聚到大尺度特徵。使用2個3x3卷積,第二個卷積對輸入資料的感受視野為5x5。可以看出如果使用擴展卷積,感受視野將迅速增長。

池化層

在卷積神經網路中,常常在連續卷積層中間隔插入池化層。池化操作可以減小資料量,從而減小引數,降低計算,因此防止過擬合。池化操作在每個深度切片上進行,例如使用MAX操作。常用的池化核實2x2大小,在每個深度切片的width和height方向下進行下采樣,忽略掉75%(3/4)的啟用資訊。池化操作,保持深度depth大小不變。

池化層配置:

  • 接收資料size W1×H1×D1
  • 需要引數
    1、池化核大小F
    2、步長S
  • 輸出資料大小W2×H2×D2
    W2=(W1F)/S+1
    H2=(H1F)/S+1
    D2=D1

  • 池化層沒有引數。

  • 注意,在池化層一般不會使用零填充。

在實際使用中,最長見到的兩種池化層配置:F=3,S=2(叫做重疊池化);F=2,S=2,這個更常見。更大的池化核對網路有破壞性。

通用池化
除了MAX池化操作外,還有平均池化核L2-norm池化。平均池化在歷史上用的比較多,現在漸漸被遺棄,因為和MAX池化相比,MAX池化往往效能更好。

cs231n08_06.jpeg
上圖就是池化過程。左圖輸入為[224x224x64],池化核[2x2],輸出為[112x112x64];右圖為池化具體計算過程,使用的是MAX池化。

反向傳播
前面提到,對於max(x,y)的前向傳播,只允許值大的通過;反向傳播時只允許值大的輸入的梯度反向傳播。因此,池化層前向傳播時記錄下值大者的索引(有時叫做switches),這樣反向傳播就很高效。

去掉池化
有些人不喜歡池化操作,可以考慮去掉池化層。例如Striving for Simplicity: The All Convolutional Net中全是重複的卷積層。為了降低資料大小,使用了大的步長。為了訓練一個好的生成網路,可以去掉池化層,例如自編碼(VAEs)或生成對抗網路(GANs:generative adversarial networks)。在未來的架構中,不使用池化層的可能性比較小。

歸一化層

歸一化層(Normalization Layer)是根據對大腦觀察原理得來的。實踐中有很多型別歸一化層,但它們基本沒有什麼效果,即使有也微乎其微。因此逐漸被放棄。想了解歸一化層,可以參考cuda-convnet library API.

全連線層

如果一層的神經元和前一層的每個神經元都有連線,這樣的層叫做全連線層。這樣的層可以使用矩陣相乘再加上bias即可。

全連線層轉為卷積層

全連線層和卷積層相似,卷積層的神經元和上一層輸出區域性區域相連線,使用了引數共享;因此它們之間可以相互轉換。

  • 一個卷積層,可以用一個全連線層來替換;替換後權重矩陣非常大,且大部分為零(因為卷積只是區域性連線),權重矩陣中很多塊相同(因為引數共享)。

  • 全連線層可以轉換為卷積層。例如對於一個全連線層K=