轉置卷積、又稱反捲積其實是卷積的逆過程。卷積的過程通常會減小特徵圖的的大小,而轉置卷積往往增大特徵圖的大小,一直以來對轉置卷積的過程都不是很理解,最近認真學習了一下,在此分享。
卷積
卷積操作,輸入是一個特徵圖i,參數padding(p), stride(s),kernel_size(k),輸出是卷積後得到的特徵圖o,輸出的特徵圖大小
轉置卷積
轉置卷積是卷積的逆過程。在做的轉置卷積的時候,我們同樣會給轉置卷積幾個參數,如輸入特徵圖i,p,k,s,分別對應padding,kernel_size,stride。
第一如何理解轉置卷積是卷積的逆過程?假設卷積的輸入爲x,輸出爲y,而轉置卷積作爲卷積的逆過程,也就是說轉置卷積的輸入爲y,輸出爲x。即
因此,給定轉置卷積參數和輸出a,我們相當於找到完成這樣的過程
,同時。
故我們知道卷積的輸入大小和輸出大小的關係,因此我們可以計算出b的大小:
假設a=2,s=1,k=1,p=0,此時
因此可以推斷出轉置卷積的輸出的大小是,因此過程就是對大小爲2的進行轉置卷積,得到大小爲3的特徵圖。因此轉置卷積是逆卷積這句話體現在轉置卷積核卷積是互逆的。
第二、轉置卷積也是卷積。當s=1時,根據轉置卷積自身參數的信息計算出一組參數,利用這組參數對轉置卷積的輸入進行卷積,得到輸出。
然後以這組參數爲卷積的參數,對轉置卷積的輸入進行卷積得到轉置卷積的輸出。
第三、轉置卷積有時候也叫分數步長的卷積。當轉置卷積的時,對應的卷積的,因此也稱爲分數步長的卷積。
當時,根據轉置卷積自身參數的信息計算出一組參數:
,
此時不能直接利用這組參數對轉置卷積的輸入進行卷積,而是要對輸入進行處理,主要分爲兩步:
- 在輸入的每兩個像素之間增加s-1個0
- 在輸入的底邊和右邊加入,其中c就是根據第一步中計算出來的轉置卷積輸出的大小。
假設轉置卷積的輸入i=3,k=3,s=2,p=1,計算轉置卷積的輸出:
此時c有兩種情況,當c=5時,,s-1=1,因此對的輸入特診圖進行0填充,按第一步填充得到:
第二步中,故無需填充。
安照,計算出每個參數得到:
此時,再對特徵圖進行填充:
然後按照進行卷積得到結果
當c=6時,,s-1=1,因此對的輸入特診圖進行0填充,按第一步填充得到:
第二步中,因此再在特診圖下面和右邊填充一層
同樣計算出參數,對特徵圖進行填充:
然後再卷積得到輸出:
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),因爲除了每個像素之間的填充以外,在特徵圖的下面和右邊的填充是根據來計算的,是對s取餘,output_padding值也正是設置的這一項,所以output_padding值不可以超過s。