如何解决PyTorch:如何将相同的随机变换应用于多个图像?
我正在为包含多对图像的数据集编写一个简单的转换。作为数据增强,我想对每一对应用一些随机变换,但该对中的图像应该以相同的方式进行变换。
例如,给定一对两个图像A
和B
,如果A
水平翻转,B
必须水平翻转为A
。然后下一对C
和D
应该与A
和B
进行不同的转换,但是C
和D
的转换方式相同。我正在以下面的方式尝试
import random
import numpy as np
import torchvision.transforms as transforms
from PIL import Image
img_a = Image.open("sample_ajpg") # note that two images have the same size
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()]
)
random.seed(0)
display(transform(img_a))
display(transform(img_b))
random.seed(1)
display(transform(img_c))
display(transform(img_d))
然而,上面的代码并没有选择相同的转换,正如我测试的那样,它取决于调用 transform
的次数。
有没有办法强制 transforms.RandomChoice
在指定时使用相同的转换?
解决方法
通常的解决方法是对第一张图像应用变换,检索该变换的参数,然后对其余图像应用这些参数的确定性变换。但是,这里的 RandomChoice
没有提供 API 来获取应用转换的参数,因为它涉及可变数量的转换。
在这些情况下,我通常会覆盖原始函数。
看看 torchvision implementation,就这么简单:
class RandomChoice(RandomTransforms):
def __call__(self,img):
t = random.choice(self.transforms)
return t(img)
这里有两种可能的解决方案。
-
您可以在
__init__
而不是__call__
上从变换列表中采样: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
我不知道修复随机输出的函数。 也许尝试不同的逻辑,比如自己创建随机化以便能够重用相同的转换。 逻辑:
- 生成随机数
- 根据数字对两个图像应用转换
- 生成另一个随机数
- 对另外两张图片做同样的处理 试试这个:
import random
import numpy as np
import torchvision.transforms as transforms
from PIL import Image
img_a = Image.open("sample_ajpg") # note that two images have the same size
img_b = Image.open("sample_b.png")
img_c,img_d = Image.open("sample_c.jpg"),Image.open("sample_d.png")
if random.random() > 0.5:
image_a_flipped = transforms.functional_pil.vflip(img_a)
image_b_flipped = transforms.functional_pil.vflip(img_b)
else:
image_a_flipped = transforms.functional_pil.hflip(img_a)
image_b_flipped = transforms.functional_pil.hflip(img_b)
if random.random() > 0.5:
image_c_flipped = transforms.functional_pil.vflip(img_c)
image_d_flipped = transforms.functional_pil.vflip(img_d)
else:
image_c_flipped = transforms.functional_pil.hflip(img_c)
image_d_flipped = transforms.functional_pil.hflip(img_d)
display(image_a_flipped)
display(image_b_flipped)
display(image_c_flipped)
display(image_d_flipped)
,
简单地说,将 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 forum 中讨论过。官方 GitHub 存储库 page 上讨论了几种解决方案的优缺点。 PyTorch 维护者提出了这种简单的方法。
不要使用torchvision.transforms.RandomVerticalFlip(p=1)
。使用torchvision.transforms.functional.vflip
功能转换使您可以对转换管道进行细粒度控制。与上面的转换相反,函数式转换不包含用于其参数的随机数生成器。这意味着您必须指定/生成所有参数,但您可以重用函数转换。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。