在PyTorch中计算Conv2d的输入和输出尺寸,以进行图像分类。

7
我正在尝试运行PyTorch CIFAR10图像分类的教程,链接在这里 - http://pytorch.org/tutorials/beginner/blitz/cifar10_tutorial.html#sphx-glr-beginner-blitz-cifar10-tutorial-py 我做了一个小改变,现在使用另一个数据集。我有来自Wikiart数据集的图像,想按艺术家对它们进行分类(标签=艺术家姓名)。
下面是网络(Net)的代码 -
class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(3, 6, 5)
        self.pool = nn.MaxPool2d(2, 2)
        self.conv2 = nn.Conv2d(6, 16, 5)
        self.fc1 = nn.Linear(16*5*5, 120)
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, 10)

    def forward(self, x):
        x = self.pool(F.relu(self.conv1(x)))
        x = self.pool(F.relu(self.conv2(x)))
        x = x.view(-1, 16*5*5)
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x

接下来是代码的这一部分,我开始训练网络。

for epoch in range(2):
     running_loss = 0.0

     for i, data in enumerate(wiki_train_dataloader, 0):
        inputs, labels = data['image'], data['class']
        print(inputs.shape)
        inputs, labels = Variable(inputs), Variable(labels)

        optimizer.zero_grad()

        # forward + backward + optimize
        outputs = net(inputs)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()

        # print statistics
        running_loss += loss.data[0]
        if i % 2000 == 1999:  # print every 2000 mini-batches
            print('[%d, %5d] loss: %.3f' %
              (epoch + 1, i + 1, running_loss / 2000))
            running_loss = 0.0

这行代码:print(inputs.shape)在我的Wikiart数据集上返回torch.Size([4, 32, 32, 3]),而在原始的CIFAR10示例中,它打印了torch.Size([4, 3, 32, 32])
现在,我不确定如何更改我的Net中的Conv2d以与torch.Size([4, 32, 32, 3])兼容。
我得到了这个错误: RuntimeError: Given input size: (3 x 32 x 3). Calculated output size: (6 x 28 x -1). Output size is too small at /opt/conda/conda-bld/pytorch_1503965122592/work/torch/lib/THNN/generic/SpatialConvolutionMM.c:45 当读取Wikiart数据集的图像时,我将它们调整为(32,32)大小并且是三通道图像。
我尝试过的事情:
1) CIFAR10教程使用一个我没有使用的变换。 我无法将其纳入我的代码中。
2) 将self.conv2 = nn.Conv2d(6, 16, 5)更改为self.conv2 = nn.Conv2d(3, 6, 5)。 这给了我与上述相同的错误。 我只改变了这个来看看错误消息是否改变。
任何有关如何在PyTorch中计算输入和输出大小或自动重塑张量的资源都将非常感激。 我刚开始学习Torch,我觉得大小计算很复杂。
5个回答

20

你需要将输入数据转换成这种格式 (Batch, Number Channels, height, width)。目前你的数据格式是 (B,H,W,C) (4, 32, 32, 3),所以你需要交换第二和第四维度,以便将数据转换成 (B,C,H,W) 格式。你可以按照以下方式进行操作:

inputs, labels = Variable(inputs), Variable(labels)
inputs = inputs.transpose(1,3)
... the rest

5

我知道这是一个老问题,但当我使用非标准的内核大小、扩张等时,我再次遇到了这个问题。我想到了一个函数,它为我计算并检查给定的输出形状:

def find_settings(shape_in, shape_out, kernel_sizes, dilation_sizes, padding_sizes, stride_sizes, transpose=False):
    from itertools import product

    import torch
    from torch import nn

    import numpy as np

    # Fake input
    x_in = torch.tensor(np.random.randn(4, 1, shape_in, shape_in), dtype=torch.float)

    # Grid search through all combinations
    for kernel, dilation, padding, stride in product(kernel_sizes, dilation_sizes, padding_sizes, stride_sizes):
        # Define a layer
        if transpose:
            layer = nn.ConvTranspose2d
        else:
            layer = nn.Conv2d
        layer = layer(
                1, 1,
                (4, kernel),
                stride=(2, stride),
                padding=(2, padding),
                dilation=(2, dilation)
            )

        # Check if layer is valid for given input shape
        try:
            x_out = layer(x_in)
        except Exception:
            continue

        # Check for shape of out tensor
        result = x_out.shape[-1]

        if shape_out == result:
            print('Correct shape for:\n ker: {}\n dil: {}\n pad: {}\n str: {}\n'.format(kernel, dilation, padding, stride))

以下是它的一个使用示例:
transpose = True
shape_in = 128
shape_out = 1024


kernel_sizes = [3, 4, 5, 7, 9, 11]
dilation_sizes = list(range(1, 20))
padding_sizes = list(range(15))
stride_sizes = list(range(4, 16))
find_settings(shape_in, shape_out, kernel_sizes, dilation_sizes, padding_sizes, stride_sizes, transpose)

我希望这篇文章可以帮助今后遇到类似问题的人。请注意,该程序未进行并行处理,如果提供了大量选项,运行时间可能较长。


2

我最终使用

inputs = inputs.view(4, 3, 32, 32) 将输入数据转换成新的形状,紧接在

inputs, labels = data['image'], data['class'] 下面。


2
你可以使用torch.nn.AdaptiveMaxPool2d来设置特定的输出。
例如,如果我设置nn.AdaptiveMaxPool2d((5,7)),我就强制图像变成了一个5X7的尺寸。然后,你只需要将这个尺寸乘以前面Conv2d层的out_channels即可。

https://pytorch.org/docs/stable/nn.html#torch.nn.AdaptiveMaxPool2d

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(3, 6, 5)
        self.pool = nn.MaxPool2d(2, 2)
        self.conv2 = nn.Conv2d(6, 16, 5)
        self.adapt = nn.AdaptiveMaxPool2d((5,7))
        self.fc1 = nn.Linear(16*5*7, 120)
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, 10)

    def forward(self, x):
        x = self.pool(F.relu(self.conv1(x)))
        x = self.adapt(F.relu(self.conv2(x)))
        x = x.view(-1, 16*5*7)
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x

0
在预处理期间应用 transforms.ToTensor(),它会重新调整图像的尺寸。请参阅this pytorch文档。

1
链接已损坏。 - theSekyi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接