我尝试用不同尺寸的图像训练 CNN,但它抛出错误
ValueError: expected sequence of length 1200 at dim 2 (got 1069)
当我将它们转换为张量时。
我认为这是因为图像尺寸不同。但我不想调整图像大小。如何使用 AdaptiveAvgPool2d?
这是我的代码:
def makeData():
data = []
# cat
for i in range(1, 11):
data.append({"path": "images/cat_" + str(i) + ".jpeg", "label": 1})
# not cat
for i in range(1, 11):
data.append({"path": "images/not_cat_" + str(i) + ".jpeg", "label": 0})
return data
def loadImage(path):
return Image.open(path).convert('RGB')
class MyDataset(Data.Dataset):
def __init__(self, data):
self.data = data
self.transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize(mean=(0.5, 0.5, 0.5), std=(0.5, 0.5, 0.5))
])
def __getitem__(self, idx):
img = loadImage(self.data[idx]["path"])
img = self.transform(img)
label = torch.FloatTensor([self.data[idx]["label"]])
return img, torch.FloatTensor(label)
def __len__(self):
return len(self.data)
def collate_fn(batch_list):
data, labels = [], []
for item in batch_list:
data.append(item[0].tolist())
labels.append(item[1].tolist())
return torch.FloatTensor(data), torch.FloatTensor(labels)
loader = Data.DataLoader(MyDataset(makeData()), 2, True, collate_fn=collate_fn)
这是我的模型代码:
class CatModel(nn.Module):
def __init__(self):
super().__init__()
self.conv1 = nn.Conv2d(3, 32, kernel_size=(3,3), stride=1, padding=1)
self.act1 = nn.ReLU()
self.drop1 = nn.Dropout(0.3)
self.conv2 = nn.Conv2d(32, 32, kernel_size=(3,3), stride=1, padding=1)
self.act2 = nn.ReLU()
self.pool2 = nn.AdaptiveAvgPool2d((16, 16))
self.flat = nn.Flatten()
self.fc3 = nn.Linear(8192, 512)
self.act3 = nn.ReLU()
self.drop3 = nn.Dropout(0.5)
self.fc4 = nn.Linear(512, 1)
def forward(self, x):
# input 3x32x32, output 32x32x32
x = self.act1(self.conv1(x))
x = self.drop1(x)
# input 32x32x32, output 32x32x32
x = self.act2(self.conv2(x))
# input 32x32x32, output 32x16x16
x = self.pool2(x)
# input 32x16x16, output 8192
x = self.flat(x)
# input 8192, output 512
x = self.act3(self.fc3(x))
x = self.drop3(x)
# input 512, output 1
x = self.fc4(x)
return nn.Sigmoid()(x)
我添加了 AdaptiveAvgPool2d 层以及一些 dropout 和线性层。
该错误是由于尝试将不同尺寸的图像一起批处理而引起的。您需要在
transforms.Compose
之前向 transforms.ToTensor()
块添加调整大小转换,以使所有输入图像具有相同的大小。如果您查看文档,有几种方法可以做到这一点。
wrt
AdaptiveAvgPool2d
,这有不同的目的。使用固定窗口大小的最大池化的旧版 CNN 只能处理特定的输入大小,例如 224x224 图像。如果您使用不同的输入图像大小,则对于 CNN 编码器之后的线性层来说,您的池化输出将会太大或太小。 AdaptiveAvgPool2d
将张量池化为特定的所需输出大小。这允许编码器处理任何输入图像大小,并且仍然为最终线性层提供正确的池化大小。