作者:[寒小陽](http://blog.csdn.net/han_xiaoyang?viewmode=contents)
時間:2016年1月。
出處:[http://blog.csdn.net/han_xiaoyang/article/details/50542880](http://blog.csdn.net/han_xiaoyang/article/details/50542880)
聲明:版權所有,轉載請聯系作者并注明出處
### 1. 前言
前面九講對神經網絡的結構,組件,訓練方法,原理等做了介紹。現在我們回到本系列的核心:計算機視覺,神經網絡中的一種特殊版本在計算機視覺中使用最為廣泛,這就是大家都知道的卷積神經網絡。卷積神經網絡和普通的神經網絡一樣,由『神經元』按層級結構組成,其間的權重和偏移量都是可訓練得到的。同樣是輸入的數據和權重做運算,輸出結果輸入激勵神經元,輸出結果。從整體上看來,整個神經網絡做的事情,依舊是對于像素級別輸入的圖像數據,用得分函數計算最后各個類別的得分,然后我們通過最小化損失函數來得到最優的權重。之前的博文中介紹的各種技巧和訓練方法,以及注意事項,在這個特殊版本的神經網絡上依舊好使。
咳咳,我們來說說它的特殊之處,首先卷積神經網絡一般假定輸入就是圖片數據,也正是因為輸入是圖片數據,我們可以利用它的像素結構特性,去做一些假設來簡化神經網絡的訓練復雜度(減少訓練參數個數)。
### 2.卷積神經網總體結構一覽
我們前面講過的神經網絡結構都比較一致,輸入層和輸出層中間夾著數層隱藏層,每一層都由多個神經元組成,層和層之間是全連接的結構,同一層的神經元之間沒有連接。
卷積神經網絡是上述結構的一種特殊化處理,因為對于圖像這種數據而言,上面這種結構實際應用起來有較大的困難:就拿CIFAR-10舉例吧,圖片已經很小了,是32*32*3(長寬各32像素,3個顏色通道)的,那么在神經網絡當中,我們只看隱藏層中的一個神經元,就應該有32*32*3=3072個權重,如果大家覺得這個權重個數的量還行的話,再設想一下,當這是一個包含多個神經元的多層神經網(假設n個),再比如圖像的質量好一點(比如是200*200*3的),那將有200*200*3*n= 120000n個權重需要訓練,結果是拉著這么多參數訓練,基本跑不動,跑得起來也是『氣喘吁吁』,當然,最關鍵的是這么多參數的情況下,分分鐘模型就過擬合了。別急,別急,一會兒我們會提到卷積神經網絡的想法和簡化之處。
卷積神經網絡結構比較固定的原因之一,是圖片數據本身的合理結構,類圖像結構(200 * 200 * 3),我們也把卷積神經網絡的神經元排布成 width * height * depth的結構,也就是說這一層總共有width * height * depth個神經元,如下圖所示。舉個例子說,CIFAR-10的輸出層就是1 * 1* 10維的。另外我們后面會說到,每一層的神經元,其實只和上一層里某些小區域進行連接,而不是和上一層每個神經元全連接。


#### 3.卷積神經網絡的組成層
在卷積神經網絡中,有3種最主要的層:
- 卷積運算層
- pooling層
- 全連接層
一個完整的神經網絡就是由這三種層疊加組成的。
**結構示例**
我們繼續拿CIFAR-10數據集舉例,一個典型的該數據集上的卷積神經網絡分類器應該有[INPUT - CONV - RELU - POOL - FC]的結構,具體說來是這樣的:
- INPUT[32*32*3]包含原始圖片數據中的全部像素,長寬都是32,有RGB 3個顏色通道。
- CONV卷積層中,沒個神經元會和上一層的若干小區域連接,計算權重和小區域像素的內積,舉個例子可能產出的結果數據是[32*32*12]的。
- RELU層,就是神經元激勵層,主要的計算就是max(0,x),結果數據依舊是[32*32*12]。
- POOLing層做的事情,可以理解成一個下采樣,可能得到的結果維度就變為[16*16*12]了。
- 全連接層一般用于最后計算類別得分,得到的結果為[1*1*10]的,其中的10對應10個不同的類別。和名字一樣,這一層的所有神經元會和上一層的所有神經元有連接。
這樣,卷積神經網絡作為一個中間的通道,就一步步把原始的圖像數據轉成最后的類別得分了。有一個點我們要提一下,剛才說到了有幾種不同的神經網絡層,其中有一些層是有待訓練參數的,另外一些沒有。詳細一點說,卷積層和全連接層包含權重和偏移的;而RELU和POOLing層只是一個固定的函數運算,是不包含權重和偏移參數的。不過POOLing層包含了我們手動指定的超參數,這個我們之后會提到。
總結一下:
- 一個卷積神經網絡由多種不同類型的層(卷幾層/全連接層/RELU層/POOLing層等)疊加而成。
- 每一層的輸入結構是3維的數據,計算完輸出依舊是3維的數據。
- 卷積層和全連接層包含訓練參數,RELU和POOLing層不包含。
- 卷積層,全連接層和POOLing層包含超參數,RELU層沒有。
下圖為CIFAR-10數據集構建的一個卷積神經網絡結構示意圖:

既然有這么多不同的層級結構,那我們就展開來講講:
#### 3.1 卷積層
說起來,這是卷積神經網絡的核心層(從名字就可以看出來對吧-_-||)。
#### 3.1.1 卷積層綜述
**直觀看來**,卷積層的參數其實可以看做,一系列的可訓練/學習的過濾器。在前向計算過程中,我們輸入一定區域大小(width*height)的數據,和過濾器點乘后等到新的二維數據,然后滑過一個個濾波器,組成新的3維輸出數據。而我們可以理解成每個過濾器都只關心過濾數據小平面內的部分特征,當出現它學習到的特征的時候,就會呈現激活/activate態。
**局部關聯度**。這是卷積神經網絡的獨特之處其中之一,我們知道在高維數據(比如圖片)中,用全連接的神經網絡,實際工程中基本是不可行的。卷積神經網絡中每一層的神經元只會和上一層的一些局部區域相連,這就是所謂的局部連接性。你可以想象成,上一層的數據區,有一個滑動的窗口,只有這個窗口內的數據會和下一層神經元有關聯,當然,這個做法就要求我們手動敲定一個超參數:窗口大小。通常情況下,這個窗口的長和寬是相等的,我們把長x寬叫做receptive field。實際的計算中,這個窗口是會『滑動』的,會近似覆蓋圖片的所有小區域。
舉個實例,CIFAR-10中的圖片輸入數據為[32*32*3]的,如果我們把receptive field設為5*5,那receptive field的data都會和下一層的神經元關聯,所以共有5*5*3=75個權重,注意到最后的3依舊代表著RGB 3個顏色通道。
如果不是輸入數據層,中間層的data格式可能是[16 * 16 * 20]的,假如我們取3 * 3的receptive field,那單個神經元的權重為3*3*20=180。

**局部關聯細節**。我們剛才說到卷積層的局部關聯問題,這個地方有一個receptive field,也就是我們直觀理解上的『滑動數據窗口』。從輸入的數據到輸出數據,有三個超參數會決定輸出數據的維度,分別是深度/depth,步長/stride 和 填充值/zero-padding:
1. 所謂深度/depth,簡單說來指的就是卷積層中和上一層同一個輸入區域連接的神經元個數。這部分神經元會在遇到輸入中的不同feature時呈現activate狀態,舉個例子,如果這是第一個卷積層,那輸入到它的數據實際上是像素值,不同的神經元可能對圖像的邊緣。輪廓或者顏色會敏感。
1. 所謂步長/stride,是指的窗口從當前位置到下一個位置,『跳過』的中間數據個數。比如從圖像數據層輸入到卷積層的情況下,也許窗口初始位置在第1個像素,第二個位置在第5個像素,那么stride=5-1=4.
1. 所謂zero-padding是在原始數據的周邊補上0值的圈數。(下面第2張圖中的樣子)
這么解釋可能理解起來還是會有困難,我們找兩張圖來對應一下這三個量:

這是解決ImageNet分類問題用到的卷積神經網絡的一部分,我們看到卷積層直接和最前面的圖像層連接。圖像層的維度為[227 * 227 * 3],而receptive field設為11 * 11,圖上未標明,但是滑動窗口的步長stride設為4,深度depth為48+48=96(這是雙GPU并行設置),邊緣沒有補0,因此zero-padding為0,因此窗口滑完一行,總共停留次數為(data_len-receptive_field_len+2 * zero-padding)/stride+1=(227-11+2 * 0)/4+1=55,因為圖像的長寬相等,因此縱向窗口數也是55,最后得到的輸出數據維度為55 * 55 * 96維。

這是一張動態的卷積層計算圖,圖上的zero-padding為1,所以大家可以看到數據左右各補了一行0,窗口的長寬為3,滑動步長stride為2。
**關于zero-padding**,補0這個操作產生的根本原因是,為了保證窗口的滑動能從頭剛好到尾。舉個例子說,上2圖中的上面一幅圖,因為(data_len-receptive_field_len+2 * zero-padding)/stride剛好能夠整除,所以窗口左側貼著數據開始位置,滑到尾部剛好窗口右側能夠貼著數據尾部位置,因此是不需要補0的。而在下面那幅圖中,如果滑動步長設為4,你會發現第一次計算之后,窗口就無法『滑動』了,而尾部的數據,是沒有被窗口『看到過』的,因此補0能夠解決這個問題。
**關于窗口滑動步長**。大家可以發現一點,窗口滑動步長設定越小,兩次滑動取得的數據,重疊部分越多,但是窗口停留的次數也會越多,運算律大一些;窗口滑動步長設定越長,兩次滑動取得的數據,重疊部分越少,窗口停留次數也越少,運算量小,但是從一定程度上說數據信息不如上面豐富了。
#### 3.1.2 卷積層的參數共享
首先得說卷積層的參數共享是一個非常贊的處理方式,它使得卷積神經網絡的訓練計算復雜度和參數個數降低非常非常多。就拿實際解決ImageNet分類問題的卷積神經網絡結構來說,我們知道輸出結果有55*55*96=290400個神經元,而每個神經元因為和窗口內數據的連接,有11*11*3=363個權重和1個偏移量。所以總共有290400*364=105705600個權重。。。然后。。。恩,訓練要累掛了。。。
因此我們做了一個大膽的假設,我們剛才提到了,每一個神經元可以看做一個filter,對圖片中的數據窗區域做『過濾』。那既然是filter,我們干脆就假設這個神經元用于連接數據窗的權重是固定的,這意味著,對同一個神經元而言,不論上一層數據窗口停留在哪個位置,連接兩者之間的權重都是同一組數。那代表著,上面的例子中的卷積層,我們只需要 神經元個數*數據窗口維度=96*11*11*3=34848個權重。
如果對應每個神經元的權重是固定的,那么整個計算的過程就可以看做,一組固定的權重和不同的數據窗口數據做內積的過程,這在數學上剛好對應『卷積』操作,這也就是卷積神經網的名字來源。另外,因為每個神經元的權重固定,它可以看做一個恒定的filter,比如上面96個神經元作為filter可視化之后是如下的樣子:

需要說明的一點是,參數共享這個策略并不是每個場景下都合適的。有一些特定的場合,我們不能把圖片上的這些窗口數據都視作作用等同的。一個很典型的例子就是人臉識別,一般人的面部都集中在圖像的中央,因此我們希望,數據窗口滑過這塊區域的時候,權重和其他邊緣區域是不同的。我們有一種特殊的層對應這種功能,叫做局部連接層/Locally-Connected Layer
#### 3.1.3 卷積層的簡單numpy實現
我們假定輸入到卷積層的數據為`X`,加入`X`的維度為`X.shape: (11,11,4)`。假定我們的zero-padding為0,也就是左右上下不補充0數據,數據窗口大小為5,窗口滑動步長為2。那輸出數據的長寬應該為(11-5)/2+1=4。假定第一個神經元對應的權重和偏移量分別為W0和b0,那我們就能算得,在第一行數據窗口停留的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`
注意上述計算過程中,`*`運算符是對兩個向量進行點乘的,因此W0應該維度為(5,5,4),同樣你可以計算其他位置的計算輸出值:
- `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`
- …
每一個神經元對應不同的一組`W`和`b`,在每個數據窗口停留的位置,得到一個輸出值。
我們之前提到了卷積層在做的事情,是不斷做權重和窗口數據的點乘和求和。因此我們也可以把這個過程整理成一個大的矩陣乘法。
1. 看看數據端,我們可以做一個操作**im2col**將數據轉成一個可直接供神經元filter計算的大矩陣。舉個例子說,輸入是[227*227*3]的圖片,而神經元權重為[11*11*3],同時窗口移動步長為4,那我們知道數據窗口滑動過程中總共產生[(227-11)/4+1]*[(227-11)/4+1]=55*55=3025個局部數據區域,又每個區域包含11*11*3=363個數據值,因此我們想辦法把原始數據重復和擴充成一個[363*3025]的數據矩陣`X_col`,就可以直接和filter進行運算了。
1. 對于filter端(卷積層),假如厚度為96(有96個不同權重組的filter),每個filter的權重為[11*11*3],因此filter矩陣`W_row`維度為[96*363]
1. 在得到上述兩個矩陣后,我們的輸出結果即可以通過`np.dot(W_row, X_col)`計算得到,結果數據為[96*3025]維的。
這個實現的弊端是,因為數據窗口的滑動過程中有重疊,因此我們出現了很多重復數據,占用內存較大。好處是,實際計算過程非常簡單,如果我們用類似BLAS這樣的庫,計算將非常迅速。
另外,在反向傳播過程中,其實卷積對應的操作還是卷積,因此實現起來也很方便。
#### 3.2 Pooling層
簡單說來,在卷積神經網絡中,Pooling層是夾在連續的卷積層中間的層。它的作用也非常簡單,就是逐步地壓縮/減少數據和參數的量,也在一定程度上減小過擬合的現象。Pooling層做的操作也非常簡單,就是將原數據上的區域壓縮成一個值(區域最大值/MAX或者平均值/AVERAGE),最常見的Pooling設定是,將原數據切成2 * 2的小塊,每塊里面取最大值作為輸出,這樣我們就自然而然減少了75%的數據量。需要提到的是,除掉MAX和AVERAGE的Pooling方式,其實我們也可以設定別的pooling方式,比如L2范數pooling。說起來,歷史上average pooling用的非常多,但是近些年熱度降了不少,工程師們在實踐中發現max pooling的效果相對好一些。
一個對Pooling層和它的操作直觀理解的示意圖為:


上圖為Pooling層的一個直觀示例,相當于對厚度為64的data,每一個切片做了一個下采樣。下圖為Pooling操作的實際max操作。
Pooling層(假定是MAX-Pooling)在反向傳播中的計算也是很簡單的,大家都知道如何去求max(x,y)函數的偏導。
#### 3.3 歸一化層(Normalization Layer)
卷積神經網絡里面有時候會用到各種各樣的歸一化層,尤其是早期的研究,經常能見到它們的身影,不過近些年來的研究表明,似乎這個層級對最后結果的幫助非常小,所以后來大多數時候就干脆拿掉了。
#### 3.4 全連接層
這是我們在介紹神經網絡的時候,最標準的形式,任何神經元和上一層的任何神經元之間都有關聯,然后矩陣運算也非常簡單和直接。現在的很多卷積神經網絡結構,末層會采用全連接去學習更多的信息。
### 4. 搭建卷積神經網結構
從上面的內容我們知道,卷積神經網絡一般由3種層搭建而成:卷積層,POOLing層(我們直接指定用MAX-Pooling)和全連接層。然后我們一般選用最常見的神經元ReLU,我們來看看有這些『組件』之后,怎么『拼』出一個合理的卷積神經網。
#### 4.1 層和層怎么排
最常見的組合方式是,用ReLU神經元的卷積層組一個神經網絡,同時在卷積層和卷積層之間插入Pooling層,經過多次的[卷積層]=>[Pooling層]疊加之后,數據的總體量級就不大了,這個時候我們可以放一層全連接層,然后最后一層和output層之間是一個全連接層。所以總結一下,最常見的卷積神經網結構為:
[輸入層] => [[ReLU卷積層] * N => [Pooling層]?] * M => [ReLU全連接層]*K => [全連接層]
解釋一下,其中`\*`操作代表可以疊加很多層,而`[Pooling層]?`表示Pooling層其實是可選的,可有可無。`N`和`M`是具體層數。比如說`[輸入層] -> [[ReLU卷積層]=>[ReLU卷積層]=>[Pooling層]]*3 -> [ReLU全連接層]*2 -> [全連接層]`就是一個合理的深層的卷積神經網。
『在同樣的視野范圍內,選擇多層疊加的卷積層,而不是一個大的卷積層』
這句話非常拗口,但這是實際設計卷積神經網絡時候的經驗,我們找個例子來解釋一下這句話:如果你設計的卷積神經網在數據層有3層連續的卷積層,同時每一層滑動數據窗口為3*3,第一層每個神經元可以同時『看到』3*3的原始數據層,那第二層每個神經元可以『間接看到』(1+3+1)*(1+3+1)=5*5的數據層內容,第三層每個神經元可以『間接看到』(1+5+1)*(1+5+1)=7*7的數據層內容。那從最表層看,還不如直接設定滑動數據窗口為7*7的,為啥要這么設計呢,我們來分析一下優劣:
- 雖然第三層對數據層的『視野』范圍是一致的。但是單層卷積層加7*7的上層滑動數據窗口,結果是這7個位置的數據,都是線性組合后得到最后結果的;而3層卷積層加3*3的滑動數據窗口,得到的結果是原數據上7*7的『視野』內數據多層非線性組合,因此這樣的特征也會具備更高的表達能力。
- 如果我們假設所有層的`『厚度』/channel`數是一致的,為C,那7*7的卷積層,會得到C×(7×7×C)=49C2個參數,而3層疊加的3*3卷積層只有3×(C×(3×3×C))=27C2個參數。在計算量上后者顯然是有優勢的。
- 同上一點,我們知道為了反向傳播方便,實際計算過程中,我們會在前向計算時保留很多中間梯度,3層疊加的3*3卷積層需要保持的中間梯度要小于前一種情況,這在工程實現上是很有好處的。
#### 4.2 層大小的設定
話說層級結構確定了,也得知道每一層大概什么規模啊。現在我們就來聊聊這個。說起來,每一層的大小(神經元個數和排布)并沒有嚴格的數字規則,但是我們有一些通用的工程實踐經驗和系數:
- 對于輸入層(圖像層),我們一般把數據歸一化成2的次方的長寬像素值。比如CIFAR-10是32*32*3,STL-10數據集是64*64*3,而ImageNet是224*224*3或者512*512*3。
- 卷積層通常會把每個[濾子/filter/神經元]對應的上層滑動數據窗口設為3*3或者5*5,滑動步長stride設為1(工程實踐結果表明stride設為1雖然比較密集,但是效果比較好,步長拉太大容易損失太多信息),zero-padding就不用了。
- Pooling層一般采用max-pooling,同時設定采樣窗口為2*2。偶爾會見到設定更大的采樣窗口,但是那意味著損失掉比較多的信息了。
- 比較重要的是,我們得預估一下內存,然后根據內存的情況去設定合理的值。我們舉個例子,在ImageNet分類問題中,圖片是224*224*3的,我們跟在數據層后面3個3*3『視野窗』的卷積層,每一層64個filter/神經元,把padding設為1,那么最后每個卷積層的output都是[224*224*64],大概需要1000萬次對output的激勵計算(非線性activation),大概花費72MB內存。而工程實踐里,一般訓練都在GPU上進行,GPU的內存比CPU要吃緊的多,所以也許我們要稍微調動一下參數。比如AlexNet用的是11*11的的視野窗,滑動步長為4。
#### 4.3 典型的工業界在用卷積神經網絡
幾個有名的卷積神經網絡如下:
- **LeNet**,這是最早用起來的卷積神經網絡,Yann LeCun在論文[LeNet](http://yann.lecun.com/exdb/publis/pdf/lecun-98.pdf)提到。
- **AlexNet**,2012 ILSVRC比賽遠超第2名的卷積神經網絡,和LeNet的結構比較像,只是更深,同時用多層小卷積層疊加提到大卷積層。
- **ZF Net**,2013 ILSVRC比賽冠軍,可以參考論文[ZF Net](http://arxiv.org/abs/1311.2901)
- **GoogLeNet**,2014 ILSVRC比賽冠軍,Google發表的論文[Going Deeper with Convolutions](http://arxiv.org/pdf/1409.4842v1.pdf)有具體介紹。
- **VGGNet**,也是2014 ILSVRC比賽中的模型,有意思的是,即使這個模型當時在分類問題上的效果,略差于google的GoogLeNet,但是在很多圖像轉化學習問題(比如object detection)上效果奇好,它也證明卷積神經網的『深度』對于最后的效果有至關重要的作用。預訓練好的模型在[pretrained model site](http://www.robots.ox.ac.uk/~vgg/research/very_deep/)可以下載。
具體一點說來,[VGGNet](http://www.robots.ox.ac.uk/~vgg/research/very_deep/)的層級結構和花費的內存如下:
~~~
INPUT: [224x224x3] memory: 224*224*3=150K weights: 0
CONV3-64: [224x224x64] memory: 224*224*64=3.2M weights: (3*3*3)*64 = 1,728
CONV3-64: [224x224x64] memory: 224*224*64=3.2M weights: (3*3*64)*64 = 36,864
POOL2: [112x112x64] memory: 112*112*64=800K weights: 0
CONV3-128: [112x112x128] memory: 112*112*128=1.6M weights: (3*3*64)*128 = 73,728
CONV3-128: [112x112x128] memory: 112*112*128=1.6M weights: (3*3*128)*128 = 147,456
POOL2: [56x56x128] memory: 56*56*128=400K weights: 0
CONV3-256: [56x56x256] memory: 56*56*256=800K weights: (3*3*128)*256 = 294,912
CONV3-256: [56x56x256] memory: 56*56*256=800K weights: (3*3*256)*256 = 589,824
CONV3-256: [56x56x256] memory: 56*56*256=800K weights: (3*3*256)*256 = 589,824
POOL2: [28x28x256] memory: 28*28*256=200K weights: 0
CONV3-512: [28x28x512] memory: 28*28*512=400K weights: (3*3*256)*512 = 1,179,648
CONV3-512: [28x28x512] memory: 28*28*512=400K weights: (3*3*512)*512 = 2,359,296
CONV3-512: [28x28x512] memory: 28*28*512=400K weights: (3*3*512)*512 = 2,359,296
POOL2: [14x14x512] memory: 14*14*512=100K weights: 0
CONV3-512: [14x14x512] memory: 14*14*512=100K weights: (3*3*512)*512 = 2,359,296
CONV3-512: [14x14x512] memory: 14*14*512=100K weights: (3*3*512)*512 = 2,359,296
CONV3-512: [14x14x512] memory: 14*14*512=100K weights: (3*3*512)*512 = 2,359,296
POOL2: [7x7x512] memory: 7*7*512=25K weights: 0
FC: [1x1x4096] memory: 4096 weights: 7*7*512*4096 = 102,760,448
FC: [1x1x4096] memory: 4096 weights: 4096*4096 = 16,777,216
FC: [1x1x1000] memory: 1000 weights: 4096*1000 = 4,096,000
TOTAL memory: 24M * 4 bytes ~= 93MB / image (only forward! ~*2 for bwd)
TOTAL params: 138M parameters
~~~
有意思的是,大家會注意到,在VGGNet這樣一個神經網絡里,大多數的內存消耗在前面的卷積層,而大多數需要訓練的參數卻集中在最后的全連接層,比如上上面的例子里,全連接層有1億權重參數,總共神經網里也就1.4億權重參數。
#### 4.4 考慮點
組一個實際可用的卷積神經網絡最大的瓶頸是GPU的內存。畢竟現在很多GPU只有3/4/6GB的內存,最大的GPU也就12G內存,所以我們應該在設計卷積神經網的時候多加考慮:
- 很大的一部分內存開銷來源于卷積層的激勵函數個數和保存的梯度數量。
- 保存的權重參數也是內存的主要消耗處,包括反向傳播要用到的梯度,以及你用momentum, Adagrad, or RMSProp這些算法時候的中間存儲值。
- 數據batch以及其他的類似版本信息或者來源信息等也會消耗一部分內存。
### 5. 更多的卷積神經網絡參考資料
- [DeepLearning.net tutorial](http://deeplearning.net/tutorial/lenet.html)是一個用Theano完整實現卷積神經網的教程。
- [cuda-convnet2](https://code.google.com/p/cuda-convnet2/)是多GPU并行化的實現。
- [ConvNetJS CIFAR-10 demo](http://cs.stanford.edu/people/karpathy/convnetjs/demo/cifar10.html)允許你手動設定參數,然后直接在瀏覽器看卷積神經網絡的結果。
- [Caffe](http://caffe.berkeleyvision.org/),主流卷積神經網絡開源庫之一。
- [Example Torch 7 ConvNet](https://github.com/nagadomi/kaggle-cifar10-torch7),在CIFAR-10上錯誤率只有7%的卷積神經網絡實現。
- [Ben Graham’s Sparse ConvNet](https://www.kaggle.com/c/cifar-10/forums/t/10493/train-you-very-own-deep-convolutional-network/56310),CIFAR-10上錯誤率只有4%的實現。
- [Face recognition for right whales using deep learning](http://deepsense.io/deep-learning-right-whale-recognition-kaggle/?from=singlemessage&isappinstalled=0#rd),Kaggle看圖識別瀕臨滅絕右鯨比賽的冠軍隊伍卷積神經網絡。