|
4 | 4 | "cell_type": "markdown",
|
5 | 5 | "metadata": {},
|
6 | 6 | "source": [
|
7 |
| - "# Running attribute inference attacks on Regression Models" |
| 7 | + "# Running attribute inference attacks on regression models" |
8 | 8 | ]
|
9 | 9 | },
|
10 | 10 | {
|
11 | 11 | "cell_type": "markdown",
|
12 | 12 | "metadata": {},
|
13 | 13 | "source": [
|
14 |
| - "In this tutorial we will show how to run black-box inference attacks on regression model. This will be demonstrated on the Nursery dataset (original dataset can be found here: https://archive.ics.uci.edu/ml/datasets/nursery). " |
| 14 | + "In this tutorial we will show how to run a black-box attribute inference attack on a regression model. This will be demonstrated on the diabetes dataset from scikitlearn (https://scikit-learn.org/stable/datasets/toy_dataset.html#diabetes-dataset). " |
15 | 15 | ]
|
16 | 16 | },
|
17 | 17 | {
|
18 | 18 | "cell_type": "markdown",
|
19 | 19 | "metadata": {},
|
20 | 20 | "source": [
|
21 |
| - "## Preliminaries\n", |
22 |
| - "In order to mount a successful attribute inference attack, the attacked feature must be categorical, and with a relatively small number of possible values (preferably binary).\n", |
23 |
| - "\n", |
24 |
| - "In the case of the diabetes dataset, the sensitive feature we want to infer is the 'sex' feature, which is a binary feature." |
| 21 | + "## Attacking a categorical feature\n", |
| 22 | + "We start by trying to infer the 'sex' feature, which is a binary feature." |
25 | 23 | ]
|
26 | 24 | },
|
27 | 25 | {
|
|
33 | 31 | },
|
34 | 32 | {
|
35 | 33 | "cell_type": "code",
|
36 |
| - "execution_count": 1, |
| 34 | + "execution_count": 20, |
37 | 35 | "metadata": {},
|
38 | 36 | "outputs": [],
|
39 | 37 | "source": [
|
40 | 38 | "import os\n",
|
41 | 39 | "import sys\n",
|
42 | 40 | "sys.path.insert(0, os.path.abspath('..'))\n",
|
43 | 41 | "\n",
|
| 42 | + "import warnings\n", |
| 43 | + "warnings.filterwarnings('ignore')\n", |
| 44 | + "\n", |
44 | 45 | "from art.utils import load_diabetes\n",
|
45 | 46 | "\n",
|
46 | 47 | "(x_train, y_train), (x_test, y_test), _, _ = load_diabetes(test_set=0.5)"
|
|
55 | 56 | },
|
56 | 57 | {
|
57 | 58 | "cell_type": "code",
|
58 |
| - "execution_count": 13, |
| 59 | + "execution_count": 21, |
59 | 60 | "metadata": {},
|
60 | 61 | "outputs": [
|
61 | 62 | {
|
62 | 63 | "name": "stdout",
|
63 | 64 | "output_type": "stream",
|
64 | 65 | "text": [
|
65 |
| - "Base model score: -0.04773984870966275\n" |
| 66 | + "Base model score: -0.053305975661749994\n" |
66 | 67 | ]
|
67 | 68 | }
|
68 | 69 | ],
|
|
110 | 111 | "# only attacked feature\n",
|
111 | 112 | "attack_x_test_feature = attack_x_test[:, attack_feature].copy().reshape(-1, 1)\n",
|
112 | 113 | "# training data without attacked feature\n",
|
113 |
| - "attack_x_test = np.delete(attack_x_test, attack_feature, 1)\n", |
| 114 | + "x_test_for_attack = np.delete(attack_x_test, attack_feature, 1)\n", |
114 | 115 | "\n",
|
115 | 116 | "bb_attack = AttributeInferenceBlackBox(art_regressor, attack_feature=attack_feature)\n",
|
116 | 117 | "\n",
|
|
134 | 135 | "name": "stdout",
|
135 | 136 | "output_type": "stream",
|
136 | 137 | "text": [
|
137 |
| - "0.5585585585585585\n" |
| 138 | + "0.6126126126126126\n" |
138 | 139 | ]
|
139 | 140 | }
|
140 | 141 | ],
|
141 | 142 | "source": [
|
142 | 143 | "# get inferred values\n",
|
143 | 144 | "values = [-0.88085106, 1.]\n",
|
144 |
| - "inferred_train_bb = bb_attack.infer(attack_x_test, pred=attack_x_test_predictions, values=values)\n", |
| 145 | + "inferred_train_bb = bb_attack.infer(x_test_for_attack, pred=attack_x_test_predictions, values=values)\n", |
145 | 146 | "# check accuracy\n",
|
146 | 147 | "train_acc = np.sum(inferred_train_bb == np.around(attack_x_test_feature, decimals=8).reshape(1,-1)) / len(inferred_train_bb)\n",
|
147 | 148 | "print(train_acc)"
|
|
151 | 152 | "cell_type": "markdown",
|
152 | 153 | "metadata": {},
|
153 | 154 | "source": [
|
154 |
| - "This means that for 56% of the training set, the attacked feature is inferred correctly using this attack.\n", |
| 155 | + "This means that for 74% of the training set, the attacked feature is inferred correctly using this attack.\n", |
155 | 156 | "Now let's check the precision and recall:"
|
156 | 157 | ]
|
157 | 158 | },
|
158 | 159 | {
|
159 | 160 | "cell_type": "code",
|
160 |
| - "execution_count": 16, |
| 161 | + "execution_count": 24, |
161 | 162 | "metadata": {},
|
162 | 163 | "outputs": [
|
163 | 164 | {
|
164 | 165 | "name": "stdout",
|
165 | 166 | "output_type": "stream",
|
166 | 167 | "text": [
|
167 |
| - "(0.5483870967741935, 0.32075471698113206)\n" |
| 168 | + "(0.5816326530612245, 0.9661016949152542)\n" |
168 | 169 | ]
|
169 | 170 | }
|
170 | 171 | ],
|
|
205 | 206 | },
|
206 | 207 | {
|
207 | 208 | "cell_type": "code",
|
208 |
| - "execution_count": 17, |
| 209 | + "execution_count": 25, |
209 | 210 | "metadata": {},
|
210 | 211 | "outputs": [
|
211 | 212 | {
|
212 | 213 | "name": "stdout",
|
213 | 214 | "output_type": "stream",
|
214 | 215 | "text": [
|
215 |
| - "0.5585585585585585\n" |
| 216 | + "0.6666666666666666\n" |
216 | 217 | ]
|
217 | 218 | }
|
218 | 219 | ],
|
|
224 | 225 | "# train attack model\n",
|
225 | 226 | "baseline_attack.fit(attack_x_train)\n",
|
226 | 227 | "# infer values\n",
|
227 |
| - "inferred_train_baseline = baseline_attack.infer(attack_x_test, values=values)\n", |
| 228 | + "inferred_train_baseline = baseline_attack.infer(x_test_for_attack, values=values)\n", |
228 | 229 | "# check accuracy\n",
|
229 | 230 | "baseline_train_acc = np.sum(inferred_train_baseline == np.around(attack_x_test_feature, decimals=8).reshape(1,-1)) / len(inferred_train_baseline)\n",
|
230 | 231 | "print(baseline_train_acc)"
|
|
234 | 235 | "cell_type": "markdown",
|
235 | 236 | "metadata": {},
|
236 | 237 | "source": [
|
237 |
| - "In this case, the black-box attack does not do better than the baseline." |
| 238 | + "In this case, the black-box attack does significantly better than the baseline." |
| 239 | + ] |
| 240 | + }, |
| 241 | + { |
| 242 | + "cell_type": "markdown", |
| 243 | + "metadata": {}, |
| 244 | + "source": [ |
| 245 | + "## Attacking a numerical feature\n", |
| 246 | + "Now we will try to infer the bmi level feature." |
| 247 | + ] |
| 248 | + }, |
| 249 | + { |
| 250 | + "cell_type": "code", |
| 251 | + "execution_count": 29, |
| 252 | + "metadata": {}, |
| 253 | + "outputs": [ |
| 254 | + { |
| 255 | + "name": "stdout", |
| 256 | + "output_type": "stream", |
| 257 | + "text": [ |
| 258 | + "54.80737471036833\n" |
| 259 | + ] |
| 260 | + } |
| 261 | + ], |
| 262 | + "source": [ |
| 263 | + "attack_feature = 3 # bmi\n", |
| 264 | + "\n", |
| 265 | + "# only attacked feature\n", |
| 266 | + "attack_x_test_feature = attack_x_test[:, attack_feature].copy().reshape(-1, 1)\n", |
| 267 | + "# training data without attacked feature\n", |
| 268 | + "x_test_for_attack = np.delete(attack_x_test, attack_feature, 1)\n", |
| 269 | + "\n", |
| 270 | + "bb_attack = AttributeInferenceBlackBox(art_regressor, attack_feature=attack_feature)\n", |
| 271 | + "\n", |
| 272 | + "# train attack model\n", |
| 273 | + "bb_attack.fit(attack_x_train)\n", |
| 274 | + "\n", |
| 275 | + "inferred_train_bb = bb_attack.infer(x_test_for_attack, pred=attack_x_test_predictions)\n", |
| 276 | + "# check MSE\n", |
| 277 | + "train_acc = np.sum((attack_x_test_feature - inferred_train_bb) ** 2) / len(inferred_train_bb)\n", |
| 278 | + "print(train_acc)" |
| 279 | + ] |
| 280 | + }, |
| 281 | + { |
| 282 | + "cell_type": "code", |
| 283 | + "execution_count": 30, |
| 284 | + "metadata": {}, |
| 285 | + "outputs": [ |
| 286 | + { |
| 287 | + "name": "stdout", |
| 288 | + "output_type": "stream", |
| 289 | + "text": [ |
| 290 | + "67.66769489356126\n" |
| 291 | + ] |
| 292 | + } |
| 293 | + ], |
| 294 | + "source": [ |
| 295 | + "baseline_attack = AttributeInferenceBaseline(attack_feature=attack_feature)\n", |
| 296 | + "\n", |
| 297 | + "# train attack model\n", |
| 298 | + "baseline_attack.fit(attack_x_train)\n", |
| 299 | + "# infer values\n", |
| 300 | + "inferred_train_baseline = baseline_attack.infer(x_test_for_attack)\n", |
| 301 | + "# check MSE\n", |
| 302 | + "baseline_train_acc = np.sum((attack_x_test_feature - inferred_train_baseline) ** 2) / len(inferred_train_baseline)\n", |
| 303 | + "print(baseline_train_acc)" |
| 304 | + ] |
| 305 | + }, |
| 306 | + { |
| 307 | + "cell_type": "markdown", |
| 308 | + "metadata": {}, |
| 309 | + "source": [ |
| 310 | + "The attack succeeds better than the baseline (a lower MSE means higher accuracy)." |
238 | 311 | ]
|
239 | 312 | }
|
240 | 313 | ],
|
241 | 314 | "metadata": {
|
242 | 315 | "kernelspec": {
|
243 |
| - "display_name": "Python 3", |
| 316 | + "display_name": "Python 3 (ipykernel)", |
244 | 317 | "language": "python",
|
245 | 318 | "name": "python3"
|
246 | 319 | },
|
|
254 | 327 | "name": "python",
|
255 | 328 | "nbconvert_exporter": "python",
|
256 | 329 | "pygments_lexer": "ipython3",
|
257 |
| - "version": "3.8.3" |
| 330 | + "version": "3.9.6" |
258 | 331 | }
|
259 | 332 | },
|
260 | 333 | "nbformat": 4,
|
|
0 commit comments