PyTorch数据扩充时间太长

时间:2019-11-01 08:44:34

标签: pytorch data-augmentation

对于涉及回归的任务,我需要训练模型以从RGB图像生成密度图。为了扩大数据集,我决定水平翻转所有图像。为此,我还必须翻转地面真实图像,然后这样做。

dataset_for_augmentation.listDataset(train_list,
                        shuffle=True,
                        transform=transforms.Compose([
                            transforms.RandomHorizontalFlip(p=1),
                            transforms.ToTensor(),
                            transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
                        ]),
                        target_transform=transforms.Compose([
                            transforms.RandomHorizontalFlip(p=1),
                            transforms.ToTensor()
                        ]),
                        train=True,
                        resize=4,
                        batch_size=args.batch_size,
                        num_workers=args.workers),

但这是问题所在:由于某些原因,PyTorch转换.RandomHorizo​​ntalFlip函数仅接受PIL图像(不允许numpy)作为输入。所以我决定将类型转换为PIL图像。

img_path = self.lines[index]

img, target = load_data(img_path, self.train, resize=self.resize)

if type(target[0][0]) is np.float64:
    target = np.float32(target)

img = Image.fromarray(img)
target = Image.fromarray(target)

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

return img, target

是的,此操作需要大量时间。考虑到我需要对数千张图像执行此操作,因此每批次23秒(最多应该不到半秒)是不能容忍的。

2019-11-01 16:29:02,497 - INFO - Epoch: [0][0/152]  Time 27.095 (27.095)    Data 23.150 (23.150)    Loss 93.7401 (93.7401)

我希望您能提出一些加快我的增强过程的建议

2 个答案:

答案 0 :(得分:3)

您无需更改DataLoader即可。您可以使用ToPILImage()

transform=transforms.Compose([
    transforms.ToPILImage(),  # check mode assumption in the documentation
    transforms.RandomHorizontalFlip(p=1),
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
])

无论如何,我会避免转换为PIL。看来完全没有必要。如果您要翻转所有图像,那么为什么不仅使用NumPy进行翻转呢?

img_path = self.lines[index]

img, target = load_data(img_path, self.train, resize=self.resize)

if type(target[0][0]) is np.float64:
    target = np.float32(target)

# assuming width axis=1 -- see my comment below
img = np.flip(img, axis=1)
target = np.flip(target, axis=1)

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

return img, target

然后从transforms.RandomHorizontalFlip(p=1)中删除Compose。由于ToTensor(...)也可以处理ndarray,所以您很高兴。

注意:我假设宽度轴等于1,因为ToTensor希望宽度轴在那里。

来自docs

  

转换PIL图像或 numpy.ndarray (H xW x C)...

答案 1 :(得分:1)

@Berriel答案的更多补充。

水平翻转

您同时为transforms.RandomHorizontalFlip(p=1)X图像使用y。在您的情况下,使用p=1时,这些转换将完全相同,但由于网络只能看到翻转的图像(而不是原始图像),因此您缺少数据扩充的要点。您应该选择小于1且大于0(通常为0.5)的概率,以使图像的版本具有较高的可变性。

如果是这种情况(p=0.5,您可以肯定会发生X被翻转而y未被翻转的情况。

我建议使用albumentations库,并且albumentations.augmentations.transforms.HorizontalFlip可以以相同的方式对两个图像进行翻转。

规范化

您可以在normalization中找到ImageNet的均值和标准差。

缓存

此外,为加快速度,您可以使用torchdata第三方库(免责声明,我是作者)。在您的情况下,您可以将PIL的图像从Tensor转换为Normalize,将albumentations转换为cache在磁盘上,甚至可以将RAM图像转换为{ {1}},最后应用您的转换。这样一来,您仅可以在初始时期之后将torchdata应用于图像和目标,而之前的步骤将被预先计算。