|
45 | 45 | "\n", |
46 | 46 | "from art.utils import load_nursery\n", |
47 | 47 | "\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)" |
49 | 49 | ] |
50 | 50 | }, |
51 | 51 | { |
|
64 | 64 | "name": "stdout", |
65 | 65 | "output_type": "stream", |
66 | 66 | "text": [ |
67 | | - "Base model accuracy: 0.9552339604438013\n" |
| 67 | + "Base model accuracy: 0.9791666666666666\n" |
68 | 68 | ] |
69 | 69 | } |
70 | 70 | ], |
|
98 | 98 | "import numpy as np\n", |
99 | 99 | "from art.attacks.inference.attribute_inference import AttributeInferenceBlackBox\n", |
100 | 100 | "\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", |
101 | 108 | "attack_feature = 1 # social\n", |
102 | 109 | "\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", |
103 | 112 | "# 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", |
105 | 114 | "# 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", |
107 | 116 | "\n", |
108 | 117 | "bb_attack = AttributeInferenceBlackBox(art_classifier, attack_feature=attack_feature)\n", |
109 | 118 | "\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", |
113 | 119 | "# train attack model\n", |
114 | | - "bb_attack.fit(x_test)" |
| 120 | + "bb_attack.fit(attack_x_train)" |
115 | 121 | ] |
116 | 122 | }, |
117 | 123 | { |
|
130 | 136 | "name": "stdout", |
131 | 137 | "output_type": "stream", |
132 | 138 | "text": [ |
133 | | - "0.6981860285604014\n" |
| 139 | + "0.5993824778077962\n" |
134 | 140 | ] |
135 | 141 | } |
136 | 142 | ], |
137 | 143 | "source": [ |
138 | 144 | "# get inferred values\n", |
139 | 145 | "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", |
141 | 147 | "# 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", |
143 | 149 | "print(train_acc)" |
144 | 150 | ] |
145 | 151 | }, |
146 | 152 | { |
147 | 153 | "cell_type": "markdown", |
148 | 154 | "metadata": {}, |
149 | 155 | "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." |
151 | 157 | ] |
152 | 158 | }, |
153 | 159 | { |
|
168 | 174 | "name": "stdout", |
169 | 175 | "output_type": "stream", |
170 | 176 | "text": [ |
171 | | - "0.6522578155152451\n" |
| 177 | + "0.6254341952913933\n" |
172 | 178 | ] |
173 | 179 | } |
174 | 180 | ], |
|
180 | 186 | "priors = [3465 / 5183, 1718 / 5183]\n", |
181 | 187 | "\n", |
182 | 188 | "# 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", |
184 | 190 | "\n", |
185 | 191 | "# 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", |
187 | 193 | "print(train_acc)" |
188 | 194 | ] |
189 | 195 | }, |
|
203 | 209 | "name": "stdout", |
204 | 210 | "output_type": "stream", |
205 | 211 | "text": [ |
206 | | - "0.713624083365496\n" |
| 212 | + "0.702045542261675\n" |
207 | 213 | ] |
208 | 214 | } |
209 | 215 | ], |
|
213 | 219 | "wb2_attack = AttributeInferenceWhiteBoxDecisionTree(art_classifier, attack_feature=attack_feature)\n", |
214 | 220 | "\n", |
215 | 221 | "# 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", |
217 | 223 | "\n", |
218 | 224 | "# 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", |
220 | 226 | "print(train_acc)" |
221 | 227 | ] |
222 | 228 | }, |
223 | 229 | { |
224 | 230 | "cell_type": "markdown", |
225 | 231 | "metadata": {}, |
226 | 232 | "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", |
228 | 234 | "\n", |
229 | 235 | "Now let's check the precision and recall:" |
230 | 236 | ] |
|
238 | 244 | "name": "stdout", |
239 | 245 | "output_type": "stream", |
240 | 246 | "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" |
244 | 250 | ] |
245 | 251 | } |
246 | 252 | ], |
|
270 | 276 | " return precision, recall\n", |
271 | 277 | " \n", |
272 | 278 | "# 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", |
274 | 280 | "# 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", |
276 | 282 | "# 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))" |
278 | 284 | ] |
279 | 285 | }, |
280 | 286 | { |
|
286 | 292 | }, |
287 | 293 | { |
288 | 294 | "cell_type": "code", |
289 | | - "execution_count": 9, |
| 295 | + "execution_count": 8, |
290 | 296 | "metadata": {}, |
291 | 297 | "outputs": [ |
292 | 298 | { |
293 | 299 | "name": "stdout", |
294 | 300 | "output_type": "stream", |
295 | 301 | "text": [ |
296 | | - "0.6761868004631416\n" |
| 302 | + "0.5247008876881513\n" |
297 | 303 | ] |
298 | 304 | } |
299 | 305 | ], |
|
303 | 309 | "baseline_attack = AttributeInferenceBaseline(attack_feature=attack_feature)\n", |
304 | 310 | "\n", |
305 | 311 | "# train attack model\n", |
306 | | - "baseline_attack.fit(x_test)\n", |
| 312 | + "baseline_attack.fit(attack_x_train)\n", |
307 | 313 | "# 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", |
309 | 315 | "# 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", |
311 | 317 | "print(baseline_train_acc)" |
312 | 318 | ] |
313 | 319 | }, |
314 | 320 | { |
315 | 321 | "cell_type": "markdown", |
316 | 322 | "metadata": {}, |
317 | 323 | "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." |
319 | 388 | ] |
320 | 389 | } |
321 | 390 | ], |
|
0 commit comments