我对PyTorch中执行的数据扩充有些困惑。现在,据我所知,当我们执行数据扩充时,我们将保留原始数据集,然后添加它的其他版本(Flipping,Cropping等)。但这似乎并没有在PyTorch中发生。据参考资料了解,当我们在PyTorch中使用data.transforms
时,它将一一应用。例如:
data_transforms = {
'train': transforms.Compose([
transforms.RandomResizedCrop(224),
transforms.RandomHorizontalFlip(),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
]),
'val': transforms.Compose([
transforms.Resize(256),
transforms.CenterCrop(224),
transforms.ToTensor(),
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
]),
}
在这里,为了进行训练,我们首先要随机裁剪图像并将其大小调整为(224,224)
。然后,我们拍摄这些(224,224)
图像并水平翻转它们。因此,我们的数据集现在仅包含水平翻转的图像,因此在这种情况下我们的原始图像会丢失。
我是对的吗?这种理解正确吗?如果不是,那么我们在上面的代码中(从官方文档中获取)告诉PyTorch如何保留原始图像并将其大小调整为预期的形状(224,224)
?
谢谢
答案 0 :(得分:15)
我假设您是在问这些数据增强转换(例如,RandomHorizontalFlip)是否确实也增加了数据集的大小,还是将它们分别应用于数据集中的每个项目?而不会增加数据集的大小。
运行下面的简单代码片段,我们可以观察到后来是真的,即,如果您有一个包含8张图像的数据集,并在遍历该数据集时为该数据集创建一个PyTorch数据集对象,在每个数据点上调用转换,然后返回转换后的数据点。因此,举例来说,如果您进行随机翻转,则某些数据点将作为原始数据返回,某些数据点将作为翻转数据返回(例如4个翻转数据和4个原始数据)。 换句话说,通过遍历数据集项目一次,您将获得8个数据点(有些翻转,有些则没有)。 [与扩充数据集的传统理解不一致(例如,在这种情况下,扩充数据集中有16个数据点)]
class experimental_dataset(Dataset):
def __init__(self, data, transform):
self.data = data
self.transform = transform
def __len__(self):
return len(self.data.shape[0])
def __getitem__(self, idx):
item = self.data[idx]
item = self.transform(item)
return item
transform = transforms.Compose([
transforms.ToPILImage(),
transforms.RandomHorizontalFlip(),
transforms.ToTensor()
])
x = torch.rand(8, 1, 2, 2)
print(x)
dataset = experimental_dataset(x,transform)
for item in dataset:
print(item)
结果:(浮点数的微小差异是由转换为pil图像和向后转换引起的)
原始虚拟数据集:
tensor([[[[0.1872, 0.5518],
[0.5733, 0.6593]]],
[[[0.6570, 0.6487],
[0.4415, 0.5883]]],
[[[0.5682, 0.3294],
[0.9346, 0.1243]]],
[[[0.1829, 0.5607],
[0.3661, 0.6277]]],
[[[0.1201, 0.1574],
[0.4224, 0.6146]]],
[[[0.9301, 0.3369],
[0.9210, 0.9616]]],
[[[0.8567, 0.2297],
[0.1789, 0.8954]]],
[[[0.0068, 0.8932],
[0.9971, 0.3548]]]])
转换后的数据集:
tensor([[[0.1843, 0.5490],
[0.5725, 0.6588]]])
tensor([[[0.6549, 0.6471],
[0.4392, 0.5882]]])
tensor([[[0.5647, 0.3255],
[0.9333, 0.1216]]])
tensor([[[0.5569, 0.1804],
[0.6275, 0.3647]]])
tensor([[[0.1569, 0.1176],
[0.6118, 0.4196]]])
tensor([[[0.9294, 0.3333],
[0.9176, 0.9608]]])
tensor([[[0.8549, 0.2275],
[0.1765, 0.8941]]])
tensor([[[0.8902, 0.0039],
[0.3529, 0.9961]]])
答案 1 :(得分:10)
Infinity
操作在每个批次生成时都应用于原始图像。因此,您的数据集保持不变,每次迭代仅复制和转换批处理图像。
这种混淆可能是由于这样的事实,例如在您的示例中,state = (0, 1)
for i in x.length - 2 downto 0
noPreSwap, withPreSwap = [#INFINITY], [#INFINITY]
if (isValid(i, preSwap = false, postSwap = false)) noPreSwap += state.left
if (isValid(i, preSwap = false, postSwap = true)) noPreSwap += state.right
if (isValid(i, preSwap = true, postSwap = true)) withPreSwap += state.right + 1
if (isValid(i, preSwap = true, postSwap = false)) withPreSwap += state.right
state = (noPreSwap.min(), withPreSwap.min())
return if state.min().isInfinity() -1 else state.min()
经常用于数据准备(调整大小/裁剪到期望的尺寸,标准化值等)和数据扩充(随机分配调整大小/裁剪,随机翻转图像等)。
您的transforms
所做的是:
transforms
补丁data_transforms['train']
(224, 224)
进行归一化您的Tensor
所做的是:
Tensor
data_transforms['val']
补丁(256, 256)
(224, 224)
进行归一化(即将训练数据的随机调整大小/裁剪替换为用于验证的固定操作,以得到可靠的验证结果)
如果您不希望训练图像以50/50的机会水平翻转,只需移除Tensor
行即可。
类似地,如果希望始终对图像进行中心裁剪,则将Tensor
替换为transforms.RandomHorizontalFlip()
和transforms.RandomResizedCrop
,就像transforms.Resize
一样。
答案 2 :(得分:0)
是的,转换后数据集大小不会更改。每个图像都会传递给转换并返回,因此大小保持不变。
如果您希望将原始数据集与转换后的一个连接使用。
例如increased_dataset = torch.utils.data.ConcatDataset([transformed_dataset,original])
答案 3 :(得分:0)
在 PyTorch 中,有一些裁剪类型会改变数据集的大小。它们是 FiveCrop
和 TenCrop
:
CLASS torchvision.transforms.FiveCrop(尺寸)
将给定的图像裁剪成四个角和中央裁剪。
此转换返回一个图像元组,可能存在不匹配 在您的数据集返回的输入和目标数量中。见下文 有关如何处理此问题的示例。
示例:
>>> transform = Compose([
>>> TenCrop(size), # this is a list of PIL Images
>>> Lambda(lambda crops: torch.stack([ToTensor()(crop) for crop in crops])) # returns a 4D tensor
>>> ])
>>> #In your test loop you can do the following:
>>> input, target = batch # input is a 5d tensor, target is 2d
>>> bs, ncrops, c, h, w = input.size()
>>> result = model(input.view(-1, c, h, w)) # fuse batch size and ncrops
>>> result_avg = result.view(bs, ncrops, -1).mean(1) # avg over crops
TenCrop
是相同的加上五个补丁的翻转版本(默认使用水平翻转)。
答案 4 :(得分:-1)
TLDR:
变换操作以一定的概率将一组变换应用于循环中的输入批次。因此,该模型现在在多个时期的过程中会接触到更多示例。
就我个人而言,当我在自己的数据集上训练音频分类模型时,在增强之前,我的模型似乎总是以 72% 的准确率收敛。我使用了增强以及增加训练时期的数量,这将测试集中的验证准确率提高到了 89%。