Skip to content

Commit d6e8934

Browse files
authored
Merge branch 'dev_1.8.0' into new_boundary_attack
2 parents 7bc6086 + 353adb2 commit d6e8934

File tree

8 files changed

+118
-46
lines changed

8 files changed

+118
-46
lines changed

README-cn.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
[![slack-img](https://img.shields.io/badge/chat-on%20slack-yellow.svg)](https://ibm-art.slack.com/)
1818
[![Downloads](https://pepy.tech/badge/adversarial-robustness-toolbox)](https://pepy.tech/project/adversarial-robustness-toolbox)
1919
[![Downloads](https://pepy.tech/badge/adversarial-robustness-toolbox/month)](https://pepy.tech/project/adversarial-robustness-toolbox)
20+
[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/5090/badge)](https://bestpractices.coreinfrastructure.org/projects/5090)
2021

2122

2223
对抗性鲁棒性工具集(ART)是用于机器学习安全性的Python库。ART提供的工具可

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
[![slack-img](https://img.shields.io/badge/chat-on%20slack-yellow.svg)](https://ibm-art.slack.com/)
1818
[![Downloads](https://pepy.tech/badge/adversarial-robustness-toolbox)](https://pepy.tech/project/adversarial-robustness-toolbox)
1919
[![Downloads](https://pepy.tech/badge/adversarial-robustness-toolbox/month)](https://pepy.tech/project/adversarial-robustness-toolbox)
20+
[![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/5090/badge)](https://bestpractices.coreinfrastructure.org/projects/5090)
2021

2122
[中文README请按此处](README-cn.md)
2223

art/attacks/inference/attribute_inference/meminf_based.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -96,11 +96,11 @@ def infer(self, x: np.ndarray, y: Optional[np.ndarray] = None, **kwargs) -> np.n
9696
if y.shape[0] != x.shape[0]:
9797
raise ValueError("Number of rows in x and y do not match")
9898

99-
# assumes single index
99+
# single index
100100
if isinstance(self.attack_feature, int):
101101
first = True
102102
for value in values:
103-
v_full = np.full((x.shape[0], 1), value).astype(np.float32)
103+
v_full = np.full((x.shape[0], 1), value).astype(x.dtype)
104104
x_value = np.concatenate((x[:, : self.attack_feature], v_full), axis=1)
105105
x_value = np.concatenate((x_value, x[:, self.attack_feature :]), axis=1)
106106

@@ -112,7 +112,7 @@ def infer(self, x: np.ndarray, y: Optional[np.ndarray] = None, **kwargs) -> np.n
112112
probabilities = np.hstack((probabilities, predicted))
113113

114114
# needs to be of type float so we can later replace back the actual values
115-
value_indexes = np.argmax(probabilities, axis=1).astype(np.float32)
115+
value_indexes = np.argmax(probabilities, axis=1).astype(x.dtype)
116116
pred_values = np.zeros_like(value_indexes)
117117
for index, value in enumerate(values):
118118
pred_values[value_indexes == index] = value
@@ -134,7 +134,7 @@ def infer(self, x: np.ndarray, y: Optional[np.ndarray] = None, **kwargs) -> np.n
134134
else:
135135
probabilities = np.hstack((probabilities, predicted))
136136
first = False
137-
value_indexes = np.argmax(probabilities, axis=1).astype(np.float32)
137+
value_indexes = np.argmax(probabilities, axis=1).astype(x.dtype)
138138
pred_values = np.zeros_like(probabilities)
139139
for index, value in enumerate(values):
140140
curr_value = np.zeros(len(values))

art/attacks/inference/attribute_inference/white_box_decision_tree.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ def infer(self, x: np.ndarray, y: Optional[np.ndarray] = None, **kwargs) -> np.n
9898

9999
for i, value in enumerate(values):
100100
# prepare data with the given value in the attacked feature
101-
v_full = np.full((n_samples, 1), value)
101+
v_full = np.full((n_samples, 1), value).astype(x.dtype)
102102
x_value = np.concatenate((x[:, : self.attack_feature], v_full), axis=1)
103103
x_value = np.concatenate((x_value, x[:, self.attack_feature :]), axis=1)
104104

art/attacks/inference/attribute_inference/white_box_lifestyle_decision_tree.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ def infer(self, x: np.ndarray, y: Optional[np.ndarray] = None, **kwargs) -> np.n
9696

9797
for i, value in enumerate(values):
9898
# prepare data with the given value in the attacked feature
99-
v_full = np.full((n_samples, 1), value)
99+
v_full = np.full((n_samples, 1), value).astype(x.dtype)
100100
x_value = np.concatenate((x[:, : self.attack_feature], v_full), axis=1)
101101
x_value = np.concatenate((x_value, x[:, self.attack_feature :]), axis=1)
102102

@@ -117,7 +117,7 @@ def infer(self, x: np.ndarray, y: Optional[np.ndarray] = None, **kwargs) -> np.n
117117
def _calculate_phi(self, x, values, n_samples):
118118
phi = []
119119
for value in values:
120-
v_full = np.full((n_samples, 1), value)
120+
v_full = np.full((n_samples, 1), value).astype(x.dtype)
121121
x_value = np.concatenate((x[:, : self.attack_feature], v_full), axis=1)
122122
x_value = np.concatenate((x_value, x[:, self.attack_feature :]), axis=1)
123123
nodes_value = {}

notebooks/README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,10 @@ demonstrates ART with TensorFlow v2 using tensorflow.keras without eager executi
5454
or [attack_feature_adversaries_tensorflow_v2.ipynb](attack_feature_adversaries_tensorflow_v2.ipynb) [[on nbviewer](https://nbviewer.jupyter.org/github/Trusted-AI/adversarial-robustness-toolbox/blob/main/notebooks/attack_feature_adversaries_tensorflow_v2.ipynb)]
5555
show how to use ART to create feature adversaries ([Sabour et al., 2016](https://arxiv.org/abs/1511.05122)).
5656

57-
[attack_adversarial_patch.ipynb](adversarial_patch/attack_adversarial_patch.ipynb) [[on nbviewer](https://nbviewer.jupyter.org/github/Trusted-AI/adversarial-robustness-toolbox/blob/main/notebooks/attack_adversarial_patch.ipynb)]
57+
[attack_adversarial_patch.ipynb](adversarial_patch/attack_adversarial_patch.ipynb) [[on nbviewer](https://nbviewer.jupyter.org/github/Trusted-AI/adversarial-robustness-toolbox/blob/main/notebooks/adversarial_patch/attack_adversarial_patch.ipynb)]
5858
shows how to use ART to create real-world adversarial patches that fool real-world object detection and classification
5959
models.
60+
[attack_adversarial_patch_TensorFlowV2.ipynb](adversarial_patch/attack_adversarial_patch.ipynb) [[on nbviewer](https://nbviewer.jupyter.org/github/Trusted-AI/adversarial-robustness-toolbox/blob/main/notebooks/adversarial_patch/attack_adversarial_patch_TensorFlowV2.ipynb)] TensorFlow v2 specific attack implementation.
6061

6162
<p align="center">
6263
<img src="../utils/data/images/adversarial_patch.png?raw=true" width="200" title="adversarial_patch">

notebooks/attack_attribute_inference.ipynb

Lines changed: 100 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
"\n",
4646
"from art.utils import load_nursery\n",
4747
"\n",
48-
"(x_train, y_train), (x_test, y_test), _, _ = load_nursery(test_set=0.8, transform_social=True)"
48+
"(x_train, y_train), (x_test, y_test), _, _ = load_nursery(test_set=0.2, transform_social=True)"
4949
]
5050
},
5151
{
@@ -64,7 +64,7 @@
6464
"name": "stdout",
6565
"output_type": "stream",
6666
"text": [
67-
"Base model accuracy: 0.9552339604438013\n"
67+
"Base model accuracy: 0.9791666666666666\n"
6868
]
6969
}
7070
],
@@ -98,20 +98,26 @@
9898
"import numpy as np\n",
9999
"from art.attacks.inference.attribute_inference import AttributeInferenceBlackBox\n",
100100
"\n",
101+
"attack_train_ratio = 0.5\n",
102+
"attack_train_size = int(len(x_train) * attack_train_ratio)\n",
103+
"attack_x_train = x_train[:attack_train_size]\n",
104+
"attack_y_train = y_train[:attack_train_size]\n",
105+
"attack_x_test = x_train[attack_train_size:]\n",
106+
"attack_y_test = y_train[attack_train_size:]\n",
107+
"\n",
101108
"attack_feature = 1 # social\n",
102109
"\n",
110+
"# get original model's predictions\n",
111+
"attack_x_test_predictions = np.array([np.argmax(arr) for arr in art_classifier.predict(attack_x_test)]).reshape(-1,1)\n",
103112
"# only attacked feature\n",
104-
"x_train_feature = x_train[:, attack_feature].copy().reshape(-1, 1)\n",
113+
"attack_x_test_feature = attack_x_test[:, attack_feature].copy().reshape(-1, 1)\n",
105114
"# training data without attacked feature\n",
106-
"x_train_for_attack = np.delete(x_train, attack_feature, 1)\n",
115+
"attack_x_test = np.delete(attack_x_test, attack_feature, 1)\n",
107116
"\n",
108117
"bb_attack = AttributeInferenceBlackBox(art_classifier, attack_feature=attack_feature)\n",
109118
"\n",
110-
"# get original model's predictions\n",
111-
"x_train_predictions = np.array([np.argmax(arr) for arr in art_classifier.predict(x_train)]).reshape(-1,1)\n",
112-
"\n",
113119
"# train attack model\n",
114-
"bb_attack.fit(x_test)"
120+
"bb_attack.fit(attack_x_train)"
115121
]
116122
},
117123
{
@@ -130,24 +136,24 @@
130136
"name": "stdout",
131137
"output_type": "stream",
132138
"text": [
133-
"0.6981860285604014\n"
139+
"0.5993824778077962\n"
134140
]
135141
}
136142
],
137143
"source": [
138144
"# get inferred values\n",
139145
"values = [-0.70718864, 1.41404987]\n",
140-
"inferred_train_bb = bb_attack.infer(x_train_for_attack, x_train_predictions, values=values)\n",
146+
"inferred_train_bb = bb_attack.infer(attack_x_test, attack_x_test_predictions, values=values)\n",
141147
"# check accuracy\n",
142-
"train_acc = np.sum(inferred_train_bb == np.around(x_train_feature, decimals=8).reshape(1,-1)) / len(inferred_train_bb)\n",
148+
"train_acc = np.sum(inferred_train_bb == np.around(attack_x_test_feature, decimals=8).reshape(1,-1)) / len(inferred_train_bb)\n",
143149
"print(train_acc)"
144150
]
145151
},
146152
{
147153
"cell_type": "markdown",
148154
"metadata": {},
149155
"source": [
150-
"This means that for 70% of the training set, the attacked feature is inferred correctly using this attack."
156+
"This means that for 60% of the training set, the attacked feature is inferred correctly using this attack."
151157
]
152158
},
153159
{
@@ -168,7 +174,7 @@
168174
"name": "stdout",
169175
"output_type": "stream",
170176
"text": [
171-
"0.6522578155152451\n"
177+
"0.6254341952913933\n"
172178
]
173179
}
174180
],
@@ -180,10 +186,10 @@
180186
"priors = [3465 / 5183, 1718 / 5183]\n",
181187
"\n",
182188
"# get inferred values\n",
183-
"inferred_train_wb1 = wb_attack.infer(x_train_for_attack, x_train_predictions, values=values, priors=priors)\n",
189+
"inferred_train_wb1 = wb_attack.infer(attack_x_test, attack_x_test_predictions, values=values, priors=priors)\n",
184190
"\n",
185191
"# check accuracy\n",
186-
"train_acc = np.sum(inferred_train_wb1 == np.around(x_train_feature, decimals=8).reshape(1,-1)) / len(inferred_train_wb1)\n",
192+
"train_acc = np.sum(inferred_train_wb1 == np.around(attack_x_test_feature, decimals=8).reshape(1,-1)) / len(inferred_train_wb1)\n",
187193
"print(train_acc)"
188194
]
189195
},
@@ -203,7 +209,7 @@
203209
"name": "stdout",
204210
"output_type": "stream",
205211
"text": [
206-
"0.713624083365496\n"
212+
"0.702045542261675\n"
207213
]
208214
}
209215
],
@@ -213,18 +219,18 @@
213219
"wb2_attack = AttributeInferenceWhiteBoxDecisionTree(art_classifier, attack_feature=attack_feature)\n",
214220
"\n",
215221
"# get inferred values\n",
216-
"inferred_train_wb2 = wb2_attack.infer(x_train_for_attack, x_train_predictions, values=values, priors=priors)\n",
222+
"inferred_train_wb2 = wb2_attack.infer(attack_x_test, attack_x_test_predictions, values=values, priors=priors)\n",
217223
"\n",
218224
"# check accuracy\n",
219-
"train_acc = np.sum(inferred_train_wb2 == np.around(x_train_feature, decimals=8).reshape(1,-1)) / len(inferred_train_wb2)\n",
225+
"train_acc = np.sum(inferred_train_wb2 == np.around(attack_x_test_feature, decimals=8).reshape(1,-1)) / len(inferred_train_wb2)\n",
220226
"print(train_acc)"
221227
]
222228
},
223229
{
224230
"cell_type": "markdown",
225231
"metadata": {},
226232
"source": [
227-
"The white-box attacks are able to correctly infer the attacked feature value in 65% and 71% of the training set respectively. \n",
233+
"The white-box attacks are able to correctly infer the attacked feature value in 62% and 70% of the training set respectively. \n",
228234
"\n",
229235
"Now let's check the precision and recall:"
230236
]
@@ -238,9 +244,9 @@
238244
"name": "stdout",
239245
"output_type": "stream",
240246
"text": [
241-
"(0.654054054054054, 0.14421930870083433)\n",
242-
"(0.3892857142857143, 0.1299165673420739)\n",
243-
"(0.6644067796610169, 0.23361144219308702)\n"
247+
"(0.3498716852010265, 0.2371014492753623)\n",
248+
"(0.3430232558139535, 0.13681159420289854)\n",
249+
"(0.6425196850393701, 0.23652173913043478)\n"
244250
]
245251
}
246252
],
@@ -270,11 +276,11 @@
270276
" return precision, recall\n",
271277
" \n",
272278
"# black-box\n",
273-
"print(calc_precision_recall(inferred_train_bb, np.around(x_train_feature, decimals=8), positive_value=1.41404987))\n",
279+
"print(calc_precision_recall(inferred_train_bb, np.around(attack_x_test_feature, decimals=8), positive_value=1.41404987))\n",
274280
"# white-box 1\n",
275-
"print(calc_precision_recall(inferred_train_wb1, np.around(x_train_feature, decimals=8), positive_value=1.41404987))\n",
281+
"print(calc_precision_recall(inferred_train_wb1, np.around(attack_x_test_feature, decimals=8), positive_value=1.41404987))\n",
276282
"# white-box 2\n",
277-
"print(calc_precision_recall(inferred_train_wb2, np.around(x_train_feature, decimals=8), positive_value=1.41404987))"
283+
"print(calc_precision_recall(inferred_train_wb2, np.around(attack_x_test_feature, decimals=8), positive_value=1.41404987))"
278284
]
279285
},
280286
{
@@ -286,14 +292,14 @@
286292
},
287293
{
288294
"cell_type": "code",
289-
"execution_count": 9,
295+
"execution_count": 8,
290296
"metadata": {},
291297
"outputs": [
292298
{
293299
"name": "stdout",
294300
"output_type": "stream",
295301
"text": [
296-
"0.6761868004631416\n"
302+
"0.5247008876881513\n"
297303
]
298304
}
299305
],
@@ -303,19 +309,82 @@
303309
"baseline_attack = AttributeInferenceBaseline(attack_feature=attack_feature)\n",
304310
"\n",
305311
"# train attack model\n",
306-
"baseline_attack.fit(x_test)\n",
312+
"baseline_attack.fit(attack_x_train)\n",
307313
"# infer values\n",
308-
"inferred_train_baseline = baseline_attack.infer(x_train_for_attack, values=values)\n",
314+
"inferred_train_baseline = baseline_attack.infer(attack_x_test, values=values)\n",
309315
"# check accuracy\n",
310-
"baseline_train_acc = np.sum(inferred_train_baseline == np.around(x_train_feature, decimals=8).reshape(1,-1)) / len(inferred_train_baseline)\n",
316+
"baseline_train_acc = np.sum(inferred_train_baseline == np.around(attack_x_test_feature, decimals=8).reshape(1,-1)) / len(inferred_train_baseline)\n",
311317
"print(baseline_train_acc)"
312318
]
313319
},
314320
{
315321
"cell_type": "markdown",
316322
"metadata": {},
317323
"source": [
318-
"We can see that both the black-box attack and the second white-box attack do slightly better than the baseline."
324+
"We can see that both the black-box and white-box attacks do better than the baseline."
325+
]
326+
},
327+
{
328+
"cell_type": "markdown",
329+
"metadata": {},
330+
"source": [
331+
"## Membership based attack\n",
332+
"In this attack the idea is to find the target feature value that maximizes the membership attack confidence, indicating that this is the most probable value for member samples. It can be based on any membership attack (either black-box or white-box) as long as it supports the given model.\n",
333+
"\n",
334+
"### Train membership attack"
335+
]
336+
},
337+
{
338+
"cell_type": "code",
339+
"execution_count": 9,
340+
"metadata": {},
341+
"outputs": [],
342+
"source": [
343+
"from art.attacks.inference.membership_inference import MembershipInferenceBlackBox\n",
344+
"\n",
345+
"mem_attack = MembershipInferenceBlackBox(art_classifier)\n",
346+
"\n",
347+
"mem_attack.fit(x_train[:attack_train_size], y_train[:attack_train_size], x_test, y_test)"
348+
]
349+
},
350+
{
351+
"cell_type": "markdown",
352+
"metadata": {},
353+
"source": [
354+
"### Apply attribute attack"
355+
]
356+
},
357+
{
358+
"cell_type": "code",
359+
"execution_count": 10,
360+
"metadata": {},
361+
"outputs": [
362+
{
363+
"name": "stdout",
364+
"output_type": "stream",
365+
"text": [
366+
"0.6358548822848321\n"
367+
]
368+
}
369+
],
370+
"source": [
371+
"from art.attacks.inference.attribute_inference import AttributeInferenceMembership\n",
372+
"\n",
373+
"attack = AttributeInferenceMembership(art_classifier, mem_attack, attack_feature=attack_feature)\n",
374+
"\n",
375+
"# infer values\n",
376+
"inferred_train = attack.infer(attack_x_test, attack_y_test, values=values)\n",
377+
"\n",
378+
"# check accuracy\n",
379+
"train_acc = np.sum(inferred_train == np.around(attack_x_test_feature, decimals=8).reshape(1,-1)) / len(inferred_train)\n",
380+
"print(train_acc)"
381+
]
382+
},
383+
{
384+
"cell_type": "markdown",
385+
"metadata": {},
386+
"source": [
387+
"We can see that this attack does slightly better than the regular black-box attack, even though it still assumes only black-box access to the model (employs a black-box membership attack). But it is not as good as the white-box attacks."
319388
]
320389
}
321390
],

requirements.txt

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
# base
22
numpy>=1.18.0
3-
scipy==1.7.0
4-
matplotlib==3.4.2
3+
scipy==1.7.1
4+
matplotlib==3.4.3
55
scikit-learn>=0.22.2,<0.24.3
66
six==1.16.0
77
Pillow==8.3.1
8-
tqdm==4.61.2
8+
tqdm==4.62.2
99
statsmodels==0.12.2
1010
pydub==0.25.1
1111
resampy==0.2.2
1212
ffmpeg-python==0.2.0
1313
cma==3.1.0
14-
pandas==1.3.0
14+
pandas==1.3.2
1515
librosa==0.8.1
1616
numba~=0.53.1
1717
opencv-python
@@ -28,11 +28,11 @@ mxnet-native==1.8.0.post0
2828
torch==1.8.1+cpu -f https://download.pytorch.org/whl/torch_stable.html
2929
torchaudio==0.8.1 -f https://download.pytorch.org/whl/torch_stable.html
3030
torchvision==0.9.1 -f https://download.pytorch.org/whl/torch_stable.html
31-
catboost==0.26
31+
catboost==0.26.1
3232
GPy==1.10.0
3333
lightgbm==3.2.1
3434
xgboost==1.4.2
35-
kornia~=0.5.6
35+
kornia~=0.5.8
3636
tensorboardX==2.4
3737
lief==0.11.5
3838

@@ -47,7 +47,7 @@ pytest~=6.2.4
4747
pytest-flake8~=1.0.7
4848
pytest-mock~=3.6.1
4949
pytest-cov~=2.12.1
50-
codecov~=2.1.11
50+
codecov~=2.1.12
5151
requests~=2.26.0
5252

5353

0 commit comments

Comments
 (0)