使用 PyTorch 和 TorchVision 对自定义数据集进行训练-有效-测试拆分
Posted
技术标签:
【中文标题】使用 PyTorch 和 TorchVision 对自定义数据集进行训练-有效-测试拆分【英文标题】:Train-Valid-Test split for custom dataset using PyTorch and TorchVision 【发布时间】:2020-08-31 20:22:12 【问题描述】:我有一些用于二进制分类任务的图像数据,图像被组织到 2 个文件夹中,分别是 data/model_data/class-A 和 data/model_data/class-B。
共有 N 张图片。我想对训练/验证/测试进行 70/20/10 拆分。 我正在使用 PyTorch 和 Torchvision 来完成这项任务。这是我到目前为止的代码。
from torch.utils.data import Dataset, DataLoader
from torchvision import transforms, utils, datasets, models
data_transform = transforms.Compose([
transforms.RandomResizedCrop(224),
transforms.RandomHorizontalFlip(),
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])])
model_dataset = datasets.ImageFolder(root, transform=data_transform)
train_count = int(0.7 * total_count)
valid_count = int(0.2 * total_count)
test_count = total_count - train_count - valid_count
train_dataset, valid_dataset, test_dataset = torch.utils.data.random_split(model_dataset, (train_count, valid_count, test_count))
train_dataset_loader = torch.utils.data.DataLoader(train_dataset, batch_size=BATCH_SIZE, shuffle=True, num_workers=NUM_WORKER)
valid_dataset_loader = torch.utils.data.DataLoader(valid_dataset, batch_size=BATCH_SIZE, shuffle=True, num_workers=NUM_WORKER)
test_dataset_loader = torch.utils.data.DataLoader(test_dataset , batch_size=BATCH_SIZE, shuffle=False,num_workers=NUM_WORKER)
dataloaders = 'train': train_dataset_loader, 'val': valid_dataset_loader, 'test': test_dataset_loader
我觉得这不是正确的做法,原因有两个。
我正在对所有拆分应用相同的转换。 (这显然不是我想要做的!解决这个问题的答案很可能是here。) 通常人们首先将原始数据分成测试/训练,然后他们 将 train 分离为 train/val,而我直接将 原始数据进入训练/验证/测试。 (正确吗?)所以,我的问题是,我所做的是否正确? (可能不是) 如果不正确,我该如何编写数据加载器以实现所需的拆分,以便我可以对每个 train/test/val 应用单独的转换?
【问题讨论】:
【参考方案1】:通常人们首先将原始数据分成测试/训练和 然后他们将train分成train/val,而我直接 将原始数据分成训练/验证/测试。 (这是正确的吗?)
是的,它完全正确、可读且完全没问题
我正在对所有拆分应用相同的转换。 (这不是什么 我想做,很明显!解决方案很可能是 在这里回答。)
是的,这个答案是可能的,但它是毫无意义的冗长tbh。您可以使用第三方工具torchdata,只需安装:
pip install torchdata
文档可以在here 找到(同时免责声明:我是作者)。
它允许您轻松地将转换映射到任何torch.utils.data.Dataset
(在本例中为train
)。您的代码看起来像这样(只需更改两行,检查 cmets,还格式化您的代码以便更容易理解):
import torch
import torchvision
import torchdata as td
data_transform = torchvision.transforms.Compose(
[
torchvision.transforms.RandomResizedCrop(224),
torchvision.transforms.RandomHorizontalFlip(),
torchvision.transforms.ToTensor(),
torchvision.transforms.Normalize(
mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]
),
]
)
# Single change, makes an instance of torchdata.Dataset
# Works just like PyTorch's torch.utils.data.Dataset, but has
# additional capabilities like .map, cache etc., see project's description
model_dataset = td.datasets.WrapDataset(torchvision.datasets.ImageFolder(root))
# Also you shouldn't use transforms here but below
train_count = int(0.7 * total_count)
valid_count = int(0.2 * total_count)
test_count = total_count - train_count - valid_count
train_dataset, valid_dataset, test_dataset = torch.utils.data.random_split(
model_dataset, (train_count, valid_count, test_count)
)
# Apply transformations here only for train dataset
train_dataset = train_dataset.map(data_transform)
# Rest of the code goes the same
train_dataset_loader = torch.utils.data.DataLoader(
train_dataset, batch_size=BATCH_SIZE, shuffle=True, num_workers=NUM_WORKER
)
valid_dataset_loader = torch.utils.data.DataLoader(
valid_dataset, batch_size=BATCH_SIZE, shuffle=True, num_workers=NUM_WORKER
)
test_dataset_loader = torch.utils.data.DataLoader(
test_dataset, batch_size=BATCH_SIZE, shuffle=False, num_workers=NUM_WORKER
)
dataloaders =
"train": train_dataset_loader,
"val": valid_dataset_loader,
"test": test_dataset_loader,
是的,我同意在拆分之前指定 transform
并不太清楚,而且 IMO 这更具可读性。
【讨论】:
非常感谢!这真的很有帮助。 我在导入torchdata 时收到class conflict
错误。你知道是什么问题吗?以上是关于使用 PyTorch 和 TorchVision 对自定义数据集进行训练-有效-测试拆分的主要内容,如果未能解决你的问题,请参考以下文章
pytorch土堆pytorch教程学习torchvision 中的数据集的使用
使用 PyTorch 和 TorchVision 对自定义数据集进行训练-有效-测试拆分
如何在 Pytorch 中使用 torchvision.transforms 对分割任务进行数据增强?
如何使用 plt.imshow 和 torchvision.utils.make_grid 在 PyTorch 中生成和显示图像网格?