转置卷积

Note

在语义分割中,我们期望输入和输出的空间维度相同,这样输出像素各通道可以保有输入像素同一位置上的分类结果。
但是卷积层和pooling层会使得高和宽越来越小,为了使空间维度增加,我们可以使用转置卷积。

基本操作

假设步幅为1且没有填充,那么 \(n_{h}\times{n_{w}}\) 的输入和 \(k_{h}\times{k_{w}}\) 的卷积核经过转置卷积后会产生 \((n_{h} + k_{h} - 1)\times(n_{w} + k_{w} - 1)\) 的输出。

image

如上图所示,转置卷积就是input中各数与kernel相乘,结果嵌入到相应的位置,最后相加。

import torch
from torch import nn

X = torch.tensor([[0., 1.], [2., 3.]]).reshape(1, 1, 2, 2)
K = torch.tensor([[0., 1.], [2., 3.]]).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=<SlowConvTranspose2DBackward>)

填充和步幅

与常规卷积不同,填充被用于输出,如将高宽两侧填充指定为1时,转置卷积的输出中将删去第一和最后的行和列

tconv = nn.ConvTranspose2d(1, 1, kernel_size=2, padding=1, bias=False)
tconv.weight.data = K
tconv(X)
tensor([[[[4.]]]], grad_fn=<SlowConvTranspose2DBackward>)

步幅作用于输出,步幅的增加会导致输出高和宽的增加:

image

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=<SlowConvTranspose2DBackward>)