轉置卷積 反捲積 PyTorch torch.nn.ConvTranspose2d() output_padding

轉置卷積、又稱反捲積其實是卷積的逆過程。卷積的過程通常會減小特徵圖的的大小,而轉置卷積往往增大特徵圖的大小,一直以來對轉置卷積的過程都不是很理解,最近認真學習了一下,在此分享。

卷積

卷積操作,輸入是一個特徵圖i,參數padding(p), stride(s),kernel_size(k),輸出是卷積後得到的特徵圖o,輸出的特徵圖大小

o=\left \lfloor \frac{i+2p-k}{s} \right \rfloor +1

轉置卷積

轉置卷積是卷積的逆過程。在做的轉置卷積的時候,我們同樣會給轉置卷積幾個參數,如輸入特徵圖i,p,k,s,分別對應padding,kernel_size,stride。

第一如何理解轉置卷積是卷積的逆過程?假設卷積的輸入爲x,輸出爲y,而轉置卷積作爲卷積的逆過程,也就是說轉置卷積的輸入爲y,輸出爲x。即

x \overset{Conv}{\rightarrow}y,y\overset{transConv}{\rightarrow}x

因此,給定轉置卷積參數和輸出a,我們相當於找到完成這樣的過程

a \overset{transConv}{\rightarrow}b,同時b \overset{Conv}{\rightarrow}a

故我們知道卷積的輸入大小和輸出大小的關係,因此我們可以計算出b的大小:

a=\left \lfloor \frac{b+2p-k}{s} \right \rfloor +1\,\,\,\,\,\,\,\,\,\,\,\, (1)

假設a=2,s=1,k=1,p=0,此時

2=\left \lfloor \frac{b+2*0-1}{1} \right \rfloor +1\Rightarrow b=3

因此可以推斷出轉置卷積的輸出的大小是3,因此過程就是對大小爲2的進行轉置卷積,得到大小爲3的特徵圖。因此轉置卷積是逆卷積這句話體現在轉置卷積核卷積是互逆的。

第二、轉置卷積也是卷積。當s=1時,根據轉置卷積自身參數的信息計算出一組參數p^{'},s^{'},k^{'},利用這組參數對轉置卷積的輸入進行卷積,得到輸出。

k^{'}=k,s^{'}=s,p^{'}=k-p-1

然後以這組參數爲卷積的參數,對轉置卷積的輸入進行卷積得到轉置卷積的輸出。

第三、轉置卷積有時候也叫分數步長的卷積。當轉置卷積的s>1時,對應的卷積的s<1,因此也稱爲分數步長的卷積。

s>1時,根據轉置卷積自身參數的信息計算出一組參數p^{'},s^{'},k^{'}

k^{'}=k,s^{'}=1,p^{'}=k-p-1

此時不能直接利用這組參數對轉置卷積的輸入進行卷積,而是要對輸入進行處理,主要分爲兩步:

  1. 在輸入的每兩個像素之間增加s-1個0
  2. 在輸入的底邊和右邊加入(c+2*p-k)mod\,\, s,其中c就是根據第一步中計算出來的轉置卷積輸出的大小。

假設轉置卷積的輸入i=3,k=3,s=2,p=1,計算轉置卷積的輸出:

3=\left \lfloor \frac{c+2*1-3}{2} \right \rfloor +1\Rightarrow c=5,6

此時c有兩種情況,當c=5時,(c+2*p-k)mod\,\, s=(5+2*1-3)mod \,\, 2=0,s-1=1,因此對3 \times 3的輸入特診圖進行0填充,按第一步填充得到:

第二步中(c+2*p-k)mod\,\, s=(5+2*1-3)mod \,\, 2=0,故無需填充。

安照k^{'}=k,s^{'}=1,p^{'}=k-p-1,計算出每個參數得到:k^{'}=3,s^{'}=1,p^{'}=3-1-1=1

此時p^{'}=1,再對特徵圖進行填充:

然後按照k^{'}=3,s^{'}=1進行卷積得到結果

當c=6時,(c+2*p-k)mod\,\, s=(6+2*1-3)mod \,\, 2=1,s-1=1,因此對3 \times 3的輸入特診圖進行0填充,按第一步填充得到:

第二步中(c+2*p-k)mod\,\, s=(6+2*1-3)mod \,\, 2=1,因此再在特診圖下面和右邊填充一層

同樣計算出參數k^{'}=3,s^{'}=1,p^{'}=3-1-1=1,對特徵圖進行填充:

然後再卷積得到輸出:

Pytorch中,

import torch.nn as nn

nn.ConvTranspose2d(in_channels=, out_channels=, kernel_size=, stride=, padding=, output_padding=)

PyTorch給出的官方文檔: 

根據輸入輸出大小的計算公式,output_padding參數的設置就可以直接影響輸出的大小,而上述部分計算轉置卷積的輸出的大小的時候,因爲有向下取整操作,所以卷積輸出的大小是不確定的。因此output_padding的設置正好可以除去這種不確定性。

比如在上面的例子中設置output_padding=0,對應第一種情況c=5,下面用代碼驗證,先設置output_padding=0

import torch.nn as nn
import torch

class TC(nn.Module):
    def __init__(self):
        super(TC, self).__init__()
        self.tc = nn.ConvTranspose2d(in_channels=3, out_channels=3, 
kernel_size=3, stride=2, padding=1,output_padding=0)

    def forward(self, x):
        return self.tc(x)


x = torch.zeros((1, 3, 3, 3))
print(x.shape)
tc = TC()
print(tc(x).shape)

輸出:

修改output_padding=1,此時輸出:

當然,設置的output_padding值不可以大於等於s(stride),因爲除了每個像素之間的填充以外,在特徵圖的下面和右邊的填充是根據(c+2*p-k)mod\,\, s來計算的,是對s取餘,output_padding值也正是設置的這一項,所以output_padding值不可以超過s。

參考文獻https://github.com/vdumoulin/conv_arithmetic

發佈了155 篇原創文章 · 獲贊 31 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章