Skip to content

Commit

Permalink
Improve pylint score
Browse files Browse the repository at this point in the history
Signed-off-by: Beat Buesser <beat.buesser@ibm.com>
  • Loading branch information
beat-buesser committed Jan 23, 2025
1 parent af19fde commit cbb9d46
Show file tree
Hide file tree
Showing 19 changed files with 108 additions and 135 deletions.
3 changes: 3 additions & 0 deletions .pylintrc
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,9 @@ disable=
too-many-arguments,
too-many-locals,
unsupported-binary-operation,
too-many-branches,
too-many-statements,


[REPORTS]

Expand Down
12 changes: 6 additions & 6 deletions art/attacks/evasion/adversarial_patch/adversarial_patch_numpy.py
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,7 @@ def _scale(self, x, scale):
elif self.nb_dims == 4:
x_out[:, :, top : top + scale_h, left : left + scale_w] = zoom(x, zoom=zooms, order=1)
else:
if self.nb_dims == 3:
if self.nb_dims == 3: # pylint: disable=else-if-used
x_out[top : top + scale_h, left : left + scale_w, :] = zoom(x, zoom=zooms, order=1)
elif self.nb_dims == 4:
x_out[:, top : top + scale_h, left : left + scale_w, :] = zoom(x, zoom=zooms, order=1)
Expand All @@ -433,7 +433,7 @@ def _scale(self, x, scale):
elif self.nb_dims == 4:
x_out = zoom(x[:, :, top : top + scale_h, left : left + scale_w], zoom=zooms, order=1)
else:
if self.nb_dims == 3:
if self.nb_dims == 3: # pylint: disable=else-if-used
x_out = zoom(x[top : top + scale_h, left : left + scale_w, :], zoom=zooms, order=1)
elif self.nb_dims == 4:
x_out = zoom(x[:, top : top + scale_h, left : left + scale_w, :], zoom=zooms, order=1)
Expand All @@ -450,7 +450,7 @@ def _scale(self, x, scale):
elif self.nb_dims == 4:
x_out = x_out[:, :, cut_top : cut_top + height, cut_left : cut_left + width]
else:
if self.nb_dims == 3:
if self.nb_dims == 3: # pylint: disable=else-if-used
x_out = x_out[cut_top : cut_top + height, cut_left : cut_left + width, :]
elif self.nb_dims == 4:
x_out = x_out[:, cut_top : cut_top + height, cut_left : cut_left + width, :]
Expand All @@ -469,7 +469,7 @@ def _shift(self, x, shift_h, shift_w):
elif self.nb_dims == 4:
shift_hw = (0, 0, shift_h, shift_w)
else:
if self.nb_dims == 3:
if self.nb_dims == 3: # pylint: disable=else-if-used
shift_hw = (shift_h, shift_w, 0)
elif self.nb_dims == 4:
shift_hw = (0, shift_h, shift_w, 0)
Expand Down Expand Up @@ -509,7 +509,7 @@ def _random_transformation(self, patch, scale, mask_2d):
elif self.nb_dims == 4:
pad_width = ((0, 0), (0, 0), (pad_h_before, pad_h_after), (pad_w_before, pad_w_after)) # type: ignore
else:
if self.nb_dims == 3:
if self.nb_dims == 3: # pylint: disable=else-if-used
pad_width = ((pad_h_before, pad_h_after), (pad_w_before, pad_w_after), (0, 0)) # type: ignore
elif self.nb_dims == 4:
pad_width = ((0, 0), (pad_h_before, pad_h_after), (pad_w_before, pad_w_after), (0, 0)) # type: ignore
Expand Down Expand Up @@ -591,7 +591,7 @@ def _reverse_transformation(self, gradients: np.ndarray, patch_mask_transformed,
elif self.nb_dims == 4:
gradients = gradients[:, :, pad_h_before : pad_h_before + height, pad_w_before : pad_w_before + width]
else:
if self.nb_dims == 3:
if self.nb_dims == 3: # pylint: disable=else-if-used
gradients = gradients[pad_h_before : pad_h_before + height, pad_w_before : pad_w_before + width, :]
elif self.nb_dims == 4:
gradients = gradients[:, pad_h_before : pad_h_before + height, pad_w_before : pad_w_before + width, :]
Expand Down
52 changes: 16 additions & 36 deletions art/attacks/evasion/adversarial_patch/adversarial_patch_pytorch.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
import logging
import math
from packaging.version import parse
from typing import Any, cast, TYPE_CHECKING
from typing import Any, TYPE_CHECKING

import numpy as np
from tqdm.auto import trange
Expand All @@ -41,7 +41,7 @@

import torch

from art.utils import CLASSIFIER_NEURALNETWORK_TYPE, PYTORCH_OBJECT_DETECTOR_TYPE
from art.utils import CLASSIFIER_NEURALNETWORK_TYPE

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -72,7 +72,7 @@ class AdversarialPatchPyTorch(EvasionAttack):

def __init__(
self,
estimator: "CLASSIFIER_NEURALNETWORK_TYPE | PYTORCH_OBJECT_DETECTOR_TYPE",
estimator: "CLASSIFIER_NEURALNETWORK_TYPE",
rotation_max: float = 22.5,
scale_min: float = 0.1,
scale_max: float = 1.0,
Expand All @@ -91,7 +91,7 @@ def __init__(
"""
Create an instance of the :class:`.AdversarialPatchPyTorch`.
:param estimator: A trained PyTorch estimator for classification or object detection.
:param estimator: A trained estimator.
:param rotation_max: The maximum rotation applied to random patches. The value is expected to be in the
range `[0, 180]`.
:param scale_min: The minimum scaling applied to random patches. The value should be in the range `[0, 1]`,
Expand Down Expand Up @@ -183,10 +183,7 @@ def __init__(
self._optimizer = torch.optim.Adam([self._patch], lr=self.learning_rate)

def _train_step(
self,
images: "torch.Tensor",
target: "torch.Tensor" | list[dict[str, "torch.Tensor"]],
mask: "torch.Tensor" | None = None,
self, images: "torch.Tensor", target: "torch.Tensor", mask: "torch.Tensor" | None = None
) -> "torch.Tensor":
import torch

Expand Down Expand Up @@ -230,12 +227,7 @@ def _predictions(

return predictions, target

def _loss(
self,
images: "torch.Tensor",
target: "torch.Tensor" | list[dict[str, "torch.Tensor"]],
mask: "torch.Tensor" | None,
) -> "torch.Tensor":
def _loss(self, images: "torch.Tensor", target: "torch.Tensor", mask: "torch.Tensor" | None) -> "torch.Tensor":
import torch

if isinstance(target, torch.Tensor):
Expand Down Expand Up @@ -483,17 +475,13 @@ def _random_overlay(
return patched_images

def generate( # type: ignore
self, x: np.ndarray, y: np.ndarray | list[dict[str, np.ndarray | "torch.Tensor"]] | None = None, **kwargs
self, x: np.ndarray, y: np.ndarray | None = None, **kwargs
) -> tuple[np.ndarray, np.ndarray]:
"""
Generate an adversarial patch and return the patch and its mask in arrays.
:param x: An array with the original input images of shape NCHW or input videos of shape NFCHW.
:param y: True or target labels of format `list[dict[str, Union[np.ndarray, torch.Tensor]]]`, one for each
input image. The fields of the dict are as follows:
- boxes [N, 4]: the boxes in [x1, y1, x2, y2] format, with 0 <= x1 < x2 <= W and 0 <= y1 < y2 <= H.
- labels [N]: the labels for each image.
:param y: An array with the original true labels.
:param mask: A boolean array of shape equal to the shape of a single samples (1, H, W) or the shape of `x`
(N, H, W) without their channel dimensions. Any features for which the mask is True can be the
center location of the patch during sampling.
Expand All @@ -511,19 +499,12 @@ def generate( # type: ignore
if self.patch_location is not None and mask is not None:
raise ValueError("Masks can only be used if the `patch_location` is `None`.")

if hasattr(self.estimator, "nb_classes"):

y_array: np.ndarray
if y is None: # pragma: no cover
logger.info("Setting labels to estimator predictions and running untargeted attack because `y=None`.")
y = to_categorical(np.argmax(self.estimator.predict(x=x), axis=1), nb_classes=self.estimator.nb_classes)

if y is None: # pragma: no cover
logger.info("Setting labels to estimator classification predictions.")
y_array = to_categorical(
np.argmax(self.estimator.predict(x=x), axis=1), nb_classes=self.estimator.nb_classes
)
else:
y_array = cast(np.ndarray, y)

y = check_and_transform_label_format(labels=y_array, nb_classes=self.estimator.nb_classes)
if hasattr(self.estimator, "nb_classes"):
y = check_and_transform_label_format(labels=y, nb_classes=self.estimator.nb_classes)

# check if logits or probabilities
y_pred = self.estimator.predict(x=x[[0]])
Expand All @@ -532,10 +513,9 @@ def generate( # type: ignore
self.use_logits = False
else:
self.use_logits = True
else:
if y is None: # pragma: no cover
logger.info("Setting labels to estimator object detection predictions.")
y = self.estimator.predict(x=x)
elif y is None: # pragma: no cover
logger.info("Setting labels to estimator object detection predictions.")
y = self.estimator.predict(x=x)

if isinstance(y, np.ndarray):
x_tensor = torch.Tensor(x)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -460,7 +460,7 @@ def generate( # type: ignore
else:
dataset = tf.data.Dataset.from_tensor_slices((x, y)).batch(self.batch_size)
else:
if shuffle:
if shuffle: # pylint: disable=else-if-used
dataset = tf.data.Dataset.from_tensor_slices((x, y, mask)).shuffle(10000).batch(self.batch_size)
else:
dataset = tf.data.Dataset.from_tensor_slices((x, y, mask)).batch(self.batch_size)
Expand Down
4 changes: 2 additions & 2 deletions art/attacks/evasion/decision_tree_attack.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ def _df_subtree(
else:
path = [-1]
else: # targeted case
if self.estimator.get_classes_at_node(position) == target:
if self.estimator.get_classes_at_node(position) == target: # pylint: disable=else-if-used
path = [position]
else:
path = [-1]
Expand Down Expand Up @@ -138,7 +138,7 @@ def generate(self, x: np.ndarray, y: np.ndarray | None = None, **kwargs) -> np.n
y[index],
)
else: # search in left subtree
if y is None:
if y is None: # pylint: disable=else-if-used
adv_path = self._df_subtree(self.estimator.get_left_child(ancestor), legitimate_class)
else:
adv_path = self._df_subtree(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -229,16 +229,16 @@ def _check_params(self) -> None:

if isinstance(self.eps, (int, float)):
if self.eps < 0:
raise ValueError("The perturbation size `eps` has to be nonnegative.")
raise ValueError("The perturbation size `eps` has to be non-negative.")
else:
if (self.eps < 0).any():
raise ValueError("The perturbation size `eps` has to be nonnegative.")
if (self.eps < 0).any(): # pylint: disable=else-if-used
raise ValueError("The perturbation size `eps` has to be non-negative.")

if isinstance(self.eps_step, (int, float)):
if self.eps_step <= 0:
raise ValueError("The perturbation step-size `eps_step` has to be positive.")
else:
if (self.eps_step <= 0).any():
if (self.eps_step <= 0).any(): # pylint: disable=else-if-used
raise ValueError("The perturbation step-size `eps_step` has to be positive.")

if isinstance(self.eps, np.ndarray) and isinstance(self.eps_step, np.ndarray):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -200,14 +200,14 @@ def _check_params(self) -> None: # pragma: no cover
if self.eps < 0:
raise ValueError("The perturbation size `eps` has to be non-negative.")
else:
if (self.eps < 0).any():
if (self.eps < 0).any(): # pylint: disable=else-if-used
raise ValueError("The perturbation size `eps` has to be non-negative.")

if isinstance(self.eps_step, (int, float)):
if self.eps_step <= 0:
raise ValueError("The perturbation step-size `eps_step` has to be positive.")
else:
if (self.eps_step <= 0).any():
if (self.eps_step <= 0).any(): # pylint: disable=else-if-used
raise ValueError("The perturbation step-size `eps_step` has to be positive.")

if isinstance(self.eps, np.ndarray) and isinstance(self.eps_step, np.ndarray):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -502,17 +502,14 @@ def _projection(
torch.ones(1).to(values_tmp.device), torch.tensor(eps).to(values_tmp.device) / values_norm
),
)
else: # Optimal
if norm == np.inf: # Easy exact case
values_tmp = values_tmp.sign() * torch.minimum(
values_tmp.abs(), torch.tensor(eps).to(values_tmp.device)
)
elif norm >= 1: # Convex optim
raise NotImplementedError(
"Finite values of `norm_p >= 1` are currently not supported with `suboptimal=False`."
)
else: # Non-convex optim
raise NotImplementedError("Values of `norm_p < 1` are currently not supported with `suboptimal=False`")
elif norm == np.inf: # Optimal - Easy exact case
values_tmp = values_tmp.sign() * torch.minimum(values_tmp.abs(), torch.tensor(eps).to(values_tmp.device))
elif norm >= 1: # Optimal - Convex optim

Check warning on line 507 in art/attacks/evasion/projected_gradient_descent/projected_gradient_descent_pytorch.py

View check run for this annotation

Codecov / codecov/patch

art/attacks/evasion/projected_gradient_descent/projected_gradient_descent_pytorch.py#L507

Added line #L507 was not covered by tests
raise NotImplementedError(
"Finite values of `norm_p >= 1` are currently not supported with `suboptimal=False`."
)
else: # Non-convex optim
raise NotImplementedError("Values of `norm_p < 1` are currently not supported with `suboptimal=False`")

values = values_tmp.reshape(values.shape).to(values.dtype)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -504,15 +504,14 @@ def _projection(
if (suboptimal or norm == 2) and norm != np.inf: # Simple rescaling
values_norm = tf.norm(values_tmp, ord=norm, axis=1, keepdims=True) # (n_samples, 1)
values_tmp = values_tmp * tf.where(values_norm == 0, 0, tf.minimum(1, eps / values_norm))
else: # Optimal
if norm == np.inf: # Easy exact case
values_tmp = tf.sign(values_tmp) * tf.minimum(tf.abs(values_tmp), eps)
elif norm >= 1: # Convex optim
raise NotImplementedError(
"Finite values of `norm_p >= 1` are currently not supported with `suboptimal=False`."
)
else: # Non-convex optim
raise NotImplementedError("Values of `norm_p < 1` are currently not supported with `suboptimal=False`")
elif norm == np.inf: # Optimal - Easy exact case
values_tmp = tf.sign(values_tmp) * tf.minimum(tf.abs(values_tmp), eps)
elif norm >= 1: # Convex optim

Check warning on line 509 in art/attacks/evasion/projected_gradient_descent/projected_gradient_descent_tensorflow_v2.py

View check run for this annotation

Codecov / codecov/patch

art/attacks/evasion/projected_gradient_descent/projected_gradient_descent_tensorflow_v2.py#L509

Added line #L509 was not covered by tests
raise NotImplementedError(
"Finite values of `norm_p >= 1` are currently not supported with `suboptimal=False`."
)
else: # Optimal - Non-convex optim
raise NotImplementedError("Values of `norm_p < 1` are currently not supported with `suboptimal=False`")

values = tf.cast(tf.reshape(values_tmp, values.shape), values.dtype)

Expand Down
8 changes: 4 additions & 4 deletions art/attacks/evasion/rescaling_auto_conjugate_gradient.py
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ def __call__(self, y_true: tf.Tensor, y_pred: tf.Tensor, *args, **kwargs) -> tf.
"the estimator has to to predict logits."
)

class CrossEntropyLossTorch(torch.nn.modules.loss._Loss): # pylint: disable=W0212
class CrossEntropyLossTorch(torch.nn.modules.loss._Loss): # pylint: disable=protected-access
"""Class defining cross entropy loss with reduction options."""

def __init__(self, reduction="sum"):
Expand All @@ -264,7 +264,7 @@ def __call__(self, y_true: torch.Tensor, y_pred: torch.Tensor, *args, **kwargs)
raise NotImplementedError()

def forward(
self, input: torch.Tensor, target: torch.Tensor # pylint: disable=W0622
self, input: torch.Tensor, target: torch.Tensor # pylint: disable=redefined-builtin
) -> torch.Tensor:
"""
Forward method.
Expand All @@ -285,7 +285,7 @@ def forward(
"If loss_type='difference_logits_ratio' the estimator has to to predict logits."
)

class DifferenceLogitsRatioPyTorch(torch.nn.modules.loss._Loss): # pylint: disable=W0212
class DifferenceLogitsRatioPyTorch(torch.nn.modules.loss._Loss): # pylint: disable=protected-access
"""
Callable class for Difference Logits Ratio loss in PyTorch.
"""
Expand Down Expand Up @@ -334,7 +334,7 @@ def __call__(self, y_pred: torch.Tensor, y_true: torch.Tensor) -> torch.Tensor:
raise NotImplementedError()

def forward(
self, input: torch.Tensor, target: torch.Tensor # pylint: disable=W0622
self, input: torch.Tensor, target: torch.Tensor # pylint: disable=redefined-builtin
) -> torch.Tensor:
"""
Forward method.
Expand Down
2 changes: 1 addition & 1 deletion art/attacks/evasion/steal_now_attack_later/bbox_ioa.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# pylint: disable=C0114
# pylint: disable=missing-module-docstring
# GNU AFFERO GENERAL PUBLIC LICENSE
# Version 3, 19 November 2007
#
Expand Down
4 changes: 2 additions & 2 deletions art/attacks/evasion/steal_now_attack_later/drop_block2d.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# pylint: disable=C0114
# pylint: disable=missing-module-docstring
# BSD 3-Clause License
#
# Copyright (c) Soumith Chintala 2016,
Expand Down Expand Up @@ -55,7 +55,7 @@ def drop_block2d(x: "torch.Tensor", prob: float, block_size: int):
if x.ndim != 4:
raise ValueError(f"input should be 4 dimensional. Got {x.ndim} dimensions.")

N, _, H, W = x.size() # pylint: disable=C0103
N, _, H, W = x.size() # pylint: disable=invalid-name
block_size = min(block_size, W, H)
# compute the gamma of Bernoulli distribution
gamma = (prob * H * W) / ((block_size**2) * ((H - block_size + 1) * (W - block_size + 1)))
Expand Down
Loading

0 comments on commit cbb9d46

Please sign in to comment.