From 32964ffccf22ad9a9721f7a6b7d37e4e7e4ec546 Mon Sep 17 00:00:00 2001 From: Aleksandr Date: Sat, 27 Jul 2024 12:54:54 +0300 Subject: [PATCH 1/6] test --- experiments.ipynb | 901 ++++++------------------ fdd_defense/attackers/carlini_wagner.py | 2 +- fdd_defense/defenders/atonquant.py | 4 +- 3 files changed, 236 insertions(+), 671 deletions(-) diff --git a/experiments.ipynb b/experiments.ipynb index 4d2f493..9082c14 100644 --- a/experiments.ipynb +++ b/experiments.ipynb @@ -42,12 +42,12 @@ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "d0134859afbb428a9d26bd2d28f879d6", + "model_id": "4ba0e25c03f44c84845d4f2c50ad701a", "version_major": 2, "version_minor": 0 }, "text/plain": [ - "Reading data/reinartz_tep/dataset.csv: 0%| | 0/5600000 [00:00 6\u001b[0m unprotected_acc\u001b[38;5;241m.\u001b[39mappend(accuracy(attacker, defender, step_size\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m10\u001b[39m))\n", + "File \u001b[0;32m~/work/github/attacks/fdd-defense/fdd_defense/utils.py:28\u001b[0m, in \u001b[0;36maccuracy\u001b[0;34m(attacker, defender, step_size)\u001b[0m\n\u001b[1;32m 26\u001b[0m pred \u001b[38;5;241m=\u001b[39m attacker\u001b[38;5;241m.\u001b[39mmodel\u001b[38;5;241m.\u001b[39mpredict(sample)\n\u001b[1;32m 27\u001b[0m adv_sample \u001b[38;5;241m=\u001b[39m attacker\u001b[38;5;241m.\u001b[39mattack(sample, pred)\n\u001b[0;32m---> 28\u001b[0m pred \u001b[38;5;241m=\u001b[39m defender\u001b[38;5;241m.\u001b[39mpredict(adv_sample)\n\u001b[1;32m 29\u001b[0m preds\u001b[38;5;241m.\u001b[39mappend(pred)\n\u001b[1;32m 30\u001b[0m labels\u001b[38;5;241m.\u001b[39mappend(label)\n", + "File \u001b[0;32m~/work/github/attacks/fdd-defense/fdd_defense/defenders/base.py:12\u001b[0m, in \u001b[0;36mBaseDefender.predict\u001b[0;34m(self, ts)\u001b[0m\n\u001b[1;32m 11\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mpredict\u001b[39m(\u001b[38;5;28mself\u001b[39m, ts: np\u001b[38;5;241m.\u001b[39mndarray):\n\u001b[0;32m---> 12\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mmodel\u001b[38;5;241m.\u001b[39mpredict(ts)\n", + "File \u001b[0;32m~/work/github/attacks/fdd-defense/fdd_defense/models/base.py:80\u001b[0m, in \u001b[0;36mBaseTorchModel.predict\u001b[0;34m(self, ts)\u001b[0m\n\u001b[1;32m 78\u001b[0m ts \u001b[38;5;241m=\u001b[39m torch\u001b[38;5;241m.\u001b[39mFloatTensor(ts)\u001b[38;5;241m.\u001b[39mto(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdevice)\n\u001b[1;32m 79\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m torch\u001b[38;5;241m.\u001b[39mno_grad():\n\u001b[0;32m---> 80\u001b[0m logits \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mmodel(ts)\n\u001b[1;32m 81\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m logits\u001b[38;5;241m.\u001b[39margmax(axis\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m1\u001b[39m)\u001b[38;5;241m.\u001b[39mcpu()\u001b[38;5;241m.\u001b[39mnumpy()\n", + "File \u001b[0;32m~/anaconda3/lib/python3.11/site-packages/torch/nn/modules/module.py:1511\u001b[0m, in \u001b[0;36mModule._wrapped_call_impl\u001b[0;34m(self, *args, **kwargs)\u001b[0m\n\u001b[1;32m 1509\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_compiled_call_impl(\u001b[38;5;241m*\u001b[39margs, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs) \u001b[38;5;66;03m# type: ignore[misc]\u001b[39;00m\n\u001b[1;32m 1510\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m-> 1511\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_call_impl(\u001b[38;5;241m*\u001b[39margs, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n", + "File \u001b[0;32m~/anaconda3/lib/python3.11/site-packages/torch/nn/modules/module.py:1520\u001b[0m, in \u001b[0;36mModule._call_impl\u001b[0;34m(self, *args, **kwargs)\u001b[0m\n\u001b[1;32m 1515\u001b[0m \u001b[38;5;66;03m# If we don't have any hooks, we want to skip the rest of the logic in\u001b[39;00m\n\u001b[1;32m 1516\u001b[0m \u001b[38;5;66;03m# this function, and just call forward.\u001b[39;00m\n\u001b[1;32m 1517\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m (\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_backward_hooks \u001b[38;5;129;01mor\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_backward_pre_hooks \u001b[38;5;129;01mor\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_forward_hooks \u001b[38;5;129;01mor\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_forward_pre_hooks\n\u001b[1;32m 1518\u001b[0m \u001b[38;5;129;01mor\u001b[39;00m _global_backward_pre_hooks \u001b[38;5;129;01mor\u001b[39;00m _global_backward_hooks\n\u001b[1;32m 1519\u001b[0m \u001b[38;5;129;01mor\u001b[39;00m _global_forward_hooks \u001b[38;5;129;01mor\u001b[39;00m _global_forward_pre_hooks):\n\u001b[0;32m-> 1520\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m forward_call(\u001b[38;5;241m*\u001b[39margs, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n\u001b[1;32m 1522\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 1523\u001b[0m result \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n", + "File \u001b[0;32m~/work/github/attacks/fdd-defense/fdd_defense/models/tcn.py:195\u001b[0m, in \u001b[0;36mTCNModule.forward\u001b[0;34m(self, x)\u001b[0m\n\u001b[1;32m 193\u001b[0m x \u001b[38;5;241m=\u001b[39m x\u001b[38;5;241m.\u001b[39mtranspose(\u001b[38;5;241m1\u001b[39m, \u001b[38;5;241m2\u001b[39m)\n\u001b[1;32m 194\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m res_block \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mres_blocks_list:\n\u001b[0;32m--> 195\u001b[0m x \u001b[38;5;241m=\u001b[39m res_block(x)\n\u001b[1;32m 196\u001b[0m x \u001b[38;5;241m=\u001b[39m x\u001b[38;5;241m.\u001b[39mtranspose(\u001b[38;5;241m1\u001b[39m, \u001b[38;5;241m2\u001b[39m)[:, \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m1\u001b[39m, :]\n\u001b[1;32m 197\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m x\n", + "File \u001b[0;32m~/anaconda3/lib/python3.11/site-packages/torch/nn/modules/module.py:1511\u001b[0m, in \u001b[0;36mModule._wrapped_call_impl\u001b[0;34m(self, *args, **kwargs)\u001b[0m\n\u001b[1;32m 1509\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_compiled_call_impl(\u001b[38;5;241m*\u001b[39margs, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs) \u001b[38;5;66;03m# type: ignore[misc]\u001b[39;00m\n\u001b[1;32m 1510\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m-> 1511\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_call_impl(\u001b[38;5;241m*\u001b[39margs, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n", + "File \u001b[0;32m~/anaconda3/lib/python3.11/site-packages/torch/nn/modules/module.py:1520\u001b[0m, in \u001b[0;36mModule._call_impl\u001b[0;34m(self, *args, **kwargs)\u001b[0m\n\u001b[1;32m 1515\u001b[0m \u001b[38;5;66;03m# If we don't have any hooks, we want to skip the rest of the logic in\u001b[39;00m\n\u001b[1;32m 1516\u001b[0m \u001b[38;5;66;03m# this function, and just call forward.\u001b[39;00m\n\u001b[1;32m 1517\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m (\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_backward_hooks \u001b[38;5;129;01mor\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_backward_pre_hooks \u001b[38;5;129;01mor\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_forward_hooks \u001b[38;5;129;01mor\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_forward_pre_hooks\n\u001b[1;32m 1518\u001b[0m \u001b[38;5;129;01mor\u001b[39;00m _global_backward_pre_hooks \u001b[38;5;129;01mor\u001b[39;00m _global_backward_hooks\n\u001b[1;32m 1519\u001b[0m \u001b[38;5;129;01mor\u001b[39;00m _global_forward_hooks \u001b[38;5;129;01mor\u001b[39;00m _global_forward_pre_hooks):\n\u001b[0;32m-> 1520\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m forward_call(\u001b[38;5;241m*\u001b[39margs, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n\u001b[1;32m 1522\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 1523\u001b[0m result \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n", + "File \u001b[0;32m~/work/github/attacks/fdd-defense/fdd_defense/models/tcn.py:98\u001b[0m, in \u001b[0;36mResidualBlock.forward\u001b[0;34m(self, x)\u001b[0m\n\u001b[1;32m 94\u001b[0m \u001b[38;5;66;03m# first step\u001b[39;00m\n\u001b[1;32m 95\u001b[0m left_padding \u001b[38;5;241m=\u001b[39m (\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdilation_base\u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mnr_blocks_below) \u001b[38;5;241m*\u001b[39m (\n\u001b[1;32m 96\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mkernel_size \u001b[38;5;241m-\u001b[39m \u001b[38;5;241m1\u001b[39m\n\u001b[1;32m 97\u001b[0m )\n\u001b[0;32m---> 98\u001b[0m x \u001b[38;5;241m=\u001b[39m F\u001b[38;5;241m.\u001b[39mpad(x, (left_padding, \u001b[38;5;241m0\u001b[39m))\n\u001b[1;32m 99\u001b[0m x \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdropout_fn(F\u001b[38;5;241m.\u001b[39mrelu(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mconv1(x)))\n\u001b[1;32m 101\u001b[0m \u001b[38;5;66;03m# second step\u001b[39;00m\n", + "File \u001b[0;32m~/anaconda3/lib/python3.11/site-packages/torch/nn/functional.py:4495\u001b[0m, in \u001b[0;36mpad\u001b[0;34m(input, pad, mode, value)\u001b[0m\n\u001b[1;32m 4488\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mlen\u001b[39m(pad) \u001b[38;5;241m==\u001b[39m \u001b[38;5;241m4\u001b[39m \u001b[38;5;129;01mand\u001b[39;00m (\u001b[38;5;28minput\u001b[39m\u001b[38;5;241m.\u001b[39mdim() \u001b[38;5;241m==\u001b[39m \u001b[38;5;241m3\u001b[39m \u001b[38;5;129;01mor\u001b[39;00m \u001b[38;5;28minput\u001b[39m\u001b[38;5;241m.\u001b[39mdim() \u001b[38;5;241m==\u001b[39m \u001b[38;5;241m4\u001b[39m) \u001b[38;5;129;01mand\u001b[39;00m mode \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mreplicate\u001b[39m\u001b[38;5;124m'\u001b[39m:\n\u001b[1;32m 4489\u001b[0m \u001b[38;5;66;03m# Use slow decomp whose backward will be in terms of index_put.\u001b[39;00m\n\u001b[1;32m 4490\u001b[0m \u001b[38;5;66;03m# importlib is required because the import cannot be top level\u001b[39;00m\n\u001b[1;32m 4491\u001b[0m \u001b[38;5;66;03m# (cycle) and cannot be nested (TS doesn't support)\u001b[39;00m\n\u001b[1;32m 4492\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m importlib\u001b[38;5;241m.\u001b[39mimport_module(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mtorch._decomp.decompositions\u001b[39m\u001b[38;5;124m'\u001b[39m)\u001b[38;5;241m.\u001b[39mreplication_pad2d(\n\u001b[1;32m 4493\u001b[0m \u001b[38;5;28minput\u001b[39m, pad\n\u001b[1;32m 4494\u001b[0m )\n\u001b[0;32m-> 4495\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m torch\u001b[38;5;241m.\u001b[39m_C\u001b[38;5;241m.\u001b[39m_nn\u001b[38;5;241m.\u001b[39mpad(\u001b[38;5;28minput\u001b[39m, pad, mode, value)\n", + "\u001b[0;31mKeyboardInterrupt\u001b[0m: " ] - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "6ddcda5c38ba40bca43f513963d65582", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - " 0%| | 0/216 [00:00" ] @@ -919,7 +442,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 7, "id": "e65bff16-eba3-4193-9db4-0bcde5433bef", "metadata": {}, "outputs": [ @@ -933,7 +456,7 @@ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "2c8e40bc2f864384857f1fbdd6055826", + "model_id": "ebcb82357a4047b9a6782cb98feb2a3b", "version_major": 2, "version_minor": 0 }, @@ -962,7 +485,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Epoch 1, Loss: 0.3352\n" + "Epoch 1, Loss: 0.4765\n" ] }, { @@ -983,7 +506,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Epoch 2, Loss: 0.1898\n" + "Epoch 2, Loss: 0.3754\n" ] }, { @@ -1004,7 +527,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Epoch 3, Loss: 0.1417\n" + "Epoch 3, Loss: 0.3646\n" ] }, { @@ -1025,7 +548,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Epoch 4, Loss: 0.1212\n" + "Epoch 4, Loss: 0.3617\n" ] }, { @@ -1046,7 +569,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Epoch 5, Loss: 0.1102\n" + "Epoch 5, Loss: 0.3428\n" ] }, { @@ -1067,7 +590,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Epoch 6, Loss: 0.1041\n" + "Epoch 6, Loss: 0.2908\n" ] }, { @@ -1088,7 +611,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Epoch 7, Loss: 0.1018\n" + "Epoch 7, Loss: 0.2828\n" ] }, { @@ -1109,7 +632,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Epoch 8, Loss: 0.1017\n" + "Epoch 8, Loss: 0.2774\n" ] }, { @@ -1130,7 +653,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Epoch 9, Loss: 0.0993\n" + "Epoch 9, Loss: 0.2787\n" ] }, { @@ -1151,7 +674,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Epoch 10, Loss: 0.0972\n" + "Epoch 10, Loss: 0.2699\n" ] } ], @@ -1162,7 +685,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 11, "id": "1f49ea67-0e0d-4d46-acbe-e9e537cc47b0", "metadata": {}, "outputs": [ @@ -1170,13 +693,13 @@ "name": "stderr", "output_type": "stream", "text": [ - "Creating sequence of samples: 100%|██████████| 560/560 [00:01<00:00, 540.93it/s]\n" + "Creating sequence of samples: 100%|██████████| 560/560 [00:00<00:00, 591.09it/s]\n" ] }, { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "6edc35ba40934fd298b311a007bad98d", + "model_id": "e5449fa13e454533a8cd3607655f2b37", "version_major": 2, "version_minor": 0 }, @@ -1191,13 +714,13 @@ "name": "stderr", "output_type": "stream", "text": [ - "Creating sequence of samples: 100%|██████████| 560/560 [00:00<00:00, 578.68it/s]\n" + "Creating sequence of samples: 100%|██████████| 560/560 [00:00<00:00, 561.37it/s]\n" ] }, { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "5fac71fb47b547b982fd2673a221be27", + "model_id": "a05dece2aa244377a048e3a881c54cee", "version_major": 2, "version_minor": 0 }, @@ -1212,13 +735,13 @@ "name": "stderr", "output_type": "stream", "text": [ - "Creating sequence of samples: 100%|██████████| 560/560 [00:00<00:00, 563.36it/s]\n" + "Creating sequence of samples: 100%|██████████| 560/560 [00:00<00:00, 594.07it/s]\n" ] }, { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "1aa6ccfad2b94d26b76d79b0706800b9", + "model_id": "26eaed15cd2e4e2cb529aac39dae0b91", "version_major": 2, "version_minor": 0 }, @@ -1233,13 +756,13 @@ "name": "stderr", "output_type": "stream", "text": [ - "Creating sequence of samples: 100%|██████████| 560/560 [00:00<00:00, 560.19it/s]\n" + "Creating sequence of samples: 100%|██████████| 560/560 [00:00<00:00, 592.93it/s]\n" ] }, { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "c6b5013c867b4fd79e417c25b7fab2c4", + "model_id": "826b0e041a51447e84fb75d12a778ccb", "version_major": 2, "version_minor": 0 }, @@ -1254,13 +777,13 @@ "name": "stderr", "output_type": "stream", "text": [ - "Creating sequence of samples: 100%|██████████| 560/560 [00:00<00:00, 587.94it/s]\n" + "Creating sequence of samples: 100%|██████████| 560/560 [00:00<00:00, 577.33it/s]\n" ] }, { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "b73b704ad1044bca942459357cdfa901", + "model_id": "15327e1a31d949a285964744c95e648d", "version_major": 2, "version_minor": 0 }, @@ -1275,13 +798,13 @@ "name": "stderr", "output_type": "stream", "text": [ - "Creating sequence of samples: 100%|██████████| 560/560 [00:00<00:00, 587.63it/s]\n" + "Creating sequence of samples: 100%|██████████| 560/560 [00:00<00:00, 589.87it/s]\n" ] }, { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "9933c2ddadb14d4bb99b218231073e8e", + "model_id": "4c34afc7f42c447bba1693079d6ab3d5", "version_major": 2, "version_minor": 0 }, @@ -1296,13 +819,13 @@ "name": "stderr", "output_type": "stream", "text": [ - "Creating sequence of samples: 100%|██████████| 560/560 [00:00<00:00, 578.35it/s]\n" + "Creating sequence of samples: 100%|██████████| 560/560 [00:00<00:00, 589.43it/s]\n" ] }, { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "83833cc88e7847fbb28beef4d255f058", + "model_id": "b84598b0cd794ee68374ab2318af32ef", "version_major": 2, "version_minor": 0 }, @@ -1317,13 +840,13 @@ "name": "stderr", "output_type": "stream", "text": [ - "Creating sequence of samples: 100%|██████████| 560/560 [00:00<00:00, 583.99it/s]\n" + "Creating sequence of samples: 100%|██████████| 560/560 [00:01<00:00, 543.41it/s]\n" ] }, { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "94cbf9d2527b4344b1e825c780c30408", + "model_id": "360cdafc7b9141b0ad50d6ce5cfa99d3", "version_major": 2, "version_minor": 0 }, @@ -1338,13 +861,13 @@ "name": "stderr", "output_type": "stream", "text": [ - "Creating sequence of samples: 100%|██████████| 560/560 [00:01<00:00, 525.20it/s]\n" + "Creating sequence of samples: 100%|██████████| 560/560 [00:00<00:00, 589.54it/s]\n" ] }, { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "ad8265fef31d4797ac432c510fb753b5", + "model_id": "1dca0d5453174409918d7a33238cd115", "version_major": 2, "version_minor": 0 }, @@ -1359,13 +882,13 @@ "name": "stderr", "output_type": "stream", "text": [ - "Creating sequence of samples: 100%|██████████| 560/560 [00:01<00:00, 517.74it/s]\n" + "Creating sequence of samples: 100%|██████████| 560/560 [00:00<00:00, 583.84it/s]\n" ] }, { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "a947e57bdb6a4449961500b2c0efc943", + "model_id": "efefefcd401d416595b033f31cd344b7", "version_major": 2, "version_minor": 0 }, @@ -1380,13 +903,13 @@ "name": "stderr", "output_type": "stream", "text": [ - "Creating sequence of samples: 100%|██████████| 560/560 [00:00<00:00, 576.44it/s]\n" + "Creating sequence of samples: 100%|██████████| 560/560 [00:00<00:00, 586.65it/s]\n" ] }, { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "56b1ee413ebc442094b801369f9fa0d2", + "model_id": "48ead7b1e86b431583fc64e1d9c607ef", "version_major": 2, "version_minor": 0 }, @@ -1401,13 +924,13 @@ "name": "stderr", "output_type": "stream", "text": [ - "Creating sequence of samples: 100%|██████████| 560/560 [00:01<00:00, 555.83it/s]\n" + "Creating sequence of samples: 100%|██████████| 560/560 [00:00<00:00, 588.96it/s]\n" ] }, { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "756fdbc2a4dc44349819a668819bdf30", + "model_id": "aa061d198bda430e8ec22a3621f59def", "version_major": 2, "version_minor": 0 }, @@ -1422,13 +945,13 @@ "name": "stderr", "output_type": "stream", "text": [ - "Creating sequence of samples: 100%|██████████| 560/560 [00:01<00:00, 550.42it/s]\n" + "Creating sequence of samples: 100%|██████████| 560/560 [00:00<00:00, 590.22it/s]\n" ] }, { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "85f838dcde54435fa05adf764a77ceae", + "model_id": "e1ee733379324ff7aa0b86f490e4ec89", "version_major": 2, "version_minor": 0 }, @@ -1443,13 +966,13 @@ "name": "stderr", "output_type": "stream", "text": [ - "Creating sequence of samples: 100%|██████████| 560/560 [00:00<00:00, 567.67it/s]\n" + "Creating sequence of samples: 100%|██████████| 560/560 [00:00<00:00, 592.73it/s]\n" ] }, { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "98b8fbfd340348189641ebf54f0a28d2", + "model_id": "6529c1d6e7c94675a0df5f586da9eaca", "version_major": 2, "version_minor": 0 }, @@ -1464,13 +987,13 @@ "name": "stderr", "output_type": "stream", "text": [ - "Creating sequence of samples: 100%|██████████| 560/560 [00:00<00:00, 581.09it/s]\n" + "Creating sequence of samples: 100%|██████████| 560/560 [00:00<00:00, 584.72it/s]\n" ] }, { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "7ca8f9df1c1944db8d6b5ac93fb66cb5", + "model_id": "ba853d0eedf54f0e90435e3abc73808d", "version_major": 2, "version_minor": 0 }, @@ -1485,13 +1008,13 @@ "name": "stderr", "output_type": "stream", "text": [ - "Creating sequence of samples: 100%|██████████| 560/560 [00:00<00:00, 572.17it/s]\n" + "Creating sequence of samples: 100%|██████████| 560/560 [00:00<00:00, 578.61it/s]\n" ] }, { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "353e25f670904737902e35bce2106796", + "model_id": "4f7a8691e6854a689583f18e24a8e471", "version_major": 2, "version_minor": 0 }, @@ -1506,13 +1029,13 @@ "name": "stderr", "output_type": "stream", "text": [ - "Creating sequence of samples: 100%|██████████| 560/560 [00:00<00:00, 574.02it/s]\n" + "Creating sequence of samples: 100%|██████████| 560/560 [00:00<00:00, 585.03it/s]\n" ] }, { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "f42e57286e6e4b0c9ebad592040dd6f2", + "model_id": "a44c7a68e0804ab48ac624af8005bc41", "version_major": 2, "version_minor": 0 }, @@ -1527,13 +1050,13 @@ "name": "stderr", "output_type": "stream", "text": [ - "Creating sequence of samples: 100%|██████████| 560/560 [00:00<00:00, 578.76it/s]\n" + "Creating sequence of samples: 100%|██████████| 560/560 [00:01<00:00, 542.41it/s]\n" ] }, { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "89da8094266f41e99e7ea660baf16279", + "model_id": "7d0cfc8a257d488faf9b9db092e20e3c", "version_major": 2, "version_minor": 0 }, @@ -1548,13 +1071,13 @@ "name": "stderr", "output_type": "stream", "text": [ - "Creating sequence of samples: 100%|██████████| 560/560 [00:00<00:00, 581.87it/s]\n" + "Creating sequence of samples: 100%|██████████| 560/560 [00:00<00:00, 579.91it/s]\n" ] }, { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "70efe8069b9d4f8cbbe1ed5fb9828102", + "model_id": "5cccd850bbfd479ebe99d51319cdbe05", "version_major": 2, "version_minor": 0 }, @@ -1569,13 +1092,13 @@ "name": "stderr", "output_type": "stream", "text": [ - "Creating sequence of samples: 100%|██████████| 560/560 [00:00<00:00, 570.70it/s]\n" + "Creating sequence of samples: 100%|██████████| 560/560 [00:00<00:00, 587.27it/s]\n" ] }, { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "1608c83b6eb4417a81632c67323f57c2", + "model_id": "9e4008ae66a54c57a0a7dc5beb1f9410", "version_major": 2, "version_minor": 0 }, @@ -1590,19 +1113,19 @@ "source": [ "protected_acc = []\n", "for eps in eps_space:\n", - " attacker = FGSMAttacker(model, eps=eps)\n", + " attacker = PGDAttacker(model, eps=eps)\n", " protected_acc.append(accuracy(attacker, defender, step_size=10))" ] }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 12, "id": "eacd66d8-ea8e-46dc-a295-4ddb8f279820", "metadata": {}, "outputs": [ { "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjcAAAG2CAYAAACDLKdOAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy81sbWrAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAzGUlEQVR4nO3de3hU9b32/3vOIWBAAkaQEIMiBxHEYJXTploJIupPi0LLo6iFp6awDRCFguguUH6AdqOoCHgAqVaRgmhpS5W0lDNawaBoUrHAJioJbEBJgJJMZtbzxySTDDPAzDCTSRbv13XlyqzvfNeaz/p0tdxdh4zFMAxDAAAAJmFNdAEAAACxRLgBAACmQrgBAACmQrgBAACmQrgBAACmQrgBAACmQrgBAACmQrgBAACmQrgBAACmQrgBAACmktBws3HjRt1xxx1q27atLBaL3nvvvXOus2HDBmVlZSkpKUkdOnTQokWL4l8oAABoNBIabk6cOKEePXpo/vz5Yc3ft2+fbrvtNvXv318FBQV6/PHHlZubq3feeSfOlQIAgMbC0lC+ONNisejdd9/VXXfddcY5v/zlL7V69WoVFRX5x3JycvTpp59q27Zt9VAlAABo6OyJLiAS27ZtU3Z2dsDYoEGDtHjxYrndbjkcjqB1KioqVFFR4V/2er06evSoUlNTZbFY4l4zAAA4f4ZhqLy8XG3btpXVevYLT40q3JSWliotLS1gLC0tTVVVVTp8+LDatGkTtM7s2bM1ffr0+ioRAADE0ddff6127dqddU6jCjeSgs621FxVO9NZmClTpigvL8+/fOzYMbVv31779u3TRRddFNPa3G63/v73v+umm24KeRYJtehV+OhV+OhVZOhX+OhV+OLVq/LycmVmZob1b3ejCjeXXnqpSktLA8YOHToku92u1NTUkOu4XC65XK6g8ZYtWyolJSWm9bndbiUnJys1NZWD/xzoVfjoVfjoVWToV/joVfji1auabYVzS0mj+js3vXv3Vn5+fsDY2rVr1atXLw42AAAgKcHh5vjx49q5c6d27twpyfeo986dO1VcXCzJd0lp5MiR/vk5OTnav3+/8vLyVFRUpCVLlmjx4sV67LHHElE+AABogBJ6WWr79u266aab/Ms198Y88MADWrp0qUpKSvxBR5IyMzO1Zs0aTZgwQS+++KLatm2r559/XkOH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e25mz56tJUuWBI0vWbJETz311HkXBQAAEK2ows1LL72kzp07B41fffXVWrRo0XkXBQAAEK2owk1paanatGkTNN66dWuVlJScd1EAAADRiircpKena8uWLUHjW7ZsUdu2bc+7KAAAgGhFdUPx6NGjNX78eLndbt18882SfDcZT5o0SY8++mhMCwQAAIhEVOFm0qRJOnr0qMaMGeP/PqmkpCT98pe/1JQpU2JaIAAAQCSiCjcWi0VPPfWUnnzySRUVFalJkybq2LGjXC5XrOsDAACISFThpkazZs10/fXXx6oWAACA8xZ1uPn444+1YsUKFRcX+y9N1Vi1atV5FwYAABCNqJ6Wevvtt9W3b18VFhbq3XffldvtVmFhodatW6fmzZvHukYAAICwRRVuZs2apWeffVZ/+tOf5HQ69dxzz6moqEjDhg1T+/btY10jAABA2KIKN3v27NGQIUMkSS6XSydOnJDFYtGECRP08ssvx7RAAACASEQVblq2bKny8nJJ0mWXXabPP/9ckvT999/r5MmTsasOAAAgQlHdUNy/f3/l5+frmmuu0bBhwzRu3DitW7dO+fn5+tGPfhTrGgEAAMIWVbiZP3++Tp06JUmaMmWKHA6HNm/erB//+Md68sknY1ogAABAJCION1VVVfrjH/+oQYMGSZKsVqsmTZqkSZMmxbw4AACASEV8z43dbtcvfvELVVRUxKMeAACA8xLVDcU33HCDCgoKYl0LAADAeYvqnpsxY8bo0Ucf1TfffKOsrCw1bdo04P3u3bvHpDgAAIBIRRVuhg8fLknKzc31j1ksFhmGIYvFIo/HE5vqAAAAIhRVuNm3b1+s6wAAAIiJqMJNRkZGrOsAAACIiajCzeuvv37W90eOHBlVMQAAAOcrqnAzbty4gGW3262TJ0/K6XQqOTmZcAMAABImqkfBv/vuu4Cf48eP68svv1S/fv20bNmyWNcIAAAQtqjCTSgdO3bUnDlzgs7qAAAA1KeYhRtJstlsOnDgQCw3CQAAEJGo7rlZvXp1wLJhGCopKdH8+fPVt2/fmBQGAAAQjajCzV133RWwbLFY1Lp1a918882aO3duLOoCAACISlThxuv1xroOAACAmIjpPTcAAACJFlW4ueeeezRnzpyg8d/85je69957z7soAACAaEUVbjZs2KAhQ4YEjd96663auHHjeRcFAAAQrajCzfHjx+V0OoPGHQ6HysrKzrsoAACAaEUVbrp166bly5cHjb/99tvq2rXreRcFAAAQraielnryySc1dOhQ7dmzRzfffLMk6W9/+5uWLVumFStWxLRAAACASEQVbu6880699957mjVrllauXKkmTZqoe/fu+utf/6oBAwbEukYAAICwRRVuJGnIkCEhbyoGAABIpKjuufn444/10UcfBY1/9NFH2r59+3kXBQAAEK2ows3YsWP19ddfB41/++23Gjt27HkXBQAAEK2owk1hYaGuu+66oPGePXuqsLDwvIsCAACIVlThxuVy6eDBg0HjJSUlstujvo0HAADgvEUVbgYOHKgpU6bo2LFj/rHvv/9ejz/+uAYOHBiz4gAAACIV1WmWuXPn6j/+4z+UkZGhnj17SpJ27typtLQ0vfHGGzEtEAAAIBJRhZvLLrtMn332md588019+umnatKkiR566CH99Kc/lcPhiHWNAAAAYYv6BpmmTZuqX79+at++vSorKyVJf/nLXyT5/sgfAABAIkQVbvbu3au7775bu3btksVikWEYslgs/vc9Hk/MCgQAAIhEVDcUjxs3TpmZmTp48KCSk5P1+eefa8OGDerVq5fWr18f4xIBAADCF9WZm23btmndunVq3bq1rFarbDab+vXrp9mzZys3N1cFBQWxrhMAACAsUZ258Xg8atasmSSpVatWOnDggCQpIyNDX375ZeyqAwAAiFBUZ266deumzz77TB06dNANN9ygp59+Wk6nUy+//LI6dOgQ6xoBAADCFlW4eeKJJ3TixAlJ0syZM3X77berf//+Sk1N1fLly2NaIAAAQCSiCjeDBg3yv+7QoYMKCwt19OhRXXzxxQFPTQEAANS3qO65CaVly5ZRBZsFCxYoMzNTSUlJysrK0qZNm8Jab8uWLbLb7br22msj/kwAAGBeMQs30Vi+fLnGjx+vqVOnqqCgQP3799fgwYNVXFx81vWOHTumkSNH6kc/+lE9VQoAABqLhIabZ555RqNGjdLo0aPVpUsXzZs3T+np6Vq4cOFZ13v44Yc1YsQI9e7du54qBQAAjUXUX79wviorK7Vjxw5Nnjw5YDw7O1tbt24943qvvfaa9uzZo9/97neaOXPmOT+noqJCFRUV/uWysjJJktvtltvtjrL60Gq2F+vtmhG9Ch+9Ch+9igz9Ch+9Cl+8ehXJ9hIWbg4fPiyPx6O0tLSA8bS0NJWWloZc56uvvtLkyZO1adMm2e3hlT579mxNnz49aHzt2rVKTk6OvPAw5Ofnx2W7ZkSvwkevwkevIkO/wkevwhfrXp08eTLsuQkLNzVOvwn59O+pquHxeDRixAhNnz5dV111VdjbnzJlivLy8vzLZWVlSk9PV3Z2tlJSUqIvPAS32638/HwNHDiQb0c/B3oVPnoVPnoVGfoVPnoVvnj1qubKSzgSFm5atWolm80WdJbm0KFDQWdzJKm8vFzbt29XQUGB/vM//1OS5PV6ZRiG7Ha71q5dq5tvvjloPZfLJZfLFTTucDjidoDGc9tmQ6/CR6/CR68iQ7/CR6/CF+teRbKthN1Q7HQ6lZWVFXTaKj8/X3369Aman5KSol27dmnnzp3+n5ycHHXq1Ek7d+7UDTfcUF+lAwCABiyhl6Xy8vJ0//33q1evXurdu7defvllFRcXKycnR5LvktK3336r119/XVarVd26dQtY/5JLLlFSUlLQOAAAuHAlNNwMHz5cR44c0YwZM1RSUqJu3bppzZo1ysjIkCSVlJSc82/eAAAA1JXwG4rHjBmjMWPGhHxv6dKlZ1132rRpmjZtWuyLAgAAjVZC/4gfAABArBFuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqRBuAACAqSQ83CxYsECZmZlKSkpSVlaWNm3adMa5q1at0sCBA9W6dWulpKSod+/e+uCDD+qx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6rnnntOll16qxx9/XHfeead2794th8OhsWPHqrKyUhs3blTTpk1VWFioZs2aJXCPAMQLX5wJoME7ceKEWrVqpXXr1ql3797+8dGjR+vkyZP6+c9/rptuuklvv/22hg8fLkk6evSo2rVrp6VLl2rYsGHq3r27hg4dql/96leJ2g0A9YQzNwAavMLCQp06dUoDBw4MGK+srFTPnj39y3WDT8uWLdWpUycVFRVJknJzc/WLX/xCa9eu1S233KKhQ4eqe/fu9bMDAOoV99wAaPC8Xq8k6c9//rN27tzp/yksLPTfd3MmFotFku8sz969e3X//fdr165d6tWrl1544YW41w6g/hFuADR4Xbt2lcvlUnFxsa688sqAn/T0dP+8Dz/80P/6u+++0+7du9W5c2f/WHp6unJycrRq1So9+uijeuWVV+p1PwDUDy5LAWjwLrroIj322GOaMGGCvF6v+vXrp7KyMm3dulXNmjVTRkaGJGnGjBlKTU1VWlqapk6dqlatWumuu+6SJI0fP16DBw/WVVddpe+++07r1q1Tly5dErhXAOKFcAOgUfj1r3+tSy65RLNnz9bevXvVokULXXfddXr88cf9l63mzJmjcePG6auvvlKPHj20evVqOZ1OSZLH49HYsWP1zTffKCUlRbfeequeffbZRO4SgDjhaSkAjd769et100036bvvvlOLFi0SXQ6ABOOeGwAAYCqEGwAAYCpclgIAAKbCmRsAAGAqhBsAAGAqhBsAAGAqhBsAAGAqhBsAAGAqhBsAAGAqhBsAAGAqhBsAAGAqhBsAAGAq/w+FTovqX7BlsQAAAABJRU5ErkJggg==", + "image/png": "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rkWLFmn06NFavHixbr755rPOdTqdcjqdfuN2u73JDtCm3LfZ0KvA0avA0avGoV+Bo1eBC3WvGrOvsC0odjgcysjI8DttlZ2drX79+p1xu4ULF+r+++/XW2+9pVtvvbWpywQAABeYsF6WysrK0r333qs+ffqob9++ev3115Wfn6+xY8dKqrmkdODAAf3pT3+SVBNsRo0apRdffFHXXnut76xPZGSk4uLiwvY+AADA+SOs4WbkyJE6cuSInnjiCRUUFKhbt25avny50tLSJEkFBQX17nnz2muvqaqqSuPHj9f48eN94/fdd58WLFjQ3OUDAIDzUNgXFI8bN07jxo1r8LXvBpZVq1Y1fUEAAOCCFvavXwAAAAglwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADAVwg0AADCVsIebOXPmKD09XS6XSxkZGVq7du1Z569evVoZGRlyuVzq2LGjXn311WaqFAAAXAjCGm4WLVqkSZMmadq0acrJydHAgQM1dOhQ5efnNzh/7969GjZsmAYOHKicnBw9/vjjmjBhgt55551mrhwAAJyvwhpunn/+eY0ePVpjxoxR165dNWvWLKWmpmru3LkNzn/11VfVoUMHzZo1S127dtWYMWP04IMP6ne/+10zVw4AAM5XtnD94srKSm3atElTpkypN56Zman169c3uM2GDRuUmZlZb2zIkCGaN2+ePB6P7Ha73zZut1tut9v3vLi4WJJ09OhReTyec30b9Xg8HpWXl+vIkSMN1oJT6FXg6FXg6FXj0K/A0avANVWvSktLJUmGYXzv3LCFm8OHD8vr9SopKaneeFJSkgoLCxvcprCwsMH5VVVVOnz4sJKTk/22mTlzpmbMmOE3np6efg7VAwCAcCgtLVVcXNxZ54Qt3NSxWCz1nhuG4Tf2ffMbGq8zdepUZWVl+Z5XV1fr6NGjSkhIOOvvCUZJSYlSU1P1zTffKDY2NqT7Nht6FTh6FTh61Tj0K3D0KnBN1SvDMFRaWqqUlJTvnRu2cJOYmCir1ep3lqaoqMjv7Eydtm3bNjjfZrMpISGhwW2cTqecTme9sZYtWwZfeABiY2M5+ANErwJHrwJHrxqHfgWOXgWuKXr1fWds6oRtQbHD4VBGRoays7PrjWdnZ6tfv34NbtO3b1+/+StWrFCfPn24BgoAACSF+dNSWVlZ+v3vf6/58+drx44dmjx5svLz8zV27FhJNZeURo0a5Zs/duxY7du3T1lZWdqxY4fmz5+vefPm6ZFHHgnXWwAAAOeZsK65GTlypI4cOaInnnhCBQUF6tatm5YvX660tDRJUkFBQb173qSnp2v58uWaPHmyXnnlFaWkpOill17S3XffHa63UI/T6dRvfvMbv8tg8EevAkevAkevGod+BY5eBe586JXFCOQzVQAAABeIsH/9AgAAQCgRbgAAgKkQbgAAgKkQbgAAgKkQbs5izpw5Sk9Pl8vlUkZGhtauXXvW+atXr1ZGRoZcLpc6duyoV1991W/OO++8oyuuuEJOp1NXXHGF3n333aYqv1mFulcLFiyQxWLx+6moqGjKt9FsGtOvgoIC3XPPPercubMiIiI0adKkBudxbAXWKzMfW43p1dKlSzV48GC1bt1asbGx6tu3rz766CO/eRxXgfWK46rGJ598ov79+yshIUGRkZHq0qWLXnjhBb95TX5cGWjQ22+/bdjtduONN94w8vLyjIkTJxrR0dHGvn37Gpy/Z88eIyoqypg4caKRl5dnvPHGG4bdbjeWLFnim7N+/XrDarUaTz31lLFjxw7jqaeeMmw2m/Hpp58219tqEk3Rqz/84Q9GbGysUVBQUO/HDBrbr7179xoTJkww/vjHPxo9e/Y0Jk6c6DeHY6tGIL0y67HV2F5NnDjReOaZZ4zPP//c2LlzpzF16lTDbrcbmzdv9s3huKoRSK84rmps3rzZeOutt4wvv/zS2Lt3r/Hmm28aUVFRxmuvveab0xzHFeHmDH7wgx8YY8eOrTfWpUsXY8qUKQ3Of+yxx4wuXbrUG/v5z39uXHvttb7nI0aMMG655ZZ6c4YMGWL85Cc/CVHV4dEUvfrDH/5gxMXFhbzW80Fj+3W6QYMGNfgPNseWvzP1yqzH1rn0qs4VV1xhzJgxw/ec4+rMvtsrjqszu+uuu4yf/exnvufNcVxxWaoBlZWV2rRpkzIzM+uNZ2Zmav369Q1us2HDBr/5Q4YM0caNG+XxeM4650z7vBA0Va8k6cSJE0pLS1P79u112223KScnJ/RvoJkF069AcGw1jtmOrVD0qrq6WqWlpYqPj/eNcVw1rKFeSRxXDcnJydH69es1aNAg31hzHFeEmwYcPnxYXq/X7ws8k5KS/L64s05hYWGD86uqqnT48OGzzjnTPi8ETdWrLl26aMGCBVq2bJkWLlwol8ul/v37a9euXU3zRppJMP0KBMdW4Mx4bIWiV88995zKyso0YsQI3xjHVcMa6hXHVX3t27eX0+lUnz59NH78eI0ZM8b3WnMcV2H9+oXzncViqffcMAy/se+b/93xxu7zQhHqXl177bW69tprfa/3799fvXv31ssvv6yXXnopVGWHTVMcBxxbgTHzsRVsrxYuXKjp06frvffeU5s2bUKyz/NdqHvFcVXf2rVrdeLECX366aeaMmWKLrvsMv30pz89p302BuGmAYmJibJarX4psqioyC9t1mnbtm2D8202mxISEs4650z7vBA0Va++KyIiQldfffUF/V9BUnD9CgTHVvDMcGydS68WLVqk0aNHa/Hixbr55pvrvcZxVd/ZevVdF/txlZ6eLkm66qqrdOjQIU2fPt0XbprjuOKyVAMcDocyMjKUnZ1dbzw7O1v9+vVrcJu+ffv6zV+xYoX69Okju91+1jln2ueFoKl69V2GYSg3N1fJycmhKTxMgulXIDi2gmeGYyvYXi1cuFD333+/3nrrLd16661+r3NcnfJ9vfqui/m4+i7DMOR2u33Pm+W4CtnSZJOp+/jbvHnzjLy8PGPSpElGdHS08e9//9swDMOYMmWKce+99/rm1328efLkyUZeXp4xb948v483r1u3zrBarcbTTz9t7Nixw3j66adN9bHKUPZq+vTpxocffmjs3r3byMnJMR544AHDZrMZn332WbO/v1BrbL8MwzBycnKMnJwcIyMjw7jnnnuMnJwcY/v27b7XObZO+b5emfXYamyv3nrrLcNmsxmvvPJKvY8uHz9+3DeH46pGIL3iuKoxe/ZsY9myZcbOnTuNnTt3GvPnzzdiY2ONadOm+eY0x3FFuDmLV155xUhLSzMcDofRu3dvY/Xq1b7X7rvvPmPQoEH15q9atcro1auX4XA4jEsuucSYO3eu3z4XL15sdO7c2bDb7UaXLl2Md955p6nfRrMIda8mTZpkdOjQwXA4HEbr1q2NzMxMY/369c3xVppFY/slye8nLS2t3hyOrRrf1yszH1uN6dWgQYMa7NV9991Xb58cV4H1iuOqxksvvWRceeWVRlRUlBEbG2v06tXLmDNnjuH1euvts6mPK4th1K7kBAAAMAHW3AAAAFMh3AAAAFMh3AAAAFMh3AAAAFMh3AAAAFMh3AAAAFMh3AAAAFMh3AAAAFMh3AAAAFMh3AAAAFMh3AC4IBiGoWeffVYdO3ZUZGSkevTooSVLlkiSVq1aJYvFog8++EA9evSQy+XSNddco23btvm237dvn4YPH65WrVopOjpaV155pZYvXx6utwOgCdnCXQAABOJXv/qVli5dqrlz56pTp05as2aNfvazn6l169a+OY8++qhefPFFtW3bVo8//rhuv/127dy5U3a7XePHj1dlZaXWrFmj6Oho5eXlKSYmJozvCEBT4YszAZz3ysrKlJiYqJUrV6pv376+8TFjxqi8vFz/9V//pRtuuEFvv/22Ro4cKUk6evSo2rdvrwULFmjEiBHq3r277r77bv3mN78J19sA0Ew4cwPgvJeXl6eKigoNHjy43nhlZaV69erle3568ImPj1fnzp21Y8cOSdKECRP0i1/8QitWrNDNN9+su+++W927d2+eNwCgWbHmBsB5r7q6WpL0wQcfKDc31/eTl5fnW3dzJhaLRVLNWZ49e/bo3nvv1bZt29SnTx+9/PLLTV47gOZHuAFw3rviiivkdDqVn5+vyy67rN5Pamqqb96nn37qe3zs2DHt3LlTXbp08Y2lpqZq7NixWrp0qR5++GG98cYbzfo+ADQPLksBOO+1aNFCjzzyiCZPnqzq6moNGDBAJSUlWr9+vWJiYpSWliZJeuKJJ5SQkKCkpCRNmzZNiYmJuvPOOyVJkyZN0tChQ3X55Zfr2LFjWrlypbp27RrGdwWgqRBuAFwQfvvb36pNmzaaOXOm9uzZo5YtW6p37956/PHHfZetnn76aU2cOFG7du1Sjx49tGzZMjkcDkmS1+vV+PHjtX//fsXGxuqWW27RCy+8EM63BKCJ8GkpABe8VatW6YYbbtCxY8fUsmXLcJcDIMxYcwMAAEyFcAMAAEyFy1IAAMBUOHMDAABMhXADAABMhXADAABMhXADAABMhXADAABMhXADAABMhXADAABMhXADAABMhXADAABM5f8DMF+2Vldq9Z0AAAAASUVORK5CYII=", "text/plain": [ "
" ] @@ -1622,9 +1145,51 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "id": "10f99abc-9e65-49e5-96d8-788028ca2f72", "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Creating sequence of samples: 100%|██████████| 560/560 [00:01<00:00, 517.86it/s]\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "d2e332308d6f4790bb53cee473d9fdf4", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + " 0%| | 0/2154 [00:00 Date: Fri, 28 Jun 2024 13:58:38 +0300 Subject: [PATCH 2/6] upd readme --- README.md | 106 ++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 99 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index a063ab7..047768a 100644 --- a/README.md +++ b/README.md @@ -1,18 +1,110 @@ -# Defense of adversarial attacks on FDD models +# FDD Defense: Adversarial Attacks and Defenses on Fault Diagnosis and Detection models -`fdd-defense` is a python library with adversarial attacks on Fault Detection and Diagnostic (FDD) models and defense methods against attacks. +## Introduction + +The development of the smart manufacturing trend includes the integration of Artificial Intelligence technologies into industrial processes. One example of such implementation is deep learning models that diagnose the current state of a technological process. Recent studies have demonstrated that small data perturbations, named adversarial attacks, can significantly affect the correct predictions of such models. This fact is critical in industrial systems, where AI-based decisions can be made to manage physical equipment. `fdd-defense` helps to evaluate the robustness of technological process diagnosis models to adversarial attacks, as well as consider defense methods. + +`fdd-defense` is a python library with adversarial attacks on Fault Detection and Diagnostic (FDD) models and defense methods against adversarial attacks. This repository contains the original implementation of methods from the paper [Adversarial Attacks and Defenses in Fault Detection and Diagnosis: A Comprehensive Benchmark on the Tennessee Eastman Process](https://ieeexplore.ieee.org/abstract/document/10531068). ## Installing -To install the library, go to the `fdd-defense` directory and run `pip` as follows +To install `fdd-defense`, run the following command: ``` -pip install -e . +pip install git+https://github.com/AIRI-Institute/fdd-defense.git ``` -## Testing +## Usage + +```python +from fdd_defense.models import MLP +from fdd_defense.attackers import FGSMAttacker +from fdd_defense.defenders import AdversarialTrainingDefender +from fdd_defense.utils import evaluate +from fddbenchmark import FDDDataset +from sklearn.preprocessing import StandardScaler + +# Download and scale the TEP dataset +dataset = FDDDataset(name='reinartz_tep') +scaler = StandardScaler() +scaler.fit(dataset.df[dataset.train_mask]) +dataset.df[:] = scaler.transform(dataset.df) + +# Define and train a FDD model +model = MLP( + window_size=50, + step_size=1, + device='cuda', + batch_size=128, + num_epochs=10 +) +model.fit(dataset) -To test the library, run +# Test the FDD model on original data without defense +defender = NoDefenceDefender(model) +attacker = NoAttacker(model, eps=epsilon) +accuracy = evaluate(defender, attacker) +print(f'Accuracy: {accuracy:.4f}') + +# Test the FDD model under FGSM attack without defense +defender = NoDefenceDefender(model) +attacker = FGSMAttacker(defender, eps=epsilon) +accuracy = evaluate(defender, attacker) +print(f'Accuracy: {accuracy:.4f}') + +# Test the FDD model under FGSM attack with Adversarial Training defense +defender = AdversarialTrainingDefender(model) +attacker = FGSMAttacker(defender, eps=epsilon) +accuracy = evaluate(defender, attacker) +print(f'Accuracy: {accuracy:.4f}') ``` -pytest tests + +## Implemented methods + +### FDD models + +| FDD model | Reference | +|-----------------|-----------| +| Linear |Pandya, D., Upadhyay, S. H., & Harsha, S. P. (2014). Fault diagnosis of rolling element bearing by using multinomial logistic regression and wavelet packet transform. Soft Computing, 18, 255-266.| +|Boosting |Ruder, Sebastian. "An overview of gradient descent optimization algorithms." arXiv preprint arXiv:1609.04747 (2016).| +| MLP |Khoualdia, T., Lakehal, A., Chelli, Z., Khoualdia, K., & Nessaib, K. (2021). Optimized multi layer perceptron artificial neural network based fault diagnosis of induction motor using vibration signals. Diagnostyka, 22.| +| GRU, TCN |Lomov, Ildar, et al. "Fault detection in Tennessee Eastman process with temporal deep learning models." Journal of Industrial Information Integration 23 (2021): 100216.| + +### Adversarial attacks + +| Adversarial attack | Reference | +|------------------------|-----------| +| Noise |Zhuo, Yue, Zhenqin Yin, and Zhiqiang Ge. "Attack and defense: Adversarial security of data-driven FDC systems." IEEE Transactions on Industrial Informatics 19.1 (2022): 5-19.| +| FGSM |Goodfellow, Ian J., Jonathon Shlens, and Christian Szegedy. "Explaining and harnessing adversarial examples." arXiv preprint arXiv:1412.6572 (2014).| +| PGD |Madry, Aleksander, et al. "Towards deep learning models resistant to adversarial attacks." arXiv preprint arXiv:1706.06083 (2017).| +| DeepFool |Moosavi-Dezfooli, Seyed-Mohsen, Alhussein Fawzi, and Pascal Frossard. "Deepfool: a simple and accurate method to fool deep neural networks." Proceedings of the IEEE conference on computer vision and pattern recognition. 2016.| +| Carlini & Wagner |Carlini, Nicholas, and David Wagner. "Towards evaluating the robustness of neural networks." 2017 ieee symposium on security and privacy (sp). Ieee, 2017.| +| Distillation black-box |Cui, Weiyu, et al. "Substitute model generation for black-box adversarial attack based on knowledge distillation." 2020 IEEE International Conference on Image Processing (ICIP). IEEE, 2020.| + +### Defense methods + +| Defense method | Reference | +|-------------------------|-----------| +| Adversarial training |Goodfellow, Ian J., Jonathon Shlens, and Christian Szegedy. "Explaining and harnessing adversarial examples." arXiv preprint arXiv:1412.6572 (2014).| +| Data quantization |Guo, Chuan, et al. "Countering adversarial images using input transformations." arXiv preprint arXiv:1711.00117 (2017).| +| Gradient regularization |Finlay, Chris, and Adam M. Oberman. "Scaleable input gradient regularization for adversarial robustness." Machine Learning with Applications 3 (2021): 100017.| +| Defensive distillation |Papernot, Nicolas, et al. "Distillation as a defense to adversarial perturbations against deep neural networks." 2016 IEEE symposium on security and privacy (SP). IEEE, 2016.| +| ATQ |Pozdnyakov, Vitaliy, et al. "Adversarial Attacks and Defenses in Fault Detection and Diagnosis: A Comprehensive Benchmark on the Tennessee Eastman Process." IEEE Open Journal of the Industrial Electronics Society (2024).| + +## Testing + +To test the library, run the command `pytest tests` from the root directory. + +## Citation + +Please cite our paper as follows: + ``` +@article{pozdnyakov2024adversarial, + title={Adversarial Attacks and Defenses in Fault Detection and Diagnosis: A Comprehensive Benchmark on the Tennessee Eastman Process}, + author={Pozdnyakov, Vitaliy and Kovalenko, Aleksandr and Makarov, Ilya and Drobyshevskiy, Mikhail and Lukyanov, Kirill}, + journal={IEEE Open Journal of the Industrial Electronics Society}, + year={2024}, + publisher={IEEE} +} +``` \ No newline at end of file From 794c647c6b0ee77936dedc5e58ca605b4efc37a1 Mon Sep 17 00:00:00 2001 From: Vitaliy Pozdnyakov Date: Wed, 24 Jul 2024 14:47:04 +0300 Subject: [PATCH 3/6] Update README.md --- README.md | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 047768a..1981004 100644 --- a/README.md +++ b/README.md @@ -17,9 +17,9 @@ pip install git+https://github.com/AIRI-Institute/fdd-defense.git ```python from fdd_defense.models import MLP -from fdd_defense.attackers import FGSMAttacker -from fdd_defense.defenders import AdversarialTrainingDefender -from fdd_defense.utils import evaluate +from fdd_defense.attackers import NoAttacker, FGSMAttacker +from fdd_defense.defenders import NoDefenceDefender, AdversarialTrainingDefender +from fdd_defense.utils import accuracy from fddbenchmark import FDDDataset from sklearn.preprocessing import StandardScaler @@ -40,22 +40,22 @@ model = MLP( model.fit(dataset) # Test the FDD model on original data without defense +attacker = NoAttacker(model, eps=0.05) defender = NoDefenceDefender(model) -attacker = NoAttacker(model, eps=epsilon) -accuracy = evaluate(defender, attacker) -print(f'Accuracy: {accuracy:.4f}') +acc = accuracy(attacker, defender, step_size=1) +print(f'Accuracy: {acc:.4f}') # Test the FDD model under FGSM attack without defense +attacker = FGSMAttacker(model, eps=0.05) defender = NoDefenceDefender(model) -attacker = FGSMAttacker(defender, eps=epsilon) -accuracy = evaluate(defender, attacker) -print(f'Accuracy: {accuracy:.4f}') +acc = accuracy(attacker, defender, step_size=1) +print(f'Accuracy: {acc:.4f}') # Test the FDD model under FGSM attack with Adversarial Training defense -defender = AdversarialTrainingDefender(model) -attacker = FGSMAttacker(defender, eps=epsilon) -accuracy = evaluate(defender, attacker) -print(f'Accuracy: {accuracy:.4f}') +attacker = FGSMAttacker(model, eps=0.05) +defender = AdversarialTrainingDefender(model, attacker) +acc = accuracy(attacker, defender, step_size=1) +print(f'Accuracy: {acc:.4f}') ``` @@ -107,4 +107,4 @@ Please cite our paper as follows: year={2024}, publisher={IEEE} } -``` \ No newline at end of file +``` From d23cfb892236fd1b9e846625edcb955012510d7b Mon Sep 17 00:00:00 2001 From: Vitaliy Pozdnyakov Date: Fri, 26 Jul 2024 18:18:56 +0300 Subject: [PATCH 4/6] Update README.md Fix the reference of data quantization --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1981004..3be19c2 100644 --- a/README.md +++ b/README.md @@ -86,7 +86,7 @@ print(f'Accuracy: {acc:.4f}') | Defense method | Reference | |-------------------------|-----------| | Adversarial training |Goodfellow, Ian J., Jonathon Shlens, and Christian Szegedy. "Explaining and harnessing adversarial examples." arXiv preprint arXiv:1412.6572 (2014).| -| Data quantization |Guo, Chuan, et al. "Countering adversarial images using input transformations." arXiv preprint arXiv:1711.00117 (2017).| +| Data quantization |Xu, Weilin, David Evans, and Yanjun Qi. "Feature squeezing: Detecting adversarial examples in deep neural networks." arXiv preprint arXiv:1704.01155 (2017).| | Gradient regularization |Finlay, Chris, and Adam M. Oberman. "Scaleable input gradient regularization for adversarial robustness." Machine Learning with Applications 3 (2021): 100017.| | Defensive distillation |Papernot, Nicolas, et al. "Distillation as a defense to adversarial perturbations against deep neural networks." 2016 IEEE symposium on security and privacy (SP). IEEE, 2016.| | ATQ |Pozdnyakov, Vitaliy, et al. "Adversarial Attacks and Defenses in Fault Detection and Diagnosis: A Comprehensive Benchmark on the Tennessee Eastman Process." IEEE Open Journal of the Industrial Electronics Society (2024).| From 0a768b3257ecee8511b3cc7c0dbbf5f5a8b029d2 Mon Sep 17 00:00:00 2001 From: alex Date: Mon, 5 Aug 2024 08:43:28 +0300 Subject: [PATCH 5/6] n --- experiments.ipynb | 1218 --------------------------------------------- 1 file changed, 1218 deletions(-) delete mode 100644 experiments.ipynb diff --git a/experiments.ipynb b/experiments.ipynb deleted file mode 100644 index 9082c14..0000000 --- a/experiments.ipynb +++ /dev/null @@ -1,1218 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "id": "cee04ff8-462f-4d43-adf9-1596b44fbc6c", - "metadata": {}, - "outputs": [], - "source": [ - "import pandas as pd\n", - "import numpy as np\n", - "from sklearn.preprocessing import StandardScaler\n", - "from tqdm.auto import tqdm\n", - "import matplotlib.pyplot as plt\n", - "import torch\n", - "import warnings\n", - "warnings.filterwarnings('ignore')\n", - "\n", - "from fddbenchmark import FDDDataset, FDDDataloader, FDDEvaluator\n", - "\n", - "from fdd_defense.models import MLP, TCN, GRU\n", - "from fdd_defense.attackers import *\n", - "from fdd_defense.defenders import *\n", - "from fdd_defense.utils import accuracy" - ] - }, - { - "cell_type": "markdown", - "id": "83f1c191-a0c7-4bf1-9f83-8f479bedf28b", - "metadata": {}, - "source": [ - "### Dataset preparation\n", - "https://github.com/airi-industrial-ai/fddbenchmark.git - fdd benchmark with TEP dataset" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "12038362-a880-4cd2-b559-84caaf731a91", - "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "4ba0e25c03f44c84845d4f2c50ad701a", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Reading data/small_tep/dataset.csv: 0%| | 0/153300 [00:00 6\u001b[0m unprotected_acc\u001b[38;5;241m.\u001b[39mappend(accuracy(attacker, defender, step_size\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m10\u001b[39m))\n", - "File \u001b[0;32m~/work/github/attacks/fdd-defense/fdd_defense/utils.py:28\u001b[0m, in \u001b[0;36maccuracy\u001b[0;34m(attacker, defender, step_size)\u001b[0m\n\u001b[1;32m 26\u001b[0m pred \u001b[38;5;241m=\u001b[39m attacker\u001b[38;5;241m.\u001b[39mmodel\u001b[38;5;241m.\u001b[39mpredict(sample)\n\u001b[1;32m 27\u001b[0m adv_sample \u001b[38;5;241m=\u001b[39m attacker\u001b[38;5;241m.\u001b[39mattack(sample, pred)\n\u001b[0;32m---> 28\u001b[0m pred \u001b[38;5;241m=\u001b[39m defender\u001b[38;5;241m.\u001b[39mpredict(adv_sample)\n\u001b[1;32m 29\u001b[0m preds\u001b[38;5;241m.\u001b[39mappend(pred)\n\u001b[1;32m 30\u001b[0m labels\u001b[38;5;241m.\u001b[39mappend(label)\n", - "File \u001b[0;32m~/work/github/attacks/fdd-defense/fdd_defense/defenders/base.py:12\u001b[0m, in \u001b[0;36mBaseDefender.predict\u001b[0;34m(self, ts)\u001b[0m\n\u001b[1;32m 11\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mpredict\u001b[39m(\u001b[38;5;28mself\u001b[39m, ts: np\u001b[38;5;241m.\u001b[39mndarray):\n\u001b[0;32m---> 12\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mmodel\u001b[38;5;241m.\u001b[39mpredict(ts)\n", - "File \u001b[0;32m~/work/github/attacks/fdd-defense/fdd_defense/models/base.py:80\u001b[0m, in \u001b[0;36mBaseTorchModel.predict\u001b[0;34m(self, ts)\u001b[0m\n\u001b[1;32m 78\u001b[0m ts \u001b[38;5;241m=\u001b[39m torch\u001b[38;5;241m.\u001b[39mFloatTensor(ts)\u001b[38;5;241m.\u001b[39mto(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdevice)\n\u001b[1;32m 79\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m torch\u001b[38;5;241m.\u001b[39mno_grad():\n\u001b[0;32m---> 80\u001b[0m logits \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mmodel(ts)\n\u001b[1;32m 81\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m logits\u001b[38;5;241m.\u001b[39margmax(axis\u001b[38;5;241m=\u001b[39m\u001b[38;5;241m1\u001b[39m)\u001b[38;5;241m.\u001b[39mcpu()\u001b[38;5;241m.\u001b[39mnumpy()\n", - "File \u001b[0;32m~/anaconda3/lib/python3.11/site-packages/torch/nn/modules/module.py:1511\u001b[0m, in \u001b[0;36mModule._wrapped_call_impl\u001b[0;34m(self, *args, **kwargs)\u001b[0m\n\u001b[1;32m 1509\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_compiled_call_impl(\u001b[38;5;241m*\u001b[39margs, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs) \u001b[38;5;66;03m# type: ignore[misc]\u001b[39;00m\n\u001b[1;32m 1510\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m-> 1511\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_call_impl(\u001b[38;5;241m*\u001b[39margs, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n", - "File \u001b[0;32m~/anaconda3/lib/python3.11/site-packages/torch/nn/modules/module.py:1520\u001b[0m, in \u001b[0;36mModule._call_impl\u001b[0;34m(self, *args, **kwargs)\u001b[0m\n\u001b[1;32m 1515\u001b[0m \u001b[38;5;66;03m# If we don't have any hooks, we want to skip the rest of the logic in\u001b[39;00m\n\u001b[1;32m 1516\u001b[0m \u001b[38;5;66;03m# this function, and just call forward.\u001b[39;00m\n\u001b[1;32m 1517\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m (\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_backward_hooks \u001b[38;5;129;01mor\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_backward_pre_hooks \u001b[38;5;129;01mor\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_forward_hooks \u001b[38;5;129;01mor\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_forward_pre_hooks\n\u001b[1;32m 1518\u001b[0m \u001b[38;5;129;01mor\u001b[39;00m _global_backward_pre_hooks \u001b[38;5;129;01mor\u001b[39;00m _global_backward_hooks\n\u001b[1;32m 1519\u001b[0m \u001b[38;5;129;01mor\u001b[39;00m _global_forward_hooks \u001b[38;5;129;01mor\u001b[39;00m _global_forward_pre_hooks):\n\u001b[0;32m-> 1520\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m forward_call(\u001b[38;5;241m*\u001b[39margs, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n\u001b[1;32m 1522\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 1523\u001b[0m result \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n", - "File \u001b[0;32m~/work/github/attacks/fdd-defense/fdd_defense/models/tcn.py:195\u001b[0m, in \u001b[0;36mTCNModule.forward\u001b[0;34m(self, x)\u001b[0m\n\u001b[1;32m 193\u001b[0m x \u001b[38;5;241m=\u001b[39m x\u001b[38;5;241m.\u001b[39mtranspose(\u001b[38;5;241m1\u001b[39m, \u001b[38;5;241m2\u001b[39m)\n\u001b[1;32m 194\u001b[0m \u001b[38;5;28;01mfor\u001b[39;00m res_block \u001b[38;5;129;01min\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mres_blocks_list:\n\u001b[0;32m--> 195\u001b[0m x \u001b[38;5;241m=\u001b[39m res_block(x)\n\u001b[1;32m 196\u001b[0m x \u001b[38;5;241m=\u001b[39m x\u001b[38;5;241m.\u001b[39mtranspose(\u001b[38;5;241m1\u001b[39m, \u001b[38;5;241m2\u001b[39m)[:, \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m1\u001b[39m, :]\n\u001b[1;32m 197\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m x\n", - "File \u001b[0;32m~/anaconda3/lib/python3.11/site-packages/torch/nn/modules/module.py:1511\u001b[0m, in \u001b[0;36mModule._wrapped_call_impl\u001b[0;34m(self, *args, **kwargs)\u001b[0m\n\u001b[1;32m 1509\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_compiled_call_impl(\u001b[38;5;241m*\u001b[39margs, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs) \u001b[38;5;66;03m# type: ignore[misc]\u001b[39;00m\n\u001b[1;32m 1510\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m-> 1511\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_call_impl(\u001b[38;5;241m*\u001b[39margs, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n", - "File \u001b[0;32m~/anaconda3/lib/python3.11/site-packages/torch/nn/modules/module.py:1520\u001b[0m, in \u001b[0;36mModule._call_impl\u001b[0;34m(self, *args, **kwargs)\u001b[0m\n\u001b[1;32m 1515\u001b[0m \u001b[38;5;66;03m# If we don't have any hooks, we want to skip the rest of the logic in\u001b[39;00m\n\u001b[1;32m 1516\u001b[0m \u001b[38;5;66;03m# this function, and just call forward.\u001b[39;00m\n\u001b[1;32m 1517\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m (\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_backward_hooks \u001b[38;5;129;01mor\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_backward_pre_hooks \u001b[38;5;129;01mor\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_forward_hooks \u001b[38;5;129;01mor\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_forward_pre_hooks\n\u001b[1;32m 1518\u001b[0m \u001b[38;5;129;01mor\u001b[39;00m _global_backward_pre_hooks \u001b[38;5;129;01mor\u001b[39;00m _global_backward_hooks\n\u001b[1;32m 1519\u001b[0m \u001b[38;5;129;01mor\u001b[39;00m _global_forward_hooks \u001b[38;5;129;01mor\u001b[39;00m _global_forward_pre_hooks):\n\u001b[0;32m-> 1520\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m forward_call(\u001b[38;5;241m*\u001b[39margs, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n\u001b[1;32m 1522\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[1;32m 1523\u001b[0m result \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m\n", - "File \u001b[0;32m~/work/github/attacks/fdd-defense/fdd_defense/models/tcn.py:98\u001b[0m, in \u001b[0;36mResidualBlock.forward\u001b[0;34m(self, x)\u001b[0m\n\u001b[1;32m 94\u001b[0m \u001b[38;5;66;03m# first step\u001b[39;00m\n\u001b[1;32m 95\u001b[0m left_padding \u001b[38;5;241m=\u001b[39m (\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdilation_base\u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mnr_blocks_below) \u001b[38;5;241m*\u001b[39m (\n\u001b[1;32m 96\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mkernel_size \u001b[38;5;241m-\u001b[39m \u001b[38;5;241m1\u001b[39m\n\u001b[1;32m 97\u001b[0m )\n\u001b[0;32m---> 98\u001b[0m x \u001b[38;5;241m=\u001b[39m F\u001b[38;5;241m.\u001b[39mpad(x, (left_padding, \u001b[38;5;241m0\u001b[39m))\n\u001b[1;32m 99\u001b[0m x \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mdropout_fn(F\u001b[38;5;241m.\u001b[39mrelu(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mconv1(x)))\n\u001b[1;32m 101\u001b[0m \u001b[38;5;66;03m# second step\u001b[39;00m\n", - "File \u001b[0;32m~/anaconda3/lib/python3.11/site-packages/torch/nn/functional.py:4495\u001b[0m, in \u001b[0;36mpad\u001b[0;34m(input, pad, mode, value)\u001b[0m\n\u001b[1;32m 4488\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mlen\u001b[39m(pad) \u001b[38;5;241m==\u001b[39m \u001b[38;5;241m4\u001b[39m \u001b[38;5;129;01mand\u001b[39;00m (\u001b[38;5;28minput\u001b[39m\u001b[38;5;241m.\u001b[39mdim() \u001b[38;5;241m==\u001b[39m \u001b[38;5;241m3\u001b[39m \u001b[38;5;129;01mor\u001b[39;00m \u001b[38;5;28minput\u001b[39m\u001b[38;5;241m.\u001b[39mdim() \u001b[38;5;241m==\u001b[39m \u001b[38;5;241m4\u001b[39m) \u001b[38;5;129;01mand\u001b[39;00m mode \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124mreplicate\u001b[39m\u001b[38;5;124m'\u001b[39m:\n\u001b[1;32m 4489\u001b[0m \u001b[38;5;66;03m# Use slow decomp whose backward will be in terms of index_put.\u001b[39;00m\n\u001b[1;32m 4490\u001b[0m \u001b[38;5;66;03m# importlib is required because the import cannot be top level\u001b[39;00m\n\u001b[1;32m 4491\u001b[0m \u001b[38;5;66;03m# (cycle) and cannot be nested (TS doesn't support)\u001b[39;00m\n\u001b[1;32m 4492\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m importlib\u001b[38;5;241m.\u001b[39mimport_module(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mtorch._decomp.decompositions\u001b[39m\u001b[38;5;124m'\u001b[39m)\u001b[38;5;241m.\u001b[39mreplication_pad2d(\n\u001b[1;32m 4493\u001b[0m \u001b[38;5;28minput\u001b[39m, pad\n\u001b[1;32m 4494\u001b[0m )\n\u001b[0;32m-> 4495\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m torch\u001b[38;5;241m.\u001b[39m_C\u001b[38;5;241m.\u001b[39m_nn\u001b[38;5;241m.\u001b[39mpad(\u001b[38;5;28minput\u001b[39m, pad, mode, value)\n", - "\u001b[0;31mKeyboardInterrupt\u001b[0m: " - ] - } - ], - "source": [ - "eps_space = np.linspace(1e-6, 0.3, 20)\n", - "unprotected_acc = []\n", - "defender = NoDefenceDefender(model)\n", - "for eps in eps_space:\n", - " attacker = CarliniWagnerAttacker(model, eps=eps)\n", - " unprotected_acc.append(accuracy(attacker, defender, step_size=10))" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "035a15eb-bff7-4aad-91af-563013d91f37", - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "plt.plot(eps_space, unprotected_acc)\n", - "plt.xlabel('eps')\n", - "plt.ylabel('accuracy')\n", - "plt.ylim(ymin=0,ymax=1)\n", - "plt.grid()\n", - "plt.show()" - ] - }, - { - "cell_type": "markdown", - "id": "4361e602-edc6-43a1-9442-db691a2ea148", - "metadata": {}, - "source": [ - "### Accuracy of the protected model under attack\n", - "defender -- can be selected from AdversarialTrainingDefender, QuantizationDefender, DistillationDefender, RegularizationDefender, AutoEncoderDefender and ATQDefender" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "e65bff16-eba3-4193-9db4-0bcde5433bef", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "ATQ training...\n" - ] - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "ebcb82357a4047b9a6782cb98feb2a3b", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "Epochs ...: 0%| | 0/10 [00:00" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "plt.plot(eps_space, protected_acc)\n", - "plt.xlabel('eps')\n", - "plt.ylabel('accuracy')\n", - "plt.ylim(ymin=0,ymax=1)\n", - "plt.grid()\n", - "plt.show()" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "10f99abc-9e65-49e5-96d8-788028ca2f72", - "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Creating sequence of samples: 100%|██████████| 560/560 [00:01<00:00, 517.86it/s]\n" - ] - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "d2e332308d6f4790bb53cee473d9fdf4", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - " 0%| | 0/2154 [00:00 Date: Wed, 7 Aug 2024 11:23:58 +0300 Subject: [PATCH 6/6] notebook add comments --- experiments.ipynb | 1682 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1682 insertions(+) create mode 100644 experiments.ipynb diff --git a/experiments.ipynb b/experiments.ipynb new file mode 100644 index 0000000..0a9489a --- /dev/null +++ b/experiments.ipynb @@ -0,0 +1,1682 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "cee04ff8-462f-4d43-adf9-1596b44fbc6c", + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "import numpy as np\n", + "from sklearn.preprocessing import StandardScaler\n", + "from tqdm.auto import tqdm\n", + "import matplotlib.pyplot as plt\n", + "import torch\n", + "import warnings\n", + "warnings.filterwarnings('ignore')\n", + "\n", + "from fddbenchmark import FDDDataset, FDDDataloader, FDDEvaluator\n", + "\n", + "from fdd_defense.models import MLP, TCN, GRU\n", + "from fdd_defense.attackers import *\n", + "from fdd_defense.defenders import *\n", + "from fdd_defense.utils import accuracy" + ] + }, + { + "cell_type": "markdown", + "id": "83f1c191-a0c7-4bf1-9f83-8f479bedf28b", + "metadata": {}, + "source": [ + "### Dataset preparation\n", + "https://github.com/airi-industrial-ai/fddbenchmark.git - fdd benchmark with TEP dataset" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "12038362-a880-4cd2-b559-84caaf731a91", + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "d0134859afbb428a9d26bd2d28f879d6", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Reading data/reinartz_tep/dataset.csv: 0%| | 0/5600000 [00:00" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plt.plot(eps_space, unprotected_acc)\n", + "plt.xlabel('eps')\n", + "plt.ylabel('accuracy')\n", + "plt.ylim(ymin=0,ymax=1)\n", + "plt.grid()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "4361e602-edc6-43a1-9442-db691a2ea148", + "metadata": {}, + "source": [ + "### Accuracy of the protected model under attack\n", + "defender -- can be selected from AdversarialTrainingDefender, QuantizationDefender, DistillationDefender, RegularizationDefender, AutoEncoderDefender and ATQDefender" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "e65bff16-eba3-4193-9db4-0bcde5433bef", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ATQ training...\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "2c8e40bc2f864384857f1fbdd6055826", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Epochs ...: 0%| | 0/10 [00:00" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plt.plot(eps_space, protected_acc)\n", + "plt.xlabel('eps')\n", + "plt.ylabel('accuracy')\n", + "plt.ylim(ymin=0,ymax=1)\n", + "plt.grid()\n", + "plt.show()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "10f99abc-9e65-49e5-96d8-788028ca2f72", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.7" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}