精华内容
下载资源
问答
  • 转置卷积
    万次阅读 多人点赞
    2021-10-11 19:25:42


    前言

    转置卷积(Transposed Convolution) 在语义分割或者对抗神经网络(GAN)中比较常见,其主要作用就是做上采样(UpSampling)。在有些地方转置卷积又被称作fractionally-strided convolution或者deconvolution,但deconvolution具有误导性,不建议使用。对于转置卷积需要注意的是:

    • 转置卷积不是卷积的逆运算、不是逆运算、不是逆运算(重要的事情说三遍)
    • 转置卷积也是卷积

    本文主要介绍转置卷积是如何计算的,关于转置卷积详细内容可以参考下面的文章:

    不想看文章的可以看下我在bilibili上录的视频:


    卷积操作

    首先回顾下普通卷积,下图以stride=1,padding=0,kernel_size=3为例,假设输入特征图大小是4x4的(假设输入输出都是单通道),通过卷积后得到的特征图大小为2x2。一般使用卷积的情况中,要么特征图变小(stride > 1),要么保持不变(stride = 1),当然也可以通过四周padding让特征图变大但没有意义。关于卷积的详细介绍可以参考我之前的博文
    在这里插入图片描述


    转置卷积操作

    转置卷积刚刚说了,主要作用就是起到上采样的作用。但转置卷积不是卷积的逆运算(一般卷积操作是不可逆的),它只能恢复到原来的大小(shape)数值与原来不同。转置卷积的运算步骤可以归为以下几步:

    • 在输入特征图元素间填充s-1行、列0(其中s表示转置卷积的步距)
    • 在输入特征图四周填充k-p-1行、列0(其中k表示转置卷积的kernel_size大小,p为转置卷积的padding,注意这里的padding和卷积操作中有些不同)
    • 将卷积核参数上下、左右翻转
    • 做正常卷积运算(填充0,步距1)

    下面假设输入的特征图大小为2x2(假设输入输出都为单通道),通过转置卷积后得到4x4大小的特征图。这里使用的转置卷积核大小为k=3,stride=1,padding=0的情况(忽略偏执bias)。

    • 首先在元素间填充s-1=0行、列0(等于0不用填充)
    • 然后在特征图四周填充k-p-1=2行、列0
    • 接着对卷积核参数进行上下、左右翻转
    • 最后做正常卷积(填充0,步距1)

    在这里插入图片描述

    下图展示了转置卷积中不同s和p的情况:

    s=1, p=0, k=3
    s=2, p=0, k=3
    s=2, p=1, k=3

    转置卷积操作后特征图的大小可以通过如下公式计算:
    H o u t = ( H i n − 1 ) × s t r i d e [ 0 ] − 2 × p a d d i n g [ 0 ] + k e r n e l _ s i z e [ 0 ] W o u t = ( W i n − 1 ) × s t r i d e [ 1 ] − 2 × p a d d i n g [ 1 ] + k e r n e l _ s i z e [ 1 ] H_{out} =(H_{in}-1) \times {\rm stride[0]} - 2 \times {\rm padding[0]}+ {\rm kernel \_ size[0]} \\ W_{out} =(W_{in}-1) \times {\rm stride[1]} - 2 \times {\rm padding[1]}+ {\rm kernel \_ size[1]} Hout=(Hin1)×stride[0]2×padding[0]+kernel_size[0]Wout=(Win1)×stride[1]2×padding[1]+kernel_size[1]
    其中stride[0]表示高度方向的stride,padding[0]表示高度方向的padding,kernel_size[0]表示高度方向的kernel_size,索引[1]都表示宽度方向上的。通过上面公式可以看出padding越大,输出的特征矩阵高、宽越小,你可以理解为正向卷积过程中进行了padding然后得到了特征图,现在使用转置卷积还原到原来高、宽后要把之前的padding减掉。


    Pytorch中的转置卷积参数

    pytorch官方关于转置卷积ConvTranspose2d的文档:https://pytorch.org/docs/stable/generated/torch.nn.ConvTranspose2d.html

    官方原话:
    Applies a 2D transposed convolution operator over an input image composed of several input planes.This module can be seen as the gradient of Conv2d with respect to its input. It is also known as a fractionally-strided convolution or a deconvolution (although it is not an actual deconvolution operation).

    官方对转置卷积使用到的参数介绍:

    在这里插入图片描述上面讲的例子中已经介绍了in_channels, out_channels, kernel_size, stride, padding这几个参数了,在官方提供的方法中还有:

    • output_padding:在计算得到的输出特征图的高、宽方向各填充几行或列0(注意,这里只是在上下以及左右的一侧one side填充,并不是两侧都填充,有兴趣自己做个实验看下),默认为0不使用。
    • groups:当使用到组卷积时才会用到的参数,默认为1即普通卷积。
    • bias:是否使用偏执bias,默认为True使用。
    • dilation:当使用到空洞卷积(膨胀卷积)时才会使用到的参数,默认为1即普通卷积。

    输出特征图宽、高计算:
    H o u t = ( H i n − 1 ) × s t r i d e [ 0 ] − 2 × p a d d i n g [ 0 ] + d i l a t i o n [ 0 ] × ( k e r n e l _ s i z e [ 0 ] − 1 ) + o u t p u t _ p a d d i n g [ 0 ] + 1 W o u t = ( W i n − 1 ) × s t r i d e [ 1 ] − 2 × p a d d i n g [ 1 ] + d i l a t i o n [ 1 ] × ( k e r n e l _ s i z e [ 1 ] − 1 ) + o u t p u t _ p a d d i n g [ 1 ] + 1 H_{out} =(H_{in}-1) \times {\rm stride[0]} - 2 \times {\rm padding[0]}+ {\rm dilation[0]} \times ({\rm kernel \_ size[0]}-1) + {\rm output\_padding[0]}+1 \\ W_{out} =(W_{in}-1) \times {\rm stride[1]} - 2 \times {\rm padding[1]}+ {\rm dilation[1]} \times ({\rm kernel \_ size[1]}-1) + {\rm output\_padding[1]}+1 Hout=(Hin1)×stride[0]2×padding[0]+dilation[0]×(kernel_size[0]1)+output_padding[0]+1Wout=(Win1)×stride[1]2×padding[1]+dilation[1]×(kernel_size[1]1)+output_padding[1]+1


    Pytorch转置卷积实验

    下面使用Pytorch框架来模拟s=1, p=0, k=3的转置卷积操作:
    在这里插入图片描述

    在代码中transposed_conv_official函数是使用官方的转置卷积进行计算,transposed_conv_self函数是按照上面讲的步骤自己对输入特征图进行填充并通过卷积得到的结果。

    import torch
    import torch.nn as nn
    
    
    def transposed_conv_official():
        feature_map = torch.as_tensor([[1, 0],
                                       [2, 1]], dtype=torch.float32).reshape([1, 1, 2, 2])
        print(feature_map)
        trans_conv = nn.ConvTranspose2d(in_channels=1, out_channels=1,
                                        kernel_size=3, stride=1, bias=False)
        trans_conv.load_state_dict({"weight": torch.as_tensor([[1, 0, 1],
                                                               [0, 1, 1],
                                                               [1, 0, 0]], dtype=torch.float32).reshape([1, 1, 3, 3])})
        print(trans_conv.weight)
        output = trans_conv(feature_map)
        print(output)
    
    
    def transposed_conv_self():
        feature_map = torch.as_tensor([[0, 0, 0, 0, 0, 0],
                                       [0, 0, 0, 0, 0, 0],
                                       [0, 0, 1, 0, 0, 0],
                                       [0, 0, 2, 1, 0, 0],
                                       [0, 0, 0, 0, 0, 0],
                                       [0, 0, 0, 0, 0, 0]], dtype=torch.float32).reshape([1, 1, 6, 6])
        print(feature_map)
        conv = nn.Conv2d(in_channels=1, out_channels=1,
                         kernel_size=3, stride=1, bias=False)
        conv.load_state_dict({"weight": torch.as_tensor([[0, 0, 1],
                                                         [1, 1, 0],
                                                         [1, 0, 1]], dtype=torch.float32).reshape([1, 1, 3, 3])})
        print(conv.weight)
        output = conv(feature_map)
        print(output)
    
    
    def main():
        transposed_conv_official()
        print("---------------")
        transposed_conv_self()
    
    
    if __name__ == '__main__':
        main()
    
    

    终端输出:

    tensor([[[[1., 0.],
              [2., 1.]]]])
    Parameter containing:
    tensor([[[[1., 0., 1.],
              [0., 1., 1.],
              [1., 0., 0.]]]], requires_grad=True)
    tensor([[[[1., 0., 1., 0.],
              [2., 2., 3., 1.],
              [1., 2., 3., 1.],
              [2., 1., 0., 0.]]]], grad_fn=<SlowConvTranspose2DBackward>)
    ---------------
    tensor([[[[0., 0., 0., 0., 0., 0.],
              [0., 0., 0., 0., 0., 0.],
              [0., 0., 1., 0., 0., 0.],
              [0., 0., 2., 1., 0., 0.],
              [0., 0., 0., 0., 0., 0.],
              [0., 0., 0., 0., 0., 0.]]]])
    Parameter containing:
    tensor([[[[0., 0., 1.],
              [1., 1., 0.],
              [1., 0., 1.]]]], requires_grad=True)
    tensor([[[[1., 0., 1., 0.],
              [2., 2., 3., 1.],
              [1., 2., 3., 1.],
              [2., 1., 0., 0.]]]], grad_fn=<ThnnConv2DBackward>)
    
    Process finished with exit code 0
    

    通过对比能够发现,官方转置卷积的结果,和我们自己实现的转置卷积结果是一样的。对于其他的情况大家可以自己动手做做实验。

    更多相关内容
  • 目录前言转置卷积图解卷积核大小对转置卷积的影响kernel_size=2,stride=1,padding=0,output_padding=0kernel_size=3,stride=1,padding=0,output_padding=0padding对转置卷积结果的影响kernel_size=3,stride=1...

    前言

    在我们用深度学习做图像处理需要上采样操作时,目前比较常用的两种上采样方式
    一是转置卷积
    二是PixelShuffle

    这里先谈一下转置卷积的实现过程。谈到转置卷积肯定得与卷积联系起来,在pytorch中卷积类的参数如下:

    torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True, padding_mode='zeros', device=None, dtype=None)
    

    这些都是我们很熟悉的卷积参数:

    • in_channels:输入的通道数
    • out_channels:输出的通道数
    • kernel_size:卷积核大小
    • stride:步长
    • padding:对输入进行填充
    • dilation:卷积核的空洞
    • groups:卷积的分组
    • bias:卷积结果后添加的偏置
    • padding_mode:填充的类型

    在pytorch中转置卷积的类torch.nn.ConvTranspose2d参数如下:

    torch.nn.ConvTranspose2d(in_channels, out_channels, kernel_size, stride=1, padding=0, output_padding=0, groups=1, bias=True, dilation=1, padding_mode='zeros', device=None, dtype=None)
    

    可以看到pytorch中转置卷积的参数与卷积的参数一模一样!说明它们之间肯定是有联系的,在进行转置卷积操作时首先对输入的每行每列之间填充(stride-1)行(列)的0,然后再对填充的输入的外围填充(kernel_size-1)圈的0,然后再用旋转180°的卷积核对填充后的输入进行步长为1卷积,如果padding不等于0,则对卷积后的结果的外围进行去除padding圈,如果output_padding不等于0,则还需要对最后的结果右侧和下方填充output_padding的0.下面用图形来详细说明转置卷积的计算过程。

    转置卷积图解

    为了更好的验证结果的正确性,这里用torch.nn.functional.conv_transpose2d来进行结果的验证。

    torch.nn.functional.conv_transpose2d(input, weight, bias=None, stride=1, padding=0, output_padding=0, groups=1, dilation=1) → Tensor
    

    这里主要讨论kernel_size,stride,padding与output_padding对转置卷积结果的影响。

    卷积核大小对转置卷积的影响

    卷积核大小对转置卷积的影响主要是对输入的填充多少圈0——(kernel_size-1)圈
    下面通过对kernel_size=2和kernel_size=3来进行验证。

    kernel_size=2,stride=1,padding=0,output_padding=0

    下面是用于转置卷积的输入与卷积核及转置卷积后的结果:
    输入
    输入
    转置卷积核
    卷积核
    结果
    结果
    图形解释其过程:由于卷积核的大小为2,所以先对输入外围填充2-1=1圈的0,然后用旋转180°的卷积核对填充后的结果进行常规卷积(步长始终为1)操作。
    图1

    kernel_size=3,stride=1,padding=0,output_padding=0

    输入还是和之前一样,转置卷积核为下图所示:
    在这里插入图片描述
    转置卷积的输出结果:
    在这里插入图片描述
    图形解释其过程:由于卷积核的大小为3,所以先对输入外围填充3-1=2圈的0,然后用旋转180°的卷积核对填充后的结果进行常规卷积操作(步长始终为1)。
    在这里插入图片描述

    padding对转置卷积结果的影响

    padding对转置卷积结果的影响主要体现在对转置卷积得到的结果进行去除

    kernel_size=3,stride=1,padding=1,output_padding=0

    输入
    在这里插入图片描述
    转置卷积核
    在这里插入图片描述
    结果
    在这里插入图片描述
    图形解释其过程:由于卷积核的大小为3,所以先对输入外围填充3-1=2圈的0,然后用旋转180°的卷积核对填充后的结果进行常规卷积操作(步长始终为1),又由于padding=1,所以对卷积得到的结果的最外一层去掉(这正好与卷积里的padding的用法相反,卷积里的padding是对输入进行填充)。
    在这里插入图片描述

    kernel_size=3,stride=1,padding=2,output_padding=0

    输入和卷积核还是和上面一样,只是将padding设为2.
    结果
    在这里插入图片描述
    图形解释其过程:由于卷积核的大小为3,所以先对输入外围填充3-1=2圈的0,然后用旋转180°的卷积核对填充后的结果进行常规卷积操作(步长始终为1),又由于padding=2,所以对卷积得到的结果的最外两层去掉
    在这里插入图片描述

    步长stride对转置卷积结果的影响

    步长stride对转置卷积的影响主要体现在对输入进行0填充,输入的每行每列之间填充stride-1的0.
    输入
    在这里插入图片描述
    转置卷积核
    在这里插入图片描述

    kernel_size=2,stride=2,padding=0,output_padding=0的结果

    在这里插入图片描述
    图形解释其过程:由于步长stride=2,则需对输入的每行每列之间填充2-1=1的0。又由于卷积核的大小为2,所以还需对输入外围填充2-1=1圈的0,然后用旋转180°的卷积核对填充后的结果进行常规卷积操作(步长始终为1)。
    在这里插入图片描述

    kernel_size=2,stride=3,padding=0,output_padding=0的结果

    在这里插入图片描述
    图形解释其过程:由于步长stride=3,则需对输入的每行每列之间填充3-1=2的0。又由于卷积核的大小为2,所以还需对输入外围填充2-1=1圈的0,然后用旋转180°的卷积核对填充后的结果进行常规卷积操作(步长始终为1)。
    在这里插入图片描述

    out_padding对转置卷积结果的影响——对输出填充0

    out_padding对转置卷积的影响是对卷积得到的结果的右侧和下方进行0填充(注意stride的大小必须大于out_padding的大小)
    输入
    在这里插入图片描述

    转置卷积核

    在这里插入图片描述

    kernel_size=2,stride=2,padding=0,output_padding=1的结果

    在这里插入图片描述
    图形解释其过程:由于步长stride=2,则需对输入的每行每列之间填充2-1=1的0。又由于卷积核的大小为2,所以还需对输入外围填充2-1=1圈的0,然后用旋转180°的卷积核对填充后的结果进行常规卷积操作(步长始终为1),又由于out_padding=1,所以还需对卷积得到的结果的右侧和下方进行1列/行的0填充。
    在这里插入图片描述

    kernel_size=2,stride=3,padding=0,output_padding=2的结果

    输入和卷积核还是和上面一样,不过由于stride的大小必须大于out_padding的大小,所以stride设为3.输出如下
    在这里插入图片描述

    图形解释其过程:由于步长stride=2,则需对输入的每行每列之间填充2-1=1的0。又由于卷积核的大小为2,所以还需对输入外围填充2-1=1圈的0,然后用旋转180°的卷积核对填充后的结果进行常规卷积操作(步长始终为1),又由于out_padding=2,所以还需对卷积得到的结果的右侧和下方进行2列/行的0填充

    在这里插入图片描述

    转置卷积计算公式理解

    有了上面的分析,对pytorch官方文档给出的转置卷积的计算公式就不难理解了。
    假设输入的大小为 H × W H\times W H×W,这里只考虑对 H H H的影响,首先,由于参数sttride的影响需要对输入的每行每列之间填充(stride-1)行或列的0,则输入 H H H的大小变为 H + ( s t r i d e − 1 ) × ( H − 1 ) = ( H − 1 ) × s t r i d e + 1 H+(stride-1)\times (H-1)=(H-1)\times stride+1 H+(stride1)×(H1)=(H1)×stride+1,又由于参数kernel_size的影响需要对输入的外围填充 k e r n e l _ s i z e − 1 kernel\_size-1 kernel_size1圈的0,则输入的大小变为 ( H − 1 ) × s t r i d e + 1 + 2 × ( k e r n e l _ s i z e − 1 ) (H-1)\times stride+1+2\times (kernel\_size-1) (H1)×stride+1+2×(kernel_size1),接下来进行的是步长为1的常规卷积操作,则由卷积的计算公式有: ( H − 1 ) × s t r i d e + 1 + 2 × ( k e r n e l _ s i z e − 1 ) − k e r n e l _ s i z e + 1 = ( H − 1 ) × s t r i d e + 1 + ( k e r n e l _ s i z e − 1 ) (H-1)\times stride+1+2\times (kernel\_size-1)-kernel\_size+1=(H-1)\times stride+1+(kernel\_size-1) (H1)×stride+1+2×(kernel_size1)kernel_size+1=(H1)×stride+1+(kernel_size1),由于padding与out_padding的存在需要对卷积后结果的去除或填充,则:
    ( H − 1 ) × s t r i d e + 1 + ( k e r n e l _ s i z e − 1 ) − 2 × p a d d i n g + o u t _ p a d d i n g (H-1)\times stride+1+(kernel\_size-1)-2\times padding+out\_padding (H1)×stride+1+(kernel_size1)2×padding+out_padding.这就是pytorch官方文档给的转置卷积计算公式,当然这里没考虑dilation.

    总结

    这篇文章主要说明了转置卷积里的参数kernel_size, stride, padding, out_padding对转置卷积结果的影响。其中前两个参数影响输入的填充,后两个参数影响卷积后结果的去除或填充。总之,转置卷积还是卷积,只不过对输入和输出进行某些处理而已。

    展开全文
  • Pytorch 转置卷积

    2022-06-01 19:20:49
    转置卷积则可以用来增大输入高宽。 假设忽略通道,步幅为 1 且填充为 0。输入张量形状为 nh×nwn_h \times n_wnh​×nw​,卷积核形状为 kh×kwk_h \times k_wkh​×kw​。共产生 nhnwn_hn_wnh​nw​ 个中间结果...

    Pytorch 转置卷积

    0. 环境介绍

    环境使用 Kaggle 里免费建立的 Notebook

    教程使用李沐老师的 动手学深度学习 网站和 视频讲解

    小技巧:当遇到函数看不懂的时候可以按 Shift+Tab 查看函数详解。

    1. 转置卷积(transposed convolution)

    卷积不会增大输入的高和宽,通常要么不变,要么减半。而转置卷积则可以用来增大输入高宽。
    在这里插入图片描述
    假设忽略通道,步幅为 1 且填充为 0。输入张量形状为 n h × n w n_h \times n_w nh×nw,卷积核形状为 k h × k w k_h \times k_w kh×kw。共产生 n h n w n_hn_w nhnw 个中间结果。每个中间结果都是一个 ( n h + k h − 1 ) × ( n w + k w − 1 ) (n_h+k_h-1)\times(n_w+k_w-1) (nh+kh1)×(nw+kw1) 的张量(初始化为 0)。计算中间张量的方法:输入张量中的每个元素乘以卷积核,得到 k h × k w k_h \times k_w kh×kw 的张量替换中间张量的一部分。
    每个中间张量被替换部分的位置与输入张量中元素的位置相对应。 最后,所有中间结果相加以获得最终结果。

    中间张量计算公式如下
    Y [ i : i + h , j : j + w ] + = X [ i , j ] ∗ K Y[i: i + h, j: j + w] += X[i, j] * K Y[i:i+h,j:j+w]+=X[i,j]K

    1.1 为什么称之 “转置” ?

    对于卷积 Y = X ★ W Y = X ★ W Y=XW ★ ★ 表示卷积操作)

    • 可以对 W W W 构造一个 V V V,使得卷积等价于矩阵乘法 Y ′ = V X ′ Y^{\prime} = VX^{\prime} Y=VX
    • 这里 Y ′ 和 X ′ Y^{\prime} 和 X^{\prime} YX Y , X Y, X Y,X 对应的向量版本。

    转置卷积则等价于 Y ′ = V T X ′ Y^{\prime} = V^TX^{\prime} Y=VTX
    如果卷积将输入从 ( h , w ) (h, w) (h,w) 变成了 ( h ′ , w ′ ) (h^{\prime}, w^{\prime}) (h,w)

    • 同样超参数的转置卷积则从 ( h ′ , w ′ ) (h^{\prime}, w^{\prime}) (h,w) 变成了 ( h , w ) (h, w) (h,w)

    2. 转置卷积实现

    2.1 转置卷积

    !pip install -U d2l
    import torch
    from torch import nn
    from d2l import torch as d2l
    
    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
    
    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)
    

    在这里插入图片描述

    2.2 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)
    

    在这里插入图片描述

    2.3 填充,步幅和多通道

    与常规卷积不同,在转置卷积中,填充被应用于的输出(常规卷积将填充应用于输入)。 例如,当将高和宽两侧的填充数指定为1时,转置卷积的输出中将删除第一和最后的行与列。

    tconv = nn.ConvTranspose2d(1, 1, kernel_size=2, padding=1, bias=False)
    tconv.weight.data = K
    tconv(X)
    

    在这里插入图片描述

    在转置卷积中,步幅被指定为中间结果(输出),而不是输入。

    tconv = nn.ConvTranspose2d(1, 1, kernel_size=2, stride=2, bias=False)
    tconv.weight.data = K
    tconv(X)
    

    在这里插入图片描述

    在这里插入图片描述

    输入 X X 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
    

    在这里插入图片描述

    2.4 与矩阵变换的联系

    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
    

    在这里插入图片描述

    将卷积核 K K K 重写为包含大量 0 0 0 的稀疏权重矩阵 W W W 4 × 9 4 \times 9 4×9):

    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
    

    在这里插入图片描述

    Y == torch.matmul(W, X.reshape(-1)).reshape(2, 2)
    

    在这里插入图片描述

    Z = trans_conv(Y, K)
    Z == torch.matmul(W.T, Y.reshape(-1)).reshape(3, 3)
    

    在这里插入图片描述

    3. 再谈转置卷积

    转置卷积是一种卷积

    • 它将输入和核进行了重新排列
    • 同卷积一般是做下采样(将高和宽变得更小),而转置卷积通常用作上采样(输出高宽变大)
    • 如果卷积将输入从 ( h , w ) (h, w) (h,w) 变成了 ( h ′ , w ′ ) (h^{\prime}, w^{\prime}) (h,w),同样超参数下转置卷积将 ( h ′ , w ′ ) (h^{\prime}, w^{\prime}) (h,w) 变成 ( h , w ) (h, w) (h,w)

    注:
    下采样:由输入图片得到特征图
    上采样:由特征图得到预测图

    3.1 重新排列输入和核

    当填充为 0 0 0,步幅为 1 1 1

    • 将输入填充 k − 1 k-1 k1 k k k 是核窗口)
    • 将核矩阵上下、左右翻转
    • 然后做正常卷积(填充 0 0 0, 步幅 1 1 1

    ( p , s ) = ( 0 , 1 ) (p,s) = (0, 1) (ps)=(0,1)
    在这里插入图片描述

    当填充为 p p p,步幅为 1 1 1

    • 将输入填充 k − p − 1 k-p-1 kp1 k k k 是核窗口)
    • 将核矩阵上下、左右翻转
    • 然后做正常卷积(填充 0 0 0、步幅 1 1 1

    ( p , s ) = ( 1 , 1 ) (p,s) = (1, 1) (ps)=(1,1)
    在这里插入图片描述

    当填充为 p p p,步幅为 s s s

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

    ( p , s ) = ( 0 , 2 ) (p,s) = (0, 2) (ps)=(0,2)
    在这里插入图片描述

    3.2 形状换算

    输入高(宽)为 n n n,核 k k k,填充 p p p,步幅 s s s
    转置卷积: n ′ = s n + k − 2 p − s n^{\prime} = sn + k -2p - s n=sn+k2ps

    • 卷积: n ′ = ⌊ ( n − k − 2 p + s ) / s ⌋ → n ≥ s n ′ + k − 2 p − s n^{\prime} = \lfloor(n-k-2p+s)/s\rfloor \to n \ge sn^{\prime} +k -2p -s n=(nk2p+s)/snsn+k2ps

    如果让高宽成倍增加,那么 k = 2 p + s k=2p+s k=2p+s

    3.3 转置卷积与反卷积的关系

    数学上的反卷积(deconvolution)是指卷积的逆运算

    • 如果 Y = c o n v ( X , K ) Y=conv(X, K) Y=conv(X,K),那么 X = d e c o n v ( Y , K ) X = deconv(Y, K) X=deconv(Y,K)

    反卷积很少用在深度学习中

    • 我们说的反卷积神经网络指的是用了转置卷积的神经网络
    展开全文
  • 图解转置卷积原理

    千次阅读 2022-03-12 00:56:20
    声明:本文大部分搬运自【机器学习】详解 转置卷积 (Transpose Convolution) 感谢博主花与人间事同,本人只是在博主原创文章上做补充以及添加一些自己的理解。 1 转置卷积的背景 通常,对图像进行多次卷积运算后,...

    声明:本文大部分搬运自【机器学习】详解 转置卷积 (Transpose Convolution)
    感谢博主花与人间事同,本人只是在博主原创文章上做补充以及添加一些自己的理解。

    1 转置卷积的背景

    通常,对图像进行多次卷积运算后,特征图的尺寸会不断缩小。而对于某些特定任务 (如图像分割和图像生成等),需将图像恢复到原尺寸再操作。这个将图像由小分辨率映射到大分辨率的尺寸恢复操作,称为上采样 (Upsample),如下图所示:

    在这里插入图片描述

    上采样方法有很多,详见【图像处理】详解 最近邻插值、线性插值、双线性插值、双三次插值。然而,这些上采样方法都是基于人们的先验经验来设计的,规则固定且不可学习,在很多场景中效果并不理想。因此,我们希望神经网络自己学习如何更好地插值,即接下来要介绍的转置卷积

    2 转置卷积的应用

    曾经,转置卷积也被称为反卷积(Deconvolution)。与传统的上采样方法相比,转置卷积的上采样方式并非预设的插值方法,而是同标准卷积一样,具有可学习的参数,可通过网络学习来获取最优的上采样方式
    转置卷积在某些特定领域具有广泛应用,比如:

    • 在 DCGAN 中,生成器将随机值转变为一个全尺寸图片,此时需用到转置卷积。
    • 在语义分割中,会在编码器中用卷积层提取特征,然后在解码器中恢复原先尺寸,从而对原图中的每个像素分类。该过程同样需用转置卷积。经典方法有 FCN 和 U-net 。
    • CNN 可视化:通过转置卷积将 CNN 的特征图还原到像素空间,以观察特定特征图对哪些模式的图像敏感。

    3 转置卷积的区别

    标准卷积的运算操作其实是对卷积核中的元素与输入矩阵上对应位置的元素进行逐像素的乘积并求和。然后,卷积核在输入矩阵上以步长为单位进行滑动,直到遍历完输入矩阵的所有位置。
    假设,输入是一个 4×4 矩阵,使用 3×3 的标准卷积进行计算,同时令 padding=0,stride=1。最终输出结果应是一个 2×2 矩阵,如图 2 所示:

    在这里插入图片描述

    在上例中,输入矩阵右上角 3×3 范围的值 (黄色 2 3 4) 会影响输出矩阵右上角的值 (黄色 27),这其实也对应了标准卷积中感受野的概念。所以,可以说 3×3 标准卷积核 建立了 输入矩阵中 9 个值输出矩阵中 1 个值 的映射关系。
    当然,从信息论的角度上看,常规卷积操作是不可逆的,所以转置卷积并不是通过输出矩阵和卷积核计算原始输入矩阵,而是计算得到保持了相对位置关系的矩阵
    也就是说转置卷积是卷积的一个逆向过程,可以恢复卷积前的输入尺寸,而不是恢复原始值

    4 转置卷积的推导

    定义一个 4×4 输入矩阵 input:

    在这里插入图片描述

    再定义一个 3×3 标准卷积核 kernel:

    在这里插入图片描述

    设步长 stride=1、填充 padding=0,可得 2×2 输出矩阵 output:

    在这里插入图片描述

    这里开始我们换一个表达方式,将输入矩阵 input 和输出矩阵 output 展开成 16×1 列向量 X4×1 列向量 Y,可分别表示为:

    在这里插入图片描述

    接着再用矩阵运算来描述标准卷积运算,设有 新卷积核矩阵 C

    在这里插入图片描述

    经卷积运算关系推导,可得 4×16 稀疏矩阵 C

    在这里插入图片描述

    以下用图 4 展示矩阵运算过程:

    在这里插入图片描述

    而转置卷积其实就是要对这个过程进行逆运算,即 通过 C 和 Y 得到 X

    在这里插入图片描述

    此时, C T C^T CT即为新的 16×4 稀疏矩阵。以下通过图 5 展示转置后的卷积矩阵运算。需要注意的是,用于转置卷积的权重矩阵 C T C^T CT 不一定来自于原卷积矩阵 C C C (通常不会如此恰巧),但其形状和原卷积矩阵 C C C 的转置相同

    在这里插入图片描述

    最后,将 16×1 的输出结果重新排序,即可通过 2×2 输入矩阵得到 4×4 输出矩阵。

    5 转置卷积的输出

    这里主要想说明的是,转置卷积其实也是一种卷积,转置卷积可以等价于标准卷积

    5.1 stride = 1, padding=0

    同样,使用上文中的 3×3 卷积核矩阵 C

    在这里插入图片描述

    输出矩阵 output 仍为:

    在这里插入图片描述

    将输出矩阵展开为 列向量 Y

    在这里插入图片描述

    带入到上文中的转置卷积计算公式,则转置卷积的计算结果为:

    在这里插入图片描述

    这其实等价于 先填充 padding=2 的输入矩阵 input

    在这里插入图片描述

    然后,将标准卷积核 kernel朝上翻转,再朝左翻转,得到转置标准卷积核 kernel
    以一个 2x2 的标准卷积核为例,操作的图示如下,右下角是我们标准卷积核。标准卷积核内不同的颜色代表值不同。根据 1 ,我们先沿着水平红色的轴将卷积核向上翻转,再根据 2 ,沿着竖直红色的轴朝左翻转,得到转置标准卷积核。

    在这里插入图片描述

    根据上面的方法,同理我们可以得到 3x3 的转置标准卷积核 kernel

    在这里插入图片描述

    最后,在 填零的输入矩阵 input 上使用 经转置的标准卷积核 kernel 执行 标准卷积运算,如图 6 所示:

    这里我们定义stride=1的普通卷积运算为标准卷积运算

    在这里插入图片描述

    更一般地,对于卷积核尺寸 kernel size = k,步长 stride = s = 1,填充 padding = p = 0 的转置卷积,其 等价的标准卷积 在原尺寸为 i ′ i' i 的输入矩阵上进行运算,输出特征图的尺寸 o ′ o' o 为:

    在这里插入图片描述

    至于为什么等于上面的关系式,下面会解释,这里我们先复习一下普通卷积的输入与输出尺寸的关系
    k e r n e l = k , s t r i d e = s , p a d d i n g = p kernel=k,stride=s,padding=p kernel=k,stride=s,padding=p , 输入尺寸为 i i i , 输出尺寸为 o o o , 则有
    o = ⌊ i − k + 2 p s ⌋ + 1 o=\lfloor \frac{i-k+2p}{s} \rfloor+1 o=sik+2p+1
    后面我们在利用这个公式的时候,一般忽略公式中的向下取整,因为等价成标准卷积时有stride=1,不存在不整除的情况

    即 kernel size = k,步长 stride = s = 1,填充 padding = p = 0 的转置卷积(注意这里的k、s、p都是针对转置卷积的)等价于这样的标准卷积:输入矩阵 input 在卷积运算前,需先进行 p a d d i n g ′ = k − 1 padding' = k-1 padding=k1 的填充,得到尺寸 i ′ ′ = i ′ + 2 ( k − 1 ) i'' = i' + 2(k-1) i=i+2(k1)

    因此,转置卷积输出尺寸可以由标准卷积输入输出尺寸公式推算出来,根据标准卷积输入输出尺寸计算公式可得 (等价的标准卷积的步长 s ′ = 1 s' = 1 s=1,因为padding已经在 i ′ ′ i'' i内进行了,所以下面公式的 p = 0 p=0 p=0):

    在这里插入图片描述

    到这里我们已经可以知道公式是怎么来的了,这里再简单总结一下,根据矩阵 C T y ′ C^Ty' CTy ,转置卷积可以等价为标准卷积。我们需要根据转置卷积的参数k、s、p等先对输入进行填充,然后将转置卷积核进行两次翻转,最后做stride=1的标准卷积。因此我们可以根据标准卷积输入输出尺寸的公式计算出转置卷积的输入输出尺寸关系公式。

    5.2 stride > 1, padding=0

    在实际中,我们大多数时候会使用 stride>1 的转置卷积,从而获得较大的上采样倍率。

    如下,令输入尺寸为 5 × 5 5×5 5×5,标准卷积核同上 k e r n e l s i z e = k = 3 kernel size = k = 3 kernelsize=k=3,步长 s t r i d e = s = 2 stride = s = 2 stride=s=2,填充 p a d d i n g = p = 0 padding = p = 0 padding=p=0,标准卷积运算后,输出矩阵尺寸为 2 × 2 2×2 2×2

    在这里插入图片描述

    此处,转换后的稀疏矩阵尺寸变为 25×4,由于矩阵太大这里不展开进行罗列。最终转置卷积的结果为:

    在这里插入图片描述

    此时,等价于 输入矩阵同时添加了 空洞填充,再由转置的标准卷积核进行运算,过程如图 7 所示:

    在这里插入图片描述

    更一般地,对于卷积核尺寸 k e r n e l s i z e = k kernel size = k kernelsize=k,步长 s t r i d e = s > 1 stride = s > 1 stride=s>1,填充 p a d d i n g = p = 0 padding = p = 0 padding=p=0 的转置卷积,其 等价的标准卷积 在原尺寸为 i ′ i' i 的输入矩阵上进行运算,输出特征图的尺寸 o ′ o' o 为:

    在这里插入图片描述

    即卷积核尺寸 k e r n e l s i z e = k kernel size = k kernelsize=k,步长 s t r i d e = s > 1 stride = s > 1 stride=s>1,填充 p a d d i n g = p = 0 padding = p = 0 padding=p=0 的转置卷积等价于这样的标准卷积:输入矩阵 input 在卷积运算前,需先进行 p a d d i n g ′ = k − 1 padding' = k-1 padding=k1 的填充;然后,相邻元素间的空洞数为 s − 1 s-1 s1,共有 i ′ − 1 i' - 1 i1 组空洞需插入;从而,实际尺寸为 i ′ ′ = i ′ + 2 ( k − 1 ) + ( i ′ − 1 ) × ( s − 1 ) = s × ( i ′ − 1 ) + 2 k − 1 i'' = i' + 2(k-1) + (i' -1) \times (s-1) = s \times (i' - 1) + 2k - 1 i=i+2(k1)+(i1)×(s1)=s×(i1)+2k1

    因此,根据标准卷积输入输出尺寸计算公式得 (等价的标准卷积的步长 s ′ = 1 s' = 1 s=1,因为padding已经在 i ′ ′ i'' i内进行了,所以下面公式的 p = 0 p=0 p=0):

    在这里插入图片描述

    可见,通过控制步长 s t r i d e = s stride = s stride=s 的大小可以控制上采样的倍率

    5.3 stride=s, padding=p

    我们来讨论更一般的情况,这里我直接给出结论。
    k e r n e l s i z e = k kernel size = k kernelsize=k,步长 s t r i d e = s stride = s stride=s,填充 p a d d i n g = p padding = p padding=p 的转置卷积,等价于这样的标准卷积:输入矩阵 input 在卷积运算前,需先进行 p a d d i n g ′ = k − p − 1 padding' = k-p-1 padding=kp1 的填充;然后,相邻元素间的空洞数为 s − 1 s-1 s1,共有 i ′ − 1 i' - 1 i1 组空洞需插入;从而,实际尺寸为 i ′ ′ = i ′ + 2 ( k − p − 1 ) + ( i ′ − 1 ) × ( s − 1 ) = s × ( i ′ − 1 ) + 2 k − 1 − 2 p i'' = i' + 2(k-p-1) + (i' -1) \times (s-1) = s \times (i' - 1) + 2k - 1 -2p i=i+2(kp1)+(i1)×(s1)=s×(i1)+2k12p
    因此,根据标准卷积输入输出尺寸计算公式得 (等价的标准卷积的步长 s ′ = 1 s' = 1 s=1,因为padding已经在 i ′ ′ i'' i内进行了,所以下面公式的 p = 0 p=0 p=0):
    o ′ = i ′ ′ − k + 2 p s ′ + 1 = s ( i ′ − 1 ) + 2 k − 1 − k + 1 − 2 p = s ( i ′ − 1 ) + k − 2 p o'=\frac{i''-k+2p}{s'}+1=s(i'-1)+2k-1-k+1-2p=s(i'-1)+k-2p o=sik+2p+1=s(i1)+2k1k+12p=s(i1)+k2p
    再回忆下标准卷积输入输出尺寸的公式:
    o = ⌊ i − k + 2 p s ⌋ + 1 o=\lfloor \frac{i-k+2p}{s} \rfloor+1 o=sik+2p+1
    不考虑向下取整,我们根据输出 o o o反过来计算输入 i i i
    i = s ( o − 1 ) + k − 2 p i=s(o-1)+k-2p i=s(o1)+k2p
    有没有发现,我们最后就得到了一般情况下的转置卷积输入输出尺寸关系公式。

    6 小结

    • 我们可以用转置卷积来上采样,而 转置卷积的权值是可学习的,所以无需一个预定义的插值方法。

    • 尽管它被称为转置卷积,但这并不意味着我们取某个已有的卷积矩阵并使用转置后的版本

    • 可以用卷积来模拟转置卷积。通过在输入矩阵的值间插入零值 (以及周围填零) 上采样输入矩阵,然后进行常规卷积就会产生与转置卷积相同的效果。你可能会发现一些文章用这种方式解释了转置卷积。但是,由于需要在常规卷积前对输入进行上采样,所以效率较低。

    • 注意:矩阵中的实际权值不一定来自原始卷积矩阵。重要的是权重的排布是由卷积矩阵的转置得来的。

    • 注意:转置卷积会导致生成图像中出现 网格/棋盘效应 (checkerboard artifacts),因此后续也存在许多针对该问题的改进工作。

    展开全文
  • 转置卷积的理论解释和输入输出大小的分析推导。
  • 【机器学习】详解 转置卷积 (Transpose Convolution)

    万次阅读 多人点赞 2021-11-06 17:11:42
    【机器学习】详解 转置卷积 (Transpose Convolution)
  • 转置卷积

    2021-04-22 20:23:13
    转置卷积transposed convolution个人备忘总结转置卷积特点实现总结 转置卷积 上采样方式有三种:双线性或最近邻插值、反池化和转置卷积。现在见的比较多的是双线性和转置卷积。在经典的FCN8中用的就是转置卷积(文中...
  • 转置卷积直观上是想将H和W较小的featuremap还原到输入图像尺寸的过程。注意,只是将尺寸还原到和输入图像相同,具体的权重是不同的。这样做是因为在某些应用如语义分割中,最后要求的输出是一个和输入尺寸相同的...
  • 文章目录一、转置卷积1.1 基本操作1.2 为什么称之为"转置"1.3 实现二维转置卷积和调用高级API实现更高维度转置卷积1.4 填充、步幅和多通道1.4.1 填充1.4.2 步幅1.4.3 多通道1.5 转置卷积与矩阵变换的关系二、小结 ...
  • 转置卷积的介绍以及理论讲解
  • 10.转置卷积

    2022-04-27 17:31:30
    视频:47 转置卷积【动手学深度学习v2】_哔哩哔哩_bilibili 教材:13.10. 转置卷积 — 动手学深度学习 2.0.0-beta0 documentation (d2l.ai) PPT:part-2_14.pdf (d2l.ai) 代码:transposed-conv slides (d2l.ai) ...
  • 卷积神经网络层中卷积层和汇聚层,通常会减少下采样输入图像的空间维度(高和宽)。 然而如果输入和输出图像的空间维度保持相同,在以像素级分类的语义分割...先暂时忽略通道(通道为1),从基本的转置卷积开始,设步
  • 转置卷积和膨胀卷积的详细讲解
  • 转置卷积学习笔记

    千次阅读 2022-01-03 17:44:43
    文章目录1. 转置卷积定义2. 1. 转置卷积定义 2.
  • 本文首先回顾了普通的直接卷积操作,然后讲解了在语义分割中十分常见的两种卷积操作:转置卷积(Transposed Convolution)与膨胀卷积(Dilated Convolution)同时,还给出了相关实例,方便读者理解。具体的语义分割...
  • 转置卷积、又称反卷积其实是卷积的逆过程。卷积的过程通常会减小特征图的的大小,而转置卷积往往增大特征图的大小 卷积 卷积操作,输入是一个特征图i,参数padding§, stride(s),kernel_size(k),输出是卷积后得到...
  • 抽丝剥茧,带你理解转置卷积(反卷积)

    万次阅读 多人点赞 2019-02-18 14:12:18
    这里写自定义目录标题转置卷积普通卷积(直接卷积)转置卷积形象化的转置卷积欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片...
  • 卷积 卷积层的结构参数 卷积核大小(Kernel Size):定义卷积操作的感受野。 步幅(Stride): 定义卷积核遍历图像时的步幅大小。其默认值通常设置为1。设置大于1的值后对图像进行下采样,这种方式类似池化操作。 ...
  • Pytorch中的转置卷积

    千次阅读 2021-11-22 16:46:40
    又称为转置卷积。 torch.nn.ConvTranspose2d(in_channels, out_channels, kernel_size, stride=1, padding=0, output_padding=0, groups=1, bias=True, dilation=1, padding_mode='zeros') 输出大小
  • 下采样、转置卷积、反卷积、下池化,傻傻分不清
  • 转置卷积详解

    万次阅读 2020-03-14 11:53:18
    转置卷积详解   前面文章对卷积做了讲解,感觉既然重新整理,就将系列概念整体做个梳理,也算是将自己知道的所有东西拿来献丑把。   转置卷积(Transposed Convolution)是后来的叫法,一开始大家都是称逆卷积/反...
  • 卷积和转置卷积

    2021-07-23 09:51:56
    首先我们知道,卷积是一种提取特征的过程,通过卷积核操作,就是**输入和卷积核“逐”元素相乘求和的过**程,在图像中 的理解就是,某一处特征的边缘特征也是一样的,那么就可以通过卷积提取,简化中间的计算操作: ...
  • 1. 转置卷积介绍 转置卷积(Transposed Convolution),另外常见的两个英文翻译:fractionally-strided convolution、deconvolution。转置卷积在目标检测、语义分割中主要起到up-sampling(上采样)的作用。 参考: A ...
  • 在以像素级分类的语义分割中有使用转置卷积使得输入和输出的图像的空间维度相同,例如FCN(全卷积神经网络),它将全连接层替换成一个转置卷积层,将分类的预测概率保存在通道中。 一个例子介绍转置卷积直观计算...
  • 转置卷积理解

    2022-05-27 15:18:45
    转置矩阵理解1、卷积2、转置卷积3、转置卷积计算整除情况不整除 参考资料: https://www.cnblogs.com/shine-lee/p/11559825.html 转置卷积(transposed convolution)是一种上采样的方法。对于语义分割等问题,...
  • 语义分割|学习记录(2)转置卷积

    千次阅读 2022-02-09 11:33:01
    什么是转置卷积 - 转置卷积操作步骤 - 转置卷积常见参数 - 转置卷积实例
  • PyTorch 入坑八:卷积与转置卷积

    千次阅读 2021-09-21 16:26:38
    卷积 操作 略 输入输出尺寸变化 略 PyTorch实现 nn.Conv2d(in_channels, out_channels, kernel_size, stride=1. padding=0, dilation=1, groups=1, bias=True, padding_mode='zeros') in_channels:输入...
  • 前两篇我们对卷积层的原理和实现做了一些介绍。这一节我们来深入了解两个常用的卷积——转置卷积和空洞卷积。传送门:卷积核的基本概况转置卷积利用神经网络去生成图片,通察情况下是从低像素、粗糙的图...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 10,824
精华内容 4,329
关键字:

转置卷积