You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PyTorch训练自定义数据集报错:矩阵形状不匹配求助

PyTorch自定义图像分类模型形状不匹配错误解决

问题描述

我尝试用PyTorch训练自定义图像分类模型,数据集包含train_data和test_data两个文件夹,每个文件夹下有detected和not_detected两类子文件夹,内部是不同尺寸的PNG图片。之前用MNIST数据集时代码正常运行,但使用自定义数据集时,即便通过transforms.Resize((256,256))和RandomCrop((224,224))处理图像,仍出现如下错误:

RuntimeError: mat1 and mat2 shapes cannot be multiplied (32x150528 and 784x512)

原代码

import torch
import torch.nn as nn
from torch.utils.data import Dataset
from torchvision import datasets
import torch.optim as optim
import os
from PIL import Image

import torchvision.transforms as transforms
from torch.utils.data import DataLoader

is_gpu = torch.cuda.is_available()

class CustomDataset(Dataset):
    def __init__(self, root_dir, transform=None):
        self.root_dir = root_dir
        self.transform = transform
        self.classes = os.listdir(root_dir)
        self.data = []
        self.targets = []

        for class_idx, class_name in enumerate(self.classes):
            class_dir = os.path.join(root_dir, class_name)
            for filename in os.listdir(class_dir):
                img_path = os.path.join(class_dir, filename)
                self.data.append(img_path)
                self.targets.append(class_idx)

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

    def __getitem__(self, idx):
        img_path = self.data[idx]
        target = self.targets[idx]

        img = Image.open(img_path).convert('RGB')

        if self.transform is not None:
            img = self.transform(img)

        return img, target

transform = transforms.Compose([
    transforms.Resize((256, 256)),
    transforms.RandomCrop((224, 224)),
    transforms.ToTensor()
])

train_dataset = CustomDataset(root_dir=r'C:\Users\enis_\Desktop\yololu\train_data', transform=transform)
test_dataset = CustomDataset(root_dir=r'C:\Users\enis_\Desktop\yololu\test_data', transform=transform)

train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=32, shuffle=False)


model = nn.Sequential(nn.Flatten(),
                     nn.Linear(28*28,512),
                     nn.ReLU(),
                     nn.Linear(512,256),
                     nn.ReLU(),
                     nn.Linear(256,10))

if is_gpu:
    model = model.cuda()

print(model)

criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(),lr=0.7)

epochs = 5

for i in range(epochs):
    train_loss = 0.0
    for data,label in train_loader:
        if is_gpu:
            data, label = data.cuda(), label.cuda()
        optimizer.zero_grad()
        
        output = model(data)
        loss = criterion(output,label)
        loss.backward()
        
        optimizer.step()
        
        train_loss += loss.item() * data.size(0)
    print(f'Epoch: {i+1} / {epochs} \t\t\t Training Loss:{train_loss/len(train_loader)}')

完整报错信息

Sequential(
(0): Flatten(start_dim=1, end_dim=-1)
(1): Linear(in_features=784, out_features=512, bias=True)
(2): ReLU()
(3): Linear(in_features=512, out_features=256, bias=True)
(4): ReLU()
(5): Linear(in_features=256, out_features=10, bias=True)
)
Traceback (most recent call last):
File "c:\Users\enis_\Desktop\yololu\tempCodeRunnerFile.py", line 80, in 
output = model(data)
^^^^^^^^^^^
File "C:\Users\enis_\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\LocalCache\local-packages\Python311\site-packages\torch\nn\modules\module.py", line 1501, in _call_impl
return forward_call(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\enis_\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\LocalCache\local-packages\Python311\site-packages\torch\nn\modules\container.py", line 217, in forward
input = module(input)
^^^^^^^^^^^^^
File "C:\Users\enis_\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\LocalCache\local-packages\Python311\site-packages\torch\nn\modules\module.py", line 1501, in _call_impl
return forward_call(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Users\enis_\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\LocalCache\local-packages\Python311\site-packages\torch\nn\modules\linear.py", line 114, in forward
return F.linear(input, self.weight, self.bias)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
RuntimeError: mat1 and mat2 shapes cannot be multiplied (32x150528 and 784x512)

错误原因分析

  • 原模型是为MNIST单通道28x28图像设计的,第一层Linear输入为28*28=784,但自定义数据是RGB三通道,经过裁剪后尺寸为224x224,展平后特征数为3*224*224=150528,与Linear层输入维度不匹配,导致矩阵乘法错误。
  • 最后一层Linear输出设置为10类,但数据集只有2类,后续损失计算也会出现逻辑错误。
  • SGD优化器学习率设置为0.7过高,会导致模型训练过程中损失剧烈震荡,难以收敛。

修改后的代码

import torch
import torch.nn as nn
from torch.utils.data import Dataset
import torch.optim as optim
import os
from PIL import Image
import torchvision.transforms as transforms
from torch.utils.data import DataLoader

is_gpu = torch.cuda.is_available()

class CustomDataset(Dataset):
    def __init__(self, root_dir, transform=None):
        self.root_dir = root_dir
        self.transform = transform
        self.classes = os.listdir(root_dir)
        self.data = []
        self.targets = []

        for class_idx, class_name in enumerate(self.classes):
            class_dir = os.path.join(root_dir, class_name)
            for filename in os.listdir(class_dir):
                img_path = os.path.join(class_dir, filename)
                self.data.append(img_path)
                self.targets.append(class_idx)

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

    def __getitem__(self, idx):
        img_path = self.data[idx]
        target = self.targets[idx]

        img = Image.open(img_path).convert('RGB')

        if self.transform is not None:
            img = self.transform(img)

        return img, target

transform = transforms.Compose([
    transforms.Resize((256, 256)),
    transforms.RandomCrop((224, 224)),
    transforms.ToTensor()
])

train_dataset = CustomDataset(root_dir=r'C:\Users\enis_\Desktop\yololu\train_data', transform=transform)
test_dataset = CustomDataset(root_dir=r'C:\Users\enis_\Desktop\yololu\test_data', transform=transform)

train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=32, shuffle=False)

# 适配RGB 224x224图像与二分类任务的模型
model = nn.Sequential(nn.Flatten(),
                     nn.Linear(3*224*224, 512),  # 输入特征数匹配RGB图像展平后维度
                     nn.ReLU(),
                     nn.Linear(512, 256),
                     nn.ReLU(),
                     nn.Linear(256, 2))  # 输出类别数匹配数据集的两类

if is_gpu:
    model = model.cuda()

print(model)

criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=0.01)  # 调整学习率到合理范围

epochs = 5

for i in range(epochs):
    train_loss = 0.0
    for data,label in train_loader:
        if is_gpu:
            data, label = data.cuda(), label.cuda()
        optimizer.zero_grad()
        
        output = model(data)
        loss = criterion(output,label)
        loss.backward()
        
        optimizer.step()
        
        train_loss += loss.item() * data.size(0)
    # 修正损失计算方式:除以数据集总长度得到平均样本损失
    print(f'Epoch: {i+1} / {epochs} \t\t\t Training Loss:{train_loss/len(train_loader.dataset):.4f}')

关键修改点

  • 第一层Linear输入特征数改为3*224*224,匹配RGB图像展平后的维度
  • 最后一层Linear输出改为2,对应数据集的二分类任务
  • 将SGD学习率从0.7调整为0.01,避免训练过程中损失震荡
  • 修正训练损失计算方式:除以数据集总长度,结果更直观反映平均样本损失

内容的提问来源于stack exchange,提问作者user19224948

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 08:05:33