卷积与转置卷积——输出特征图边长公式推导

目录

一、公式

1.卷积

2.转置卷积

二、公式推导

1.卷积公式推导

2.转置卷积公式推导

3.代码演示


一、公式

1.卷积

H_{out}=\frac{(H_{in}+2\times Padding-KernelSize)}{Stride}+1

W_{out}=\frac{(W_{in}+2\times Padding-KernelSize)}{Stride}+1

2.转置卷积

H_{out}=(H_{in}-1)\times Stride-2\times Padding+KernelSize

W_{out}=(W_{in}-1)\times Stride-2\times Padding+KernelSize

Pytorch中,转置卷积层参数还含有output_padding,用于解决输出大小不唯一(歧义)的问题,因此转置卷积公式稍有变化:

H_{out}=(H_{in}-1)\times Stride-2\times Padding+KernelSize+OutputPadding

W_{out}=(W_{in}-1)\times Stride-2\times Padding+KernelSize+OutputPadding

二、公式推导

1.卷积公式推导

为了直观,这里选择3\times 3的卷积核,输入大小为5\times 5

(1)Stride1Padding0时,输出特征图边长H_{out}(H_{out}=W_{out})大小为

H_{out}=\frac{(H_{in}+2\times Padding-KernelSize)}{Stride}+1=\frac{(5+2\times 0-3)}{1}+1=3

具体过程如下

(2)Stride2Padding0时,输出特征图边长H_{out}(H_{out}=W_{out})大小为

H_{out}=\frac{(H_{in}+2\times Padding-KernelSize)}{Stride}+1=\frac{(5+2\times 0-3)}{2}+1=2

(3)那么到底如何得到真正的公式呢?

我们可以先观察一下卷积的过程,一行一行看,可以发现输出特征图的每个小方块都代表卷积核在原特征图上的卷积之后的结果,那么卷积核在每一行移动的距离原特征图边长减去卷积核边长,即:

D=H_{in}-KernelSize

那么卷积核移动的次数就是每一行移动的距离除以每一次移动的步长,即:

N=\frac{D}{Stride}=\frac{H_{in}-KernelSize}{Stride}

这个也就是除去第一个卷积核卷积结果输出特征图的边长减去1,即:

N=H_{out}-1

那么,输出特征图的边长就是:

H_{out}=\frac{H_{in}-KernelSize}{Stride}+1

如果考虑padding的情况,则卷积区域则不再是输入特征图,其边长为:

H_{newin}=H_{in}+2\times Padding

*为什么padding需要乘以2,是因为padding的时候是在卷积图上下左右进行一样的操作,横向看是左边和右边各加了padding。

那么最终的输出特征图的边长就是:

H_{out}=\frac{H_{in}+2\times Padding-KernelSize}{Stride}+1

2.转置卷积公式推导

即卷积公式的逆过程:

(H_{out}-1)\times Stride=H_{in}+2\times Padding-KernelSize

(H_{out}-1)\times Stride-2\times Padding+KernelSize=H_{in}

由于卷积输入是反卷积输出卷积输出是反卷积输入,因此在反卷积这里需要对调:

(H_{in}-1)\times Stride-2\times Padding+KernelSize=H_{out}

H_{out}=(H_{in}-1)\times Stride-2\times Padding+KernelSize

注意,这里的StridePadding是来自卷积操作,因为本来就是由卷积输出边长公式推导而来。

3.代码演示

定义一个网络,里面只有一个转置卷积层,输入通道是3,输入通道也是3,输入特征图大小是2\times 2,3通道,1张,因此Size是(1,3,2,2)

import torch
from torch.nn import Module
from torch import nn


class Net(Module):
    def __init__(self):
        super(Net, self).__init__()
        # outsize=(2-1)*2-2*1+3=3
        # outsize=(2-1)*1-2*1+3=2
        # outsize=(2-1)*1-2*0+3=4
        # outsize=(2-1)*2-2*0+3=5
        self.trans_conv = nn.ConvTranspose2d(
            in_channels=3,
            out_channels=3,
            kernel_size=3,
            stride=2,
            padding=0)

    def forward(self, x):
        x = self.trans_conv(x)
        return x


model = Net()
x = torch.ones((1, 3, 2, 2)) 
print(model(x).size())

验证:

(1)Stride=2padding=0,输出为torch.Size([1, 3, 5, 5]),因此输出大小为5\times 5

公式推导:H_{out}=(H_{in}-1)\times Stride-2\times Padding+KernelSize

(2-1)\times 2-2\times 0+3=2-0+3=5

(2)Stride=2padding=1,输出为torch.Size([1, 3, 3, 3]),因此输出大小为3\times 3

公式推导:H_{out}=(H_{in}-1)\times Stride-2\times Padding+KernelSize

(2-1)\times 2-2\times 1+3=2-2+3=3

(3)Stride=2padding=2,输出为torch.Size([1, 3, 1, 1]),因此输出大小为1\times 1

公式推导:H_{out}=(H_{in}-1)\times Stride-2\times Padding+KernelSize

(2-1)\times 2-2\times 2+3=2-4+3=1

(4)Stride=1padding=0,输出为torch.Size([1, 3, 4, 4]),因此输出大小为4\times 4

公式推导:H_{out}=(H_{in}-1)\times Stride-2\times Padding+KernelSize

(2-1)\times 1-2\times 0+3=1-0+3=4

(5)Stride=1padding=1,输出为torch.Size([1, 3, 2, 2]),因此输出大小为2\times 2

公式推导:H_{out}=(H_{in}-1)\times Stride-2\times Padding+KernelSize

(2-1)\times 1-2\times 1+3=1-2+3=2

(6)Stride=1padding=2,输出为torch.Size([1, 3, 0, 0]),因此输出大小为0\times 0,提示太小了报错

公式推导:H_{out}=(H_{in}-1)\times Stride-2\times Padding+KernelSize

(2-1)\times 1-2\times 2+3=1-4+3=0

RuntimeError: Given input size per channel: (2 x 2). Calculated output size per channel: (0 x 0). Output size is too small...

由此验证完毕

发布了129 篇原创文章 · 获赞 1105 · 访问量 169万+

猜你喜欢

转载自blog.csdn.net/qq_36556893/article/details/103399442
今日推荐