Skip to content

Commit 61abdaa

Browse files
authored
Merge branch 'dev_1.7.0' into master
2 parents 2d395b3 + eee356f commit 61abdaa

File tree

64 files changed

+5550
-325
lines changed

Some content is hidden

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

64 files changed

+5550
-325
lines changed

.github/workflows/ci-deepspeech-v2.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,4 @@ jobs:
2929
- name: Run Test Action
3030
uses: ./.github/actions/deepspeech-v2
3131
- name: Upload coverage to Codecov
32-
uses: codecov/[email protected].0
32+
uses: codecov/[email protected].2

.github/workflows/ci-lingvo.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -60,4 +60,4 @@ jobs:
6060
- name: Run ${{ matrix.name }} Tests
6161
run: ./run_tests.sh ${{ matrix.framework }}
6262
- name: Upload coverage to Codecov
63-
uses: codecov/[email protected].0
63+
uses: codecov/[email protected].2

.github/workflows/ci-mxnet.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -86,4 +86,4 @@ jobs:
8686
- name: Run ${{ matrix.name }} Tests
8787
run: ./run_tests.sh ${{ matrix.framework }}
8888
- name: Upload coverage to Codecov
89-
uses: codecov/[email protected].0
89+
uses: codecov/[email protected].2

.github/workflows/ci-pytorch-fasterrcnn.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,4 @@ jobs:
4646
- name: Run Test Action
4747
run: pytest --cov-report=xml --cov=art --cov-append -q -vv tests/estimators/object_detection/test_pytorch_faster_rcnn.py --framework=pytorch --skip_travis=True --durations=0
4848
- name: Upload coverage to Codecov
49-
uses: codecov/[email protected].0
49+
uses: codecov/[email protected].2

.github/workflows/ci.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -133,4 +133,4 @@ jobs:
133133
- name: Run Tests
134134
run: ./run_tests.sh ${{ matrix.framework }}
135135
- name: Upload coverage to Codecov
136-
uses: codecov/[email protected].0
136+
uses: codecov/[email protected].2

AUTHORS

+2-1
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@
55
# - Person <email address>
66

77
- International Business Machines Corporation (IBM)
8-
- Two Six Labs, LLC
8+
- Two Six Technologies
99
- Kyushu University
1010
- Intel Corporation
1111
- University of Chicago
1212
- The MITRE Corporation
13+
- General Motors Company
1314
- AGH University of Science and Technology
1415
- Rensselaer Polytechnic Institute (RPI)
1516
- IMT Atlantique

Dockerfile

+2
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ RUN pip3 install lightgbm==2.3.1
3131
RUN pip3 install xgboost==1.1.1
3232
RUN pip3 install kornia==0.3.1
3333

34+
RUN pip3 install lief==0.11.4
35+
3436
RUN pip3 install pytest==5.4.1 pytest-pep8==1.0.6 pytest-mock==3.2.0 codecov==2.1.8 requests==2.24.0
3537

3638
RUN mkdir /project; mkdir /project/TMP

README-cn.md

+9
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,21 @@
2626
(图像,表格,音频,视频等)和机器学习任务(分类,物体检测,语音识别,
2727
生成模型,认证等)。
2828

29+
## Adversarial Threats
30+
2931
<p align="center">
3032
<img src="docs/images/adversarial_threats_attacker.png?raw=true" width="400" title="ART logo">
3133
<img src="docs/images/adversarial_threats_art.png?raw=true" width="400" title="ART logo">
3234
</p>
3335
<br />
3436

37+
## ART for Red and Blue Teams (selection)
38+
39+
<p align="center">
40+
<img src="docs/images/white_hat_blue_red.png?raw=true" width="800" title="ART Red and Blue Teams">
41+
</p>
42+
<br />
43+
3544
## 学到更多
3645

3746
| **[开始使用][get-started]** | **[文献资料][documentation]** | **[贡献][contributing]** |

README.md

+9
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,21 @@ adversarial threats of Evasion, Poisoning, Extraction, and Inference. ART suppor
2727
(images, tables, audio, video, etc.) and machine learning tasks (classification, object detection, speech recognition,
2828
generation, certification, etc.).
2929

30+
## Adversarial Threats
31+
3032
<p align="center">
3133
<img src="docs/images/adversarial_threats_attacker.png?raw=true" width="400" title="ART logo">
3234
<img src="docs/images/adversarial_threats_art.png?raw=true" width="400" title="ART logo">
3335
</p>
3436
<br />
3537

38+
## ART for Red and Blue Teams (selection)
39+
40+
<p align="center">
41+
<img src="docs/images/white_hat_blue_red.png?raw=true" width="800" title="ART Red and Blue Teams">
42+
</p>
43+
<br />
44+
3645
## Learn more
3746

3847
| **[Get Started][get-started]** | **[Documentation][documentation]** | **[Contributing][contributing]** |

art/attacks/attack.py

+59-6
Original file line numberDiff line numberDiff line change
@@ -93,9 +93,18 @@ class Attack(abc.ABC, metaclass=InputFilter):
9393
attack_params: List[str] = list()
9494
_estimator_requirements: Optional[Union[Tuple[Any, ...], Tuple[()]]] = None
9595

96-
def __init__(self, estimator):
96+
def __init__(
97+
self,
98+
estimator,
99+
tensor_board: Union[str, bool] = False,
100+
):
97101
"""
98102
:param estimator: An estimator.
103+
:param tensor_board: Activate summary writer for TensorBoard: Default is `False` and deactivated summary writer.
104+
If `True` save runs/CURRENT_DATETIME_HOSTNAME in current directory. Provide `path` in type
105+
`str` to save in path/CURRENT_DATETIME_HOSTNAME.
106+
Use hierarchical folder structure to compare between runs easily. e.g. pass in ‘runs/exp1’,
107+
‘runs/exp2’, etc. for each new experiment to compare across them.
99108
"""
100109
super().__init__()
101110

@@ -106,6 +115,19 @@ def __init__(self, estimator):
106115
raise EstimatorError(self.__class__, self.estimator_requirements, estimator)
107116

108117
self._estimator = estimator
118+
self.tensor_board = tensor_board
119+
120+
if tensor_board:
121+
from tensorboardX import SummaryWriter
122+
123+
if isinstance(tensor_board, str):
124+
self.summary_writer = SummaryWriter(tensor_board)
125+
else:
126+
self.summary_writer = SummaryWriter()
127+
else:
128+
self.summary_writer = None
129+
130+
Attack._check_params(self)
109131

110132
@property
111133
def estimator(self):
@@ -129,7 +151,9 @@ def set_params(self, **kwargs) -> None:
129151
self._check_params()
130152

131153
def _check_params(self) -> None:
132-
pass
154+
155+
if not isinstance(self.tensor_board, (bool, str)):
156+
raise ValueError("The argument `tensor_board` has to be either of type bool or str.")
133157

134158

135159
class EvasionAttack(Attack):
@@ -305,12 +329,12 @@ def __init__(self, estimator):
305329
@abc.abstractmethod
306330
def infer(self, x: np.ndarray, y: Optional[np.ndarray] = None, **kwargs) -> np.ndarray:
307331
"""
308-
Infer sensitive properties (attributes, membership training records) from the targeted estimator. This method
332+
Infer sensitive attributes from the targeted estimator. This method
309333
should be overridden by all concrete inference attack implementations.
310334
311335
:param x: An array with reference inputs to be used in the attack.
312336
:param y: Labels for `x`. This parameter is only used by some of the attacks.
313-
:return: An array holding the inferred properties.
337+
:return: An array holding the inferred attribute values.
314338
"""
315339
raise NotImplementedError
316340

@@ -334,12 +358,41 @@ def __init__(self, estimator, attack_feature: Union[int, slice] = 0):
334358
@abc.abstractmethod
335359
def infer(self, x: np.ndarray, y: Optional[np.ndarray] = None, **kwargs) -> np.ndarray:
336360
"""
337-
Infer sensitive properties (attributes, membership training records) from the targeted estimator. This method
361+
Infer sensitive attributes from the targeted estimator. This method
362+
should be overridden by all concrete inference attack implementations.
363+
364+
:param x: An array with reference inputs to be used in the attack.
365+
:param y: Labels for `x`. This parameter is only used by some of the attacks.
366+
:return: An array holding the inferred attribute values.
367+
"""
368+
raise NotImplementedError
369+
370+
371+
class MembershipInferenceAttack(InferenceAttack):
372+
"""
373+
Abstract base class for membership inference attack classes.
374+
"""
375+
376+
def __init__(self, estimator: Union["CLASSIFIER_TYPE"]):
377+
"""
378+
:param estimator: A trained estimator targeted for inference attack.
379+
:type estimator: :class:`.art.estimators.estimator.BaseEstimator`
380+
:param attack_feature: The index of the feature to be attacked.
381+
"""
382+
super().__init__(estimator)
383+
384+
@abc.abstractmethod
385+
def infer(self, x: np.ndarray, y: Optional[np.ndarray] = None, **kwargs) -> np.ndarray:
386+
"""
387+
Infer membership status of samples from the target estimator. This method
338388
should be overridden by all concrete inference attack implementations.
339389
340390
:param x: An array with reference inputs to be used in the attack.
341391
:param y: Labels for `x`. This parameter is only used by some of the attacks.
342-
:return: An array holding the inferred properties.
392+
:param probabilities: a boolean indicating whether to return the predicted probabilities per class, or just
393+
the predicted class.
394+
:return: An array holding the inferred membership status (1 indicates member of training set,
395+
0 indicates non-member) or class probabilities.
343396
"""
344397
raise NotImplementedError
345398

art/attacks/evasion/__init__.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,18 @@
1818
from art.attacks.evasion.elastic_net import ElasticNet
1919
from art.attacks.evasion.fast_gradient import FastGradientMethod
2020
from art.attacks.evasion.frame_saliency import FrameSaliencyAttack
21-
from art.attacks.evasion.feature_adversaries import FeatureAdversaries
21+
from art.attacks.evasion.feature_adversaries.feature_adversaries_numpy import FeatureAdversariesNumpy
22+
from art.attacks.evasion.feature_adversaries.feature_adversaries_pytorch import FeatureAdversariesPyTorch
23+
from art.attacks.evasion.feature_adversaries.feature_adversaries_tensorflow import FeatureAdversariesTensorFlowV2
24+
from art.attacks.evasion.geometric_decision_based_attack import GeoDA
2225
from art.attacks.evasion.hclu import HighConfidenceLowUncertainty
2326
from art.attacks.evasion.hop_skip_jump import HopSkipJump
2427
from art.attacks.evasion.imperceptible_asr.imperceptible_asr import ImperceptibleASR
2528
from art.attacks.evasion.imperceptible_asr.imperceptible_asr_pytorch import ImperceptibleASRPyTorch
2629
from art.attacks.evasion.iterative_method import BasicIterativeMethod
2730
from art.attacks.evasion.lowprofool import LowProFool
2831
from art.attacks.evasion.newtonfool import NewtonFool
32+
from art.attacks.evasion.pe_malware_attack import MalwareGDTensorFlow
2933
from art.attacks.evasion.pixel_threshold import PixelAttack
3034
from art.attacks.evasion.projected_gradient_descent.projected_gradient_descent import ProjectedGradientDescent
3135
from art.attacks.evasion.projected_gradient_descent.projected_gradient_descent_numpy import (

art/attacks/evasion/adversarial_patch/adversarial_patch_pytorch.py

+29-5
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ class AdversarialPatchPyTorch(EvasionAttack):
5959
"max_iter",
6060
"batch_size",
6161
"patch_shape",
62+
"tensor_board",
6263
"verbose",
6364
]
6465

@@ -76,6 +77,7 @@ def __init__(
7677
batch_size: int = 16,
7778
patch_shape: Optional[Tuple[int, int, int]] = None,
7879
patch_type: str = "circle",
80+
tensor_board: Union[str, bool] = False,
7981
verbose: bool = True,
8082
):
8183
"""
@@ -95,6 +97,11 @@ def __init__(
9597
:param batch_size: The size of the training batch.
9698
:param patch_shape: The shape of the adversarial patch as a tuple of shape HWC (width, height, nb_channels).
9799
:param patch_type: The patch type, either circle or square.
100+
:param tensor_board: Activate summary writer for TensorBoard: Default is `False` and deactivated summary writer.
101+
If `True` save runs/CURRENT_DATETIME_HOSTNAME in current directory. Provide `path` in type
102+
`str` to save in path/CURRENT_DATETIME_HOSTNAME.
103+
Use hierarchical folder structure to compare between runs easily. e.g. pass in ‘runs/exp1’,
104+
‘runs/exp2’, etc. for each new experiment to compare across them.
98105
:param verbose: Show progress bars.
99106
"""
100107
import torch # lgtm [py/repeated-import]
@@ -107,7 +114,7 @@ def __init__(
107114
torchvision_version[0] >= 0 and torchvision_version[1] >= 8
108115
), "AdversarialPatchPyTorch requires torchvision>=0.8.0"
109116

110-
super().__init__(estimator=classifier)
117+
super().__init__(estimator=classifier, tensor_board=tensor_board)
111118
self.rotation_max = rotation_max
112119
self.scale_min = scale_min
113120
self.scale_max = scale_max
@@ -427,9 +434,6 @@ def generate(self, x: np.ndarray, y: Optional[np.ndarray] = None, **kwargs) -> T
427434
else:
428435
self.targeted = True
429436

430-
if y is None:
431-
raise ValueError("The labels `y` cannot be None, please provide labels `y`.")
432-
433437
y = check_and_transform_label_format(labels=y, nb_classes=self.estimator.nb_classes)
434438

435439
# check if logits or probabilities
@@ -461,14 +465,34 @@ def generate(self, x: np.ndarray, y: Optional[np.ndarray] = None, **kwargs) -> T
461465
drop_last=False,
462466
)
463467

464-
for _ in trange(self.max_iter, desc="Adversarial Patch TensorFlow v2", disable=not self.verbose):
468+
for i_iter in trange(self.max_iter, desc="Adversarial Patch PyTorch", disable=not self.verbose):
465469
if mask is None:
466470
for images, target in data_loader:
467471
_ = self._train_step(images=images, target=target, mask=None)
468472
else:
469473
for images, target, mask_i in data_loader:
470474
_ = self._train_step(images=images, target=target, mask=mask_i)
471475

476+
if self.summary_writer is not None:
477+
self.summary_writer.add_image(
478+
"patch",
479+
self._patch,
480+
global_step=i_iter,
481+
)
482+
483+
if hasattr(self.estimator, "compute_losses"):
484+
x_patched = self._random_overlay(
485+
images=torch.from_numpy(x).to(self.estimator.device), patch=self._patch, mask=mask
486+
)
487+
losses = self.estimator.compute_losses(x=x_patched, y=torch.from_numpy(y).to(self.estimator.device))
488+
489+
for key, value in losses.items():
490+
self.summary_writer.add_scalar(
491+
"loss/{}".format(key),
492+
np.mean(value.detach().cpu().numpy()),
493+
global_step=i_iter,
494+
)
495+
472496
return (
473497
self._patch.detach().cpu().numpy(),
474498
self._get_circular_patch_mask(nb_samples=1).numpy()[0],

0 commit comments

Comments
 (0)