当前位置:   article > 正文

动手学深度学习之转置卷积_转置卷积的宽高

转置卷积的宽高

转置卷积

  • 卷积不会增大输入的高宽,通常要么不变、要么减半
  • 转置卷积则可以用来增大输入高宽。假设我们有一个2*2的输入,有一个2*2的核,这个卷积核会进行一个滑动,在输入中的每一个元素会和卷积核中的每一个元素做乘法,然后将每一个元素都写会到对应的地方,如下图,会得到4个大一点的矩阵,然后将这4个矩阵加起来。
    在这里插入图片描述

为什么称之为“转置”

  • 假设卷积可以将一个4*4的矩阵变为2*2的话,那么转置卷积就可以将一个矩阵从2*2变为一个4*4
    在这里插入图片描述

代码实现

import torch
from torch import nn
from d2l import torch as d2l
  • 1
  • 2
  • 3
# 实现基本的转置卷积运算
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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
# 验证上述实现输出
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)
  • 1
  • 2
  • 3
  • 4
tensor([[ 0.,  0.,  1.],
        [ 0.,  4.,  6.],
        [ 4., 12.,  9.]])
  • 1
  • 2
  • 3
# 使用高级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)
  • 1
  • 2
  • 3
  • 4
  • 5
tensor([[[[ 0.,  0.,  1.],
          [ 0.,  4.,  6.],
          [ 4., 12.,  9.]]]], grad_fn=<SlowConvTranspose2DBackward>)
  • 1
  • 2
  • 3
# 填充、步幅和多通道
tconv = nn.ConvTranspose2d(1, 1, kernel_size=2, padding=1, bias=False)  # 填充,这里填充的意思是:将输出的最外面一层去掉
tconv.weight.data = K
tconv(X)
  • 1
  • 2
  • 3
  • 4
tensor([[[[4.]]]], grad_fn=<SlowConvTranspose2DBackward>)
  • 1
tconv = nn.ConvTranspose2d(1, 1, kernel_size=2, stride=2, bias=False)
tconv.weight.data = K
tconv(X)
  • 1
  • 2
  • 3
tensor([[[[0., 0., 0., 1.],
          [0., 0., 2., 3.],
          [0., 2., 0., 3.],
          [4., 6., 6., 9.]]]], grad_fn=<SlowConvTranspose2DBackward>)
  • 1
  • 2
  • 3
  • 4
# 这个例子告诉我们,通过卷积和转置卷积后shape是一样的。
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
  • 1
  • 2
  • 3
  • 4
  • 5
True
  • 1
# 与矩阵变换的联系
X = torch.arange(9.0).reshape(3, 3)
K = torch.tensor([[1.0, 2.0], [3.0, 4.0]])
Y = d2l.corr2d(X, K)
Y
  • 1
  • 2
  • 3
  • 4
  • 5
tensor([[27., 37.],
        [57., 67.]])
  • 1
  • 2
# 给我们一个kernel我们将它变为刚刚的V
def kernel2matrix(K):
    k, W = torch.zeros(5), torch.zeros((4, 9))
    k[:2], k[3:5] = K[0, :], K[1, :]
    W[0, :5], W[1, 1:6], W[2, 3:8], W[3, 4:] = k, k, k, k
    return W

W = kernel2matrix(K)
W
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
tensor([[1., 2., 0., 3., 4., 0., 0., 0., 0.],
        [0., 1., 2., 0., 3., 4., 0., 0., 0.],
        [0., 0., 0., 1., 2., 0., 3., 4., 0.],
        [0., 0., 0., 0., 1., 2., 0., 3., 4.]])
  • 1
  • 2
  • 3
  • 4
Y == torch.matmul(W, X.reshape(-1)).reshape(2, 2)
  • 1
tensor([[True, True],
        [True, True]])
  • 1
  • 2
Z = trans_conv(Y, K)
Z == torch.matmul(W.T, Y.reshape(-1)).reshape(3, 3)
  • 1
  • 2
tensor([[True, True, True],
        [True, True, True],
        [True, True, True]])
  • 1
  • 2
  • 3

转置卷积

  • 转置卷积是一种卷积,可以认为在同样的超参数的情况下,转置卷积核卷积是一对逆变换
    • 它将输入和核进行了重新排列
    • 同卷积一般是做下采样不同,它通常是做上采样
    • 如果卷积将输入从(h,w)变成了(h’,w’), 同样超参数下转置卷积将(h’,w’)变为了(h,w)

列输入和核

  • 当填充为0步幅为时

    • 将输入填充k-1(k是核窗口)
    • 将核举证上下,左右翻转
    • 然后做正常卷积(填充0、步幅1)
      在这里插入图片描述
  • 当填充为p步幅为1时

    • 将输入填充k-p-1(k是核窗口)
    • 将核矩阵上下、左右翻转
    • 然后做正常卷积(填充0、步幅1)
      在这里插入图片描述
  • 当填充为p步幅为s时

    • 在行和列之间插入s-1行或列
    • 将输入填充k-p-1(k是核窗口)
    • 将核矩阵上下、左右翻转
    • 然后做正常卷积(填充0、步幅1)
      在这里插入图片描述

形状换算

在这里插入图片描述

同反卷积的关系

在这里插入图片描述

总结

在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/888291
推荐阅读
相关标签
  

闽ICP备14008679号