卷積神經網絡類似于一般的神經網絡,由可學習的權重和誤差組成,每一個神經元接受一些輸入,完成一些非線性的操作。整個神經網絡完成了一個可微的打分函數,從圖像點到分類得分。在全連接或者最后一層他們也有一個損失函數。
而卷積神經網絡中有明確的假設那就是輸入時圖像,這代表了網絡機構具有特殊的性質。
概覽
神經網絡接受一個單個的輸入并且沿著一系列的隱含層轉換。每個隱含層由一系列的神經元構成,在單層的神經元中相互獨立而且沒有什么聯系,最后一層叫做輸出層,在分類問題中代表著類的分數。
普通的神經網絡對于圖像數據表現并不好,因為權重的參數過多,沒辦法很快的訓練。3d容量的神經元,cnn每層的神經元都有三個維度,長寬高。在每一層神經元都會連接到一個小的區域而不是全部鏈接。
用來建立卷積神經網絡的層
一個簡單的卷積神經網絡是一層,每一層都通過一個可微的函數轉化成另一個網絡層。我們用三種結構來建立卷積神經網絡,convolutional,pooling以及fully connected 層。
INPUT-CONV-RELU-POOL-FC
- 輸入[32x32x3]存有圖像的原始像素值,本例中圖像寬高均為32,有3個顏色通道。
- 卷積層中,神經元與輸入層中的一個局部區域相連,每個神經元都計算自己與輸入層相連的小區域與自己權重的內積。卷積層會計算所有神經元的輸出。如果我們使用12個濾波器(也叫作核),得到的輸出數據體的維度就是[32x32x12]。
-
ReLU層將會逐個元素地進行激活函數操作,比如使用以0為閾值的max(0,x)
作為激活函數。該層對數據尺寸沒有改變,還是[32x32x12]。
- 匯聚層在在空間維度(寬度和高度)上進行降采樣(downsampling)操作,數據尺寸變為[16x16x12]。
- 全連接層將會計算分類評分,數據尺寸變為[1x1x10],其中10個數字對應的就是CIFAR-10中10個類別的分類評分值。正如其名,全連接層與常規神經網絡一樣,其中每個神經元都與前一層中所有神經元相連接。
卷積層
卷積層是建立cnn的主要步驟。大意是說,首先由很多個深度一樣但是大小比較小的過濾器,然后這個過濾器在整個面積上進行移動,在移動的過程中產生一個單獨的2維的激活層,然后我們把每一個激活層疊加在一起就產生了一個結果輸出。
換個說法,每一個3維的輸出都可以被解釋成一個僅僅對應一個小部分的神經元,與其他的空間上的神經元共享參數,應用同樣的篩選器,現在我們來討論神經元鏈接情況的細節,包括空間的分布等等。
本地的連接,當我們處理高維的輸入比如圖像的時候,把神經元與過去所有的神經元鏈接是不實際的,換句話說,我們可以把神經元在局部連接在一起,但是在空間上擴展這種連接的參數。連接的程度總是等于輸入的深度,強調這種對稱性很重要在我們處理這三個維度上:因為這種連接在長和寬上是局部的,但是在深度上是完全的。
空間管理:我們已經解釋了每個卷積層對于輸入容量的連接,但是我們還沒有討論到底有多少個神經元或者他們是怎么分布的。參數控制:depth,stride和padding就是控制輸出的重要參數。
depth:首先,輸出量的深度是一個超級參數:它對應于我們想要使用的過濾器的數量,每個學習在輸入中尋找不同的東西。例如,如果第一卷積層作為原始圖像的輸入,則沿著深度維度的不同神經元可以在存在各種定向邊緣或顏色的斑點的情況下激活。我們將參考一組神經元,它們都是與輸入的相同區域作為深度列(有些人也喜歡術語-纖維)。
其次,我們必須指定我們滑動過濾器的步幅。當步幅為1時,我們一次移動一個像素的濾鏡。當步幅為2(或不常見的3或更多,雖然這在實踐中是罕見的),然后當我們滑動它們時,過濾器一次跳過2像素。這將在空間上產生較小的產量。
此零填充的大小是超參數。零填充的一個很好的特點是,它將允許我們控制輸出量的空間大小(最常見的是我們將會看到,我們將很快使用它來精確保留輸入容積的空間大小,從而輸入和輸出寬度高度相同)。
輸出數據體在空間上的尺寸可以通過輸入數據體尺寸(W),卷積層中神經元的感受野尺寸(F),步長(S)和零填充的數量(P)的函數來計算。(譯者注:這里假設輸入數組的空間形狀是正方形,即高度和寬度相等)輸出數據體的空間尺寸為(W-F +2P)/S+1。比如輸入是7x7,濾波器是3x3,步長為1,填充為0,那么就能得到一個5x5的輸出。如果步長為2,輸出就是3x3。下面是例子:
使用零填充:在上面左邊例子中,注意輸入維度是5,輸出維度也是5。之所以如此,是因為感受野是3并且使用了1的零填充。如果不使用零填充,則輸出數據體的空間維度就只有3,因為這就是濾波器整齊滑過并覆蓋原始數據需要的數目。一般說來,當步長
步長的限制:注意這些空間排列的超參數之間是相互限制的。舉例說來,當輸入尺寸
真實案例:Krizhevsky*
"); background-size: cover; background-position: 0px 2px;">*構架贏得了2012年的ImageNet挑戰,其輸入圖像的尺寸是[227x227x3]。在第一個卷積層,神經元使用的感受野尺寸
參數共享:在卷積層中使用參數共享是用來控制參數的數量。就用上面的例子,在第一個卷積層就有55x55x96=290,400個神經元,每個有11x11x3=364個參數和1個偏差。將這些合起來就是290400x364=105,705,600個參數。單單第一層就有這么多參數,顯然這個數目是非常大的。
作一個合理的假設:如果一個特征在計算某個空間位置(x,y)的時候有用,那么它在計算另一個不同位置(x2,y2)的時候也有用。基于這個假設,可以顯著地減少參數數量。換言之,就是將深度維度上一個單獨的2維切片看做深度切片(depth slice),比如一個數據體尺寸為[55x55x96]的就有96個深度切片,每個尺寸為[55x55]。在每個深度切片上的神經元都使用同樣的權重和偏差。在這樣的參數共享下,例子中的第一個卷積層就只有96個不同的權重集了,一個權重集對應一個深度切片,共有96x11x11x3=34,848個不同的權重,或34,944個參數(+96個偏差)。在每個深度切片中的55x55個權重使用的都是同樣的參數。在反向傳播的時候,都要計算每個神經元對它的權重的梯度,但是需要把同一個深度切片上的所有神經元對權重的梯度累加,這樣就得到了對共享權重的梯度。這樣,每個切片只更新一個權重集。
注意,如果在一個深度切片中的所有權重都使用同一個權重向量,那么卷積層的前向傳播在每個深度切片中可以看做是在計算神經元權重和輸入數據體的卷積(這就是“卷積層”名字由來)。這也是為什么總是將這些權重集合稱為濾波器(filter)(或卷積核(kernel)),因為它們和輸入進行了卷積。
注意有時候參數共享假設可能沒有意義,特別是當卷積神經網絡的輸入圖像是一些明確的中心結構時候。這時候我們就應該期望在圖片的不同位置學習到完全不同的特征。一個具體的例子就是輸入圖像是人臉,人臉一般都處于圖片中心。你可能期望不同的特征,比如眼睛特征或者頭發特征可能(也應該)會在圖片的不同位置被學習。在這個例子中,通常就放松參數共享的限制,將層稱為局部連接層(Locally-Connected Layer)。
Numpy例子:為了讓討論更加的具體,我們用代碼來展示上述思路。假設輸入數據體是numpy數組X。那么:
一個位于(x,y)的深度列(或纖維)將會是X[x,y,:]。
在深度為d處的深度切片,或激活圖應該是X[:,:,d]。
卷積層例子:假設輸入數據體X的尺寸X.shape:(11,11,4),不使用零填充(
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
在numpy中,*操作是進行數組間的逐元素相乘。權重向量W0是該神經元的權重,b0是其偏差。在這里,W0被假設尺寸是W0.shape: (5,5,4),因為濾波器的寬高是5,輸入數據量的深度是4。注意在每一個點,計算點積的方式和之前的常規神經網絡是一樣的。同時,計算內積的時候使用的是同一個權重和偏差(因為參數共享),在寬度方向的數字每次上升2(因為步長為2)。要構建輸出數據體中的第二張激活圖,代碼應該是:
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 (在y方向上)
V[2,3,1] = np.sum(X[4:9,6:11,:] * W1) + b1 (或兩個方向上同時)
我們訪問的是V的深度維度上的第二層(即index1),因為是在計算第二個激活圖,所以這次試用的參數集就是W1了。在上面的例子中,為了簡潔略去了卷積層對于輸出數組V中其他部分的操作。還有,要記得這些卷積操作通常后面接的是ReLU層,對激活圖中的每個元素做激活函數運算,這里沒有顯示。
小結: 我們總結一下卷積層的性質:
輸入數據體的尺寸為
4個超參數:濾波器的數量
濾波器的空間尺寸
步長
零填充數量
,其中:
由于參數共享,每個濾波器包含
在輸出數據體中,第
對這些超參數,常見的設置是
卷積層演示:下面是一個卷積層的運行演示。因為3D數據難以可視化,所以所有的數據(輸入數據體是藍色,權重數據體是紅色,輸出數據體是綠色)都采取將深度切片按照列的方式排列展現。輸入數據體的尺寸是
"); background-size: cover; background-position: 0px 2px;">*查看此演示。
輸入圖像的局部區域被im2col操作拉伸為列。比如,如果輸入是[227x227x3],要與尺寸為11x11x3的濾波器以步長為4進行卷積,就取輸入中的[11x11x3]數據塊,然后將其拉伸為長度為11x11x3=363的列向量。重復進行這一過程,因為步長為4,所以輸出的寬高為(227-11)/4+1=55,所以得到im2col操作的輸出矩陣X_col的尺寸是[363x3025],其中每列是拉伸的感受野,共有55x55=3,025個。注意因為感受野之間有重疊,所以輸入數據體中的數字在不同的列中可能有重復。
卷積層的權重也同樣被拉伸成行。舉例,如果有96個尺寸為[11x11x3]的濾波器,就生成一個矩陣W_row,尺寸為[96x363]。
現在卷積的結果和進行一個大矩陣乘np.dot(W_row, X_col)是等價的了,能得到每個濾波器和每個感受野間的點積。在我們的例子中,這個操作的輸出是[96x3025],給出了每個濾波器在每個位置的點積輸出。
結果最后必須被重新變為合理的輸出尺寸[55x55x96]。
這個方法的缺點就是占用內存太多,因為在輸入數據體中的某些值在X_col中被復制了多次。但是,其優點是矩陣乘法有非常多的高效實現方式,我們都可以使用(比如常用的BLAS*
"); background-size: cover; background-position: 0px 2px;">*API)。還有,同樣的im2col思路可以用在匯聚操作中。
反向傳播:卷積操作的反向傳播(同時對于數據和權重)還是一個卷積(但是是和空間上翻轉的濾波器)。使用一個1維的例子比較容易演示。
1x1卷積:一些論文中使用了1x1的卷積,這個方法最早是在論文Network in Network*
"); background-size: cover; background-position: 0px 2px;">*中出現。人們剛開始看見這個1x1卷積的時候比較困惑,尤其是那些具有信號處理專業背景的人。因為信號是2維的,所以1x1卷積就沒有意義。但是,在卷積神經網絡中不是這樣,因為這里是對3個維度進行操作,濾波器和輸入數據體的深度是一樣的。比如,如果輸入是[32x32x3],那么1x1卷積就是在高效地進行3維點積(因為輸入深度是3個通道)。
擴張卷積:最近一個研究(Fisher Yu和Vladlen Koltun的論文*
"); background-size: cover; background-position: 0px 2px;">*)給卷積層引入了一個新的叫擴張(dilation)的超參數。到目前為止,我們只討論了卷積層濾波器是連續的情況。但是,讓濾波器中元素之間有間隙也是可以的,這就叫做擴張。舉例,在某個維度上濾波器w的尺寸是3,那么計算輸入x的方式是:w[0]x[0] + w[1]x[1] + w[2]x[2],此時擴張為0。如果擴張為1,那么計算為: w[0]x[0] + w[1]x[2] + w[2]x[4]。換句話說,操作中存在1的間隙。在某些設置中,擴張卷積與正常卷積結合起來非常有用,因為在很少的層數內更快地匯集輸入圖片的大尺度特征。比如,如果上下重疊2個3x3的卷積層,那么第二個卷積層的神經元的感受野是輸入數據體中5x5的區域(可以成這些神經元的有效感受野是5x5)。如果我們對卷積進行擴張,那么這個有效感受野就會迅速增長。
匯聚層
通常,在連續的卷積層之間會周期性地插入一個匯聚層。它的作用是逐漸降低數據體的空間尺寸,這樣的話就能減少網絡中參數的數量,使得計算資源耗費變少,也能有效控制過擬合。匯聚層使用MAX操作,對輸入數據體的每一個深度切片獨立進行操作,改變它的空間尺寸。最常見的形式是匯聚層使用尺寸2x2的濾波器,以步長為2來對每個深度切片進行降采樣,將其中75%的激活信息都丟掉。每個MAX操作是從4個數字中取最大值(也就是在深度切片中某個2x2的區域)。深度保持不變。匯聚層的一些公式:
輸入數據體尺寸
有兩個超參數:
空間大小
步長
,其中
在匯聚層中很少使用零填充
在實踐中,最大匯聚層通常只有兩種形式:一種是
普通匯聚(General Pooling):除了最大匯聚,匯聚單元還可以使用其他的函數,比如平均匯聚(average pooling)或L-2范式匯聚(L2-norm pooling)。平均匯聚歷史上比較常用,但是現在已經很少使用了。因為實踐證明,最大匯聚的效果比平均匯聚要好。
不使用匯聚層:很多人不喜歡匯聚操作,認為可以不使用它。比如在Striving for Simplicity: The All Convolutional Net*
"); background-size: cover; background-position: 0px 2px;">*一文中,提出使用一種只有重復的卷積層組成的結構,拋棄匯聚層。通過在卷積層中使用更大的步長來降低數據體的尺寸。有發現認為,在訓練一個良好的生成模型時,棄用匯聚層也是很重要的。比如變化自編碼器(VAEs:variational autoencoders)和生成性對抗網絡(GANs:generative adversarial networks)。現在看起來,未來的卷積網絡結構中,無匯聚層的結構不太可能扮演重要的角色。
歸一化層
在卷積神經網絡的結構中,提出了很多不同類型的歸一化層,有時候是為了實現在生物大腦中觀測到的抑制機制。但是這些層漸漸都不再流行,因為實踐證明它們的效果即使存在,也是極其有限的。對于不同類型的歸一化層,可以看看Alex Krizhevsky的關于cuda-convnet library API*
"); background-size: cover; background-position: 0px 2px;">*的討論。
全連接層
在全連接層中,神經元對于前一層中的所有激活數據是全部連接的,這個常規神經網絡中一樣。它們的激活可以先用矩陣乘法,再加上偏差。更多細節請查看神經網絡章節。
把全連接層轉化成卷積層
全連接層和卷積層之間唯一的不同就是卷積層中的神經元只與輸入數據中的一個局部區域連接,并且在卷積列中的神經元共享參數。然而在兩類層中,神經元都是計算點積,所以它們的函數形式是一樣的。因此,將此兩者相互轉化是可能的:
對于任一個卷積層,都存在一個能實現和它一樣的前向傳播函數的全連接層。權重矩陣是一個巨大的矩陣,除了某些特定塊(這是因為有局部連接),其余部分都是零。而在其中大部分塊中,元素都是相等的(因為參數共享)。
相反,任何全連接層都可以被轉化為卷積層。比如,一個
全連接層轉化為卷積層:在兩種變換中,將全連接層轉化為卷積層在實際運用中更加有用。假設一個卷積神經網絡的輸入是224x224x3的圖像,一系列的卷積層和匯聚層將圖像數據變為尺寸為7x7x512的激活數據體(在AlexNet中就是這樣,通過使用5個匯聚層來對輸入數據進行空間上的降采樣,每次尺寸下降一半,所以最終空間尺寸為224/2/2/2/2/2=7)。從這里可以看到,AlexNet使用了兩個尺寸為4096的全連接層,最后一個有1000個神經元的全連接層用于計算分類評分。我們可以將這3個全連接層中的任意一個轉化為卷積層:針對第一個連接區域是[7x7x512]的全連接層,令其濾波器尺寸為
針對第二個全連接層,令其濾波器尺寸為
對最后一個全連接層也做類似的,令其
實際操作中,每次這樣的變換都需要把全連接層的權重W重塑成卷積層的濾波器。那么這樣的轉化有什么作用呢?它在下面的情況下可以更高效:讓卷積網絡在一張更大的輸入圖片上滑動(譯者注:即把一張更大的圖片的不同區域都分別帶入到卷積網絡,得到每個區域的得分),得到多個輸出,這樣的轉化可以讓我們在單個向前傳播的過程中完成上述的操作。
舉個例子,如果我們想讓224x224尺寸的浮窗,以步長為32在384x384的圖片上滑動,把每個經停的位置都帶入卷積網絡,最后得到6x6個位置的類別得分。上述的把全連接層轉換成卷積層的做法會更簡便。如果224x224的輸入圖片經過卷積層和匯聚層之后得到了[7x7x512]的數組,那么,384x384的大圖片直接經過同樣的卷積層和匯聚層之后會得到[12x12x512]的數組(因為途徑5個匯聚層,尺寸變為384/2/2/2/2/2 = 12)。然后再經過上面由3個全連接層轉化得到的3個卷積層,最終得到[6x6x1000]的輸出(因為(12 - 7)/1 + 1 = 6)。這個結果正是浮窗在原圖經停的6x6個位置的得分!(譯者注:這一段的翻譯與原文不同,經過了譯者較多的修改,使更容易理解)
面對384x384的圖像,讓(含全連接層)的初始卷積神經網絡以32像素的步長獨立對圖像中的224x224塊進行多次評價,其效果和使用把全連接層變換為卷積層后的卷積神經網絡進行一次前向傳播是一樣的。
自然,相較于使用被轉化前的原始卷積神經網絡對所有36個位置進行迭代計算,使用轉化后的卷積神經網絡進行一次前向傳播計算要高效得多,因為36次計算都在共享計算資源。這一技巧在實踐中經常使用,一次來獲得更好的結果。比如,通常將一張圖像尺寸變得更大,然后使用變換后的卷積神經網絡來對空間上很多不同位置進行評價得到分類評分,然后在求這些分值的平均值。
最后,如果我們想用步長小于32的浮窗怎么辦?用多次的向前傳播就可以解決。比如我們想用步長為16的浮窗。那么先使用原圖在轉化后的卷積網絡執行向前傳播,然后分別沿寬度,沿高度,最后同時沿寬度和高度,把原始圖片分別平移16個像素,然后把這些平移之后的圖分別帶入卷積網絡。(譯者注:這一段的翻譯與原文不同,經過了譯者較多的修改,使更容易理解)
Net Surgery*
"); background-size: cover; background-position: 0px 2px;">*上一個使用Caffe演示如何在進行變換的IPython Note教程。
卷積神經網絡的結構
卷積神經網絡通常是由三種層構成:卷積層,匯聚層(除非特別說明,一般就是最大值匯聚)和全連接層(簡稱FC)。ReLU激活函數也應該算是是一層,它逐元素地進行激活函數操作。在本節中將討論在卷積神經網絡中這些層通常是如何組合在一起的。
層的排列規律
卷積神經網絡最常見的形式就是將一些卷積層和ReLU層放在一起,其后緊跟匯聚層,然后重復如此直到圖像在空間上被縮小到一個足夠小的尺寸,在某個地方過渡成成全連接層也較為常見。最后的全連接層得到輸出,比如分類評分等。換句話說,最常見的卷積神經網絡結構如下:
INPUT -> [[CONV -> RELU]N -> POOL?]M -> [FC -> RELU]K -> FC*
其中*****指的是重復次數,POOL?指的是一個可選的匯聚層。其中N >=0,通常N<=3,M>=0,K>=0,通常K<3。例如,下面是一些常見的網絡結構規律:
INPUT -> FC,實現一個線性分類器,此處N = M = K = 0。
INPUT -> CONV -> RELU -> FC
INPUT -> [CONV -> RELU -> POOL]2 -> FC -> RELU -> FC。此處在每個匯聚層之間有一個卷積層。
INPUT -> [CONV -> RELU -> CONV -> RELU -> POOL]3 -> [FC -> RELU]2 -> FC*。此處每個匯聚層前有兩個卷積層,這個思路適用于更大更深的網絡,因為在執行具有破壞性的匯聚操作前,多重的卷積層可以從輸入數據中學習到更多的復雜特征。
幾個小濾波器卷積層的組合比一個大濾波器卷積層好:假設你一層一層地重疊了3個3x3的卷積層(層與層之間有非線性激活函數)。在這個排列下,第一個卷積層中的每個神經元都對輸入數據體有一個3x3的視野。第二個卷積層上的神經元對第一個卷積層有一個3x3的視野,也就是對輸入數據體有5x5的視野。同樣,在第三個卷積層上的神經元對第二個卷積層有3x3的視野,也就是對輸入數據體有7x7的視野。假設不采用這3個3x3的卷積層,二是使用一個單獨的有7x7的感受野的卷積層,那么所有神經元的感受野也是7x7,但是就有一些缺點。首先,多個卷積層與非線性的激活層交替的結構,比單一卷積層的結構更能提取出深層的更好的特征。其次,假設所有的數據有
最新進展:傳統的將層按照線性進行排列的方法已經受到了挑戰,挑戰來自谷歌的Inception結構和微軟亞洲研究院的殘差網絡(Residual Net)結構。這兩個網絡(下文案例學習小節中有細節)的特征更加復雜,連接結構也不同。
層的尺寸設置規律
到現在為止,我們都沒有提及卷積神經網絡中每層的超參數的使用。現在先介紹設置結構尺寸的一般性規則,然后根據這些規則進行討論:
輸入層(包含圖像的)應該能被2整除很多次。常用數字包括32(比如CIFAR-10),64,96(比如STL-10)或224(比如ImageNet卷積神經網絡),384和512。
卷積層應該使用小尺寸濾波器(比如3x3或最多5x5),使用步長
匯聚層負責對輸入數據的空間維度進行降采樣。最常用的設置是用用2x2感受野(即
減少尺寸設置的問題:上文中展示的兩種設置是很好的,因為所有的卷積層都能保持其輸入數據的空間尺寸,匯聚層只負責對數據體從空間維度進行降采樣。如果使用的步長大于1并且不對卷積層的輸入數據使用零填充,那么就必須非常仔細地監督輸入數據體通過整個卷積神經網絡結構的過程,確認所有的步長和濾波器都尺寸互相吻合,卷積神經網絡的結構美妙對稱地聯系在一起。
為什么在卷積層使用1的步長?在實際應用中,更小的步長效果更好。上文也已經提過,步長為1可以讓空間維度的降采樣全部由匯聚層負責,卷積層只負責對輸入數據體的深度進行變換。
為何使用零填充?使用零填充除了前面提到的可以讓卷積層的輸出數據保持和輸入數據在空間維度的不變,還可以提高算法性能。如果卷積層值進行卷積而不進行零填充,那么數據體的尺寸就會略微減小,那么圖像邊緣的信息就會過快地損失掉。
因為內存限制所做的妥協:在某些案例(尤其是早期的卷積神經網絡結構)中,基于前面的各種規則,內存的使用量迅速飆升。例如,使用64個尺寸為3x3的濾波器對224x224x3的圖像進行卷積,零填充為1,得到的激活數據體尺寸是[224x224x64]。這個數量就是一千萬的激活數據,或者就是72MB的內存(每張圖就是這么多,激活函數和梯度都是)。因為GPU通常因為內存導致性能瓶頸,所以做出一些妥協是必須的。在實踐中,人們傾向于在網絡的第一個卷積層做出妥協。例如,可以妥協可能是在第一個卷積層使用步長為2,尺寸為7x7的濾波器(比如在ZFnet中)。在AlexNet中,濾波器的尺寸的11x11,步長為4。
案例學習
下面是卷積神經網絡領域中比較有名的幾種結構:
LeNet: 第一個成功的卷積神經網絡應用,是Yann LeCun在上世紀90年代實現的。當然,最著名還是被應用在識別數字和郵政編碼等的LeNet*
"); background-size: cover; background-position: 0px 2px;">*結構。
AlexNet:AlexNet*
"); background-size: cover; background-position: 0px 2px;">*卷積神經網絡在計算機視覺領域中受到歡迎,它由Alex Krizhevsky,Ilya Sutskever和Geoff Hinton實現。AlexNet在2012年的ImageNet ILSVRC 競賽*
"); background-size: cover; background-position: 0px 2px;">*中奪冠,性能遠遠超出第二名(16%的top5錯誤率,第二名是26%的top5錯誤率)。這個網絡的結構和LeNet非常類似,但是更深更大,并且使用了層疊的卷積層來獲取特征(之前通常是只用一個卷積層并且在其后馬上跟著一個匯聚層)。
ZF Net:Matthew Zeiler和Rob Fergus發明的網絡在ILSVRC 2013比賽中奪冠,它被稱為 ZFNet*
"); background-size: cover; background-position: 0px 2px;">*(Zeiler & Fergus Net的簡稱)。它通過修改結構中的超參數來實現對AlexNet的改良,具體說來就是增加了中間卷積層的尺寸,讓第一層的步長和濾波器尺寸更小。
GoogLeNet:ILSVRC 2014的勝利者是谷歌的Szeged等*
"); background-size: cover; background-position: 0px 2px;">*實現的卷積神經網絡。它主要的貢獻就是實現了一個奠基模塊,它能夠顯著地減少網絡中參數的數量(AlexNet中有60M,該網絡中只有4M)。還有,這個論文中沒有使用卷積神經網絡頂部使用全連接層,而是使用了一個平均匯聚,把大量不是很重要的參數都去除掉了。GooLeNet還有幾種改進的版本,最新的一個是Inception-v4*
"); background-size: cover; background-position: 0px 2px;">*。
VGGNet:ILSVRC 2014的第二名是Karen Simonyan和 Andrew Zisserman實現的卷積神經網絡,現在稱其為VGGNet*
"); background-size: cover; background-position: 0px 2px;">*。它主要的貢獻是展示出網絡的深度是算法優良性能的關鍵部分。他們最好的網絡包含了16個卷積/全連接層。網絡的結構非常一致,從頭到尾全部使用的是3x3的卷積和2x2的匯聚。他們的預訓練模型*
"); background-size: cover; background-position: 0px 2px;">*是可以在網絡上獲得并在Caffe中使用的。VGGNet不好的一點是它耗費更多計算資源,并且使用了更多的參數,導致更多的內存占用(140M)。其中絕大多數的參數都是來自于第一個全連接層。后來發現這些全連接層即使被去除,對于性能也沒有什么影響,這樣就顯著降低了參數數量。
ResNet:殘差網絡*
"); background-size: cover; background-position: 0px 2px;">*(Residual Network)是ILSVRC2015的勝利者,由何愷明等實現。它使用了特殊的跳躍鏈接,大量使用了批量歸一化*
"); background-size: cover; background-position: 0px 2px;">*(batch normalization)。這個結構同樣在最后沒有使用全連接層。讀者可以查看何愷明的的演講(視頻*
"); background-size: cover; background-position: 0px 2px;">*,PPT*
"); background-size: cover; background-position: 0px 2px;">*),以及一些使用Torch重現網絡的實驗*
"); background-size: cover; background-position: 0px 2px;">*。ResNet當前最好的卷積神經網絡模型(2016年五月)。何開明等最近的工作是對原始結構做一些優化,可以看論文Identity Mappings in Deep Residual Networks*
"); background-size: cover; background-position: 0px 2px;">*,2016年3月發表。
VGGNet的細節:我們進一步對VGGNet*
"); background-size: cover; background-position: 0px 2px;">*的細節進行分析學習。整個VGGNet中的卷積層都是以步長為1進行3x3的卷積,使用了1的零填充,匯聚層都是以步長為2進行了2x2的最大值匯聚。可以寫出處理過程中每一步數據體尺寸的變化,然后對數據尺寸和整體權重的數量進行查看:
INPUT: [224x224x3] memory: 2242243=150K weights: 0CONV3-64: [224x224x64] memory: 22422464=3.2M weights: (333)64 = 1,728CONV3-64: [224x224x64] memory: 22422464=3.2M weights: (3364)64 = 36,864POOL2: [112x112x64] memory: 11211264=800K weights: 0CONV3-128: [112x112x128] memory: 112112128=1.6M weights: (3364)128 = 73,728CONV3-128: [112x112x128] memory: 112112128=1.6M weights: (33128)128 = 147,456POOL2: [56x56x128] memory: 5656128=400K weights: 0CONV3-256: [56x56x256] memory: 5656256=800K weights: (33128)256 = 294,912CONV3-256: [56x56x256] memory: 5656256=800K weights: (33256)256 = 589,824CONV3-256: [56x56x256] memory: 5656256=800K weights: (33256)256 = 589,824POOL2: [28x28x256] memory: 2828256=200K weights: 0CONV3-512: [28x28x512] memory: 2828512=400K weights: (33256)512 = 1,179,648CONV3-512: [28x28x512] memory: 2828512=400K weights: (33512)512 = 2,359,296CONV3-512: [28x28x512] memory: 2828512=400K weights: (33512)512 = 2,359,296POOL2: [14x14x512] memory: 1414512=100K weights: 0CONV3-512: [14x14x512] memory: 1414512=100K weights: (33512)512 = 2,359,296CONV3-512: [14x14x512] memory: 1414512=100K weights: (33512)512 = 2,359,296CONV3-512: [14x14x512] memory: 1414512=100K weights: (33512)512 = 2,359,296POOL2: [7x7x512] memory: 77512=25K weights: 0FC: [1x1x4096] memory: 4096 weights: 775124096 = 102,760,448FC: [1x1x4096] memory: 4096 weights: 40964096 = 16,777,216FC: [1x1x1000] memory: 1000 weights: 40961000 = 4,096,000TOTAL memory: 24M * 4 bytes ~= 93MB / image (only forward! ~*2 for bwd)TOTAL params: 138M parameters
注意,大部分的內存和計算時間都被前面的卷積層占用,大部分的參數都用在后面的全連接層,這在卷積神經網絡中是比較常見的。在這個例子中,全部參數有140M,但第一個全連接層就包含了100M的參數。
計算上的考量
在構建卷積神經網絡結構時,最大的瓶頸是內存瓶頸。大部分現代GPU的內存是3/4/6GB,最好的GPU大約有12GB的內存。要注意三種內存占用來源:
來自中間數據體尺寸:卷積神經網絡中的每一層中都有激活數據體的原始數值,以及損失函數對它們的梯度(和激活數據體尺寸一致)。通常,大部分激活數據都是在網絡中靠前的層中(比如第一個卷積層)。在訓練時,這些數據需要放在內存中,因為反向傳播的時候還會用到。但是在測試時可以聰明點:讓網絡在測試運行時候每層都只存儲當前的激活數據,然后丟棄前面層的激活數據,這樣就能減少巨大的激活數據量。
來自參數尺寸:即整個網絡的參數的數量,在反向傳播時它們的梯度值,以及使用momentum、Adagrad或RMSProp等方法進行最優化時的每一步計算緩存。因此,存儲參數向量的內存通常需要在參數向量的容量基礎上乘以3或者更多。
卷積神經網絡實現還有各種零散的內存占用,比如成批的訓練數據,擴充的數據等等。
一旦對于所有這些數值的數量有了一個大略估計(包含激活數據,梯度和各種雜項),數量應該轉化為以GB為計量單位。把這個值乘以4,得到原始的字節數(因為每個浮點數占用4個字節,如果是雙精度浮點數那就是占用8個字節),然后多次除以1024分別得到占用內存的KB,MB,最后是GB計量。如果你的網絡工作得不好,一個常用的方法是降低批尺寸(batch size),因為絕大多數的內存都是被激活數據消耗掉了。