在 PyTorch 中计算 Conv2d 的输入和输出大小以进行图像分类
Calculating input and output size for Conv2d in PyTorch for image classification
我正在尝试 运行 此处关于 CIFAR10 图像分类的 PyTorch 教程 - http://pytorch.org/tutorials/beginner/blitz/cifar10_tutorial.html#sphx-glr-beginner-blitz-cifar10-tutorial-py
我做了一个小改动,我正在使用不同的数据集。我有来自 Wikiart 数据集的图像,我想按艺术家分类(标签 = 艺术家姓名)。
这是网络代码 -
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)
给了我 torch.Size([4, 32, 32, 3])
我的 Wikiart 数据集,而在 CIFAR10 的原始示例中,它打印 torch.Size([4, 3, 32, 32])
。
现在,我不确定如何更改我的网络中的 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),这些是 3 通道图像。
我尝试过的事情:
1) CIFAR10 教程使用了我没有使用的转换。我无法将其合并到我的代码中。
2) 将 self.conv2 = nn.Conv2d(6, 16, 5)
更改为 self.conv2 = nn.Conv2d(3, 6, 5)
。这给了我与上面相同的错误。我只是更改它以查看错误消息是否更改。
任何有关如何在 PyTorch 中计算输入和输出大小或自动重塑张量的资源都将不胜感激。我刚开始学习 Torch,我发现尺寸计算很复杂。
您必须将输入调整为这种格式(批处理、数字通道、高度、宽度)。
目前您的格式为 (B,H,W,C) (4, 32, 32, 3),因此您需要交换第 4 轴和第 2 轴以使用 (B,C,H,W) 塑造数据。
你可以这样做:
inputs, labels = Variable(inputs), Variable(labels)
inputs = inputs.transpose(1,3)
... the rest
我终于使用
将输入更改为新形状
inputs = inputs.view(4, 3, 32, 32)
,就在
下面
inputs, labels = data['image'], data['class']
。
您可以使用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
我知道这是一个老问题,但我在处理非标准内核大小、扩张等时再次偶然发现了这个问题。
这是我想出的一个函数,它为我计算并检查给定的输出形状:
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)
我希望它能帮助将来解决这个问题的人。请注意,它不是并行化的,如果有很多选择,它可以 运行 一段时间。
在预处理时应用transforms.ToTensor(),它将重塑图像尺寸。参见 this pytorch 文档。
我正在尝试 运行 此处关于 CIFAR10 图像分类的 PyTorch 教程 - http://pytorch.org/tutorials/beginner/blitz/cifar10_tutorial.html#sphx-glr-beginner-blitz-cifar10-tutorial-py
我做了一个小改动,我正在使用不同的数据集。我有来自 Wikiart 数据集的图像,我想按艺术家分类(标签 = 艺术家姓名)。
这是网络代码 -
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)
给了我 torch.Size([4, 32, 32, 3])
我的 Wikiart 数据集,而在 CIFAR10 的原始示例中,它打印 torch.Size([4, 3, 32, 32])
。
现在,我不确定如何更改我的网络中的 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),这些是 3 通道图像。
我尝试过的事情:
1) CIFAR10 教程使用了我没有使用的转换。我无法将其合并到我的代码中。
2) 将 self.conv2 = nn.Conv2d(6, 16, 5)
更改为 self.conv2 = nn.Conv2d(3, 6, 5)
。这给了我与上面相同的错误。我只是更改它以查看错误消息是否更改。
任何有关如何在 PyTorch 中计算输入和输出大小或自动重塑张量的资源都将不胜感激。我刚开始学习 Torch,我发现尺寸计算很复杂。
您必须将输入调整为这种格式(批处理、数字通道、高度、宽度)。 目前您的格式为 (B,H,W,C) (4, 32, 32, 3),因此您需要交换第 4 轴和第 2 轴以使用 (B,C,H,W) 塑造数据。 你可以这样做:
inputs, labels = Variable(inputs), Variable(labels)
inputs = inputs.transpose(1,3)
... the rest
我终于使用
将输入更改为新形状inputs = inputs.view(4, 3, 32, 32)
,就在
inputs, labels = data['image'], data['class']
。
您可以使用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
我知道这是一个老问题,但我在处理非标准内核大小、扩张等时再次偶然发现了这个问题。 这是我想出的一个函数,它为我计算并检查给定的输出形状:
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)
我希望它能帮助将来解决这个问题的人。请注意,它不是并行化的,如果有很多选择,它可以 运行 一段时间。
在预处理时应用transforms.ToTensor(),它将重塑图像尺寸。参见 this pytorch 文档。