深度学习之卷积神经网络(11)卷积层变种
深度學習之卷積神經網絡(11)卷積層變種
- 1. 空洞卷積
- 2. 轉置卷積
- 矩陣角度
- 轉置卷積實現
- 3. 分離卷積
卷積神經網絡的研究產生了各種各樣優秀的網絡模型,還提出了各種卷積層的變種,本節將重點介紹書中典型的卷積層變種。
1. 空洞卷積
?普通的卷積層為了減少為了的參數量,卷積核的設計通常選擇較小的1×11×11×1和3×33×33×3感受野大小。小卷積核使得網絡提取特征時的感受野區域有限,但是增大感受野區域又會增加網絡的參數量和計算代價,因此需要權衡設計。
?空洞卷積(Dilated/Atrous Convolution)的提出較好地解決了這個問題,空洞卷積在普通卷積的感受野上增加一個Dilation Rate參數,用于控制感受野區域的采樣步長,如下圖所示:
當感受野的采樣步長Dilation Rate為1時,每個感受野采樣點之間的距離為1,此時的空洞卷積退化為普通的卷積; 當Dilation Rate為2時,感受野每2個單元采樣一個點,如上圖中間綠色方框中綠色格子所示,每個采樣格子之間的距離為2; 同樣的方法,最右邊圖的Dilation Rate為3,采樣步長為3,盡管Dilation Rate的增大會使得感受野區域增大,但是實際參與運算的點數仍然保持不變。
?以輸入為單通道的7×77×77×7張量,單個3×33×33×3卷積核為例,如下圖所示。在初始位置,感受野從最上、最右位置開始采樣,每隔一個點采樣一次,共采集9個數據點,如下圖中綠色方框所示。這9個數據點與卷積核相乘運算,寫入輸出張量的對應位置。
?卷積核窗口按著步長為s=1s=1s=1向右移動一個單位,如下圖所示,同樣進行個點采樣,共采樣9個數據點,與卷積核完成相乘累加運算,寫入輸出張量對應為,直至卷積核移動至最下方、最右邊位置。需要注意區分的是,卷積核窗口的移動步長s和感受野區域的采樣步長Dilation Rate是不同的概念。
?空洞卷積在不增加網絡參數的條件下,提供了更大的感受野窗口。但是在使用空洞卷積設置網絡模型時,需要精心設計Dilation Rate參數來避免出現網格效應,同樣較大的Dilation Rate參數并不利于小物體的檢測、語義分割等任務。
?在TensorFlow中,可以通過設置layers.Conv2D()類的dilation_rate參數來選擇使用普通卷積還是空洞卷積。例如:
運行結果如下圖所示:

當dilation_rate參數設置為默認值1時,使用普通卷積方式進行計算; 當dilation_rate參數大于1時,采用空洞卷積方式進行計算。
2. 轉置卷積
?轉置卷積(Transposed Convolution,或Fractionally Strided Convolution,部分資料也稱之為反卷積/Deconvolution,實際上反卷積在數學上定義為卷積的逆過程,單轉置卷積并不能恢復出原卷積的輸入,因此稱為反卷積并不妥當)通過在輸入之間填充大量的padding來實現輸出高寬大于輸入高寬的效果,從而實現向上采樣的目的,如下圖所示。我們先介紹轉置卷積的計算過程,再介紹轉置卷積與普通卷積的聯系。
?為了簡化討論,我們此處只討論輸入h=wh=wh=w,即輸入高寬相等的情況。
o+2p?k\boldsymbol {o+2p-k}o+2p?k為s\boldsymbol ss倍數
?考慮輸入為2×22×22×2的單通道特征圖,轉置卷積核為3×33×33×3大小,步長為s=2s=2s=2,填充p=0p=0p=0的例子。首先再輸入數據點之間均勻插入s?1s-1s?1個空白數據點,得到3×33×33×3的矩陣,如下圖第2個矩陣所示,根據填充量3×33×33×3矩陣周圍填充相應k?p?1=3?0?1=2k-p-1=3-0-1=2k?p?1=3?0?1=2行/列,此時輸入張量的高寬為7×77×77×7,如下圖中第3個矩陣所示。
?在7×77×77×7的輸入張量上,進行3×33×33×3卷積核,步長s′=1s'=1s′=1,填充p=0p=0p=0的普通卷積運算(注意,此階段的普通卷積的步長s′s's′始終為1,與轉置卷積的步長sss不同),根據普通卷積的輸出計算公式,得到輸出大小為:
o=[i+2?p?ks′]+1=[7+2?0?31]+1=5o=[\frac{i+2*p-k}{s'} ]+1=[\frac{7+2*0-3}{1}]+1=5o=[s′i+2?p?k?]+1=[17+2?0?3?]+1=5
5×55×55×5大小的輸出。我們直接按照此計算流程給出最終轉置卷積輸出與輸入關系。在o+2p?ko+2p-ko+2p?k為sss倍數時,滿足關系:
o=(i?1)s+k?2po=(i-1)s+k-2po=(i?1)s+k?2p
?轉置卷積并不是普通的逆過程,但是二者之間有一定的聯系,同時轉置卷積也是基于普通卷積實現的。在相同的設定下,輸入x\boldsymbol xx經過普通卷積運算得到o=Conv(x)\boldsymbol o=\text{Conv}(\boldsymbol x)o=Conv(x),我們將o送入轉置卷積運算后,得到x′=ConvTranspose(o)\boldsymbol x'=\text{ConvTranspose}(\boldsymbol o)x′=ConvTranspose(o),其中x′≠x\boldsymbol x'≠\boldsymbol xx′?=x,但是x′\boldsymbol x'x′與x\boldsymbol xx形狀相同。我們可以用輸入為5×55×55×5,步長s=2s=2s=2,填充p=0p=0p=0,3×33×33×3卷積核的普通卷積運算進行驗證演示,如下圖所示:
?可以看到,將轉置卷積的輸出5×55×55×5在同設定條件下送入普通卷積,可以得到2×22×22×2的輸出,此大小恰好就是轉置卷積的輸入大小,同時我們也觀察到,輸出2×22×22×2矩陣并不是轉置卷積輸入的2×22×22×2矩陣。轉置卷積與普通卷積并不是互為逆過程,不能恢復出對方的輸入內容,僅能恢復出等大小的張量。因此稱之為反卷積并不切貼。
&emspl;基于TensorFlow實現上述例子的轉置卷積運算,代碼如下:
運行結果如下圖所示:
?現在我們將普通卷積的輸出作為轉置卷積的輸入,驗證轉置卷積的輸出是否為5×55×55×5,代碼如下:
運行結果如下:
o+2p?k\boldsymbol{o+2p-k}o+2p?k不為s\boldsymbol ss倍數
?讓我們更加深入地分析卷積運算中輸入與輸出大小關系的一個細節。考慮卷積運算的輸出表達式:
o=[i+2?p?ks′]+1o=[\frac{i+2*p-k}{s'} ]+1o=[s′i+2?p?k?]+1
當步長s>1s>1s>1時,[i+2?p?ks′][\frac{i+2*p-k}{s'} ][s′i+2?p?k?]向下取整運算使得出現多種不同輸入尺寸iii對應到相同的輸出尺寸ooo上。舉個例子,考慮輸入大小為6×66×66×6,卷積核大小為3×33×33×3,步長為1的卷積運算,代碼如下:
運行結果如下圖所示:
此種情況也能獲得2×22×22×2大小的卷積輸出,與利用普通卷積可以獲得相同大小的輸出。因此,不同輸入大小的卷積運算可能獲得相同大小的輸出。考慮到卷積與專制卷積輸入輸出大小關系互換,從轉置卷積的角度來說,輸入尺寸iii經過轉置卷積運算后,可能獲得不同的輸出ooo大小。因此通過填充aaa行、aaa列來實現不同大小的輸出ooo,從而恢復普通卷積不同大小的輸入的情況,其中aaa關系為:
a=(o+2p?k)a=(o+2p-k)%sa=(o+2p?k)
此時轉置卷積的輸出變為:
o=(i?1)s+k?2p+ao=(i-1)s+k-2p+ao=(i?1)s+k?2p+a
?在TensorFlow中間,不需要手動指定aaa參數,只需要指定輸出尺寸即可,TensorFlow會自動推導需要填充的行列數aaa,前提是輸出尺寸合法。例如:
運行結果如下所示:
通過改變參數output_shape=[1, 5, 5, 1]也可以獲得高寬為5×5的張量。
矩陣角度
?轉置卷積的轉置是指卷積核W\boldsymbol WW產生的稀疏矩陣W′\boldsymbol W'W′在計算過程中需要先轉置W′T\boldsymbol W'^TW′T,再進行矩陣相乘運算,而普通卷積并沒有轉置W′\boldsymbol W'W′的步驟。這也是它被稱為轉置卷積的名字的由來。
?考慮普通Conv2d運算: X\boldsymbol XX和W\boldsymbol WW,需要根據strides將卷積核在行、列方向循環移動獲取參與運算的感受野的數據,串行計算每個窗口的“相乘累加”值,計算效率極地。為了加速運算,在數學上可以將卷積核W\boldsymbol WW根據strides重排成稀疏矩陣W′\boldsymbol W'W′,再通過W′@X′\boldsymbol W'@\boldsymbol X'W′@X′一次完成運算(實際上,W′\boldsymbol W'W′矩陣過于稀疏,導致很多無用的0乘運算,很多深度學習框架也不是通過這種方式實現的)。
?以4行4列的輸入X\boldsymbol XX,高寬為3×3,步長為1,無padding的卷積核W\boldsymbol WW的卷積運算為例,首先將X\boldsymbol XX打平成X′\boldsymbol X'X′,如下圖所示:
然后將卷積核W\boldsymbol WW轉換成稀疏矩陣W′\boldsymbol W'W′,如下圖所示:
?此時通過一次矩陣相乘即可實現普通卷積運算:
O′=W′@X′\boldsymbol O'=\boldsymbol W'@\boldsymbol X'O′=W′@X′
如果給定O\boldsymbol OO,希望能夠生成與X\boldsymbol XX相同形狀大小的張量,怎么實現呢?將W′\boldsymbol W'W′轉置后與上圖方法重排后的O′\boldsymbol O'O′完成矩陣相乘即可:
X′=W′T@O′\boldsymbol X'=\boldsymbol W'^T@\boldsymbol O'X′=W′T@O′
得到的X′\boldsymbol X'X′通過reshape操作變為與原來的輸入X\boldsymbol XX尺寸一致,但是內容不同。例如O′\boldsymbol O'O′的shape為[4,1][4,1][4,1],W′T\boldsymbol W'^TW′T的shape為[16,4][16,4][16,4],Reshape后即可產生[4,4][4,4][4,4]形狀的張量。由于轉置卷積在矩陣運算時,需要將W′\boldsymbol W'W′轉置后才能與轉置卷積的輸入O′\boldsymbol O'O′矩陣相乘,故稱為轉置卷積。
?轉置卷積具有“放大特征圖”的功能,在生成對抗網絡、語義分割等中得到了廣泛應用,如DCGAN[1]中的生成器通過堆疊轉置卷積層實現逐層“放大”特征圖,最后獲得十分逼真的生成圖片。
[1] A. Radford, L. Metz 和 S. Chintala, Unsupervised Representation Learning with Deep Convolutional Generative Adversarial Networks, 2015.
轉置卷積實現
?在TensorFlow中,可以通過nn.conv2d_transpose實現轉置卷積運算。我們先通過nn.conv2d完成普通卷積運算。注意轉置卷積的卷積核的定義格式為[k,k,cout,cin][k,k,c_{out},c_{in}][k,k,cout?,cin?]。例如:
import tensorflow as tf from tensorflow.keras import layers, optimizers, datasets, Sequential# 創建4×4大小的輸入 x = tf.range(16)+1 x = tf.reshape(x, [1, 4, 4, 1]) x = tf.cast(x, tf.float32) # 創建3×3卷積核 w = tf.constant([[-1, 2, -3.], [4, -5, 6], [-7, 8, -9]]) w = tf.expand_dims(w, axis=2) w = tf.expand_dims(w, axis=3) # 普通卷積運算 out = tf.nn.conv2d(x, w, strides=1, padding='VALID') print(out)
運行結果如下圖所示:
?保持strides=1,padding=‘VALID’,卷積核不變的情況下,我們通過卷積核www與輸出outoutout的轉置卷積運算嘗試恢復與輸入xxx相同大小的高寬張量,代碼如下:
運行結果如下所示:
tf.Tensor( [[[[ 56.][ -51.][ 46.][ 183.]][[-148.][ -35.][ 35.][-123.]][[ 88.][ 35.][ -35.][ 63.]][[ 532.][ -41.][ 36.][ 729.]]]], shape=(1, 4, 4, 1), dtype=float32)
可以看到,轉置卷積生成了4×44×44×4的特征圖,單特征圖的數據與輸入xxx并不相同。
?在使用tf.nn.conv2d_transpose進行轉置卷積運算時,需要額外手動設置輸出的高寬。tf.nn.conv2d_transpose并不支持自定義padding設置,只能設置為VALID或者SAME。
?當設置padding=‘VALID’時,輸出大小表達為:
o=(i?1)s+ko=(i-1)s+ko=(i?1)s+k
?當設置padding=‘SAME’時,輸出大小表達為:
o=i?so=i\cdot so=i?s
?如果我們還是對轉置卷積原理細節暫時無法理解,可以先牢記上述兩個表達式即可。例如:
2×22×22×2的轉置卷積輸入與3×33×33×3的卷積核運算,strides=1,padding=‘VALID’時,輸出大小為:
h′=w′=(2?1)?1+3=4h'=w'=(2-1)\cdot1+3=4h′=w′=(2?1)?1+3=4
2×22×22×2的轉置卷積輸入與3×33×33×3的卷積核運算,strides=1,padding=‘VALID’時,輸出大小為:
h′=w′=2?3=6h'=w'=2\cdot3=6h′=w′=2?3=6
?轉置卷積也可以和其他層一樣,通過layers.Conv2DTranspose類創建一個轉置卷積層,然后調用實例即可完成向前計算。代碼如下:
運行結果如下:
tf.Tensor( [[[[ 6.942313 ][ 33.887856 ][ 24.800087 ][ -4.222195 ]][[ 21.720724 ][ 68.23484 ][ 73.74913 ][ 28.219326 ]][[ 15.284215 ][ 10.42746 ][ 12.951116 ][ 20.34887 ]][[ -1.9099097][-26.6492 ][-56.841545 ][-32.62231 ]]]], shape=(1, 4, 4, 1), dtype=float32)3. 分離卷積
?這里以深度可分離卷積(Depth-wise Separable Convolution)為例。普通卷積在對多通道輸入進行運算時,卷積核的每個通道與輸入的每個通道分別進行卷積運算,得到多通道的特征圖,再對應元素相加產生單個卷積核的最終輸出,如下圖所示:
?分離卷積的計算流程則不同,卷積核的每個通道與輸入的每個通道進行卷積預算,得到多個通道的中間特征,如下圖所示。這個多通道的中間特征張量接下來進行多個1×11×11×1卷積核的普通卷積運算,得到多個高寬不變的輸出,這些輸出在通道軸上面進行拼接,從而產生最終的分離卷積層的輸出。可以看到,分離卷積層包含了兩步卷積運算,第一步卷積運算是單個卷積核,第二個卷積運算包含了多個卷積核。
?那么采用分離卷積有什么優勢呢?一個很明顯的優勢在于,同樣的輸入和輸出,采用Separable Convolution的參數量約是普通卷積的13\frac{1}{3}31?。考慮上圖中的普通卷積和分離卷積的例子。普通卷積的參數量是
3?3?3?4=1083\cdot3\cdot3\cdot4=1083?3?3?4=108
分離卷積的第一部分參數量是
3?3?3?1=273\cdot3\cdot3\cdot1=273?3?3?1=27
第二部分參數量是
1?1?3?4=121\cdot1\cdot3\cdot4=121?1?3?4=12
分離卷積的總參數量只有39,但是卻能實現普通卷積同樣的輸入輸出尺寸變換。分離卷積在Xception和MobileNets等對計算代價敏感的領域中得到了大量應用。
總結
以上是生活随笔為你收集整理的深度学习之卷积神经网络(11)卷积层变种的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 前端工程师美工学习建议用的软件:C4D
- 下一篇: tensorflow-TFRecord