Trusted-AI / adversarial-robustness-toolbox

Adversarial Robustness Toolbox (ART) - Python Library for Machine Learning Security - Evasion, Poisoning, Extraction, Inference - Red and Blue Teams
https://adversarial-robustness-toolbox.readthedocs.io/en/latest/
MIT License
4.82k stars 1.16k forks source link

UserWarning and RuntimeError in ProjectedGradientDescent due to Non-Writable NumPy Array and Device Mismatch #2454

Closed salomonhotegni closed 3 months ago

salomonhotegni commented 4 months ago

Describe the bug A UserWarning is raised, indicating that a given NumPy array is not writable, and PyTorch does not support non-writable tensors. Additionally, a RuntimeError is encountered stating that all tensors are expected to be on the same device.

To Reproduce Steps to reproduce the behavior:

  1. Load a model onto a GPU using CUDA and initialize the optimizer.
  2. Use the Adversarial Robustness Toolbox (ART) to perform an adversarial attack using the ProjectedGradientDescent method with norm = np.inf.
  3. Attempt to generate adversarial data with the attack.generate method.
  4. Observe the warnings and error.

Expected behavior The function should execute without raising a UserWarning or RuntimeError. The adversarial data should be generated correctly with all tensors on the same device.

Error Messages

adversarial-robustness-toolbox/art/attacks/evasion/projected_gradient_descent/projected_gradient_descent_pytorch.py:504: UserWarning: The given NumPy array is not writable, and PyTorch does not support non-writable tensors. This means writing to this tensor will result in undefined behavior. You may want to copy the array to protect its data or make it writable before converting it to a tensor. This type of warning will be suppressed for the rest of this program. (Triggered internally at ../torch/csrc/utils/tensor_numpy.cpp:199.)
  values_tmp = values_tmp.sign() * torch.minimum(values_tmp.abs(), torch.Tensor(eps))
Traceback (most recent call last):                                              
[...]
    data_attack = attack.generate(data.cpu().numpy(), y=targets.cpu().numpy())
  File "adversarial-robustness-toolbox/art/attacks/evasion/projected_gradient_descent/projected_gradient_descent.py", line 202, in generate
    return self._attack.generate(x=x, y=y, **kwargs)
  File "adversarial-robustness-toolbox/art/attacks/evasion/projected_gradient_descent/projected_gradient_descent_pytorch.py", line 223, in generate
    adv_x[batch_index_1:batch_index_2] = self._generate_batch(
  File "adversarial-robustness-toolbox/art/attacks/evasion/projected_gradient_descent/projected_gradient_descent_pytorch.py", line 284, in _generate_batch
    adv_x = self._compute_pytorch(
  File "adversarial-robustness-toolbox/art/attacks/evasion/projected_gradient_descent/projected_gradient_descent_pytorch.py", line 451, in _compute_pytorch
    perturbation = self._projection(x_adv - x_init, eps, self.norm)
  File "adversarial-robustness-toolbox/art/attacks/evasion/projected_gradient_descent/projected_gradient_descent_pytorch.py", line 504, in _projection
    values_tmp = values_tmp.sign() * torch.minimum(values_tmp.abs(), torch.Tensor(eps))
RuntimeError: Expected all tensors to be on the same device, but found at least two devices, cuda:0 and cpu!

Suggested solution: Replace line 504, in "_projection" function in "adversarial-robustness-toolbox/art/attacks/evasion/projected_gradient_descent/projected_gradient_descent_pytorch.py": From

 values_tmp = values_tmp.sign() * torch.minimum(values_tmp.abs(), torch.Tensor(eps))

to

values_tmp = values_tmp.sign() * torch.minimum(values_tmp.abs(), torch.tensor(eps).to(values_tmp.device))

This solves both the non-writable NumPy array issue and the device mismatch issue.

System information (please complete the following information):


beat-buesser commented 4 months ago

Hi @salomonhotegni Thank you very much for raising this issue and providing a pull request for the solution (#2455). We'll release it in the next days in ART 1.18.1.