Use of torchvision.utils.save_image twice on the same image tensor makes the second save not work. What's going on?
(Fast Gradient Sign Attack method detailed here: https://pytorch.org/tutorials/beginner/fgsm_tutorial.html)

I have a trained classifier with >90% accuracy which I am using to create these adversarial examples, then I am using torchvision.utils.save_image to save the images to different folders. 

The folder hierarchy is as follows:


FOLDER_1


original_image.jpg (1)
perturbed_image.jpg (2)

FOLDER_2


perturbed_image.jpg (3)



Here (2) and (3) are the same image tensor, which is the sum of the original image tensor and a perturbation image tensor---I just want to save images that fooled the classifier twice. What I'm finding is that (1) and (2) print O.K., but (3) only prints the perturbation image tensor (it subtracted the original image tensor!). So when I open up (2) I see my original picture with all the noise on top (random RGB pixel switches from the FGSM attack), but when I open up the (3) I see a blank canvas with those random RGB pixel switches ONLY. 

Since I am printing the same variable (perturbed_data) twice, I don't understand why torchvision.utils.save_image is choosing to subtract the perturbation image tensor the second time I call it. The code for what I'm describing is below, and data is the original image tensor.

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")


I'm almost sure that this is a torchvision bug, but I thought I would ask here before submitting a bug report. Maybe someone sees something I don't. I've also attached an example of (2) and (3) for visualization. The first image is in the correct format, but the second one prints without the original image tensor.




It turns out torchvision.utils.save_image modifies the input tensor. A workaround to this is to add a line somewhere before calling torchvision.utils.save_image that's similar to this:

perturbed_data_copy = perturbed_data


Then you can safely save the perturbed image twice if on the second call you use perturbed_data_copy instead of the perturbed_data (which was modified by torchvision.utils.save_image). I will be submitting a bug report and tagging this post. Thanks @Mat for pointing this out!
