Skip to content

Commit 93f5f67

Browse files
committed
Merge remote-tracking branch 'origin/dev_1.20.0' into dependabot/pip/keras-3.10.0
2 parents 00711e7 + 29b9856 commit 93f5f67

File tree

23 files changed

+366
-226
lines changed

23 files changed

+366
-226
lines changed

.github/actions/yolo/run.sh

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,11 @@ if [[ $? -ne 0 ]]; then exit_code=1; echo "Failed estimators/object_detection/te
88
pytest --cov-report=xml --cov=art --cov-append -q -vv tests/estimators/object_detection/test_object_seeker_yolo.py --framework=pytorch --durations=0
99
if [[ $? -ne 0 ]]; then exit_code=1; echo "Failed estimators/object_detection/test_object_seeker_yolo tests"; fi
1010

11+
pytest --cov-report=xml --cov=art --cov-append -q -vv tests/attacks/test_overload_attack.py --framework=pytorch --durations=0
12+
if [[ $? -ne 0 ]]; then exit_code=1; echo "Failed attacks/test_overload_attack tests"; fi
13+
14+
pytest --cov-report=xml --cov=art --cov-append -q -vv tests/attacks/test_steal_now_attack_later.py --framework=pytorch --durations=0
15+
if [[ $? -ne 0 ]]; then exit_code=1; echo "Failed attacks/teest_steal_now_attack_later tests"; fi
16+
17+
1118
exit ${exit_code}

.github/workflows/ci-huggingface.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,9 @@ jobs:
5252
pip install -q -r <(sed '/^tensorflow/d;/^keras/d;/^mxnet/d' requirements_test.txt)
5353
pip install tensorflow==2.18.1
5454
pip install keras==3.10.0
55-
pip install torch==${{ matrix.torch }} -f https://download.pytorch.org/whl/cpu/torch_stable.html
56-
pip install torchvision==${{ matrix.torchvision }} -f https://download.pytorch.org/whl/cpu/torch_stable.html
57-
pip install torchaudio==${{ matrix.torchaudio }} -f https://download.pytorch.org/whl/cpu/torch_stable.html
55+
pip install torch==${{ matrix.torch }} --index-url https://download.pytorch.org/whl/cpu
56+
pip install torchvision==${{ matrix.torchvision }} --index-url https://download.pytorch.org/whl/cpu
57+
pip install torchaudio==${{ matrix.torchaudio }} --index-url https://download.pytorch.org/whl/cpu
5858
pip install transformers==${{ matrix.transformers }}
5959
pip list
6060
- name: Run Tests

.github/workflows/ci-legacy.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,9 @@ jobs:
5656
pip install tensorflow==${{ matrix.tensorflow }}
5757
pip install keras==${{ matrix.keras }}
5858
pip install scikit-learn==${{ matrix.scikit-learn }}
59-
pip install torch==${{ matrix.torch }} -f https://download.pytorch.org/whl/cpu/torch_stable.html
60-
pip install torchvision==${{ matrix.torchvision }} -f https://download.pytorch.org/whl/cpu/torch_stable.html
61-
pip install torchaudio==${{ matrix.torchaudio }} -f https://download.pytorch.org/whl/cpu/torch_stable.html
59+
pip install torch==${{ matrix.torch }} --index-url https://download.pytorch.org/whl/cpu
60+
pip install torchvision==${{ matrix.torchvision }} --index-url https://download.pytorch.org/whl/cpu
61+
pip install torchaudio==${{ matrix.torchaudio }} --index-url https://download.pytorch.org/whl/cpu
6262
pip list
6363
- name: Run ${{ matrix.name }} ${{ matrix.module }} Tests
6464
run: ./run_tests.sh ${{ matrix.framework }} ${{ matrix.module }}

.github/workflows/ci-pytorch.yml

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,18 +28,18 @@ jobs:
2828
fail-fast: false
2929
matrix:
3030
include:
31-
- name: PyTorch 1.13.1 (Python 3.10)
31+
- name: PyTorch 2.6.0 (Python 3.10)
3232
framework: pytorch
3333
python: '3.10'
34-
torch: 1.13.1+cpu
35-
torchvision: 0.14.1+cpu
36-
torchaudio: 0.13.1
37-
- name: PyTorch 2.2.1 (Python 3.10)
34+
torch: 2.6.0
35+
torchvision: 0.21.0
36+
torchaudio: 2.6.0
37+
- name: PyTorch 2.7.0 (Python 3.10)
3838
framework: pytorch
3939
python: '3.10'
40-
torch: 2.2.1
41-
torchvision: 0.17.1+cpu
42-
torchaudio: 2.2.1
40+
torch: 2.7.0
41+
torchvision: 0.22.0
42+
torchaudio: 2.7.0
4343

4444
name: ${{ matrix.name }}
4545
steps:
@@ -55,9 +55,9 @@ jobs:
5555
sudo apt-get -y -q install ffmpeg libavcodec-extra
5656
python -m pip install --upgrade pip setuptools wheel
5757
pip install -q -r <(sed '/^mxnet/d' requirements_test.txt)
58-
pip install torch==${{ matrix.torch }} -f https://download.pytorch.org/whl/cpu/torch_stable.html
59-
pip install torchvision==${{ matrix.torchvision }} -f https://download.pytorch.org/whl/cpu/torch_stable.html
60-
pip install torchaudio==${{ matrix.torchaudio }} -f https://download.pytorch.org/whl/cpu/torch_stable.html
58+
pip install torch==${{ matrix.torch }} --index-url https://download.pytorch.org/whl/cpu
59+
pip install torchvision==${{ matrix.torchvision }} --index-url https://download.pytorch.org/whl/cpu
60+
pip install torchaudio==${{ matrix.torchaudio }} --index-url https://download.pytorch.org/whl/cpu
6161
pip list
6262
- name: Run Tests
6363
run: ./run_tests.sh ${{ matrix.framework }}

art/attacks/evasion/auto_attack.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,9 @@ def generate(self, x: np.ndarray, y: np.ndarray | None = None, **kwargs) -> np.n
201201
attack.set_params(targeted=False)
202202

203203
if self.parallel_pool_size > 0:
204+
attack.estimator._optimizer = None
205+
self.estimator._optimizer = None
206+
204207
args.append(
205208
(
206209
deepcopy(x_adv),
@@ -255,6 +258,9 @@ def generate(self, x: np.ndarray, y: np.ndarray | None = None, **kwargs) -> np.n
255258
)
256259

257260
if self.parallel_pool_size > 0:
261+
attack.estimator._optimizer = None
262+
self.estimator._optimizer = None
263+
258264
args.append(
259265
(
260266
deepcopy(x_adv),

art/attacks/evasion/feature_adversaries/feature_adversaries_pytorch.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,10 +150,10 @@ def loss_fn(source_orig, source_adv, guide):
150150
loss.backward()
151151

152152
# pgd step
153-
if adv.grad is not None:
153+
if adv.grad is not None and self.step_size is not None:
154154
adv.data = adv - adv.grad.detach().sign() * self.step_size
155155
else:
156-
raise ValueError("Gradient tensor in PyTorch model is `None`.")
156+
raise ValueError("Gradient tensor in PyTorch model or step_size is `None`.")
157157
perturbation = torch.clamp(adv.detach() - x.detach(), -self.delta, self.delta)
158158
adv.data = x.detach() + perturbation
159159
if self.estimator.clip_values is not None:

art/attacks/evasion/overload/overload.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ def __init__(
6161
max_iter: int,
6262
num_grid: int,
6363
batch_size: int,
64+
threshold: float,
6465
) -> None:
6566
"""
6667
Create an overload attack instance.
@@ -70,12 +71,14 @@ def __init__(
7071
:param max_iter: The maximum number of iterations.
7172
:param num_grid: The number of grids for width and high dimension.
7273
:param batch_size: Size of the batch on which adversarial samples are generated.
74+
:param threshold: IoU threshold.
7375
"""
7476
super().__init__(estimator=estimator)
7577
self.eps = eps
7678
self.max_iter = max_iter
7779
self.num_grid = num_grid
7880
self.batch_size = batch_size
81+
self.threshold = threshold
7982
self._check_params()
8083

8184
def generate(self, x: np.ndarray, y: np.ndarray | None = None, **kwargs) -> np.ndarray:
@@ -157,10 +160,9 @@ def _loss(self, x: "torch.Tensor") -> tuple["torch.Tensor", "torch.Tensor"]:
157160
if isinstance(adv_logits, tuple):
158161
adv_logits = adv_logits[0]
159162

160-
threshold = self.estimator.model.conf
161163
conf = adv_logits[..., 4]
162164
prob = adv_logits[..., 5:]
163-
prob = torch.where(conf[:, :, None] * prob > threshold, torch.ones_like(prob), prob)
165+
prob = torch.where(conf[:, :, None] * prob > self.threshold, torch.ones_like(prob), prob)
164166
prob = torch.sum(prob, dim=2)
165167
conf = conf * prob
166168

@@ -185,7 +187,7 @@ def _loss(self, x: "torch.Tensor") -> tuple["torch.Tensor", "torch.Tensor"]:
185187
for x_i in range(x.shape[0]):
186188
xyhw = adv_logits[x_i, :, :4]
187189
prob = torch.max(adv_logits[x_i, :, 5:], dim=1).values
188-
box_idx = adv_logits[x_i, :, 4] * prob > threshold
190+
box_idx = adv_logits[x_i, :, 4] * prob > self.threshold
189191
xyhw = xyhw[box_idx]
190192
c_xyxy = self.xywh2xyxy(xyhw)
191193
scores = box_iou(grid_box, c_xyxy)
@@ -244,3 +246,6 @@ def _check_params(self) -> None:
244246

245247
if self.batch_size < 1:
246248
raise ValueError("The batch size must be a positive integer.")
249+
250+
if self.threshold < 0.0 or self.threshold > 1.0:
251+
raise ValueError("The threshold must be in the range [0, 1].")

art/attacks/evasion/steal_now_attack_later/steal_now_attack_later.py

Lines changed: 17 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -42,15 +42,14 @@
4242
logger = logging.getLogger(__name__)
4343

4444

45-
# tiling
4645
def _generate_tile_kernel(patch: list, mask: list, tile_size: int) -> Tuple["torch.Tensor", "torch.Tensor"]:
4746
"""
48-
Generate specific size of pertuerbed tiles from randomly selected patches.
47+
Generate specific size of perturbed tiles from randomly selected patches.
4948
50-
:param patch: Candiate patches.
49+
:param patch: Candidate patches.
5150
:param mask: Masks for each patch.
5251
:param tile_size: The size of each tile.
53-
:return: Pertuerbed tiles and corresponding maskes.
52+
:return: Perturbed tiles and corresponding masks.
5453
"""
5554
import torch
5655
import torchvision
@@ -79,7 +78,7 @@ def _generate_tile_kernel(patch: list, mask: list, tile_size: int) -> Tuple["tor
7978
min_len = height
8079

8180
if max_len > tile_size:
82-
new_len = round(min_len * tile_size / max_len)
81+
new_len = max(round(min_len * tile_size / max_len), 1)
8382
p_1 = torchvision.transforms.Resize((tile_size, new_len))(t_patch)
8483
# fix for the case that (strides - new_len) > new_len
8584
p_list = []
@@ -95,22 +94,22 @@ def _generate_tile_kernel(patch: list, mask: list, tile_size: int) -> Tuple["tor
9594
n_mask = torch.where(n_patch == 0, torch.zeros_like(n_patch), torch.ones_like(n_patch))
9695

9796
elif max_len >= tile_size / 2.0:
98-
new_len = round(min_len * (tile_size / 2.0) / max_len)
97+
new_len = max(round(min_len * (tile_size / 2.0) / max_len), 1)
9998

10099
p_list = []
101100
for _ in range(tile_size // new_len):
102101
repeat = 2
103102
p1_list = []
104103
for _ in range(repeat):
105-
p_1 = torchvision.transforms.Resize((tile_size // 2, new_len))(t_patch)
104+
p_1 = torchvision.transforms.Resize((max(tile_size // 2, 1), new_len))(t_patch)
106105
if torch.rand([]) < 0.6:
107106
p1_list.append(FlipOp(p_1))
108107
else:
109108
p1_list.append(torch.zeros_like(p_1))
110109
p_1 = torch.cat(p1_list, dim=-2)
111110
p_list.append(p_1)
112111

113-
p_2 = torchvision.transforms.RandomCrop((tile_size, tile_size % new_len))(p_1)
112+
p_2 = torchvision.transforms.RandomCrop((tile_size, max(tile_size % new_len, 1)))(p_1)
114113
p_list.append(FlipOp(p_2))
115114

116115
n_patch = torch.cat(p_list, dim=-1)
@@ -150,13 +149,13 @@ def _generate_tile_kernel(patch: list, mask: list, tile_size: int) -> Tuple["tor
150149

151150
def generate_tile(patches: list, masks: list, tile_size: int, scale: list) -> Tuple["torch.Tensor", "torch.Tensor"]:
152151
"""
153-
Generate different size of pertuerbed tiles from randomly selected patches.
152+
Generate different size of perturbed tiles from randomly selected patches.
154153
155-
:param patch: Candiate patches.
154+
:param patch: Candidate patches.
156155
:param mask: Masks for each patch.
157156
:param tile_size: The size of each tile.
158-
:param scale: Scale factor for various tileing size.
159-
:return: Pertuerbed tiles and corresponding maskes.
157+
:param scale: Scale factor for various tiling size.
158+
:return: Perturbed tiles and corresponding masks.
160159
"""
161160
import torch
162161

@@ -316,8 +315,8 @@ def __init__(
316315
Create a SNAL attack instance.
317316
318317
:param estimator: A trained YOLOv8 model or other models with the same output format
319-
:param candidates: The collected pateches to generate perturbations.
320-
:param collector: A callbel uses to generate patches.
318+
:param candidates: The collected patches to generate perturbations.
319+
:param collector: A callable uses to generate patches.
321320
:param eps: Maximum perturbation that the attacker can introduce.
322321
:param max_iter: The maximum number of iterations.
323322
:param num_grid: The number of grids for width and high dimension.
@@ -391,7 +390,7 @@ def _attack(self, x_adv: "torch.Tensor", x: "torch.Tensor") -> "torch.Tensor":
391390
raise ValueError("The size of the image must be divided by the number of grids")
392391
tile_size = x.shape[-1] // self.num_grid
393392

394-
# Prapare a 2D array to store the results of each grid
393+
# Prepare a 2D array to store the results of each grid
395394
buffer_depth = 5
396395
tile_mat = {}
397396
for idx_i in range(self.num_grid):
@@ -503,10 +502,10 @@ def _attack(self, x_adv: "torch.Tensor", x: "torch.Tensor") -> "torch.Tensor":
503502

504503
def _get_loss(self, pert: "torch.Tensor", epsilon: float) -> "torch.Tensor": # pylint: disable=R0201
505504
"""
506-
Calculate accumulated distance of the perturbations outside the epslion ball.
505+
Calculate accumulated distance of the perturbations outside the epsilon ball.
507506
508507
:param pert: Perturbations in the pixel space.
509-
:param epsilon: The radius of the eplion bass.
508+
:param epsilon: The radius of the epsilon bass.
510509
:return: loss.
511510
"""
512511
import torch
@@ -526,7 +525,7 @@ def _color_projection( # pylint: disable=R0201
526525
527526
:param tile: The target to convert.
528527
:param x_ref: The source data.
529-
:param epsilon: The radius of the eplion bass.
528+
:param epsilon: The radius of the epsilon bass.
530529
:return: The converted tile.
531530
"""
532531
import torch

art/defences/detector/evasion/beyond_detector.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -105,9 +105,9 @@ def _get_metrics(self, x: np.ndarray, batch_size: int = 128) -> np.ndarray:
105105
samples = torch.from_numpy(x).to(self.device)
106106

107107
self.target_model.eval()
108-
self.backbone.eval()
109-
self.model_classifier.eval()
110-
self.projector.eval()
108+
self.backbone.eval() # type: ignore
109+
self.model_classifier.eval() # type: ignore
110+
self.projector.eval() # type: ignore
111111

112112
number_batch = int(math.ceil(len(samples) / batch_size))
113113

@@ -122,15 +122,15 @@ def _get_metrics(self, x: np.ndarray, batch_size: int = 128) -> np.ndarray:
122122
b, c, h, w = batch_samples.shape
123123

124124
trans_images = self._multi_transform(batch_samples).to(self.device)
125-
ssl_backbone_out = self.backbone(batch_samples)
125+
ssl_backbone_out = self.backbone(batch_samples) # type: ignore
126126

127-
ssl_repre = self.projector(ssl_backbone_out)
128-
ssl_pred = self.model_classifier(ssl_backbone_out)
127+
ssl_repre = self.projector(ssl_backbone_out) # type: ignore
128+
ssl_pred = self.model_classifier(ssl_backbone_out) # type: ignore
129129
ssl_label = torch.max(ssl_pred, -1)[1]
130130

131-
aug_backbone_out = self.backbone(trans_images.reshape(-1, c, h, w))
132-
aug_repre = self.projector(aug_backbone_out)
133-
aug_pred = self.model_classifier(aug_backbone_out)
131+
aug_backbone_out = self.backbone(trans_images.reshape(-1, c, h, w)) # type: ignore
132+
aug_repre = self.projector(aug_backbone_out) # type: ignore
133+
aug_pred = self.model_classifier(aug_backbone_out) # type: ignore
134134
aug_pred = aug_pred.reshape(b, self.aug_num, -1)
135135

136136
sim_repre = F.cosine_similarity(

art/defences/trainer/certified_adversarial_trainer_pytorch.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ def fit(
288288
bias = torch.unsqueeze(bias, dim=0)
289289

290290
if certification_loss == "max_logit_loss":
291-
certified_loss += self.classifier.max_logit_loss(
291+
certified_loss += self.classifier.max_logit_loss( # type: ignore
292292
prediction=torch.cat((bias, eps)),
293293
target=torch.from_numpy(np.expand_dims(label, axis=0)).to(self.classifier.device),
294294
)

art/estimators/certification/derandomized_smoothing/pytorch.py

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -173,13 +173,13 @@ def __init__(
173173
pretrained_cfg = model.pretrained_cfg
174174
supplied_state_dict = model.state_dict()
175175
supported_models = self.get_models()
176-
if pretrained_cfg["architecture"] not in supported_models:
176+
if pretrained_cfg["architecture"] not in supported_models: # type: ignore
177177
raise ValueError(
178178
"Architecture not supported. Use PyTorchDeRandomizedSmoothing.get_models() "
179179
"to get the supported model architectures."
180180
)
181181
model = timm.create_model(
182-
pretrained_cfg["architecture"], drop_tokens=drop_tokens, device_type=device_type
182+
pretrained_cfg["architecture"], drop_tokens=drop_tokens, device_type=device_type # type: ignore
183183
)
184184
model.load_state_dict(supplied_state_dict) # type: ignore
185185
if replace_last_layer:
@@ -205,24 +205,24 @@ def __init__(
205205
if not isinstance(model, PyTorchVisionTransformer):
206206
raise ValueError("Vision transformer is not of PyTorchViT. Error occurred in PyTorchViT creation.")
207207

208-
if model.default_cfg["input_size"][0] != input_shape[0]:
208+
if model.default_cfg["input_size"][0] != input_shape[0]: # type: ignore
209209
raise ValueError(
210-
f'ViT requires {model.default_cfg["input_size"][0]} channel input,'
210+
f'ViT requires {model.default_cfg["input_size"][0]} channel input,' # type: ignore
211211
f" but {input_shape[0]} channels were provided."
212212
)
213213

214-
if model.default_cfg["input_size"] != input_shape:
214+
if model.default_cfg["input_size"] != input_shape: # type: ignore
215215
if verbose:
216216
logger.warning(
217217
" ViT expects input shape of: (%i, %i, %i) but (%i, %i, %i) specified as the input shape."
218218
" The input will be rescaled to (%i, %i, %i)",
219-
*model.default_cfg["input_size"],
219+
*model.default_cfg["input_size"], # type: ignore
220220
*input_shape,
221-
*model.default_cfg["input_size"],
221+
*model.default_cfg["input_size"], # type: ignore
222222
)
223223

224224
self.to_reshape = True
225-
output_shape = model.default_cfg["input_size"]
225+
output_shape = model.default_cfg["input_size"] # type: ignore
226226

227227
# set the method back to avoid unexpected side effects later on should timm need to be reused.
228228
timm.models.vision_transformer._create_vision_transformer = tmp_func
@@ -699,7 +699,9 @@ def _predict_classifier(
699699
if not self.logits:
700700
return np.asarray((outputs >= self.threshold))
701701
return np.asarray(
702-
(torch.nn.functional.softmax(torch.from_numpy(outputs), dim=1) >= self.threshold).type(torch.int)
702+
(torch.nn.functional.softmax(torch.from_numpy(outputs), dim=1) >= self.threshold).type( # type: ignore
703+
torch.int
704+
)
703705
)
704706
return outputs
705707

0 commit comments

Comments
 (0)