PyTorch 数据增强花费的时间太长
PyTorch Data Augmentation is taking too long
对于涉及回归的任务,我需要训练我的模型以从 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 transforms.RandomHorizontalFlip 函数仅将 PIL 图像(不允许使用 numpy)作为输入。所以我决定将类型转换为PIL Image。
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)
如果有任何能加快我的增强过程的建议,我将不胜感激
您无需更改 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
并从 Compose
中删除 transforms.RandomHorizontalFlip(p=1)
。由于 ToTensor(...)
也处理 ndarray
,你可以开始了。
注意:我假设宽度轴等于 1,因为 ToTensor
期望它在那里。
来自docs:
Converts a PIL Image or numpy.ndarray (H x W x C) ...
更多 回答。
水平翻转
您正在为 X
和 y
图片使用 transforms.RandomHorizontalFlip(p=1)
。在您的情况下,使用 p=1
,这些将完全相同地转换,但您错过了数据增强点,因为网络只会看到翻转的图像(而不仅仅是原始图像)。您应该选择低于 1 和高于 0 的概率(通常 0.5
)以获得图像版本的高可变性。
如果是这种情况 (p=0.5
),您可以肯定会出现 X
被翻转而 y
不会翻转的情况。
我建议使用 albumentations
库,它 albumentations.augmentations.transforms.HorizontalFlip
以相同的方式对两个图像进行翻转。
规范化
您可以找到 normalization
和 ImageNet
方法,并且已经在那里设置了标准。
缓存
此外,为了加快速度,您可以使用 torchdata
第三方库(免责声明我是作者)。在您的情况下,您可以将图像从 PIL
转换为 Tensor
、Normalize
和 albumentations
、cache
在磁盘上,或者在使用 torchdata
最后应用你的转换。这种方式将允许您在初始纪元后仅在您的图像和目标上应用 HorizontalFlip
s,之前的步骤将被预先计算。
对于涉及回归的任务,我需要训练我的模型以从 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 transforms.RandomHorizontalFlip 函数仅将 PIL 图像(不允许使用 numpy)作为输入。所以我决定将类型转换为PIL Image。
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)
如果有任何能加快我的增强过程的建议,我将不胜感激
您无需更改 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
并从 Compose
中删除 transforms.RandomHorizontalFlip(p=1)
。由于 ToTensor(...)
也处理 ndarray
,你可以开始了。
注意:我假设宽度轴等于 1,因为 ToTensor
期望它在那里。
来自docs:
Converts a PIL Image or numpy.ndarray (H x W x C) ...
更多
水平翻转
您正在为 X
和 y
图片使用 transforms.RandomHorizontalFlip(p=1)
。在您的情况下,使用 p=1
,这些将完全相同地转换,但您错过了数据增强点,因为网络只会看到翻转的图像(而不仅仅是原始图像)。您应该选择低于 1 和高于 0 的概率(通常 0.5
)以获得图像版本的高可变性。
如果是这种情况 (p=0.5
),您可以肯定会出现 X
被翻转而 y
不会翻转的情况。
我建议使用 albumentations
库,它 albumentations.augmentations.transforms.HorizontalFlip
以相同的方式对两个图像进行翻转。
规范化
您可以找到 normalization
和 ImageNet
方法,并且已经在那里设置了标准。
缓存
此外,为了加快速度,您可以使用 torchdata
第三方库(免责声明我是作者)。在您的情况下,您可以将图像从 PIL
转换为 Tensor
、Normalize
和 albumentations
、cache
在磁盘上,或者在使用 torchdata
最后应用你的转换。这种方式将允许您在初始纪元后仅在您的图像和目标上应用 HorizontalFlip
s,之前的步骤将被预先计算。