PyTorch自定义数据集加载异常:conv2d输入类型错误求助
问题分析与解决方案
核心错误点
- 数据加载的字典解包错误
你的MyDataset返回字典格式的样本,DataLoader会将batch打包成键为'image'和'label'的字典。但你用inputs, labels = data的方式,实际是对字典的键进行解包,导致inputs变成字符串'image',直接引发conv2d的类型错误。正确做法是从字典中提取对应值:
inputs = data['image'] labels = data['label']
- 标签判断逻辑错误
你写的四个独立if语句会导致逻辑冲突:比如图片名包含cat时,第一个if把label设为cat,但后续if判断都不成立,最后会执行else把label改成lizard。必须把后续if改成elif,确保匹配到一个类别就停止判断:
if 'cat' in img_name: label = 'cat' elif 'dog' in img_name: label = 'dog' elif 'rat' in img_name: label = 'rat' elif 'bat' in img_name: label = 'bat' else: label = 'lizard'
- 标签类型不兼容
CrossEntropyLoss要求标签是整数类型的Tensor,但你返回的是字符串标签,无法计算损失。需要把字符串标签映射为整数,比如:
label_map = {'cat':0, 'dog':1, 'rat':2, 'bat':3, 'lizard':4} label = label_map[label]
同时要把标签转成Tensor(可在ToTensor类里处理)。
- 图像数据类型问题
skimage读取的图像是uint8类型(0-255),转成Tensor后是ByteTensor,而PyTorch卷积层需要float类型输入,且通常需归一化到0-1区间。需在ToTensor类里调整:
image = torch.from_numpy(image).float() / 255.0
完整修正代码
import os import torch import pandas as pd from skimage import io, transform import numpy as np import matplotlib.pyplot as plt from torch.utils.data import Dataset, DataLoader from torchvision import transforms, utils import torch.nn as nn import torch.nn.functional as F import torch.optim as optim class MyDataset(Dataset): def __init__(self, csv_file, transform=None): self.animals = pd.read_csv(csv_file) self.transform = transform # 定义标签映射 self.label_map = {'cat':0, 'dog':1, 'rat':2, 'bat':3, 'lizard':4} def __len__(self): return len(self.animals) def __getitem__(self, idx): if torch.is_tensor(idx): idx = idx.tolist() img_name = self.animals.iloc[idx, 0] # 修正标签判断逻辑 if 'cat' in img_name: label = 'cat' elif 'dog' in img_name: label = 'dog' elif 'rat' in img_name: label = 'rat' elif 'bat' in img_name: label = 'bat' else: label = 'lizard' # 转成整数标签 label = self.label_map[label] image = io.imread(img_name) sample = {'image': image, 'label': label} if self.transform: sample = self.transform(sample) return sample class CustomToTensor(object): def __call__(self, sample): image, label = sample['image'], sample['label'] # 调整通道顺序并转成float类型,归一化 image = image.transpose((2, 0, 1)) image = torch.from_numpy(image).float() / 255.0 # 标签转成long类型的Tensor(CrossEntropyLoss要求) label = torch.tensor(label, dtype=torch.long) return {'image': image, 'label': label} class Net(nn.Module): def __init__(self): super().__init__() self.conv1 = nn.Conv2d(3, 6, 5) self.pool = nn.MaxPool2d(2, 2) self.conv2 = nn.Conv2d(6, 16, 5) # 假设输入图像为32x32,两次卷积池化后尺寸为5x5 self.fc1 = nn.Linear(16 * 5 * 5, 120) self.fc2 = nn.Linear(120, 84) self.fc3 = nn.Linear(84, 5) # 输出维度对应5个类别 def forward(self, x): x = self.pool(F.relu(self.conv1(x))) x = self.pool(F.relu(self.conv2(x))) x = torch.flatten(x, 1) x = F.relu(self.fc1(x)) x = F.relu(self.fc2(x)) x = self.fc3(x) return x # 数据集与加载器 animal_trainset = MyDataset(csv_file='/Classifier/CombinedCSV.csv', transform=CustomToTensor()) animal_trainloader = DataLoader(animal_trainset, batch_size=4) animal_testset = MyDataset(csv_file='/Classifier/CombinedCSV.csv', transform=CustomToTensor()) animal_testloader = DataLoader(animal_testset, batch_size=4) classes = ('dog', 'cat', 'bat', 'rat', 'lizard') net = Net() criterion = nn.CrossEntropyLoss() optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9) for epoch in range(2): running_loss = 0.0 for i, data in enumerate(animal_trainloader, 0): # 从字典中提取数据 inputs = data['image'] labels = data['label'] optimizer.zero_grad() outputs = net(inputs) loss = criterion(outputs, labels) loss.backward() optimizer.step() running_loss += loss.item() if i % 2000 == 1999: print(f'[{epoch + 1}, {i + 1:5d}] loss: {running_loss / 2000:.3f}') running_loss = 0.0 print('Finished Training')
额外说明
- 全连接层
fc3的输出维度改为5,对应你的5个类别,原10维度多余。 - 如果你的图像尺寸不是32x32,需要重新计算
fc1的输入维度:比如输入64x64,两次卷积池化后尺寸为13x13,fc1应设为16*13*13。 - 可改用
torchvision.transforms中的现成工具,比如ToTensor()(注意和自定义类重名问题,已将自定义类改名为CustomToTensor),搭配Normalize做归一化。
内容的提问来源于stack exchange,提问作者hdbgdz
相关产品推荐
相关产品推荐

