Python PyTorch:如何对多个图像应用相同的随机变换?

Python PyTorch:如何对多个图像应用相同的随机变换?,python,pytorch,torchvision,Python,Pytorch,Torchvision,我正在为包含多对图像的数据集编写一个简单的转换。作为数据扩充,我想对每一对应用一些随机变换,但该对中的图像应以相同的方式进行变换。 例如,给定一对两个图像a和B,如果a水平翻转,B必须水平翻转为a。然后下一对C和D应与A和B进行不同的转换,但C和D的转换方式相同。我正在尝试下面的方法 随机导入 将numpy作为np导入 导入torchvision.transforms作为变换 从PIL导入图像 img_a=Image.open(“sample_ajpg”)#注意两个图像的大小相同 img_b=I

我正在为包含多对图像的数据集编写一个简单的转换。作为数据扩充,我想对每一对应用一些随机变换,但该对中的图像应以相同的方式进行变换。 例如,给定一对两个图像
a
B
,如果
a
水平翻转,
B
必须水平翻转为
a
。然后下一对
C
D
应与
A
B
进行不同的转换,但
C
D
的转换方式相同。我正在尝试下面的方法

随机导入
将numpy作为np导入
导入torchvision.transforms作为变换
从PIL导入图像
img_a=Image.open(“sample_ajpg”)#注意两个图像的大小相同
img_b=Image.open(“sample_b.png”)
img_c,img_d=Image.open(“sample_c.jpg”),Image.open(“sample_d.png”)
transform=transforms.RandomChoice(
[transforms.RandomHorizontalFlip(),
transforms.RandomVerticalFlip()]
)
随机种子(0)
显示(变换(img_a))
显示(变换(img_b))
随机种子(1)
显示(变换(img_c))
显示(变换(img_d))
然而,上面的代码并没有选择相同的转换,正如我测试的那样,它取决于调用
transform
的次数


有没有办法强制转换。RandomChoice在指定时使用相同的转换?

我不知道有什么函数可以修复随机输出。 也许可以尝试不同的逻辑,比如自己创建随机化,以便能够重用相同的转换。 逻辑:

  • 生成一个随机数
  • 根据数字对两幅图像应用变换
  • 生成另一个随机数
  • 对其他两个图像执行相同的操作 试试这个:

通常,解决方法是对第一幅图像应用变换,检索该变换的参数,然后对其余图像应用具有这些参数的确定性变换。但是,此处不提供获取应用的转换参数的API,因为它涉及的转换数量可变。 在这些情况下,我通常实现对原始函数的覆盖

看一看,它很简单:

class RandomChoice(RandomTransforms):
    def __call__(self, img):
        t = random.choice(self.transforms)
        return t(img)
这里有两种可能的解决方案

  • 您可以在
    \uuuuu init\uuuuu
    而不是
    \uuuu call\uuuuu
    上从转换列表中采样:

    import random
    import torchvision.transforms as T
    
    class RandomChoice(torch.nn.Module):
        def __init__(self):
            super().__init__()
            self.t = random.choice(self.transforms)
    
        def __call__(self, img):
            return self.t(img)
    
    因此,您可以:

    transform = T.RandomChoice([
         T.RandomHorizontalFlip(), 
         T.RandomVerticalFlip()
    ])
    display(transform(img_a)) # both img_a and img_b will
    display(transform(img_b)) # have the same transform
    
    transform = T.RandomChoice([
        T.RandomHorizontalFlip(), 
        T.RandomVerticalFlip()
    ])
    display(transform(img_c)) # both img_c and img_d will
    display(transform(img_d)) # have the same transform
    

  • 或者更好的是,成批变换图像:

    import random
    import torchvision.transforms as T
    
    class RandomChoice(torch.nn.Module):
        def __init__(self, transforms):
           super().__init__()
           self.transforms = transforms
    
        def __call__(self, imgs):
            t = random.choice(self.transforms)
            return [t(img) for img in imgs]
    
    它允许您执行以下操作:

    transform = T.RandomChoice([
         T.RandomHorizontalFlip(), 
         T.RandomVerticalFlip()
    ])
    
    img_at, img_bt = transform([img_a, img_b])
    display(img_at) # both img_a and img_b will
    display(img_bt) # have the same transform
    
    img_ct, img_dt = transform([img_c, img_d])
    display(img_ct) # both img_c and img_d will
    display(img_dt) # have the same transform
    

  • 简单地说,将PyTorch中的随机化部分放入
    if
    语句中。 下面的代码使用了
    vflip
    。对于水平变换或其他变换也是如此

    import random
    import torchvision.transforms.functional as TF
    
    if random.random() > 0.5:
        image = TF.vflip(image)
        mask  = TF.vflip(mask)
    
    这个问题已经在PyTorch中讨论过了。在官方GitHub存储库中讨论了几种解决方案的优缺点。 PyTorch维护人员提出了这种简单的方法

    不要使用
    torchvision.transforms.RandomVerticalFlip(p=1)
    。使用
    torchvision.transforms.functional.vflip


    函数转换为您提供了对转换管道的细粒度控制。与上面的变换相反,函数变换的参数不包含随机数生成器。这意味着您必须指定/生成所有参数,但您可以重用函数转换。

    只是为了澄清,
    transform=transforms.RandomChoice([
    在您的答案中实际上是
    transform=RandomChoice([
    ,对吗?Oups,很抱歉应该是
    T.RandomChoice())
    自从我导入了
    torchvision.transforms
    T
    。虽然这段代码可能会解决问题,但如何以及为什么解决问题会真正有助于提高你的文章质量,并可能导致更多的投票。请记住,你是在回答未来读者的问题,而不仅仅是问问题的人g现在。请您的答案添加解释,并说明适用的限制和假设。@AdrianMole感谢您的建议。我添加了解释:-)
    import random
    import torchvision.transforms.functional as TF
    
    if random.random() > 0.5:
        image = TF.vflip(image)
        mask  = TF.vflip(mask)