【问题标题】:Determining the result of a convolution operation确定卷积运算的结果
【发布时间】:2023-11-12 01:58:01
【问题描述】:

遵循https://medium.com/mlreview/a-guide-to-receptive-field-arithmetic-for-convolutional-neural-networks-e0f514068807 的指南,我正在尝试使用以下代码计算输出特征的数量:

输出:

%reset -f

import torch
import torch.nn as nn

my_tensor = torch.randn((1, 16, 12, 12), requires_grad=False)
print(my_tensor.shape)

update_1 = nn.Conv2d(16, 16, kernel_size=3, stride=2, padding=1)
print(update_1(my_tensor).shape)

是:

torch.Size([1, 16, 12, 12])
torch.Size([1, 16, 6, 6])

torch.Size([1, 16, 6, 6])在应用公式的上下文中是如何计算的:

(取自https://medium.com/mlreview/a-guide-to-receptive-field-arithmetic-for-convolutional-neural-networks-e0f514068807

尝试通过应用公式手动计算输出特征的数量:

stride = 2
padding = 1
kernel_size = 3

# 2304 as n_in = 1 * 16 * 16 * 12

n_out = ((2304 + (2 * padding) - kernel_size) / stride) + 1

print(n_out)

打印:1152.5

但是产生的输出特征数是print(1 * 16 * 6 *6) = 576。我取了1,16,6,6的乘积,因为这是print(update_1(my_tensor).shape)结果的形状

更新:

根据以下问题,我已将代码更新为:

%reset -f

import torch
import torch.nn as nn
from math import floor

stride_value = 2
padding_value = 1
kernel_size_value = 3

number_channels = 3
width = 10
height = 12

my_tensor = torch.randn((1, number_channels, width, height), requires_grad=False)
print(my_tensor.shape)

update_1 = nn.Conv2d(in_channels=number_channels, 
                     out_channels=16, 
                     kernel_size=kernel_size_value, 
                     stride=stride_value, 
                     padding=padding_value)

print(update_1(my_tensor).shape)

n_out = floor((number_channels + (2 * padding_value) - kernel_size_value) / stride_value) + 1
print(n_out)

print(my_tensor.shape) 产生: torch.Size([1, 3, 10, 12])

print(update_1(my_tensor).shape) 产生: torch.Size([1, 16, 5, 6])

print(update_1(n_out).shape) 产生: 2

2 与每个维度中的输出特征数不匹配。我是否正确执行了计算?

由于产生的水平特征数量为 5,而产生的垂直特征数量为 6,这个公式是否不适用于特征数量不同的图像,因此具有不同的 x 和 y 轴值长度没有意义?

【问题讨论】:

  • 不,按照惯例,二维卷积是在图像平面中完成的,消耗第一个 Conv2D 参数给定的所有通道,并在第二个 Conv2D 参数中产生通道数。查看更新的答案。

标签: deep-learning conv-neural-network pytorch


【解决方案1】:

我明白你的困惑来自哪里。该公式计算输出的线性数量,而您假设它对整个张量进行运算。

所以正确的代码是:

from math import floor

stride = 2
padding = 1
kernel_size = 3

n_out = floor((12 + (2 * padding) - kernel_size) / stride) + 1

print(n_out)

因此,它输出 6 个“水平”特征。 由于输入张量具有相同的“垂直”维度(12),因此该公式还将产生 6 个“垂直”特征。 最后,16 是您在 Conv2d 中指定的输出通道数。

把它们放在一起,输出是

1 image in a batch,
16 channels,
6 horizontal features, and
6 vertical features,

总共有 576 个特征。

更新

按照惯例,输出通道的数量不是由公式计算的,而是作为第二个参数手动提供给 nn.Conv2d。

因此,更正上面的第二个代码:

import torch
import torch.nn as nn
from math import floor

stride_value = 2
padding_value = 1
kernel_size_value = 3

number_channels = 3
width = 10
height = 12

my_tensor = torch.randn((1, number_channels, width, height), requires_grad=False)
print(my_tensor.shape)

update_1 = nn.Conv2d(in_channels=number_channels, 
                     out_channels=16, 
                     kernel_size=kernel_size_value, 
                     stride=stride_value, 
                     padding=padding_value)

print(update_1(my_tensor).shape)

n_out1 = floor((width + (2 * padding_value) - kernel_size_value) / stride_value) + 1
n_out2 = floor((height + (2 * padding_value) - kernel_size_value) / stride_value) + 1
print("(Expected: 5, 6)", n_out1, n_out2)

【讨论】:

    【解决方案2】:

    那篇文章对“功能”一词的使用方式非常奇怪,非标准。它们实际上是指“像素”或更一般地指特征图在每个维度中的大小。
    将自身限制为图像,然后该公式仅计算每个图像维度的像素数。所以在这种情况下,我们在每个维度上都有 n_in = 12n_out = 6(因此 12 像素宽的输入会产生 6 像素宽的输出),并且公式匹配。

    如果我们想要输出中特征的实际数量,我们会得到 16*6*6。

    【讨论】:

    • 您将number_channels 代入方程式。但是,正如我试图解释的那样,这个公式适用于高度/宽度。如果你插入宽度 10,你会得到正确的结果 5。如果你插入高度 12,你会得到正确的结果 6。这意味着卷积出来的“图像”是 5 像素宽和 6 像素高。它还有 16 个通道,这只是卷积中指定的值。
    最近更新 更多