Closed RSMung closed 2 years ago
Hi @RSMung,
Thanks for reporting this. Just had a quick look at the paper. Your implementation needs slight modification for the i-FGSM case. Epsilon (e), becomes alpha (as seen in equation 6 of the paper), then you also need to make sure your adv example is within certain clipping criteria, epsilon (e). We currently don't have i-FGSM implemented in our library but you can check out this implementation to better understand how to modify your current implementation. Once you have this fixed, feel free to contribute it to the library : )
Let me know if this helps.
Also, the link I shared with you implemented the Iterative least-likely class method where x = x-alpha*x.grad, but with slight modification, you should be able to make it work for the basic iterative method.
Thank you for your reply! You are so nice.
I have read your reply carefully, but I still have some confusion about the I-FGSM.
The question:
When I want to change the disturbance intensity of attack in I-FGSM, what should I going to change? It's the step size ahpha or the eps?
On the other hand, in the paper of I-FGSM , the author only show the change of eps. The picture as follow.
So I change the eps in my code from 0.5 to 32 and set the alpha to 1 , but the results are still poor, I could observe the attack using my eyes when the eps is greater than 0.01 .
Is my result normal or nor? If my result is not normal, I will feel confused because I can't find out the error in my code.
My code as follow:
"""
Args:
input: the input img
target: the label img
eps: the difference between each pixel value and the amplitude
max_iter: the number of iteration
alpha: the step size
x_val_min: the min value of each pixel
x_val_max: the max value of each pixel
Return:
x_adv: the input with disturbance
x_adv - input: the disturbance
"""
def i_fgsm(self, input, target, eps, max_iter=10, alpha=1, x_val_min=0, x_val_max=1):
x_adv = Variable(input.data, requires_grad=True)
for i in range(max_iter):
y_adv = self.model(x_adv)
loss = self.cnl_criterion(y_adv, torch.squeeze(target, 0).long())
self.model.zero_grad()
if x_adv.grad is not None:
x_adv.grad.data.fill_(0)
loss.backward()
x_adv.grad.sign_()
x_adv = x_adv + alpha * x_adv.grad
x_adv = where(x_adv > input + eps, input + eps, x_adv)
x_adv = where(x_adv < input - eps, input - eps, x_adv)
x_adv = torch.clamp(x_adv, x_val_min, x_val_max)
x_adv = Variable(x_adv.data, requires_grad=True)
return x_adv, x_adv - input
BEST WISHES TO YOU. I am looking forward to your reply.
Hi @RSMung
The paper set alpha=1 and the disturbance intensity (eps) is controlled in condition i.e
loss.backward()
optimal_perturbation = torch.sign(x_adv.grad)
x_adv = x_adv + alpha * optimal_perturbation
x_adv = torch.where(x_adv > x+eps, x+eps, x_adv)
x_adv = torch.where(x_adv < x-eps, x-eps, x_adv)
A few observations:
num_iterations=min(eps+4, floor(1.25*eps))
. So if eps=32
, max_iter should be 36
and not 10
. This might not solve your problem but it's worth checking. A small note, x_adv.grad.sign_()
will implicitly replace your x_adv.grad
with the sign which is okay in this case but might not be desirable in most cases. Instead, I'll suggest that you do optimial_pertubation = torch.sign(x_adv.grad)
. This way, you're not changing your x_adv.grad
result.
I hope this helps.
@RSMung I just realized that the basic iterative method is implemented in our repository. I deeply apologies for this. It goes by the name Projected Gradient Descent
Can you try the implementation instead and let me know if this works as expected.
Thank you for your reply.
After reading your reply, I know more about this algorithm.
Then I temporarily abandon realizing the I-FGSM by myself, I use your implemention to test my model.
After that, I find out that it still don't work well.
eps = 0.5
My Questions:
In your opinions, max_iter is dependent on epsilon i.e *num_iterations=min(eps+4, floor(1.25eps)).
But I find out that if the eps is smaller than 0.8, the num_iterations will be 0. There will be no disturbance.**
That's unreasonable, so I set the num_iterations to 10 in the previous code. Is it reasonable for me to do so?
On the other hand, I modified the code following your opinions, it still don't work well. We could see the result in the top picture.
I agree with you about seting the target as the inverse of the ground-truth masks. So I modified my code. But I don't know if it is reasonable. I set the y to torch.ones_like(y) - y, so the 0 pixels will be 1, 1 pixels will be 0.
My code as following:
def attack(self):
evaluation_list = []
# start computing all the eva value
for e in self.epsilon:
x, y = loadDataForAttack() # load my data, x is (3, h, w) and y is (1, h, w)
# --------let the data into the device-----
x, y = x.to(device).unsqueeze(dim=0), y.to(device)
# ---------seg the original img----------
seg_x = self.model(x) # seg_x is (1, 2, h, w)
if e == 0:
eva = 1 - self.cnl_criterion(seg_x, y.long())
# lel the channel to 1
# if channel 0 is the max value, the result value is 0
# if channel 1 is the max value, the result value is 1
seg_x = self.get_refine_mask(seg_x) # seg_x is 1, h, w
evaluation_list.append(eva.item())
print("e={} --- :{:f}".format(e, eva.item()))
continue # Skip the code below
# ----------get the x_adv---------
# because of An attack sets the target as the inverse of ground-truth masks
# I let y=(torch.ones_like(y) - y)
if Config.attack_algorithm_type == 0:
# fgsm algorithm
x_adv = fast_gradient_method(self.model, x, e, np.inf, clip_min=0, clip_max=1,
y=(torch.ones_like(y) - y).long(), targeted=True)
else:
# i-fgsm
x_adv = projected_gradient_descent(self.model, x, e, 0.01, min(e + 4, math.floor(1.25 * e)), np.inf,
clip_min=0, clip_max=1, y=(torch.ones_like(y) - y).long(), targeted=True)
# ------seg the x_adv------
seg_x_adv = self.model(x_adv)
# ------compute the eva value-----
eva = self.cnl_criterion(seg_x_adv, y.long())
evaluation_list.append(eva)
print("e= {} --- {:f}".format(e, eva.item()))
def get_refine_mask(self, x):
# x is 1, 2, h, w
x = x.squeeze() # 2, h, w
x = x[1] - x[0] # h, w
x = torch.where(x > 0, torch.ones_like(x), torch.zeros_like(x)) # h, w
return x.unsqueeze(dim=0) # 1, h, w
I'm so careless that *the num_iterations should not be min(eps+4, floor(1.25eps))*. The usage of API math.floor is wrong. Because the formula requires a larger integer for 1.25eps. I think there will be something difference. Let me try, then I will tell you the result.
On the other hand, I feel confused to this sentence: the L∞ norm of adversarial perturbation to in- tensity.. If it means that Could you help me understand it? I will very appreciate it. I am looking forward to your reply.
I find out that the norm is np.inf in your examples of projected_gradient_descent. But I don't understand what it means. The another question: How to choose eps_iter when the eps is changed from 0.5 to 32? If I set the eps_iter to 1 following the paper, the pycharm will give me some error caused by sanity_checks.
Hi @RSMung,
I'm sorry to hear that you haven't been able to solve this problem. I'm glad you found the math.floor
bug. Does it work now? I agree, the distinction between alpha and epsilon seem confusing. You might need to test different implementations to see which works best for the paper you're trying to re-implement. It's might also be the case that the paper is lacking in reproducibility and you might need to use a different parameter settings to get the reported results.
np.inf (l-infinity) norm measures the distance between input x
and the adversarial example x_adv
. The l-infinity
norm has the interpretation of minimizing the maximum element of the perturbation. It does so by taking the sign of the gradient i.e torch.sign(x_adv.grad)
, you might find this material on adversarial attacks useful, geometrical interpretation of the norms are presented on page 5. In the paper you shared, they used l-inf
. Our implementation only supports (l-inf, l1 and l2
), check our implementation for more descriptions of the remaining norms.
I have also found this material useful which gives an overview of adversarial example and how to solve the inner maximization problem, you can skip to the Projected gradient descent as it's the most relevant to your question.
I hope this helps.
I think I might have solved this problem.
According to this paper, I find out that the values of the pixels are integer numbers in the range(0, 255), the they use the eps from 0 to 128, including 16, 32 etc, as same as the paper I want to implemente.
But when we train our model, the image will be normalized, so the values of pixels are float numbers in the range (0, 1). As far as I'm concerned, we should let the eps divide 255 before we deliver the parameter eps to the attack function.
Do you think my idea is reasonable? Looking forward to your reply.
Hi @RSMung, were you able to resolve this issue? Your idea does sound reasonable, did it work? Apologies for my late reply - the past few months was a little hectic.
It doesn't matter. I could understand that you may be busy. On the other hand, I think my last comments are reasonable. When we set the eps, we should pay attention to the range. As a result, if I set the eps=8 or more large( I use the range [0, 255] here), the result would be very strange when my data is in [0, 1]. What's your opinion?
Describe I implements the I-FGSM modified from the your FGSM code in https://github.com/cleverhans-lab/cleverhans/blob/1115738a3f31368d73898c5bdd561a85a7c1c741/cleverhans/torch/attacks/fast_gradient_method.py But I find out that when the disturbance intensity (it is e in my code ) is greater than 0.01, I can see the attack in my eyes, which is not reasonable in my opinions. The picture as follows: disturbance intensity is 0.001
disturbance intensity is 0.1
![0 1](https://user-images.githubusercontent.com/34727963/121495815-81247300-ca0c-11eb-81cc-42382a868b74.png)
But in paper (https://ojs.aaai.org//index.php/AAAI/article/view/4857), we can't observe the attack even when its adversarial intensity set to 16. The picture as follows:![1](https://user-images.githubusercontent.com/34727963/121495838-871a5400-ca0c-11eb-8e1e-bde8f8fba560.PNG)
Then I want to know if it is normal or not? I will very appreciate it if you could help me. My code as follows: