50m專線做視頻網(wǎng)站無錫網(wǎng)絡公司
- 參考:《動手學深度學習》第六章
- 卷積神經(jīng)網(wǎng)絡(convolutional neural network,CNN)是一類針對圖像數(shù)據(jù)設計的神經(jīng)網(wǎng)絡,它充分利用了圖像數(shù)據(jù)的特點,具有適合圖像特征提取的歸納偏置,因而在圖像相關任務上,它可以用相比全連接網(wǎng)絡更少的參數(shù)量取得更好的性能。基于 CNN 的模型已經(jīng)在 CV 領域處于主導地位,當今幾乎所有的圖像識別、目標檢測或語義分割相關的學術競賽和商業(yè)應用都以這種方法為基礎
- 即使在通常使用循環(huán)神經(jīng)網(wǎng)絡的一維序列結構任務上(例如音頻、文本和時間序列分析),卷積神經(jīng)網(wǎng)絡也越來越受歡迎。 通過對卷積神經(jīng)網(wǎng)絡一些巧妙的調整,它們也能在圖結構數(shù)據(jù)和推薦系統(tǒng)中發(fā)揮作用
- 本文介紹卷積神經(jīng)網(wǎng)絡的基礎結構,不涉及任何先進模型和新架構
文章目錄
- 1. 從全連接層到卷積層
- 1.1 不變性
- 1.2 MLP 的局限性
- 1.3 卷積
- 1.3.1 卷積的數(shù)學定義
- 1.3.2 互相關運算
- 1.4 通道
- 2. 圖像卷積
- 2.1 卷積核的特征提取能力
- 2.2 學習卷積核
- 2.3 特征映射和感受野
- 3. 填充和步幅
- 3.1 填充
- 3.2 步幅
- 4. 多輸入多輸出通道
- 4.1 多輸入通道
- 4.2 多輸出通道
- 4.3 只作用在通道上的 1X1 卷積層
- 5. 匯聚層
- 5.1 最大匯聚層與平均匯聚層
- 5.2 填充和步幅
- 5.3 多個通道
- 6. 卷積神經(jīng)網(wǎng)絡
1. 從全連接層到卷積層
- 前文 經(jīng)典機器學習方法(3)—— 多層感知機 我們訓練 MLP 解決了圖像分類問題。為了適配 MLP 的輸入形式,我們直接把尺寸為 (1,28,28) 的原始圖像數(shù)據(jù)拉平成 28x28 的一維數(shù)據(jù),這種做法破壞了圖像的空間結構信息,原本圖像中相近像素之間具有相互關聯(lián)性,這些性質并不能被 MLP 利用
- MLP 適合處理表格數(shù)據(jù),其中行對應樣本,列對應特征,我們尋找的模式可能涉及特征之間的交互,但是我們不能預先假設任何與特征交互相關的先驗結構,換句話說,MLP 不具有任何歸納偏置,其訓練效率隨數(shù)據(jù)維度上升而不斷下降,最終導致模型不再實用
考慮一個圖像分類任務,每張圖像具有百萬級像素,這意味著 MLP 的每次輸入都有 1 0 6 10^6 106 維度,一個將其降維到 1000 的全連接層將有 1 0 9 10^9 109 個參數(shù),這幾乎和 GPT1 的總參數(shù)量相當
1.1 不變性
- 針對圖像數(shù)據(jù)而言,一個設計良好的模型應當對圖像的某些變換具有容忍性,這被稱為模型的不變性
平移不變性
:圖像中的目標物體在發(fā)生平移后,模型仍然能有效識別。原始 CNN 可以通過局部連接和權值共享這兩個設計實現(xiàn)平移不變性旋轉不變性
:圖像中的目標物體在發(fā)生旋轉后,模型仍然能有效識別。原始 CNN 不具備這種能力,需要通過數(shù)據(jù)增強(構造隨機旋轉的樣本)和特定的網(wǎng)絡結構(如旋轉卷積和旋轉不變池化)來實現(xiàn)尺度不變性
:圖像中的目標物體在放大或縮小后,模型仍然能有效識別。原始 CNN 不具備這種能力,需要通過數(shù)據(jù)增強(構造隨機縮放的樣本)和特定的網(wǎng)絡結構(如多尺度特征融合)來實現(xiàn)
- 原始 CNN 僅具備平移不變性,它也常被稱為
空間不變性
,為了實現(xiàn)這一點,模型應當具有以下歸納偏置平移不變
:不管檢測對象出現(xiàn)在圖像中的哪個位置,神經(jīng)網(wǎng)絡的前面幾層應該對相同的圖像區(qū)域具有相似的反應局部原則
:神經(jīng)網(wǎng)絡的前面幾層應該只探索輸入圖像中的局部區(qū)域,而不過度在意圖像中相隔較遠區(qū)域的關系。最后通過聚合這些局部特征,在整個圖像級別進行預測
1.2 MLP 的局限性
- 設 MLP 的輸入是二維圖像 X ∈ R I × J \mathbf{X}\in\mathbb{R}^{I\times J} X∈RI×J,其隱藏表示為 H ∈ R I × J \mathbf{H}\in\mathbb{R}^{I\times J} H∈RI×J,用 [ X ] i , j {[\mathbf{X}]_{i, j} } [X]i,j? 和 [ H ] i , j {[\mathbf{H}]_{i, j} } [H]i,j? 分別表示輸入圖像和隱藏表示中位置 ( i , j ) (i,j) (i,j) 處的像素
注意,真實 MLP 中 X , H \mathbf{X,H} X,H 都應當是一維的,這里為了方便理解,認為無論輸入還是隱藏表示都擁有二維空間結構
- 設 MLP 的權重和偏置參數(shù)分別為 W , U \mathbf{W,U} W,U 全連接層可以表示為
[ H ] i , j = [ U ] i , j + ∑ k ∑ l [ W ] i , j , k , l [ X ] k , l = [ U ] i , j + ∑ ∑ l [ V ] i , j , a , b [ X ] i + a , j + b (1) \begin{aligned} {[\mathbf{H}]_{i, j} } & =[\mathbf{U}]_{i, j}+\sum_{k} \sum_{l}[\mathbf{W}]_{i, j, k, l}[\mathbf{X}]_{k, l} \\ & =[\mathbf{U}]_{i, j}+\sum \sum^{l}[\mathbf{V}]_{i, j, a, b}[\mathbf{X}]_{i+a, j+b} \end{aligned} \tag{1} [H]i,j??=[U]i,j?+k∑?l∑?[W]i,j,k,l?[X]k,l?=[U]i,j?+∑∑l?[V]i,j,a,b?[X]i+a,j+b??(1) 其中從 W \mathbf{W} W 到 V \mathbf{V} V 的轉換只是形式上從絕對位置索引變成相對位置索引,即有 [ V ] i , j , a , b = [ W ] i , j , i + a , j + b [\mathbf{V}]_{i, j, a, b}=[\mathbf{W}]_{i, j, i+a, j+b} [V]i,j,a,b?=[W]i,j,i+a,j+b?,此處索引 a , b a,b a,b 通過正負偏移覆蓋了整個圖像。上式意味著:隱藏表示中任意給定位置 [ H ] i , j {[\mathbf{H}]_{i, j} } [H]i,j? 處的隱藏值,可以通過在 X \mathbf{X} X 中以為 ( i , j ) (i,j) (i,j) 為中心對像素進行加權求和得到,加權使用的權重為 [ V ] i , j , a , b [\mathbf{V}]_{i, j, a, b} [V]i,j,a,b? - 現(xiàn)在將 1.1 節(jié)的兩個歸納偏置引入以上全連接層計算式中。
- 首先考慮
平移不變性
,這意味著檢查對象在輸入 X \mathbf{X} X 中的平移應導致隱藏表示 H \mathbf{H} H 中的平移,這意味著 V , U \mathbf{V,U} V,U 不能依賴于目標位置 ( i , j ) (i,j) (i,j),即 [ V ] i , j , a , b = [ V ] a , b [\mathbf{V}]_{i, j, a, b} = [\mathbf{V}]_{a, b} [V]i,j,a,b?=[V]a,b?,且 U \mathbf{U} U 是一個常數(shù),這時 H \mathbf{H} H 的定義可以簡化為
[ H ] i , j = u + ∑ a ∑ b [ V ] a , b [ X ] i + a , j + b (2) [\mathbf{H}]_{i, j}=u+\sum_{a} \sum_[\mathbf{V}]_{a, b}[\mathbf{X}]_{i+a, j+b} \tag{2} [H]i,j?=u+a∑?b∑?[V]a,b?[X]i+a,j+b?(2) 機器學習領域中,以上運算被稱為卷積convolution
,注意我們此時用系數(shù) [ V ] a , b [\mathbf{V}]_{a, b} [V]a,b? 對 ( i , j ) (i,j) (i,j) 附近的像素 ( i + a , j + b ) (i+a,j+b) (i+a,j+b) 加權計算 [ H ] i , j [\mathbf{H}]_{i, j} [H]i,j?,由于 [ V ] a , b [\mathbf{V}]_{a, b} [V]a,b? 不再依賴于目標位置,其參數(shù)量相比 [ V ] i , j , a , b [\mathbf{V}]_{i,j,a, b} [V]i,j,a,b? 減少了很多,這就是利用歸納偏置提升模型效率的體現(xiàn) - 進一步考慮
局部性
。局部原則說明我們不應用偏移 ( i , j ) (i,j) (i,j) 太遠的信息計算隱藏值 [ H ] i , j [\mathbf{H}]_{i, j} [H]i,j?,為此我們對偏移 a , b a,b a,b 的絕對值設置上限 △ \triangle △, H \mathbf{H} H 的定義進一步簡化為
[ H ] i , j = u + ∑ a = ? Δ Δ ∑ b = ? Δ Δ [ V ] a , b [ X ] i + a , j + b (3) [\mathbf{H}]_{i, j}=u+\sum_{a=-\Delta}^{\Delta} \sum_{b=-\Delta}^{\Delta}[\mathbf{V}]_{a, b}[\mathbf{X}]_{i+a, j+b} \tag{3} [H]i,j?=u+a=?Δ∑Δ?b=?Δ∑Δ?[V]a,b?[X]i+a,j+b?(3) 執(zhí)行以上計算的神經(jīng)網(wǎng)絡層被稱為卷積層(convolutional layer)
,其中 V \mathbf{V} V 被稱為卷積核(convolution kernel)/濾波器(filter)
,亦或簡單地稱之為該卷積層的權重,通常該權重是可學習的參數(shù)
- 首先考慮
- 我們通過引入歸納偏置將全連接層變成了卷積層,大幅降低了需要學習的權重 U , V \mathbf{U,V} U,V 的參數(shù)量,這并不是沒有代價的。歸納偏置的引入其實限制了網(wǎng)絡的表示能力,卷積層無法匯聚長跨度信息,也無法考慮目標的絕對位置信息
- 當偏置與目標場景(圖像數(shù)據(jù))相符時,這種表示能力的限制是有益的,它相當于做了一個剪枝,避免了大量無用參數(shù)的訓練,在不影響模型性能的情況下提升了訓練效率
- 當偏置與目標場景(圖像數(shù)據(jù))不符時,比如當圖像不滿足平移不變時,模型可能難以擬合我們的訓練數(shù)據(jù)
1.3 卷積
1.3.1 卷積的數(shù)學定義
- 進一步討論之前,首先明確一下以上提到的卷積運算。首先,數(shù)學中卷積本質是一個泛函積分公式,它將兩個函數(shù) f , g : R d → R f,g:\mathbb{R}^d\to\mathbb{R} f,g:Rd→R 映射到一個數(shù),定義為
( f ? g ) ( x ) = ∫ f ( z ) g ( x ? z ) d z (4) (f*g)(\mathbf{x}) = \int f(\mathbf{z})g(\mathbf{x-z})d\mathbf{z} \tag{4} (f?g)(x)=∫f(z)g(x?z)dz(4) 也就是說,卷積是當把一個函數(shù)“翻轉”并移位 x \mathbf{x} x 時( g ( z ) → g ( ? z ) → g ( x ? z ) g(\mathbf{z})\to g(-\mathbf{z})\to g(\mathbf{x}-\mathbf{z}) g(z)→g(?z)→g(x?z) ),測量 f , g f,g f,g 之間的重疊。當自變量為離散對象時,積分就變成求和。例如,對于由索引為整數(shù) Z \mathbb{Z} Z 的、平方可和的、無限維向量集合中抽取的向量,我們得到以下定義
( f ? g ) ( i ) = ∑ a f ( a ) g ( i ? a ) (5) (f*g)(i) = \sum_a f(a)g(i-a) \tag{5} (f?g)(i)=a∑?f(a)g(i?a)(5) 進一步推廣到二維張量的情況
( f ? g ) ( i , j ) = ∑ a ∑ b f ( a , b ) g ( i ? a , j ? b ) . (6) (f * g)(i, j)=\sum_{a} \sum_ f(a, b) g(i-a, j-b) . \tag{6} (f?g)(i,j)=a∑?b∑?f(a,b)g(i?a,j?b).(6) 注意這個 (6) 式本質和 1.2 節(jié)的 (3) 式是一樣的,我們總是可以匹配兩者間的符號 - 下面給出兩個例子,幫助讀者直觀理解卷積的物理含義
如果一個系統(tǒng)輸入 f 是不穩(wěn)定的,消耗 g 是穩(wěn)定的,那么可以用卷積求這個系統(tǒng)的存量
。下面是一個吃飯的例子,圖中 f , g f,g f,g 分別表示一個人的進食曲線和食物的消化曲線。 f ( t ) f(t) f(t) 表示在t時刻吃下的食物量, g ( t ) g(t) g(t) 表示吃下事物后 t t t 時刻食物量的比例值。左上圖給出了這個人在 8/10/12 點吃下三種東西的量,左下圖顯示了 14 點時三種食物的消化剩余比例,右側表格列舉了 14 點時三種食物的剩余量,將其求和就是卷積運算,我們可以用卷積求取任意時刻此人肚子里剩余的實物總量
下圖可視化了卷積中的 “翻轉-平移” 操作
這種不穩(wěn)定輸入和穩(wěn)定消耗的場景在信號與系統(tǒng)中經(jīng)常用出現(xiàn),一個典型場景是系統(tǒng)處理輸入的最高速率有限,而每時每刻輸入系統(tǒng)的信號量是不定的,這時就可以用卷積計算系統(tǒng)積壓的未處理信息量卷積可以理解為影響因素的疊加,此時 f 表示影響源的強度,g 表示影響隨時間或距離的縮放系數(shù)
。一個例子是噪音的疊加,此時可以把 f f f 看作一條直路上各個坐標位置噪音源的強度, g g g 表示噪音隨距離增加的衰減系數(shù),則路上任意一點處的真實噪聲強度也可以通過卷積計算。圖像卷積可以看作這個例子的二維推廣
1.3.2 互相關運算
- 了解了卷積的數(shù)學定義后,回頭看式 (3) 給出的圖像卷積運算
[ H ] i , j = u + ∑ a = ? Δ Δ ∑ b = ? Δ Δ [ V ] a , b [ X ] i + a , j + b [\mathbf{H}]_{i, j}=u+\sum_{a=-\Delta}^{\Delta} \sum_{b=-\Delta}^{\Delta}[\mathbf{V}]_{a, b}[\mathbf{X}]_{i+a, j+b} [H]i,j?=u+a=?Δ∑Δ?b=?Δ∑Δ?[V]a,b?[X]i+a,j+b? 現(xiàn)在嘗試把它對應到 1.3.1 節(jié)的數(shù)學定義,這時原始圖像 X \mathbf{X} X 相當于影響強度 f f f,卷積核 V \mathbf{V} V 相當于影響系數(shù) g g g,忽略偏置 u u u,上式可改寫為
[ H ] i , j = ∑ a = ? Δ Δ ∑ b = ? Δ Δ g ( a , b ) f ( i + a , j + b ) [\mathbf{H}]_{i, j}=\sum_{a=-\Delta}^{\Delta} \sum_{b=-\Delta}^{\Delta} g(a, b) f(i+a, j+b) \\ [H]i,j?=a=?Δ∑Δ?b=?Δ∑Δ?g(a,b)f(i+a,j+b) 再令 a ′ = i + a , b ′ = j + b a'=i+a, b'=j+b a′=i+a,b′=j+b,把相對位置改寫成絕對位置,有
[ H ] i , j = ∑ a ′ ∑ b ′ g ( a ′ ? i , b ′ ? j ) f ( a ′ , b ′ ) (7) [\mathbf{H}]_{i, j}=\sum_{a'} \sum_{b'} g(a'-i, b'-j) f(a', b') \tag{7} [H]i,j?=a′∑?b′∑?g(a′?i,b′?j)f(a′,b′)(7) - 將 (7) 式和標準卷積運算 ( f ? g ) ( i , j ) = ∑ a ∑ b g ( i ? a , j ? b ) f ( a , b ) (f * g)(i, j)=\sum_{a} \sum_ g(i-a, j-b) f(a, b) (f?g)(i,j)=∑a?∑b?g(i?a,j?b)f(a,b) 對比,可見 CNN 中的卷積并不是標準卷積,只有把卷積核水平和垂直翻轉后才是標準卷積,準確地講,CNN 中這種運算稱為
互相關(cross-correlation)
運算。盡管如此,由于卷積核參數(shù)是從數(shù)據(jù)中學習到的,因此無論這些層執(zhí)行嚴格的卷積運算還是互相關運算,卷積層的輸出都不會受到影響為了與深度學習文獻中的標準術語保持一致,我們將繼續(xù)把“互相關運算”稱為卷積運算
1.4 通道
- 以上討論中,我們都把圖像視為黑白的,即只有一個灰度通道,但是彩色圖片都有 R/G/B 三個通道,某些特殊圖像如光電圖可能含有更多通道的信息,故大多數(shù)圖像都是三維張量,其中前兩個軸與像素的空間位置有關,第三軸可以看作每個像素的多維表示
- 由于輸入圖像是三維的,我們的隱藏表示也最好采用三維張量。換句話說,對于每一個空間位置,我們想要采用一組而不是一個隱藏表示。因此,我們可以把隱藏表示想象為一系列具有二維張量的
通道channel
。 這些通道有時也被稱為特征映射feature maps
,因為每個通道都向后續(xù)層提供一組空間化的學習特征。 直觀上可以想象在靠近輸入的底層,一些通道專門識別邊緣,而一些通道專門識別紋理 - 為了支持輸入 X \mathbf{X} X 和隱藏表示 H \mathbf{H} H 中的多個通道,我們將卷積公式調整如下
[ H ] i , j , d = ∑ a = ? Δ Δ ∑ b = ? Δ Δ ∑ c [ V ] a , b , c , d [ X ] i + a , j + b , c [\mathrm{H}]_{i, j, d}=\sum_{a=-\Delta}^{\Delta} \sum_{b=-\Delta}^{\Delta} \sum_{c}[\mathbf{V}]_{a, b, c, d}[\mathbf{X}]_{i+a, j+b, c} [H]i,j,d?=a=?Δ∑Δ?b=?Δ∑Δ?c∑?[V]a,b,c,d?[X]i+a,j+b,c?
2. 圖像卷積
- 本節(jié)中,我們暫時忽略通道(第三維),看看卷積核是如何作用于二維圖像數(shù)據(jù),算出隱藏表示的。下面給出二維互相關運算的示意圖,這里原始輸入尺寸是 ( 3 , 3 ) (3,3) (3,3),卷積核尺寸 ( 2 , 2 ) (2,2) (2,2),滑動步長 ( 1 , 1 ) (1,1) (1,1)。(注意:將核函數(shù)上下左右翻轉則是標準卷積運算)
卷積窗口從輸入張量的左上角開始,從左到右、從上到下滑動。 當卷積窗口滑動到新一個位置時,包含在該窗口中的部分張量與卷積核張量進行按元素相乘,得到的張量再求和得到一個單一的標量值,由此我們得出了這一位置的輸出張量值。輸出的隱藏表示尺寸為輸入尺寸 ( n h , n w ) (n_h,n_w) (nh?,nw?) 減去卷積核大小 ( k h , k w ) (k_h, k_w) (kh?,kw?) 即
( n h ? k h + 1 ) × ( n w ? k w + 1 ) (n_h-k_h+1) \times (n_w-k_w+1) (nh??kh?+1)×(nw??kw?+1) 稍后,我們將看到如何通過在圖像邊界周圍填充零來保證有足夠的空間移動卷積核,從而保持輸出大小不變
2.1 卷積核的特征提取能力
- 不同的卷積核可以對原始輸入做出不同的處理,從而提取圖像的各類特征。我們可以手工設計出提取水平特征和垂直特征的卷積核
類似地,還可以設計提取邊緣特征和對圖像進行一些處理的卷積核
2.2 學習卷積核
- 對于復雜的 CV 任務而言,手工設計的卷積核不一定是最合適的,注意到卷積核其實就是卷積層中的待學習權重,完全可以通過梯度下降方法通過數(shù)據(jù)驅動的形式自動學出來
- 下面給出一個學習垂直邊緣檢查卷積核的簡單示例,為簡單起見,在此使用 pytorch 內置的二維卷積層并忽略偏置
import torch from torch import nn# 構造一個二維卷積層,它具有1個輸出通道和形狀為(1,2)的卷積核 conv2d = nn.Conv2d(1,1, kernel_size=(1, 2), bias=False)# 構造一個黑白圖像 X = torch.ones((6, 8)) # 初始化為全白 X[:, 2:6] = 0 # 中間設置一塊黑區(qū)域# 構造邊緣檢查結果 Y = torch.zeros((6, 7)) Y[:,1] = 1 # 1代表從白色到黑色的邊緣 Y[:,-2] = -1 # -1代表從黑色到白色的邊緣# 這個二維卷積層使用四維輸入和輸出格式(批量大小、通道、高度、寬度), # 其中批量大小和通道數(shù)都為1 X = X.reshape((1, 1, 6, 8)) Y = Y.reshape((1, 1, 6, 7)) lr = 3e-2 # 學習率for i in range(10):Y_hat = conv2d(X)l = (Y_hat - Y) ** 2conv2d.zero_grad()l.sum().backward()# 迭代卷積核conv2d.weight.data[:] -= lr * conv2d.weight.gradif (i + 1) % 2 == 0:print(f'epoch {i+1}, loss {l.sum():.3f}')
- 訓練結束后,觀察學習到的卷積核
conv2d.weight.data.reshape((1, 2)) >>> tensor([[ 0.9910, -0.9936]])
2.3 特征映射和感受野
- 如 1.4 節(jié)所述,某個通道的卷積層輸出有時被稱為
特征映射/特征圖feature map
,因為它可以被視為一個輸入映射到下一層的空間維度的轉換器。 在卷積神經(jīng)網(wǎng)絡中,對于某一層的任意元素 x x x,其感受野receptive field
是指在前向傳播期間可能影響計算的所有元素(來自所有先前層) - 注意,感受野可能大于輸入的實際大小。還是以本節(jié)開頭的圖為例
給定 2 × 2 2\times 2 2×2 卷積核,陰影輸出元素值19的感受野是輸入陰影部分的四個元素?,F(xiàn)在設上圖的輸入和輸出分別為 X , Y \mathbf{X,Y} X,Y,現(xiàn)在我們在其后附加一個卷積層,該卷積層以 Y \mathbf{Y} Y 為輸入,輸出單個元素 z z z- z z z 在 Y \mathbf{Y} Y 上的感受野包括 Y \mathbf{Y} Y 的所有四個元素
- z z z 在 X \mathbf{X} X 上的感受野包括 X \mathbf{X} X 的所有九個輸入元素
- 因此,當一個特征圖中的任意元素需要檢測更廣區(qū)域的輸入特征時,我們可以構建一個更深的網(wǎng)絡
3. 填充和步幅
- 從以上第2節(jié)的例子可知,卷積的輸出形狀 ( n h ? k h + 1 ) × ( n w ? k w + 1 ) (n_h-k_h+1) \times (n_w-k_w+1) (nh??kh?+1)×(nw??kw?+1) 取決于輸入尺寸 ( n h , n w ) (n_h,n_w) (nh?,nw?) 和卷積核大小 ( k h , k w ) (k_h, k_w) (kh?,kw?),這種關系可能不夠靈活,比如
- 有時在連續(xù)應用卷積之后,最終得到的輸出遠小于輸入大小,原始圖像許多的邊界信息丟失了,
填充padding
是解決此問題最有效的方法 - 有時原始的輸入的分辨率可能過高了,我們希望大幅降低圖像的寬度和高度,此時
步幅stride
可以提供幫助
- 有時在連續(xù)應用卷積之后,最終得到的輸出遠小于輸入大小,原始圖像許多的邊界信息丟失了,
3.1 填充
- 卷積核尺寸大于 ( 1 , 1 ) (1,1) (1,1) 時,邊界信息的丟失是不可避免的,雖然可能僅丟失了邊緣的幾個像素,但當多個卷積層堆疊時,累計丟失的像素就不可忽略的。
填充padding
通過在輸入圖像邊緣填充元素(通常填充0)來解決這個問題給出一個示例,原始輸入尺寸為 ( 3 , 3 ) (3,3) (3,3),我們將其填充到 ( 5 , 5 ) (5,5) (5,5),使輸出尺寸增加到 ( 4 , 4 ) (4,4) (4,4)
- 通常,如果我們添加 p h p_h ph? 行填充和 p w p_w pw? 列填充,則輸出形狀將為
( n h ? k h + p h + 1 ) × ( n w ? k w + p w + 1 ) (n_h-k_h+p_h+1) \times (n_w-k_w+p_w+1) (nh??kh?+ph?+1)×(nw??kw?+pw?+1) 這意味著輸出的高度和寬度分別增加 p h p_h ph? 和 p w p_w pw?。許多時候我們設置 p h = k h ? 1 p_h=k_h-1 ph?=kh??1 和 p w = k w ? 1 p_w=k_w-1 pw?=kw??1,使輸出和輸入具有相同的尺寸,這樣可以在構建網(wǎng)絡時更容易地預測每個圖層的輸出形狀 - 卷積神經(jīng)網(wǎng)絡中卷積核的高度和寬度通常為奇數(shù),好處是
- 我們可以在原始輸入的上下、左右填充相同數(shù)量的行和列來保持空間維度
- 對于任何二維張量 X \mathbf{X} X,當所有邊的填充行列數(shù)相同且輸出保持空間維度時,輸出 Y [ i , j ] \mathbf{Y}[i, j] Y[i,j] 是通過以輸入 X [ i , j ] \mathbf{X}[i, j] X[i,j] 為中心,與卷積核進行互相關計算得到的
- 下面給出兩個例子
- 創(chuàng)建一個高度和寬度為3的二維卷積層,并在所有側邊填充1個像素(上下共填充2 / 左右共填充2)。給定高度和寬度為8的輸入,則輸出的高度和寬度也是8
import torch from torch import nn# 為了方便起見,我們定義了一個計算卷積層的函數(shù)。 # 此函數(shù)初始化卷積層權重,并對輸入和輸出提高和縮減相應的維數(shù) def comp_conv2d(conv2d, X):# 這里的(1,1)表示批量大小和通道數(shù)都是1X = X.reshape((1, 1) + X.shape)Y = conv2d(X)# 省略前兩個維度:批量大小和通道return Y.reshape(Y.shape[2:])# 請注意,這里每邊都填充了1行或1列,因此總共添加了2行或2列 conv2d = nn.Conv2d(1, 1, kernel_size=3, padding=1) X = torch.rand(size=(8, 8)) comp_conv2d(conv2d, X).shape
>>> torch.Size([8, 8])
- 我們使用高度為 5,寬度為 3 的卷積核,高度和寬度兩邊的填充分別為2(共4)和1(共2)
conv2d = nn.Conv2d(1, 1, kernel_size=(5, 3), padding=(2, 1)) comp_conv2d(conv2d, X).shape
>>> torch.Size([8, 8])
- 創(chuàng)建一個高度和寬度為3的二維卷積層,并在所有側邊填充1個像素(上下共填充2 / 左右共填充2)。給定高度和寬度為8的輸入,則輸出的高度和寬度也是8
3.2 步幅
-
在計算互相關時,卷積窗口從輸入張量的左上角開始,向下、向右滑動。 在前面的例子中,我們默認每次滑動一個元素。 但是,有時候為了高效計算或是縮減采樣次數(shù),卷積窗口可以跳過中間位置,每次滑動多個元素
-
我們將每次滑動元素的數(shù)量稱為
步幅stride
,下圖顯示了垂直步幅為3,水平步幅為2的二維互相關運算。著色部分是輸出元素以及用于輸出計算的輸入和內核張量元素
通常,當垂直步幅為 s h s_h sh?、水平步幅為 s w s_w sw? 時,輸出形狀為
? ( n h ? k h + p h + s h ) / s h ? × ? ( n w ? k w + p w + s w ) / s w ? . \left\lfloor\left(n_{h}-k_{h}+p_{h}+s_{h}\right) / s_{h}\right\rfloor \times\left\lfloor\left(n_{w}-k_{w}+p_{w}+s_{w}\right) / s_{w}\right\rfloor . ?(nh??kh?+ph?+sh?)/sh??×?(nw??kw?+pw?+sw?)/sw??. -
下面給出一個例子,將高度和寬度的步幅設置為2,從而將輸入的高度和寬度減半
conv2d = nn.Conv2d(1, 1, kernel_size=3, padding=1, stride=2) comp_conv2d(conv2d, X).shape
>>> torch.Size([4, 4])
-
為了簡潔起見,我們稱填充為 ( p h , p w ) (p_h,p_w) (ph?,pw?),步幅為 ( s h , s w ) (s_h, s_w) (sh?,sw?)。特別地,當 p h = p w = p p_h=p_w=p ph?=pw?=p 時,稱填充為 p p p;當 s h = s w = s s_h=s_w=s sh?=sw?=s 時,步幅是 s s s。默認情況下,填充為0,步幅為1。實踐中我們很少使用不一致的步幅或填充
4. 多輸入多輸出通道
- 以上 2/3 節(jié)都是基于單個輸入輸出通道進行討論的,這使得我們可以將輸入、卷積核和輸出看作二維張量。當添加通道時,輸入和輸出都變成了三維張量,本節(jié)將更深入地研究具有多輸入和多輸出通道的卷積核
4.1 多輸入通道
- 當輸入包含多個通道時,需要構造一個與輸入數(shù)據(jù)具有相同輸入通道數(shù)的卷積核,以便與輸入數(shù)據(jù)進行互相關運算。設輸入數(shù)據(jù)尺寸為 ( c i , n h , n w ) (c_i, n_h,n_w) (ci?,nh?,nw?),需要卷積核尺寸為 ( c i , k h , k w ) (c_i, k_h, k_w) (ci?,kh?,kw?),這可以看作 c i c_i ci? 個相同尺寸的卷積核,它們分別與輸入的各個通道數(shù)據(jù)進行互相關運算得到 c i c_i ci? 個二維輸出,最后把它們按位置求和得到最終輸出。如下圖所示
4.2 多輸出通道
- 在 1.4 節(jié)我們提到過,每個通道都向后續(xù)層提供一組空間化的學習特征,在最流行的神經(jīng)網(wǎng)絡架構中,隨著神經(jīng)網(wǎng)絡層數(shù)的加深,我們常會增加輸出通道的維數(shù),通過減少空間分辨率以獲得更大的通道深度
- 通道有點類似 Transformer 中的多個注意力頭,直觀地說,我們可以將每個通道看作對不同特征的響應,但多輸出通道并不僅是學習多個單通道的檢測器,因為每個通道不是獨立學習的,而是為了共同使用而優(yōu)化的
- 用 c i , c o c_i,c_o ci?,co? 分別表示輸入和輸出的通道數(shù)量,用 k h , k w k_h,k_w kh?,kw? 表示卷積核的高度和寬度,為了獲得多個通道的輸出,我們可以為每個輸出通道創(chuàng)建一個形狀為 ( c i , k h , k w ) (c_i, k_h, k_w) (ci?,kh?,kw?) 的卷積核張量,這樣卷積核的最終形狀為 ( c o , c i , k h , k w ) (c_o, c_i, k_h, k_w) (co?,ci?,kh?,kw?)。在互相關運算中,每個輸出通道先獲取所有輸入通道,再以對應該輸出通道的卷積核計算出結果
4.3 只作用在通道上的 1X1 卷積層
- 當 k h = k w = 1 k_h=k_w=1 kh?=kw?=1 時,卷積核只能輸入一個空間位置的像素,這種卷積核不再能提取相鄰像素間的相關特征,它唯一的計算發(fā)生在通道上,可以把 1x1 卷積看作在每個像素位置的所有通道上的全連接層,將 c i c_i ci? 個輸入轉換為 c o c_o co? 個輸出,如下圖所示
- 注意 1x1 卷積也是一個卷積層,故其跨像素的權重是一致的,權重維度為 c i × c o c_i\times c_o ci?×co?,再額外加上一個偏置
5. 匯聚層
- 通常當我們處理圖像時,我們希望逐漸降低隱藏表示的空間分辨率、聚集信息,這樣隨著我們在神經(jīng)網(wǎng)絡中層疊的上升,每個神經(jīng)元對其敏感的感受野(輸入)就越大。機器學習任務通常會跟全局圖像的問題有關(例如,“圖像是否包含一只貓呢?”),所以我們最后一層的神經(jīng)元應該對整個輸入的全局敏感,這需要我們逐漸聚合信息,生成越來越粗糙的映射
- 現(xiàn)實中,隨著拍攝角度的移動,任何物體幾乎不可能發(fā)生在同一像素上,我們希望模型檢查的底層特征(例如 2.1 節(jié)中討論的邊緣)保持某種程度上的平移不變性,前面介紹的卷積層相比全連接層已經(jīng)具有更強的平移不變性了,匯聚層可以進一步增強模型的平移不變能力
- 本節(jié)將介紹
匯聚/池化pooling
層,它具有雙重目的- 降低卷積層對位置的敏感性
- 降低對空間降采樣表示的敏感性
5.1 最大匯聚層與平均匯聚層
- 與卷積層類似,匯聚層運算符由一個固定形狀的窗口組成,該窗口根據(jù)其步幅大小在輸入的所有區(qū)域上滑動,為固定形狀窗口(有時稱為
匯聚窗口
)遍歷的每個位置計算一個輸出。 - 不同于卷積層中的輸入與卷積核之間的互相關計算,匯聚層不包含參數(shù)。 相反,池運算是確定性的,通常有兩種
最大匯聚層maximum pooling
:計算匯聚窗口中所有元素的最大值平均匯聚層average pooling
:計算匯聚窗口中所有元素的平均值
- 下圖顯示了最大匯聚層的處理過程
注意匯聚層的輸入是卷積層的輸出,我們可以假設上圖中的輸入 4 對應到原始圖像輸入上感受野的某個特征(隨著層數(shù)疊加,感受野可以是較大的一片區(qū)間,特征也可以是高價的,比如鳥翅膀或貓尾巴),當原始圖像輸入發(fā)生少量平移時,以上匯聚層輸入中的 4 可能偏移到左上角的 0 位置,最大匯聚層在這種情況下可以保持輸出不變,這意味著更強的平移不變性
5.2 填充和步幅
- 與卷積層一樣,匯聚層也可以通過設置填充和步幅改變輸出形狀,pytorch 中語法如下
# 定義卷積層,指定卷積核尺寸、填充和步幅 conv2d = nn.Conv2D(1, kernel_size=(3, 5), padding=(0, 1), strides=(3, 4))# 定義最大池化層,指定匯聚窗口尺寸、填充和步幅 pool2d = nn.MaxPool2d((2, 3), stride=(2, 3), padding=(0, 1))
5.3 多個通道
- 在處理多通道輸入數(shù)據(jù)時,匯聚層在每個輸入通道上單獨運算,而不是像卷積層一樣在通道上對輸入進行匯總,這意味著匯聚層的輸出通道數(shù)與輸入通道數(shù)相同
import torch import numpy as npX = np.arange(16, dtype=np.float32).reshape((1, 1, 4, 4)) X = np.concatenate((X, X + 1), 1) # (1, 2, 4, 4) pool2d = nn.MaxPool2d(3, padding=1, stride=2) # 由于匯聚層中沒有參數(shù),所以不需要調用初始化函數(shù) Y = pool2d(torch.tensor(X)) # (1, 2, 2, 2)
6. 卷積神經(jīng)網(wǎng)絡
- 一個完整的卷積神經(jīng)網(wǎng)絡通過交替堆疊卷積層和匯聚層提取圖像特征,最后接全連接層調整維度,用于分類或回歸任務。下面是經(jīng)典 CNN 模型 LeNet 的結構圖
- 考慮到篇幅問題,本文僅介紹 CNN 基礎原理,各種經(jīng)典模型的細節(jié)和 pytorch 實現(xiàn)將在后續(xù)其他文章介紹,鏈接將更新到此處。To be continue…