Skip to content

Commit 07b195e

Browse files
committed
Merge remote-tracking branch 'upstream/dev_1.15.0' into dev_issue_2148_yolo
Merging latest dev_1.15.0
2 parents 790dea2 + f1b6a50 commit 07b195e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+2353
-225
lines changed

.github/workflows/ci-lingvo.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ jobs:
6161
pip install lingvo==${{ matrix.lingvo }}
6262
pip install tensorflow-addons==0.9.1
6363
pip install model-pruning-google-research==0.0.3
64-
pip install jax[cpu]==0.2.17
6564
pip install h5py==2.10.0
6665
pip install pytest~=7.0.1
6766
pip install pytest-flake8~=1.1.0

art/attacks/evasion/auto_conjugate_gradient.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,8 @@ def __call__(self, y_true: tf.Tensor, y_pred: tf.Tensor, *args, **kwargs) -> tf.
224224
nb_classes=estimator.nb_classes,
225225
input_shape=estimator.input_shape,
226226
loss_object=_loss_object_tf,
227-
train_step=estimator._train_step,
227+
optimizer=estimator.optimizer,
228+
train_step=estimator.train_step,
228229
channels_first=estimator.channels_first,
229230
clip_values=estimator.clip_values,
230231
preprocessing_defences=estimator.preprocessing_defences,

art/attacks/evasion/auto_projected_gradient_descent.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,8 @@ def __call__(self, y_true: tf.Tensor, y_pred: tf.Tensor, *args, **kwargs) -> tf.
203203
nb_classes=estimator.nb_classes,
204204
input_shape=estimator.input_shape,
205205
loss_object=_loss_object_tf,
206-
train_step=estimator._train_step,
206+
optimizer=estimator.optimizer,
207+
train_step=estimator.train_step,
207208
channels_first=estimator.channels_first,
208209
clip_values=estimator.clip_values,
209210
preprocessing_defences=estimator.preprocessing_defences,

art/attacks/evasion/brendel_bethge.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2055,7 +2055,8 @@ def logits_difference(y_true, y_pred):
20552055
nb_classes=estimator.nb_classes,
20562056
input_shape=estimator.input_shape,
20572057
loss_object=self._loss_object,
2058-
train_step=estimator._train_step,
2058+
optimizer=estimator.optimizer,
2059+
train_step=estimator.train_step,
20592060
channels_first=estimator.channels_first,
20602061
clip_values=estimator.clip_values,
20612062
preprocessing_defences=estimator.preprocessing_defences,

art/attacks/evasion/projected_gradient_descent/projected_gradient_descent_pytorch.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ def _generate_batch(
269269
inputs = x.to(self.estimator.device)
270270
targets = targets.to(self.estimator.device)
271271
adv_x = torch.clone(inputs)
272-
momentum = torch.zeros(inputs.shape)
272+
momentum = torch.zeros(inputs.shape).to(self.estimator.device)
273273

274274
if mask is not None:
275275
mask = mask.to(self.estimator.device)

art/attacks/evasion/sign_opt.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -306,14 +306,14 @@ def _fine_grained_binary_search_local(
306306
lbd = initial_lbd
307307
# For targeted: we want to expand(x1.01) boundary away from targeted dataset
308308
# For untargeted, we want to slim(x0.99) the boundary toward the original dataset
309-
if (not self._is_label(x_0 + lbd * theta, target) and self.targeted) or (
310-
self._is_label(x_0 + lbd * theta, y_0) and not self.targeted
309+
if (self.targeted and not self._is_label(x_0 + lbd * theta, target)) or (
310+
not self.targeted and self._is_label(x_0 + lbd * theta, y_0)
311311
):
312312
lbd_lo = lbd
313313
lbd_hi = lbd * 1.01
314314
nquery += 1
315-
while (not self._is_label(x_0 + lbd_hi * theta, target) and self.targeted) or (
316-
self._is_label(x_0 + lbd_hi * theta, y_0) and not self.targeted
315+
while (self.targeted and not self._is_label(x_0 + lbd_hi * theta, target)) or (
316+
not self.targeted and self._is_label(x_0 + lbd_hi * theta, y_0)
317317
):
318318
lbd_hi = lbd_hi * 1.01
319319
nquery += 1
@@ -323,17 +323,17 @@ def _fine_grained_binary_search_local(
323323
lbd_hi = lbd
324324
lbd_lo = lbd * 0.99
325325
nquery += 1
326-
while (self._is_label(x_0 + lbd_lo * theta, target) and self.targeted) or (
327-
not self._is_label(x_0 + lbd_lo * theta, y_0) and not self.targeted
326+
while (self.targeted and self._is_label(x_0 + lbd_lo * theta, target)) or (
327+
not self.targeted and not self._is_label(x_0 + lbd_lo * theta, y_0)
328328
):
329329
lbd_lo = lbd_lo * 0.99
330330
nquery += 1
331331

332332
while (lbd_hi - lbd_lo) > tol:
333333
lbd_mid = (lbd_lo + lbd_hi) / 2.0
334334
nquery += 1
335-
if (self._is_label(x_0 + lbd_mid * theta, target) and self.targeted) or (
336-
not self._is_label(x_0 + lbd_mid * theta, y_0) and not self.targeted
335+
if (self.targeted and self._is_label(x_0 + lbd_mid * theta, target)) or (
336+
not self.targeted and not self._is_label(x_0 + lbd_mid * theta, y_0)
337337
):
338338
lbd_hi = lbd_mid
339339
else:

art/attacks/poisoning/perturbations/image_perturbations.py

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ def insert_image(
127127
original_dtype = x.dtype
128128
data = np.copy(x)
129129
if channels_first:
130-
data = data.transpose([1, 2, 0])
130+
data = np.transpose(data, (1, 2, 0))
131131

132132
height, width, num_channels = data.shape
133133

@@ -136,37 +136,36 @@ def insert_image(
136136
backdoored_img = Image.new("RGBA", (width, height), 0) # height and width are swapped for PIL
137137

138138
if no_color:
139-
backdoored_input = Image.fromarray((data * 255).astype("uint8").squeeze(axis=2), mode=mode)
139+
backdoored_input = Image.fromarray((data * 255).astype(np.uint8).squeeze(axis=2), mode=mode)
140140
else:
141-
backdoored_input = Image.fromarray((data * 255).astype("uint8"), mode=mode)
141+
backdoored_input = Image.fromarray((data * 255).astype(np.uint8), mode=mode)
142142

143143
orig_img.paste(backdoored_input)
144144

145145
trigger = Image.open(backdoor_path).convert("RGBA")
146-
if size:
147-
trigger = trigger.resize(size)
146+
if size is not None:
147+
trigger = trigger.resize((size[1], size[0])) # height and width are swapped for PIL
148148

149149
backdoor_width, backdoor_height = trigger.size # height and width are swapped for PIL
150150

151151
if backdoor_width > width or backdoor_height > height:
152152
raise ValueError("Backdoor does not fit inside original image")
153153

154154
if random:
155-
x_shift = np.random.randint(width - backdoor_width)
156-
y_shift = np.random.randint(height - backdoor_height)
155+
x_shift = np.random.randint(width - backdoor_width + 1)
156+
y_shift = np.random.randint(height - backdoor_height + 1)
157157

158158
backdoored_img.paste(trigger, (x_shift, y_shift), mask=trigger)
159159
composite = Image.alpha_composite(orig_img, backdoored_img)
160160
backdoored_img = Image.blend(orig_img, composite, blend)
161-
162161
backdoored_img = backdoored_img.convert(mode)
163162

164-
res = np.array(backdoored_img) / 255.0
163+
res = np.asarray(backdoored_img) / 255.0
165164

166165
if no_color:
167166
res = np.expand_dims(res, 2)
168167

169168
if channels_first:
170-
res = res.transpose([2, 0, 1])
169+
res = np.transpose(res, (2, 0, 1))
171170

172171
return res.astype(original_dtype)

art/defences/preprocessor/preprocessor.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ def apply_predict(self) -> bool:
8080
return self._apply_predict
8181

8282
@abc.abstractmethod
83-
def __call__(self, x: np.ndarray, y: Optional[np.ndarray] = None) -> Tuple[np.ndarray, Optional[np.ndarray]]:
83+
def __call__(self, x: np.ndarray, y: Optional[Any] = None) -> Tuple[np.ndarray, Optional[Any]]:
8484
"""
8585
Perform data preprocessing and return preprocessed data as tuple.
8686
@@ -250,7 +250,7 @@ class PreprocessorTensorFlowV2(Preprocessor):
250250
"""
251251

252252
@abc.abstractmethod
253-
def forward(self, x: "tf.Tensor", y: Optional["tf.Tensor"] = None) -> Tuple["tf.Tensor", Optional["tf.Tensor"]]:
253+
def forward(self, x: "tf.Tensor", y: Optional[Any] = None) -> Tuple["tf.Tensor", Optional[Any]]:
254254
"""
255255
Perform data preprocessing in TensorFlow v2 and return preprocessed data as tuple.
256256

art/defences/trainer/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,6 @@
88
from art.defences.trainer.adversarial_trainer_madry_pgd import AdversarialTrainerMadryPGD
99
from art.defences.trainer.adversarial_trainer_fbf import AdversarialTrainerFBF
1010
from art.defences.trainer.adversarial_trainer_fbf_pytorch import AdversarialTrainerFBFPyTorch
11+
from art.defences.trainer.adversarial_trainer_trades import AdversarialTrainerTRADES
12+
from art.defences.trainer.adversarial_trainer_trades_pytorch import AdversarialTrainerTRADESPyTorch
1113
from art.defences.trainer.dp_instahide_trainer import DPInstaHideTrainer
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
# MIT License
2+
#
3+
# Copyright (C) The Adversarial Robustness Toolbox (ART) Authors 2023
4+
#
5+
# Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
6+
# documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
7+
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
8+
# persons to whom the Software is furnished to do so, subject to the following conditions:
9+
#
10+
# The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
11+
# Software.
12+
#
13+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
14+
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
15+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
16+
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
17+
# SOFTWARE.
18+
"""
19+
This module implements adversarial training with TRADES protocol.
20+
21+
| Paper link: https://proceedings.mlr.press/v97/zhang19p.html
22+
23+
| It was noted that this protocol uses a modified loss called TRADES loss which is a combination of cross entropy
24+
loss on clean data and KL divergence loss between clean data and adversarial data. Consequently, framework specific
25+
implementations are being provided in ART.
26+
"""
27+
from __future__ import absolute_import, division, print_function, unicode_literals
28+
29+
import abc
30+
from typing import Optional, Tuple, TYPE_CHECKING
31+
32+
import numpy as np
33+
34+
from art.defences.trainer.trainer import Trainer
35+
from art.attacks.attack import EvasionAttack
36+
from art.data_generators import DataGenerator
37+
38+
if TYPE_CHECKING:
39+
from art.utils import CLASSIFIER_LOSS_GRADIENTS_TYPE
40+
41+
42+
class AdversarialTrainerTRADES(Trainer, abc.ABC):
43+
"""
44+
This is abstract class for different backend-specific implementations of TRADES protocol
45+
for adversarial training.
46+
47+
| Paper link: https://proceedings.mlr.press/v97/zhang19p.html
48+
"""
49+
50+
def __init__(
51+
self,
52+
classifier: "CLASSIFIER_LOSS_GRADIENTS_TYPE",
53+
attack: EvasionAttack,
54+
beta: float = 6.0,
55+
):
56+
"""
57+
Create an :class:`.AdversarialTrainerTRADES` instance.
58+
59+
:param classifier: Model to train adversarially.
60+
:param attack: attack to use for data augmentation in adversarial training
61+
:param beta: The scaling factor controlling tradeoff between clean loss and adversarial loss
62+
"""
63+
self._attack = attack
64+
self._beta = beta
65+
super().__init__(classifier)
66+
67+
@abc.abstractmethod
68+
def fit( # pylint: disable=W0221
69+
self,
70+
x: np.ndarray,
71+
y: np.ndarray,
72+
validation_data: Optional[Tuple[np.ndarray, np.ndarray]] = None,
73+
batch_size: int = 128,
74+
nb_epochs: int = 20,
75+
**kwargs
76+
):
77+
"""
78+
Train a model adversarially with TRADES. See class documentation for more information on the exact procedure.
79+
80+
:param x: Training set.
81+
:param y: Labels for the training set.
82+
:param validation_data: Tuple consisting of validation data, (x_val, y_val)
83+
:param batch_size: Size of batches.
84+
:param nb_epochs: Number of epochs to use for trainings.
85+
:param kwargs: Dictionary of framework-specific arguments. These will be passed as such to the `fit` function of
86+
the target classifier.
87+
"""
88+
raise NotImplementedError
89+
90+
@abc.abstractmethod
91+
def fit_generator(self, generator: DataGenerator, nb_epochs: int = 20, **kwargs):
92+
"""
93+
Train a model adversarially using a data generator.
94+
See class documentation for more information on the exact procedure.
95+
96+
:param generator: Data generator.
97+
:param nb_epochs: Number of epochs to use for trainings.
98+
:param kwargs: Dictionary of framework-specific arguments. These will be passed as such to the `fit` function of
99+
the target classifier.
100+
"""
101+
raise NotImplementedError
102+
103+
def predict(self, x: np.ndarray, **kwargs) -> np.ndarray:
104+
"""
105+
Perform prediction using the adversarially trained classifier.
106+
107+
:param x: Input samples.
108+
:param kwargs: Other parameters to be passed on to the `predict` function of the classifier.
109+
:return: Predictions for test set.
110+
"""
111+
return self._classifier.predict(x, **kwargs)

0 commit comments

Comments
 (0)