Skip to content

Commit 15e5903

Browse files
authored
Merge pull request #603 from Trusted-AI/development_issue_488
Update progress bars in PGDs and FBF adversarial trainer
2 parents 71bc9cd + 440f0be commit 15e5903

File tree

8 files changed

+52
-15
lines changed

8 files changed

+52
-15
lines changed

art/attacks/evasion/carlini.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ def __init__(
108108
:param max_halving: Maximum number of halving steps in the line search optimization.
109109
:param max_doubling: Maximum number of doubling steps in the line search optimization.
110110
:param batch_size: Size of the batch on which adversarial samples are generated.
111-
:param verbose: Indicates whether to print verbose messages.
111+
:param verbose: Show progress bars.
112112
"""
113113
super().__init__(estimator=classifier)
114114

@@ -523,7 +523,7 @@ def __init__(
523523
:param max_doubling: Maximum number of doubling steps in the line search optimization.
524524
:param eps: An upper bound for the L_0 norm of the adversarial perturbation.
525525
:param batch_size: Size of the batch on which adversarial samples are generated.
526-
:param verbose: Indicates whether to print verbose messages.
526+
:param verbose: Show progress bars.
527527
"""
528528
super().__init__(estimator=classifier)
529529

art/attacks/evasion/deepfool.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ def __init__(
7474
:param nb_grads: The number of class gradients (top nb_grads w.r.t. prediction) to compute. This way only the
7575
most likely classes are considered, speeding up the computation.
7676
:param batch_size: Batch size
77+
:param verbose: Show progress bars.
7778
"""
7879
super().__init__(estimator=classifier)
7980
self.max_iter = max_iter

art/attacks/evasion/projected_gradient_descent/projected_gradient_descent.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ class ProjectedGradientDescent(EvasionAttack):
6969
"minimal",
7070
"max_iter",
7171
"random_eps",
72+
"verbose",
7273
]
7374

7475
_estimator_requirements = (BaseEstimator, LossGradientsMixin)
@@ -84,6 +85,7 @@ def __init__(
8485
num_random_init: int = 0,
8586
batch_size: int = 32,
8687
random_eps: bool = False,
88+
verbose: bool = True,
8789
):
8890
"""
8991
Create a :class:`.ProjectedGradientDescent` instance.
@@ -101,6 +103,7 @@ def __init__(
101103
:param num_random_init: Number of random initialisations within the epsilon ball. For num_random_init=0 starting
102104
at the original input.
103105
:param batch_size: Size of the batch on which adversarial samples are generated.
106+
:param verbose: Show progress bars.
104107
"""
105108
super().__init__(estimator=estimator)
106109

@@ -112,6 +115,7 @@ def __init__(
112115
self.num_random_init = num_random_init
113116
self.batch_size = batch_size
114117
self.random_eps = random_eps
118+
self.verbose = verbose
115119
ProjectedGradientDescent._check_params(self)
116120

117121
no_preprocessing = self.estimator.preprocessing is None or (
@@ -133,6 +137,7 @@ def __init__(
133137
num_random_init=num_random_init,
134138
batch_size=batch_size,
135139
random_eps=random_eps,
140+
verbose=verbose,
136141
)
137142

138143
elif isinstance(self.estimator, TensorFlowV2Classifier) and no_preprocessing and no_defences:
@@ -146,6 +151,7 @@ def __init__(
146151
num_random_init=num_random_init,
147152
batch_size=batch_size,
148153
random_eps=random_eps,
154+
verbose=verbose,
149155
)
150156

151157
else:
@@ -159,6 +165,7 @@ def __init__(
159165
num_random_init=num_random_init,
160166
batch_size=batch_size,
161167
random_eps=random_eps,
168+
verbose=verbose,
162169
)
163170

164171
def generate(self, x: np.ndarray, y: Optional[np.ndarray] = None, **kwargs) -> np.ndarray:
@@ -207,3 +214,6 @@ def _check_params(self) -> None:
207214

208215
if self.max_iter <= 0:
209216
raise ValueError("The number of iterations `max_iter` has to be a positive integer.")
217+
218+
if not isinstance(self.verbose, bool):
219+
raise ValueError("The verbose has to be a Boolean.")

art/attacks/evasion/projected_gradient_descent/projected_gradient_descent_numpy.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030

3131
import numpy as np
3232
from scipy.stats import truncnorm
33+
from tqdm import trange
3334

3435
from art.attacks.evasion.fast_gradient import FastGradientMethod
3536
from art.config import ART_NUMPY_DTYPE
@@ -57,7 +58,7 @@ class ProjectedGradientDescentCommon(FastGradientMethod):
5758
| Paper link: https://arxiv.org/abs/1706.06083
5859
"""
5960

60-
attack_params = FastGradientMethod.attack_params + ["max_iter", "random_eps"]
61+
attack_params = FastGradientMethod.attack_params + ["max_iter", "random_eps", "verbose"]
6162
_estimator_requirements = (BaseEstimator, LossGradientsMixin)
6263

6364
def __init__(
@@ -71,6 +72,7 @@ def __init__(
7172
num_random_init: int = 0,
7273
batch_size: int = 32,
7374
random_eps: bool = False,
75+
verbose: bool = True,
7476
) -> None:
7577
"""
7678
Create a :class:`.ProjectedGradientDescentCommon` instance.
@@ -88,6 +90,7 @@ def __init__(
8890
:param num_random_init: Number of random initialisations within the epsilon ball. For num_random_init=0
8991
starting at the original input.
9092
:param batch_size: Size of the batch on which adversarial samples are generated.
93+
:param verbose: Show progress bars.
9194
"""
9295
super().__init__(
9396
estimator=estimator, # type: ignore
@@ -101,6 +104,7 @@ def __init__(
101104
)
102105
self.max_iter = max_iter
103106
self.random_eps = random_eps
107+
self.verbose = verbose
104108
ProjectedGradientDescentCommon._check_params(self)
105109

106110
if self.random_eps:
@@ -204,6 +208,7 @@ def __init__(
204208
num_random_init: int = 0,
205209
batch_size: int = 32,
206210
random_eps: bool = False,
211+
verbose: bool = True,
207212
) -> None:
208213
"""
209214
Create a :class:`.ProjectedGradientDescentNumpy` instance.
@@ -221,6 +226,7 @@ def __init__(
221226
:param num_random_init: Number of random initialisations within the epsilon ball. For num_random_init=0 starting
222227
at the original input.
223228
:param batch_size: Size of the batch on which adversarial samples are generated.
229+
:param verbose: Show progress bars.
224230
"""
225231
super().__init__(
226232
estimator=estimator,
@@ -232,6 +238,7 @@ def __init__(
232238
num_random_init=num_random_init,
233239
batch_size=batch_size,
234240
random_eps=random_eps,
241+
verbose=verbose,
235242
)
236243

237244
self._project = True
@@ -266,10 +273,12 @@ def generate(self, x: np.ndarray, y: Optional[np.ndarray] = None, **kwargs) -> n
266273
adv_x_best = None
267274
rate_best = None
268275

269-
for _ in range(max(1, self.num_random_init)):
276+
for _ in trange(
277+
max(1, self.num_random_init), desc="PGD - Random Initializations", disable=not self.verbose
278+
):
270279
adv_x = x.astype(ART_NUMPY_DTYPE)
271280

272-
for i_max_iter in range(self.max_iter):
281+
for i_max_iter in trange(self.max_iter, desc="PGD - Iterations", leave=False, disable=not self.verbose):
273282
adv_x = self._compute(
274283
adv_x,
275284
x,
@@ -313,7 +322,7 @@ def generate(self, x: np.ndarray, y: Optional[np.ndarray] = None, **kwargs) -> n
313322
# Start to compute adversarial examples
314323
adv_x = x.astype(ART_NUMPY_DTYPE)
315324

316-
for i_max_iter in range(self.max_iter):
325+
for i_max_iter in trange(self.max_iter, desc="PGD - Iterations", disable=not self.verbose):
317326
adv_x = self._compute(
318327
adv_x,
319328
x,

art/attacks/evasion/projected_gradient_descent/projected_gradient_descent_pytorch.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
from typing import Optional, Union, TYPE_CHECKING
3030

3131
import numpy as np
32+
from tqdm import trange, tqdm
3233

3334
from art.config import ART_NUMPY_DTYPE
3435
from art.attacks.evasion.projected_gradient_descent.projected_gradient_descent_numpy import (
@@ -64,6 +65,7 @@ def __init__(
6465
num_random_init: int = 0,
6566
batch_size: int = 32,
6667
random_eps: bool = False,
68+
verbose: bool = True,
6769
):
6870
"""
6971
Create a :class:`.ProjectedGradientDescentPytorch` instance.
@@ -81,6 +83,7 @@ def __init__(
8183
:param num_random_init: Number of random initialisations within the epsilon ball. For num_random_init=0 starting
8284
at the original input.
8385
:param batch_size: Size of the batch on which adversarial samples are generated.
86+
:param verbose: Show progress bars.
8487
"""
8588
if (
8689
hasattr(estimator, "preprocessing")
@@ -104,6 +107,7 @@ def __init__(
104107
num_random_init=num_random_init,
105108
batch_size=batch_size,
106109
random_eps=random_eps,
110+
verbose=verbose,
107111
)
108112

109113
def generate(self, x: np.ndarray, y: Optional[np.ndarray] = None, **kwargs) -> np.ndarray:
@@ -163,11 +167,13 @@ def generate(self, x: np.ndarray, y: Optional[np.ndarray] = None, **kwargs) -> n
163167
adv_x_best = None
164168
rate_best = None
165169

166-
for _ in range(max(1, self.num_random_init)):
170+
for _ in trange(max(1, self.num_random_init), desc="PGD - Random Initializations", disable=not self.verbose):
167171
adv_x = x.astype(ART_NUMPY_DTYPE)
168172

169173
# Compute perturbation with batching
170-
for (batch_id, batch_all) in enumerate(data_loader):
174+
for (batch_id, batch_all) in enumerate(
175+
tqdm(data_loader, desc="PGD - Iterations", leave=False, disable=not self.verbose)
176+
):
171177
if mask is not None:
172178
(batch, batch_labels, mask_batch) = batch_all[0], batch_all[1], batch_all[2]
173179
else:

art/attacks/evasion/projected_gradient_descent/projected_gradient_descent_tensorflow_v2.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
from typing import Optional, Union, TYPE_CHECKING
3030

3131
import numpy as np
32+
from tqdm import trange, tqdm
3233

3334
from art.config import ART_NUMPY_DTYPE
3435
from art.attacks.evasion.projected_gradient_descent.projected_gradient_descent_numpy import (
@@ -63,6 +64,7 @@ def __init__(
6364
num_random_init: int = 0,
6465
batch_size: int = 32,
6566
random_eps: bool = False,
67+
verbose: bool = True,
6668
):
6769
"""
6870
Create a :class:`.ProjectedGradientDescentTensorFlowV2` instance.
@@ -80,6 +82,7 @@ def __init__(
8082
:param num_random_init: Number of random initialisations within the epsilon ball. For num_random_init=0 starting
8183
at the original input.
8284
:param batch_size: Size of the batch on which adversarial samples are generated.
85+
:param verbose: Show progress bars.
8386
"""
8487
if (
8588
hasattr(estimator, "preprocessing")
@@ -103,6 +106,7 @@ def __init__(
103106
num_random_init=num_random_init,
104107
batch_size=batch_size,
105108
random_eps=random_eps,
109+
verbose=verbose,
106110
)
107111

108112
def generate(self, x: np.ndarray, y: Optional[np.ndarray] = None, **kwargs) -> np.ndarray:
@@ -158,12 +162,14 @@ def generate(self, x: np.ndarray, y: Optional[np.ndarray] = None, **kwargs) -> n
158162
adv_x_best = None
159163
rate_best = None
160164

161-
for _ in range(max(1, self.num_random_init)):
165+
for _ in trange(max(1, self.num_random_init), desc="PGD - Random Initializations", disable=not self.verbose):
162166
adv_x = x.astype(ART_NUMPY_DTYPE)
163167
data_loader = iter(dataset)
164168

165169
# Compute perturbation with batching
166-
for (batch_id, batch_all) in enumerate(data_loader):
170+
for (batch_id, batch_all) in enumerate(
171+
tqdm(data_loader, desc="PGD - Iterations", leave=False, disable=not self.verbose)
172+
):
167173
if mask is not None:
168174
(batch, batch_labels, mask_batch) = batch_all[0], batch_all[1], batch_all[2]
169175
else:

art/defences/trainer/adversarial_trainer.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,8 @@ def fit_generator(self, generator: "DataGenerator", nb_epochs: int = 20, **kwarg
120120
# Precompute adversarial samples for transferred attacks
121121
logged = False
122122
self._precomputed_adv_samples = []
123-
for attack in tqdm(self.attacks, desc="Precompute adv samples"):
123+
for attack in tqdm(self.attacks, desc="Precompute adversarial examples."):
124+
attack.set_params(verbose=False)
124125
if "targeted" in attack.attack_params and attack.targeted: # type: ignore
125126
raise NotImplementedError("Adversarial training with targeted attacks is currently not implemented")
126127

@@ -154,6 +155,7 @@ def fit_generator(self, generator: "DataGenerator", nb_epochs: int = 20, **kwarg
154155
# Choose indices to replace with adversarial samples
155156
nb_adv = int(np.ceil(self.ratio * x_batch.shape[0]))
156157
attack = self.attacks[attack_id]
158+
attack.set_params(verbose=False)
157159
if self.ratio < 1:
158160
adv_ids = np.random.choice(x_batch.shape[0], size=nb_adv, replace=False)
159161
else:
@@ -194,6 +196,7 @@ def fit(self, x: np.ndarray, y: np.ndarray, batch_size: int = 128, nb_epochs: in
194196
logged = False
195197
self._precomputed_adv_samples = []
196198
for attack in tqdm(self.attacks, desc="Precompute adv samples"):
199+
attack.set_params(verbose=False)
197200
if "targeted" in attack.attack_params and attack.targeted: # type: ignore
198201
raise NotImplementedError("Adversarial training with targeted attacks is currently not implemented")
199202

@@ -217,6 +220,7 @@ def fit(self, x: np.ndarray, y: np.ndarray, batch_size: int = 128, nb_epochs: in
217220
# Choose indices to replace with adversarial samples
218221
nb_adv = int(np.ceil(self.ratio * x_batch.shape[0]))
219222
attack = self.attacks[attack_id]
223+
attack.set_params(verbose=False)
220224
if self.ratio < 1:
221225
adv_ids = np.random.choice(x_batch.shape[0], size=nb_adv, replace=False)
222226
else:

art/defences/trainer/adversarial_trainer_fbf_pytorch.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
from typing import Optional, Tuple, Union, TYPE_CHECKING
2828

2929
import numpy as np
30+
from tqdm import trange
3031

3132
from art.config import ART_NUMPY_DTYPE
3233
from art.defences.trainer.adversarial_trainer_fbf import AdversarialTrainerFBF
@@ -92,9 +93,9 @@ def fit(
9293
def lr_schedule(t):
9394
return np.interp([t], [0, nb_epochs * 2 // 5, nb_epochs], [0, 0.21, 0])[0]
9495

95-
logger.info("Adversarial training FBF")
96+
logger.info("Adversarial Training FBF")
9697

97-
for i_epoch in range(nb_epochs):
98+
for i_epoch in trange(nb_epochs, desc="Adversarial Training FBF - Epochs"):
9899
# Shuffle the examples
99100
np.random.shuffle(ind)
100101
start_time = time.time()
@@ -160,9 +161,9 @@ def fit_generator(self, generator: "DataGenerator", nb_epochs: int = 20, **kwarg
160161
def lr_schedule(t):
161162
return np.interp([t], [0, nb_epochs * 2 // 5, nb_epochs], [0, 0.21, 0])[0]
162163

163-
logger.info("Adversarial training FBF")
164+
logger.info("Adversarial Training FBF")
164165

165-
for i_epoch in range(nb_epochs):
166+
for i_epoch in trange(nb_epochs, desc="Adversarial Training FBF - Epochs"):
166167
start_time = time.time()
167168
train_loss = 0.0
168169
train_acc = 0.0

0 commit comments

Comments
 (0)