在同一图像张量上使用 torchvision.utils.save_image 两次会使第二次保存无效。这是怎么回事?

Use of torchvision.utils.save_image twice on the same image tensor makes the second save not work. What's going on?

(这里详细介绍了快速梯度符号攻击方法:https://pytorch.org/tutorials/beginner/fgsm_tutorial.html

我有一个训练有素的分类器,准确率 >90%,我用它来创建这些对抗性示例,然后我使用 torchvision.utils.save_image 将图像保存到不同的文件夹。

文件夹层级如下:

这里的(2)(3)是同一个图像张量,是原图像张量和一个扰动图像张量---我只想保存两次愚弄分类器的图像。我发现 (1)(2) 打印 O.K.,但是 (3 ) 只打印扰动图像张量(它减去原始图像张量!)。因此,当我打开 (2) 时,我看到我的原始图片顶部有所有噪声(随机 RGB 像素从 FGSM 攻击切换),但是当我打开 (3) 我看到空白 canvas 只有那些随机的 RGB 像素开关。

因为我打印同一个变量(perturbed_data)两次,我不明白为什么torchvision.utils.save_image选择减去扰动图像张量我第二次打电话给它。我正在描述的代码如下,data 是原始图像张量。

epsilon = 0.5
# Collect datagrad
data_grad = data.grad.data

# Call FGSM Attack
perturbed_data = fgsm_attack(data, epsilon, data_grad)

# Re-classify the perturbed image
perturbed_output = model(perturbed_data)
perturbed_output = torch.sigmoid(perturbed_output)
perturbed_output = perturbed_output.max(1, keepdim=True)[1]
max_pred  = perturbed_output.item()
final_pred = torch.tensor([0, 0]).to(device)
final_pred[max_pred] = 1

# Store all original and perturbed images, regardless of model prediction
torchvision.utils.save_image(data, "./FOLDER_1/original.jpg")
torchvision.utils.save_image(perturbed_data, "./FOLDER_1/perturbed_image.jpg")

# If the perturbed image fools our classifier, put a copy of it in FOLDER_2
if !torch.all(torch.eq(final_pred, target)):
    torchvision.utils.save_image(perturbed_data, "./FOLDER_2/perturbed_image.jpg")

我几乎可以肯定这是一个 torchvision 错误,但我想在提交错误报告之前我会在这里询问。也许有人看到了我没有看到的东西。我还附上了 (2)(3) 的示例以供可视化。第一张图像格式正确,但第二张图像打印时没有原始图像张量。

原来torchvision.utils.save_image修改了输入张量。解决方法是在调用 torchvision.utils.save_image 之前在某处添加一行,类似于:

perturbed_data_copy = perturbed_data

如果在第二次调用时使用 perturbed_data_copy 而不是 perturbed_data[,则可以安全地保存扰动图像两次=19=](由 torchvision.utils.save_image 修改)。我将提交错误报告并标记此 post。感谢@Mat 指出这一点!

我也有这个问题,它源于 torchvision 只保存了第二个张量。所以我有两个(图像)张量(image1 + image2)加在一起形成一个新的张量(image3),但是当我第二次保存新的张量(image3)时,它只会保存为第二个张量(image2)总和。

PyTorch 在去年年底的某个时候有一个 PR 来解决这个问题。