47 轉(zhuǎn)置卷積【動(dòng)手學(xué)深度學(xué)習(xí)v2】

轉(zhuǎn)置卷積
卷積操作一般不會(huì)改變輸入的高寬。若改變一般是往縮小改變。
在語義分割問題中,數(shù)據(jù)是像素級(jí)別的輸入與輸出,如果使用一般卷積使得高寬減小到很小的數(shù)值,則會(huì)造成數(shù)據(jù)損失。
轉(zhuǎn)置卷積通常用于增大數(shù)據(jù)的高寬

具體來說,輸入數(shù)據(jù)中的每個(gè)值都會(huì)與整個(gè)轉(zhuǎn)置卷積核相乘,形成一個(gè)與卷積核大小相同的新數(shù)據(jù),放置在特定對(duì)應(yīng)位置,最后相加。
為什么稱此運(yùn)算方法為“轉(zhuǎn)置”?(此處設(shè)計(jì)卷積法的矩陣實(shí)現(xiàn),在下一講中會(huì)作詳細(xì)說明)

代碼實(shí)現(xiàn)
import torch from torch import nn from d2l import torch as d2l
對(duì)輸入矩陣X
和卷積核矩陣K
實(shí)現(xiàn)基本的轉(zhuǎn)置卷積運(yùn)算trans_conv
。
def trans_conv(X, K): h, w = K.shape Y = torch.zeros((X.shape[0] + h - 1, X.shape[1] + w - 1)) for i in range(X.shape[0]): for j in range(X.shape[1]): Y[i: i + h, j: j + w] += X[i, j] * K return Y
與通過卷積核“減少”輸入元素的常規(guī)卷積(在?6.2節(jié)中)相比,轉(zhuǎn)置卷積通過卷積核“廣播”輸入元素,從而產(chǎn)生大于輸入的輸出。 我們可以通過?圖13.10.1來構(gòu)建輸入張量X
和卷積核張量K
從而驗(yàn)證上述實(shí)現(xiàn)輸出。 此實(shí)現(xiàn)是基本的二維轉(zhuǎn)置卷積運(yùn)算。
X = torch.tensor([[0.0, 1.0], [2.0, 3.0]]) K = torch.tensor([[0.0, 1.0], [2.0, 3.0]]) trans_conv(X, K)
tensor([[ 0., 0., 1.], [ 0., 4., 6.], [ 4., 12., 9.]])
或者,當(dāng)輸入X
和卷積核K
都是四維張量時(shí),我們可以使用高級(jí)API獲得相同的結(jié)果。
X, K = X.reshape(1, 1, 2, 2), K.reshape(1, 1, 2, 2) tconv = nn.ConvTranspose2d(1, 1, kernel_size=2, bias=False) tconv.weight.data = K tconv(X)
tensor([[[[ 0., 0., 1.], [ 0., 4., 6.], [ 4., 12., 9.]]]], grad_fn=<ConvolutionBackward0>)
填充、步幅和多通道實(shí)現(xiàn)
與常規(guī)卷積不同,在轉(zhuǎn)置卷積中,填充被應(yīng)用于的輸出(常規(guī)卷積將填充應(yīng)用于輸入)。 例如,當(dāng)將高和寬兩側(cè)的填充數(shù)指定為1時(shí),轉(zhuǎn)置卷積的輸出中將刪除第一和最后的行與列。
tconv = nn.ConvTranspose2d(1, 1, kernel_size=2, padding=1, bias=False) tconv.weight.data = K tconv(X)
tensor([[[[4.]]]], grad_fn=<ConvolutionBackward0>)
在轉(zhuǎn)置卷積中,步幅被指定為中間結(jié)果(輸出),而不是輸入。 使用?圖13.10.1中相同輸入和卷積核張量,將步幅從1更改為2會(huì)增加中間張量的高和權(quán)重,因此輸出張量在?圖13.10.2中。

可以發(fā)現(xiàn)轉(zhuǎn)置卷積中padding和stride的作用和一般卷積完全是反過來的,一般卷積中padding會(huì)擴(kuò)大輸出結(jié)構(gòu),轉(zhuǎn)置卷積相反。一般卷積中stride會(huì)縮小輸出結(jié)構(gòu),轉(zhuǎn)置卷積則相反。
以下代碼可以驗(yàn)證?圖13.10.2中步幅為2的轉(zhuǎn)置卷積的輸出。
tconv = nn.ConvTranspose2d(1, 1, kernel_size=2, stride=2, bias=False) tconv.weight.data = K tconv(X)
tensor([[[[0., 0., 0., 1.], [0., 0., 2., 3.], [0., 2., 0., 3.], [4., 6., 6., 9.]]]], grad_fn=<ConvolutionBackward0>)
對(duì)于多個(gè)輸入和輸出通道,轉(zhuǎn)置卷積與常規(guī)卷積以相同方式運(yùn)作。 假設(shè)輸入有Ci個(gè)通道,且轉(zhuǎn)置卷積為每個(gè)輸入通道分配了一個(gè)K?×Kw
的卷積核張量。 當(dāng)指定多個(gè)輸出通道時(shí),每個(gè)輸出通道將有一個(gè)Ci×K?×Kw的卷積核。
同樣,如果我們將X代入卷積層f來輸出Y=f(X)
,并創(chuàng)建一個(gè)與f具有相同的超參數(shù)、但輸出通道數(shù)量是X中通道數(shù)的轉(zhuǎn)置卷積層g,那么g(Y)
的形狀將與X相同。 下面的示例可以解釋這一點(diǎn)。
X = torch.rand(size=(1, 10, 16, 16)) conv = nn.Conv2d(10, 20, kernel_size=5, padding=2, stride=3) tconv = nn.ConvTranspose2d(20, 10, kernel_size=5, padding=2, stride=3) tconv(conv(X)).shape == X.shape
True
知識(shí)補(bǔ)充
·轉(zhuǎn)置卷積可以視作對(duì)像素信息的放大嘗試。轉(zhuǎn)置卷積是以一個(gè)不損失信息的方式變換feature圖,把它拉大
·轉(zhuǎn)置卷積在網(wǎng)絡(luò)中的作用不是將圖片還原(指還原成原圖片的RGB信息),而是對(duì)每個(gè)像素進(jìn)行標(biāo)號(hào)歸類。
·雖然在卷積過程中會(huì)對(duì)數(shù)據(jù)結(jié)構(gòu)的高寬作一定的壓縮,但是通道數(shù)隨之也會(huì)增加,并沒有損失太多的信息量。這一過程可以看做圖片數(shù)據(jù)的空間分辨維度在下降,但是特征分辨維度在上升。