PyTorch mat1 和 mat2 形状不能相乘(4x460800 和 80000x16)

PyTorch mat1 and mat2 shapes cannot be multiplied (4x460800 and 80000x16)

我正在尝试使用 PyTorch 查找车道。我创建了数据集和我的模型。但是当我尝试训练我的模型时,出现 mat1 and mat2 shapes cannot be multiplied (4x460800 and 80000x16) 错误。我尝试过其他主题的解决方案,但这些解决方案对我的帮助不大。

我的数据集是一堆道路图像及其验证图像。我有包含图像名称的 .csv 文件(例如 'image1.jpg, image2.jpg')。图片和验证图片的原始尺寸为 1280x720。我在我的数据集代码中将它们转换为 200x200。

道路图片:

验证图像:

这是我的数据集:

import os
import pandas as pd
import random

import torch
import torchvision.transforms.functional as TF
from torch.utils.data import Dataset
from torchvision import transforms
from PIL import Image

class RNetDataset(Dataset):
    def __init__(self, csv_file, root_dir, val_dir, transform=None):
        self.annotations = pd.read_csv(csv_file)
        self.root_dir = root_dir
        self.val_dir = val_dir
        self.transform = transform

    def __len__(self):
        return len(self.annotations)

    def __getitem__(self, index):
        img_path = os.path.join(self.root_dir, self.annotations.iloc[index, 0])
        image = Image.open(img_path).convert('RGB')
        mask_path = os.path.join(self.val_dir, self.annotations.iloc[index, 0])
        mask = Image.open(mask_path).convert('RGB')

        transform = transforms.Compose([
            transforms.Resize((200, 200)), 
            transforms.ToTensor()
        ])

        if self.transform:
            image = self.transform(image)
            mask = self.transform(mask)

        return image, mask

我的模特:

import torch
import torch.nn as nn

class RNet(nn.Module):
    def __init__(self):
        super().__init__()

        self.cnn_layers = nn.Sequential(
            # Conv2d, 3 inputs, 128 outputs
            # 200x200 image size
            nn.Conv2d(3, 128, kernel_size=3, stride=1, padding=1),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2, stride=2),
            # Conv2d, 128 inputs, 64 outputs
            # 100x100 image size
            nn.Conv2d(128, 64, kernel_size=3, stride=1, padding=1),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2, stride=2),
            # Conv2d, 64 inputs, 32 outputs
            # 50x50 image size
            nn.Conv2d(64, 32, kernel_size=3, stride=1, padding=1),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2, stride=2)
        )

        self.linear_layers = nn.Sequential(
            # Linear, 32*50*50 inputs, 16 outputs
            nn.Linear(32 * 50 * 50, 16),
            # Linear, 16 inputs, 3 outputs
            nn.Linear(16, 3)
        )


    def forward(self, x):
        x = self.cnn_layers(x)
        x = x.view(x.size(0), -1)
        x = self.linear_layers(x)
        return x

如何避免此错误并在这些验证图像上训练我的图像?

答案:在您的情况下,NN 输入的形状为 (3, 1280, 720),而不是您想要的 (3, 200, 200)。可能您忘记修改 RNetDataset 中的 transform 参数。它保持 None,因此不会应用变换,也不会调整图像大小。另一种可能性是它是由于这些行而发生的:

        transform = transforms.Compose([
            transforms.Resize((200, 200)), 
            transforms.ToTensor()
        ])

        if self.transform:
            image = self.transform(image)
            mask = self.transform(mask)

您有两个名为 transform 的变量,但其中一个名为 self. - 也许您搞砸了它们。验证它,问题就会消失。

我是怎么想出来的: 460800 显然是在线性层之前重塑之后的张量大小。根据架构,用 self.cnn_layers 处理的张量应该有 32 层,所以它的高度乘以宽度应该得到 460800 / 32 = 14400。假设它的高度=H,宽度=W,所以H x W = 14400。让我们了解一下,在这种情况下,原始输入大小是多少? nn.MaxPool2d(kernel_size=2, stride=2)层将高度和宽度除以2,发生了3次。因此,原始输入大小为 8H x 8W = 64 x 14400 = 936000。最后,请注意 936000 = 1280 * 720。这不可能是神奇的巧合。案件结案!

另一个建议:即使您正确应用转换,您的代码也可能无法正常工作。假设您有一个大小为 (4, 3, 200, 200) 的输入,其中 4 是批量大小。您架构中的层将按如下方式处理此输入:

nn.Conv2d(3, 128, kernel_size=3, stride=1, padding=1) # -> (4, 128, 200, 200)
nn.MaxPool2d(kernel_size=2, stride=2) # -> (4, 128, 100, 100)
nn.Conv2d(128, 64, kernel_size=3, stride=1, padding=1) # -> (4, 64, 100, 100)
nn.MaxPool2d(kernel_size=2, stride=2) # -> (4, 64, 50, 50)
nn.Conv2d(64, 32, kernel_size=3, stride=1, padding=1) # -> (4, 32, 50, 50)
nn.MaxPool2d(kernel_size=2, stride=2) # -> (4, 32, 25, 25)

所以,你在 self.linear_layers 的第一层不应该是 nn.Linear(32 * 50 * 50, 16),而是 nn.Linear(32 * 25 * 25, 16)。有了这个改变,一切都应该没问题。