培训有效-使用PyTorch和TorchVision测试自定义数据集的拆分
问题描述
我有一些用于二进制分类任务的图像数据,图像被组织到两个文件夹中,即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。)
- 通常人们先将原始数据分成测试/训练,然后 将列车分离为列车/VAL,而我直接将 原始数据进入列车/VAL/测试。(这是正确的吗?)
如果不正确,我如何着手编写数据加载器以实现所需的拆分,以便可以将单独的转换应用于每个列车/测试/VAL?
解决方案
通常人们首先将原始数据分成测试/训练和 然后他们把火车分成火车/瓦尔,而我直接 将原始数据分成列车/VAL/测试。(这是正确的吗?)
是的,它是完全正确的,可读的,总体上是完好无损的
是的,答案是有可能的,但它毫无意义地冗长乏味。您可以使用第三方工具torchdata,只需使用:即可安装我正在对所有拆分应用相同的转换。(这不是什么 很明显,我想这么做!这个问题的解决方案很可能是 在此回答。)
pip install torchdata
可以找到文档here(另有免责声明:我是作者)。
它允许您轻松地将转换映射到任何torch.utils.data.Dataset
(在本例中映射到train
)。您的代码将如下所示(只需更改两行,检查注释,并格式化代码以使其更容易跟上):
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
不太清楚,而且我认为这更具可读性。
相关文章