博客:blog.shinelee.me | 博客園 | CSDN
寫在前面

開篇先上圖,圖為deconvolution在像素級語義分割中的一種應用,直觀感覺deconvolution是一個upsampling的過程,像是convolution的對稱過程。
本文將深入deconvolution的細節,並通過如下方式展開:
- 先回答 什么是deconvolution?為什么會有transposed convolutionon、subpixel or fractional convolution這樣的名字?
- 再介紹 各種情形下 transposed convolution是如何進行的,並提供一種統一的計算方法。
什么是deconvolution
首先要明確的是,deconvolution並不是個好名字,因為它存在歧義:
- deconvolution最初被定義為“inverse of convolution”或者“inverse filter”或者“解卷積”,是指消除先前濾波作用的方法。比如,我們認為原始圖像是清晰的,但是通過透鏡觀測到的圖像卻變得模糊,如果假設透鏡的作用相當於以某個kernel作用在原始圖像上,由此導致圖像變得模糊,那么根據模糊的圖像估計這個kernel或者根據模糊圖像恢復原始清晰圖像的過程就叫deconvolution。
- 后來論文Adaptive Deconvolutional Networks for Mid and High Level Feature Learning和Visualizing and Understanding Convolutional Networks又重新定義了deconvolution,實際上與transposed convolution、sub-pixel or fractional convolution指代相同。transposed convolution是一個更好的名字,sub-pixel or fractional convolution可以看成是transposed convolution的一個特例。對一個常規的卷積層而言,前向傳播時是convolution,將input feature map映射為output feature map,反向傳播時則是transposed convolution,根據output feature map的梯度計算出input feature map的梯度,梯度圖的尺寸與feature map的尺寸相同。
本文談論的是deconvolution的第2個含義,后面統一使用transposed convolution這個名字。
什么是transposed convolution?A guide to convolution arithmetic for deep learning中有這樣一段話:

看完好像仍不是很直觀,transposed convolution到底對應的是什么操作?等到文章的后面,這個問題的答案會逐漸清晰起來。
下面先以1個例子來對比convolution過程和transposed convolution過程,采用與A guide to convolution arithmetic for deep learning相同的設置:
- 2-D transposed convolutions (\(N=2\))
- square inputs (\(i_1=i_2=i\))
- square kernel size (\(k_1=k_2=k\))
- same strides along both axes (\(s_1=s_2=s\))
- same zero padding along both axes (\(p_1=p_2=p\))
- square outputs (\(o_1=o_2=o\))
若令\(i=4\)、\(s=1\)、\(p=0\)、\(k=3\),輸出尺寸\(o=2\),則convolution過程是將\(4\times 4\)的map映射為\(2\times 2\)的map,而transposed convolution過程則是將\(2\times 2\)的map映射為\(4\times 4\)的map,兩者的kernel size均為3,如下圖所示:

可以看到,convolution過程zero padding的數量與超參數\(p\)一致,但是transposed convolution實際的zero padding的數量為2,為什么會這樣?是為了保持連接方式相同,下面具體看一下。
convolution過程
先看convolution過程,連接方式 如下圖所示,綠色表示輸出,藍色表示輸入,每個綠色塊具與9個藍色塊連接。

令卷積核\(\mathbf{w} = \left(\begin{array}{ccc} {w_{0,0}} & {w_{0,1}} & {w_{0,2}} \\ {w_{1,0}} & {w_{1,2}} & {w_{1,2}} \\ {w_{2,0}} & {w_{2,1}} & {w_{2,2}} \end{array}\right)\),為了便於理解,將卷積寫成矩陣乘法形式,令\(\mathbf{x}\)為\(4\times 4\)輸入矩陣以行優先方式拉成的長度為16的向量,\(\mathbf{y}\)為\(2\times 2\)輸出矩陣以同樣方式拉成的長度為4的向量,同時將\(\mathbf{w}\)表示成\(4\times 16\)的稀疏矩陣\(\mathbf{C}\),
則convolution過程可以描述為\(\mathbf{C} \mathbf{x} = \mathbf{y}\),若\(\mathbf{C}_{i,j}=0\)表示\(\mathbf{x}_j\)和\(\mathbf{y}_i\)間沒有連接。
transposed convolution過程
再看transposed convolution過程,如何將長度為4的向量\(\mathbf{y}\)映射為長度為16的向量且保持連接方式相同?只需將\(\mathbf{C}\)轉置,令\(\mathbf{C}^T \mathbf{y} = \mathbf{x}'\),同樣地,\(\mathbf{C}^T_{j,i}=0\)表示\(\mathbf{x}'_j\)和\(\mathbf{y}_i\)間沒有連接。
此時,\(\mathbf{C}^T\)對應的卷積操作恰好相當於將kernel中心對稱,FULL zero padding,然后卷積,此時,1個藍色塊與9個綠色塊連接,且權重與Convolution過程相同

需要注意的是,transposed convolution的kernel與convolution的kernel可以有關,也可以無關,需要看應用在什么場景,
- 在特征可視化、訓練階段的反向傳播中應用的transposed convolution,並不是作為一個真正的layer存在於網絡中,其kernel與convolution共享(但要經過中心對稱后再卷積,相當於上面的 $ \mathbf{C} ^T $)。
- 在圖像分割、生成模型、decoder中使用的transposed convolution,是網絡中真實的layer,其kernel經初始化后需要通過學習獲得(所以卷積核也就無所謂中心對稱不對稱了)。
- 前向傳播為convolution/transposed convolution,則反向傳播為transposed convolution/convolution。
在上面舉的簡化的例子中,我們可以通過分析得知transposed convolution該如何進行,但是,對於更一般情況應該怎么做?
transposed convolution的計算
對於一般情況,只需把握一個宗旨:transposed convolution將output size恢復為input size且保持連接方式相同。
對於convolution過程,我們知道其output map與input map的尺寸關系如下:
若要將\(o\)恢復為\(i\),需考慮2種情況,\(\frac{i+2p-k}{s}\)整除以及不整除,先看整除的情況。
整除的情況
如果\(\frac{i+2p-k}{s}\)可以整除,則由上式可得
因為transposed convolution也是卷積,為了符合上面卷積操作尺寸關系的數學形式,可進一步整理成
令\(i'=o+(s-1)(o-1)\)、$p'=\frac{(k-1)+(k-2p-1)}{2} = k-p-1 \(、\)s'=1\(、\)k'=k$,即transposed convolution實際卷積時使用的超參數,可以這樣理解:
-
\(i'=o+(s-1)(o-1)\):convolution的輸出為\(o\times o\),每行每列都是\(o\)個元素,有\(o-1\)個間隔,transposed convolution時在每個間隔處插入\(s-1\)個0,整體構成transposed convolution的input map;
-
$p'=\frac{(k-1)+(k-2p-1)}{2} = k-p-1 $:在上一步input map的基礎上再進行padding,考慮convolution常用的幾種padding情況:
- VALID:\(p=0\),transposed convolution則需padding \(p'=k-1\),即FULL padding
- SAME:\(p=\frac{k-1}{2}=r\),這里考慮\(k=2r+1\)為奇數的一般情況,此時\(p'=r\),即SAME padding
- FULL:\(p=k-1\),則\(p'=0\),即VALID padding
可見,convolution和transposed convolution的padding也具有某種對稱性\(p'+p=k-1\);
-
\(k'=k\):transposed convolution的kernel size與convolution相同;
-
\(s'=1\):transposed convolution的stride均為1,但也可以換個角度理解,如果認為\(o\times o\)相鄰元素間的距離為1個像素,那么在間隔處插入\(s-1\)個0后(\(s > 1\)),得到的input map相鄰元素間的距離就是亞像素的(sub-pixel),所以此時也可以稱之為 sub-pixel or fractional convolution;
-
\(o'=i=\frac{i'+2p'-k'}{s'}+1\):transposed convolution的輸出與convolution的輸入具有相同尺寸。
不整除的情況
接下來再看\(\frac{i+2p-k}{s}\)不整除的情況,此時再按上面的方式計算得到的\(o'=\frac{i'+2p'-k'}{s'}+1\)將小於\(i\),小多少呢?不難得出少\(a = [(i+2p-k) \mod s]\),即
為了讓\(o'=i\),可寫成
只需在padding后,在下邊和右邊再擴展\(a\)行和列0,然后進行卷積即可。注意,因為\(s'=1\),我們可以將\(a\)放在分母也可以放在外面,之所以放在分母,是因為convolution過程中input map下邊和右邊的\(a\)行或列中的元素可能參與了運算,即與output map間存在連接,所以在transposed convolution時,為了保持同樣的連接,最后擴展的\(a\)行和列也要參與卷積,所以放在分母。
至此,再看transposed convolution的各種情況,就很容易推算了,更多例子可參見A guide to convolution arithmetic for deep learning。

總結
最后,總結一下,
- convolution和transposed convolution互為對稱過程,存在一個convolution,就存在一個與之對應的transposed convolution,反之亦然;
- convolution是將input size的map映射為output size的map,transposed convolution是將output size的map映射為input size的map——旨在將尺寸恢復;
- 兩者均使用卷積操作,為了方便,兩者使用同樣的stride、padding、kernel size超參數,但實際執行時的操作不同,一般情況下,transposed convolution與convolution實際超參數關系為:\(i'=o+(s-1)(o-1)\)、$p'=\frac{(k-1)+(k-2p-1)}{2} = k-p-1 \(、\)s'=1\(、\)k'=k$。
- 之所以做這樣的操作,是為了保證map間的連接方式相同(權重不一定相同),權重的設置需根據應用的場景,可能通過學習得到,也可能與convolution共享(但需要中心對稱后再使用)。
