47 转置卷积【动手学深度学习v2】

转置卷积
卷积操作一般不会改变输入的高宽。若改变一般是往缩小改变。
在语义分割问题中,数据是像素级别的输入与输出,如果使用一般卷积使得高宽减小到很小的数值,则会造成数据损失。
转置卷积通常用于增大数据的高宽

具体来说,输入数据中的每个值都会与整个转置卷积核相乘,形成一个与卷积核大小相同的新数据,放置在特定对应位置,最后相加。
为什么称此运算方法为“转置”?(此处设计卷积法的矩阵实现,在下一讲中会作详细说明)

代码实现
import torch from torch import nn from d2l import torch as d2l
对输入矩阵X
和卷积核矩阵K
实现基本的转置卷积运算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
与通过卷积核“减少”输入元素的常规卷积(在 6.2节中)相比,转置卷积通过卷积核“广播”输入元素,从而产生大于输入的输出。 我们可以通过 图13.10.1来构建输入张量X
和卷积核张量K
从而验证上述实现输出。 此实现是基本的二维转置卷积运算。
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.]])
或者,当输入X
和卷积核K
都是四维张量时,我们可以使用高级API获得相同的结果。
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>)
填充、步幅和多通道实现
与常规卷积不同,在转置卷积中,填充被应用于的输出(常规卷积将填充应用于输入)。 例如,当将高和宽两侧的填充数指定为1时,转置卷积的输出中将删除第一和最后的行与列。
tconv = nn.ConvTranspose2d(1, 1, kernel_size=2, padding=1, bias=False) tconv.weight.data = K tconv(X)
tensor([[[[4.]]]], grad_fn=<ConvolutionBackward0>)
在转置卷积中,步幅被指定为中间结果(输出),而不是输入。 使用 图13.10.1中相同输入和卷积核张量,将步幅从1更改为2会增加中间张量的高和权重,因此输出张量在 图13.10.2中。

可以发现转置卷积中padding和stride的作用和一般卷积完全是反过来的,一般卷积中padding会扩大输出结构,转置卷积相反。一般卷积中stride会缩小输出结构,转置卷积则相反。
以下代码可以验证 图13.10.2中步幅为2的转置卷积的输出。
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>)
对于多个输入和输出通道,转置卷积与常规卷积以相同方式运作。 假设输入有Ci个通道,且转置卷积为每个输入通道分配了一个Kℎ×Kw
的卷积核张量。 当指定多个输出通道时,每个输出通道将有一个Ci×Kℎ×Kw的卷积核。
同样,如果我们将X代入卷积层f来输出Y=f(X)
,并创建一个与f具有相同的超参数、但输出通道数量是X中通道数的转置卷积层g,那么g(Y)
的形状将与X相同。 下面的示例可以解释这一点。
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
知识补充
·转置卷积可以视作对像素信息的放大尝试。转置卷积是以一个不损失信息的方式变换feature图,把它拉大
·转置卷积在网络中的作用不是将图片还原(指还原成原图片的RGB信息),而是对每个像素进行标号归类。
·虽然在卷积过程中会对数据结构的高宽作一定的压缩,但是通道数随之也会增加,并没有损失太多的信息量。这一过程可以看做图片数据的空间分辨维度在下降,但是特征分辨维度在上升。