diff --git a/example/adversarial_example/example_evasion_attack_svm.ipynb b/example/adversarial_example/example_evasion_attack_svm.ipynb index 5acfec14..70fe0a8c 100644 --- a/example/adversarial_example/example_evasion_attack_svm.ipynb +++ b/example/adversarial_example/example_evasion_attack_svm.ipynb @@ -155,7 +155,7 @@ "outputs": [], "source": [ "X_minus_1 = X_train[np.where(y_train == \"3\")]\n", - "attacker = Evasion_attack_sklearn(clf = clf, X_minus_1 = X_minus_1,\n", + "attacker = Evasion_attack_sklearn(target_model = clf, X_minus_1 = X_minus_1,\n", " dmax = (5000 / 255) * 2.5,\n", " max_iter = 300,\n", " gamma = 1 / (X_train.shape[1] * np.var(X_train)),\n", diff --git a/example/adversarial_example/example_poison_attack.ipynb b/example/adversarial_example/example_poison_attack.ipynb index f039a169..5a1f0c44 100644 --- a/example/adversarial_example/example_poison_attack.ipynb +++ b/example/adversarial_example/example_poison_attack.ipynb @@ -131,7 +131,7 @@ "plt.title(\"poisoning attack against SVM\")\n", "plt.xlabel(\"num of iterations\")\n", "plt.ylabel(\"accuracy on validation data\")\n", - "plt.savefig(\"poison_loss.png\")\n", + "# plt.savefig(\"poison_loss.png\")\n", "plt.show()" ] }, @@ -143,7 +143,7 @@ "source": [ "plt.imshow(xc_attacked.reshape(28,28),cmap='gray')\n", "plt.title(\"After Attack\")\n", - "plt.savefig(\"poison_example.png\")\n", + "# plt.savefig(\"poison_example.png\")\n", "plt.show()" ] }, diff --git a/example/membership_inference/membership_inference_CIFAR10.ipynb b/example/membership_inference/membership_inference_CIFAR10.ipynb index 7ecba553..5006c8bf 100644 --- a/example/membership_inference/membership_inference_CIFAR10.ipynb +++ b/example/membership_inference/membership_inference_CIFAR10.ipynb @@ -3,7 +3,7 @@ { "cell_type": "code", "execution_count": null, - "id": "subtle-teddy", + "id": "round-northern", "metadata": { "id": "crucial-backup" }, @@ -32,7 +32,7 @@ }, { "cell_type": "markdown", - "id": "legal-sister", + "id": "indian-candy", "metadata": { "id": "7XFU8Q1i9OUt" }, @@ -43,7 +43,7 @@ { "cell_type": "code", "execution_count": null, - "id": "anonymous-junction", + "id": "upper-cambridge", "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -59,7 +59,7 @@ }, { "cell_type": "markdown", - "id": "novel-albany", + "id": "cheap-heath", "metadata": { "id": "still-column" }, @@ -70,7 +70,7 @@ { "cell_type": "code", "execution_count": null, - "id": "racial-friend", + "id": "cloudy-investing", "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -89,7 +89,7 @@ { "cell_type": "code", "execution_count": null, - "id": "coral-cedar", + "id": "terminal-couple", "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -112,7 +112,7 @@ { "cell_type": "code", "execution_count": null, - "id": "flush-montgomery", + "id": "organized-visitor", "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -144,7 +144,7 @@ { "cell_type": "code", "execution_count": null, - "id": "shaped-gamma", + "id": "dedicated-minister", "metadata": { "id": "norwegian-needle" }, @@ -163,7 +163,7 @@ { "cell_type": "code", "execution_count": null, - "id": "developmental-survival", + "id": "regulated-details", "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -178,7 +178,7 @@ }, { "cell_type": "markdown", - "id": "provincial-newark", + "id": "brilliant-occasion", "metadata": { "id": "reserved-month" }, @@ -189,7 +189,7 @@ { "cell_type": "code", "execution_count": null, - "id": "vulnerable-peter", + "id": "small-rebecca", "metadata": { "id": "special-sperm" }, @@ -247,7 +247,7 @@ { "cell_type": "code", "execution_count": null, - "id": "treated-responsibility", + "id": "finished-mathematics", "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -270,6 +270,7 @@ " inputs, labels = data\n", " inputs = inputs.to(device)\n", " labels = labels.to(device)\n", + " labels = labels.to(torch.int64)\n", " # zero the parameter gradients\n", " optimizer.zero_grad()\n", "\n", @@ -340,7 +341,7 @@ }, { "cell_type": "markdown", - "id": "limited-kidney", + "id": "excellent-emission", "metadata": { "id": "DmKyjcOI9Wy5" }, @@ -351,7 +352,7 @@ { "cell_type": "code", "execution_count": null, - "id": "innovative-individual", + "id": "stable-spencer", "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -384,7 +385,7 @@ }, { "cell_type": "markdown", - "id": "surface-daughter", + "id": "burning-supplier", "metadata": { "id": "selected-tournament" }, @@ -395,7 +396,7 @@ { "cell_type": "code", "execution_count": null, - "id": "ahead-payment", + "id": "statistical-dominant", "metadata": { "id": "atomic-insulation" }, @@ -450,39 +451,30 @@ { "cell_type": "code", "execution_count": null, - "id": "corporate-robertson", - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "dmHcP0AB1Fqp", - "outputId": "d64a3497-ca7f-417d-dbb0-732e75a258fa" - }, + "id": "fitting-webster", + "metadata": {}, "outputs": [], "source": [ - "shadow_models = [Net().to(device),\r\n", - " Net().to(device),\r\n", - " Net().to(device), \r\n", - " Net().to(device), \r\n", - " Net().to(device)]\r\n", - "shadow_data_size = 2000\r\n", - "shadow_transform = transform\r\n", - "\r\n", - "num_label = 10\r\n", - "attack_models = [SVC(probability=True) for i in range(10)]\r\n", - "\r\n", - "y_test = np.array(y_test)\r\n", - "\r\n", - "mi = Membership_Inference(shadow_models, attack_models,\r\n", - " shadow_data_size, shadow_transform)\r\n", - "mi.shadow(X_test, y_test, num_itr=20)\r\n", - "mi.attack()" + "shadow_models = [Net().to(device),\n", + " Net().to(device)]\n", + "shadow_data_size = 2000\n", + "shadow_transform = transform\n", + "\n", + "num_label = 10\n", + "attack_models = [SVC(probability=True) for i in range(num_label)]\n", + "\n", + "y_test = np.array(y_test).astype(np.int64)\n", + "\n", + "mi = Membership_Inference(victim_net, shadow_models, attack_models,\n", + " shadow_data_size, shadow_transform)\n", + "mi.train_shadow(X_test, y_test, num_itr=1)\n", + "mi.train_attacker()" ] }, { "cell_type": "code", "execution_count": null, - "id": "meaning-spirituality", + "id": "further-broadcasting", "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -505,7 +497,7 @@ { "cell_type": "code", "execution_count": null, - "id": "sufficient-cream", + "id": "greenhouse-whole", "metadata": { "colab": { "base_uri": "https://localhost:8080/" @@ -535,7 +527,7 @@ { "cell_type": "code", "execution_count": null, - "id": "attempted-interference", + "id": "sustainable-thomson", "metadata": { "colab": { "base_uri": "https://localhost:8080/", @@ -553,7 +545,7 @@ " \r\n", " plt.title(\"overfitting - membership inference performance\")\r\n", " plt.xlabel(\"victim model: trian_accuracy - test_accuracy per class\")\r\n", - " plt.ylabel(\"attack model: auc per class\")\r\n", + " plt.ylabel(\"attack model: auc per clas# s\")\r\n", "\r\n", " plt.savefig(\"membership_inference_overfitting.png\")" ] @@ -580,7 +572,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.6" + "version": "3.9.1" } }, "nbformat": 4, diff --git a/example/membership_inference/membership_inference_overfitting.png b/example/membership_inference/membership_inference_overfitting.png new file mode 100644 index 00000000..2cac9855 Binary files /dev/null and b/example/membership_inference/membership_inference_overfitting.png differ diff --git a/example/membership_inference/notebook/old/mnist.ipynb b/example/membership_inference/notebook/old/mnist.ipynb deleted file mode 100644 index f37a6b82..00000000 --- a/example/membership_inference/notebook/old/mnist.ipynb +++ /dev/null @@ -1,319 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "id": "dedicated-device", - "metadata": {}, - "outputs": [], - "source": [ - "from membership_inference import DataSet, ShadowModel, AttackerModel\n", - "\n", - "import numpy as np\n", - "import random\n", - "import matplotlib.pyplot as plt\n", - "import torch\n", - "import torchvision\n", - "import torchvision.transforms as transforms\n", - "import torch.nn as nn\n", - "import torch.nn.functional as F\n", - "import torch.optim as optim\n", - "\n", - "from torch.utils.data.dataset import Dataset\n", - "from torch.utils.data import DataLoader\n", - "\n", - "from sklearn.model_selection import train_test_split\n", - "from sklearn.metrics import accuracy_score" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "russian-profit", - "metadata": {}, - "outputs": [], - "source": [ - "# トレーニングデータをダウンロード\n", - "trainset = torchvision.datasets.MNIST(root='./data', train=True, download=True)\n", - "# テストデータをダウンロード\n", - "testset = torchvision.datasets.MNIST(root='./data', train=False, download=True)\n", - "\n", - "X_train = np.array(trainset.data)\n", - "y_train = np.array(trainset.targets)\n", - "\n", - "X_test = np.array(testset.data)\n", - "y_test = np.array(testset.targets)\n", - "\n", - "print(X_train.shape, y_train.shape)\n", - "print(X_test.shape, y_test.shape)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ambient-basin", - "metadata": {}, - "outputs": [], - "source": [ - "victim_idx = random.sample(range(X_train.shape[0]), k=1000)\n", - "attack_idx = random.sample(range(X_test.shape[0]), k=2000)\n", - "shadow_idx = attack_idx[:1000]\n", - "eval_idx = attack_idx[1000:]\n", - "\n", - "X_victim = X_train[victim_idx]\n", - "y_victim = y_train[victim_idx]\n", - "\n", - "X_shadow = X_test[shadow_idx]\n", - "y_shadow = y_test[shadow_idx]\n", - "\n", - "X_eval = X_test[eval_idx]\n", - "y_eval = y_test[eval_idx]\n", - "\n", - "print(X_victim.shape, y_victim.shape)\n", - "print(X_shadow.shape, y_shadow.shape)\n", - "print(X_eval.shape, y_eval.shape)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "sealed-shadow", - "metadata": {}, - "outputs": [], - "source": [ - "# ToTensor:画像のグレースケール化(RGBの0~255を0~1の範囲に正規化)、Normalize:Z値化(RGBの平均と標準偏差を0.5で決め打ちして正規化)\n", - "transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5, ), (0.5, ))])\n", - "\n", - "victimset = DataSet(X_victim, y_victim, transform=transform)\n", - "victimloader = torch.utils.data.DataLoader(victimset, batch_size=4, shuffle=True, num_workers=2)\n", - "\n", - "valset = DataSet(X_eval, y_eval, transform=transform)\n", - "valloader = torch.utils.data.DataLoader(valset, batch_size=4, shuffle=True, num_workers=2)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "charitable-brunswick", - "metadata": {}, - "outputs": [], - "source": [ - "class Net(nn.Module):\n", - " def __init__(self):\n", - " super(Net, self).__init__()\n", - " self.conv1 = nn.Conv2d(1, 32, 3) # 28x28x32 -> 26x26x32\n", - " self.conv2 = nn.Conv2d(32, 64, 3) # 26x26x64 -> 24x24x64 \n", - " self.pool = nn.MaxPool2d(2, 2) # 24x24x64 -> 12x12x64\n", - " self.dropout1 = nn.Dropout2d()\n", - " self.fc1 = nn.Linear(12 * 12 * 64, 128)\n", - " self.dropout2 = nn.Dropout2d()\n", - " self.fc2 = nn.Linear(128, 10)\n", - "\n", - " def forward(self, x):\n", - " x = F.relu(self.conv1(x))\n", - " x = self.pool(F.relu(self.conv2(x)))\n", - " #x = self.dropout1(x)\n", - " x = x.view(-1, 12 * 12 * 64)\n", - " x = F.relu(self.fc1(x))\n", - " #x = self.dropout2(x)\n", - " x = self.fc2(x)\n", - " #x = F.softmax(x, dim=1)\n", - " return x\n", - " \n", - "victim_net = Net()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "substantial-edwards", - "metadata": {}, - "outputs": [], - "source": [ - "# 交差エントロピー\n", - "criterion = nn.CrossEntropyLoss()\n", - "# 確率的勾配降下法\n", - "optimizer = optim.SGD(victim_net.parameters(), lr=0.005, momentum=0.9)\n", - "\n", - "for epoch in range(20): # loop over the dataset multiple times\n", - "\n", - " running_loss = 0.0\n", - " for i, data in enumerate(victimloader, 0):\n", - " # get the inputs; data is a list of [inputs, labels]\n", - " inputs, labels = data\n", - "\n", - " # zero the parameter gradients\n", - " optimizer.zero_grad()\n", - "\n", - " # forward + backward + optimize\n", - " outputs = victim_net(inputs)\n", - " loss = criterion(outputs, labels)\n", - " loss.backward()\n", - " optimizer.step()\n", - "\n", - " # print statistics\n", - " running_loss += loss.item()\n", - " if i % 2000 == 1999: # print every 2000 mini-batches\n", - " print('[%d, %5d] loss: %.3f' %\n", - " (epoch + 1, i + 1, running_loss / 2000))\n", - " running_loss = 0.0\n", - "\n", - " test_preds = []\n", - " test_label = []\n", - " with torch.no_grad():\n", - " for data in valloader:\n", - " inputs, labels = data\n", - " outputs = victim_net(inputs)\n", - " test_preds.append(outputs)\n", - " test_label.append(labels) \n", - " test_preds = torch.cat(test_preds)\n", - " test_label = torch.cat(test_label) \n", - "\n", - " print(accuracy_score(np.array(torch.argmax(test_preds, axis=1)), np.array(test_label)))\n", - "\n", - "print('Finished Training')\n", - "\n", - "\n", - "in_preds = []\n", - "in_label = []\n", - "with torch.no_grad():\n", - " for data in victimloader:\n", - " inputs, labels = data\n", - " outputs = victim_net(inputs)\n", - " in_preds.append(outputs)\n", - " in_label.append(labels) \n", - " in_preds = torch.cat(in_preds)\n", - " in_label = torch.cat(in_label) \n", - "print(accuracy_score(np.array(torch.argmax(in_preds, axis=1)),\n", - " np.array(in_label)))\n", - "\n", - "out_preds = []\n", - "out_label = []\n", - "with torch.no_grad():\n", - " for data in valloader:\n", - " inputs, labels = data\n", - " outputs = victim_net(inputs)\n", - " out_preds.append(outputs)\n", - " out_label.append(labels) \n", - " out_preds = torch.cat(out_preds)\n", - " out_label = torch.cat(out_label) \n", - "print(accuracy_score(np.array(torch.argmax(out_preds, axis=1)),\n", - " np.array(out_label)))" - ] - }, - { - "cell_type": "markdown", - "id": "complimentary-necessity", - "metadata": {}, - "source": [ - "# Shadow model" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "classified-lunch", - "metadata": {}, - "outputs": [], - "source": [ - "# CNNを実装する\n", - "class Net(nn.Module):\n", - " def __init__(self):\n", - " super(Net, self).__init__()\n", - " self.conv1 = nn.Conv2d(1, 32, 3) # 28x28x32 -> 26x26x32\n", - " self.conv2 = nn.Conv2d(32, 64, 3) # 26x26x64 -> 24x24x64 \n", - " self.pool = nn.MaxPool2d(2, 2) # 24x24x64 -> 12x12x64\n", - " self.dropout1 = nn.Dropout2d()\n", - " self.fc1 = nn.Linear(12 * 12 * 64, 128)\n", - " self.dropout2 = nn.Dropout2d()\n", - " self.fc2 = nn.Linear(128, 10)\n", - "\n", - " def forward(self, x):\n", - " x = F.relu(self.conv1(x))\n", - " x = self.pool(F.relu(self.conv2(x)))\n", - " x = self.dropout1(x)\n", - " x = x.view(-1, 12 * 12 * 64)\n", - " x = F.relu(self.fc1(x))\n", - " x = self.dropout2(x)\n", - " x = self.fc2(x)\n", - " #x = F.softmax(x, dim=1)\n", - " return x" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "related-missouri", - "metadata": {}, - "outputs": [], - "source": [ - "sm = ShadowModel([Net(), Net(),Net(), Net(), Net(), Net()], 500, shadow_transform=transform)\n", - "y_shadow = np.array(y_shadow)\n", - "result = sm.fit_transform(X_shadow, y_shadow, num_itr=10)" - ] - }, - { - "cell_type": "markdown", - "id": "permanent-eligibility", - "metadata": {}, - "source": [ - "# Attack model" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "tropical-physiology", - "metadata": {}, - "outputs": [], - "source": [ - "from sklearn.svm import SVC\n", - "models = [SVC() for i in range(len(result.keys()))]\n", - "am = AttackerModel(models)\n", - "am.fit(result)\n", - "\n", - "attack_pred_in = am.predict(in_preds, in_label)\n", - "attack_pred_out = am.predict(out_preds, out_label)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "younger-camping", - "metadata": {}, - "outputs": [], - "source": [ - "print(\"accuracy is \", (sum(attack_pred_in) + 1000 - sum(attack_pred_out)) / 2000)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "facial-matter", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "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.9.1" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/example/membership_inference/notebook/old/svm.ipynb b/example/membership_inference/notebook/old/svm.ipynb deleted file mode 100644 index f0928232..00000000 --- a/example/membership_inference/notebook/old/svm.ipynb +++ /dev/null @@ -1,350 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "id": "dominant-wheel", - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np \n", - "import time\n", - "import copy\n", - "import os\n", - "import random\n", - "import sklearn\n", - "from sklearn import datasets\n", - "from sklearn import metrics\n", - "from sklearn.svm import SVC\n", - "from sklearn.model_selection import train_test_split\n", - "import matplotlib.pyplot as plt\n", - "from sklearn.model_selection import KFold\n", - "from sklearn.linear_model import LogisticRegression" - ] - }, - { - "cell_type": "markdown", - "id": "settled-heavy", - "metadata": {}, - "source": [ - "# Load data\n", - "\n", - "we'll use mnist." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "junior-boston", - "metadata": {}, - "outputs": [], - "source": [ - "mnist = datasets.fetch_openml('mnist_784', version=1, data_home=\".\", return_X_y=True)\n", - "imagedata, labeldata = mnist[0],mnist[1]\n", - "print(\"画像データ数:\"+str(imagedata.shape))\n", - "print(\"ラベルデータ数:\"+str(labeldata.shape))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "sixth-insertion", - "metadata": {}, - "outputs": [], - "source": [ - "mnist_data = mnist[0].values / 255\n", - "mnist_label = mnist[1].values\n", - "\n", - "print(mnist_data.shape)\n", - "print(mnist_label.shape)" - ] - }, - { - "cell_type": "markdown", - "id": "middle-grammar", - "metadata": {}, - "source": [ - "We devide our data three: train data, shadow data, and evaluation data." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "eligible-roots", - "metadata": {}, - "outputs": [], - "source": [ - "random.seed(42)\n", - "\n", - "idxs = list(range(mnist_data.shape[0]))\n", - "random.shuffle(idxs)\n", - "\n", - "train_idx = idxs[:500]\n", - "shadow_idx = idxs[500:1000]\n", - "eval_idx = idxs[1000:1500]\n", - "\n", - "train_data = mnist_data[train_idx]\n", - "shadow_data = mnist_data[shadow_idx]\n", - "eval_data = mnist_data[eval_idx]\n", - "\n", - "train_label = mnist_label[train_idx]\n", - "shadow_label = mnist_label[shadow_idx]\n", - "eval_label = mnist_label[eval_idx]\n", - "\n", - "print(\"train_data shape is \", train_data.shape)\n", - "print(\"shadow_data shape is \", shadow_data.shape)\n", - "print(\"eval_data shape is \", eval_data.shape)" - ] - }, - { - "cell_type": "markdown", - "id": "significant-assist", - "metadata": { - "jupyter": { - "outputs_hidden": true - } - }, - "source": [ - "# Target model\n", - "\n", - "We assume that the target use SVM. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "tough-ordinary", - "metadata": {}, - "outputs": [], - "source": [ - "target_model = SVC(probability=True)\n", - "target_model.fit(train_data, train_label)\n", - "\n", - "target_pred = target_model.predict(train_data)\n", - "target_prob = target_model.predict_proba(train_data)\n", - "\n", - "eval_pred = target_model.predict(eval_data)\n", - "eval_prob = target_model.predict_proba(eval_data)\n", - "\n", - "ac_score = metrics.accuracy_score(target_pred, train_label)\n", - "print(ac_score)\n", - "ac_score = metrics.accuracy_score(eval_pred, eval_label)\n", - "print(ac_score)" - ] - }, - { - "cell_type": "markdown", - "id": "harmful-marble", - "metadata": {}, - "source": [ - "# Shadow model\n", - "\n", - "We also use SVM as shadow model and create 5 models with k-fold. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "affiliated-passion", - "metadata": {}, - "outputs": [], - "source": [ - "kf = KFold(n_splits=5,\n", - " random_state=42,\n", - " shuffle=True)\n", - "\n", - "in_probs = []\n", - "out_probs = []\n", - "shadow_in_labels = []\n", - "shadow_out_labels = []\n", - "\n", - "for trn_idx, val_idx in kf.split(shadow_data):\n", - " in_data = shadow_data[trn_idx]\n", - " out_data =shadow_data[val_idx]\n", - " in_label = shadow_label[trn_idx]\n", - " out_label = shadow_label[val_idx]\n", - " \n", - " shadow_model = SVC(probability=True)\n", - " shadow_model.fit(in_data, in_label)\n", - " \n", - " in_prob = shadow_model.predict_proba(in_data)\n", - " out_prob = shadow_model.predict_proba(out_data)\n", - " \n", - " in_probs.append(in_prob)\n", - " out_probs.append(out_prob)\n", - " \n", - " shadow_in_labels.append(in_label)\n", - " shadow_out_labels.append(out_label)" - ] - }, - { - "cell_type": "markdown", - "id": "twelve-statistics", - "metadata": {}, - "source": [ - "create labels to train attack model. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "imperial-intranet", - "metadata": {}, - "outputs": [], - "source": [ - "in_probs = np.concatenate(in_probs)\n", - "out_probs = np.concatenate(out_probs)\n", - "\n", - "in_labels = np.ones(in_probs.shape[0])\n", - "out_labels = np.zeros(out_probs.shape[0])\n", - "\n", - "attack_data = np.concatenate([in_probs, out_probs])\n", - "attack_label = np.concatenate([in_labels, out_labels])\n", - "\n", - "shadow_in_labels = np.concatenate(shadow_in_labels)\n", - "shadow_out_labels = np.concatenate(shadow_out_labels)\n", - "shadow_original_label = np.concatenate([shadow_in_labels,\n", - " shadow_out_labels])\n", - "\n", - "attack_data_idx = list(range(attack_data.shape[0]))\n", - "random.shuffle(attack_data_idx)\n", - "\n", - "attack_data = attack_data[attack_data_idx]\n", - "attack_label = attack_label[attack_data_idx]\n", - "shadow_original_label = shadow_original_label[attack_data_idx]" - ] - }, - { - "cell_type": "markdown", - "id": "processed-flesh", - "metadata": {}, - "source": [ - "# Attack model\n", - "\n", - "We make SVM classifier for each label as attack model." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "narrow-postcard", - "metadata": {}, - "outputs": [], - "source": [ - "unique_labels = np.unique(shadow_original_label)\n", - "\n", - "all_attack_true_label = np.zeros_like(shadow_original_label).astype(int)\n", - "all_attack_preds = np.zeros_like(shadow_original_label).astype(int)\n", - "\n", - "attack_model_dict = {ul:None for ul in unique_labels}\n", - "\n", - "for label in unique_labels:\n", - "\n", - " label_idx = np.where(shadow_original_label == label)[0]\n", - "\n", - " attack_label_data = attack_data[label_idx]\n", - " attack_label_label = attack_label[label_idx]\n", - "\n", - " attack_model = SVC(probability=True)\n", - " attack_model.fit(attack_label_data, attack_label_label)\n", - " attack_pred = attack_model.predict(attack_label_data)\n", - "\n", - " all_attack_true_label[label_idx] = attack_label_label\n", - " all_attack_preds[label_idx] = attack_pred\n", - " \n", - " attack_model_dict[label] = attack_model" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "after-quilt", - "metadata": {}, - "outputs": [], - "source": [ - "print(metrics.classification_report(all_attack_preds, all_attack_true_label))" - ] - }, - { - "cell_type": "markdown", - "id": "uniform-bailey", - "metadata": {}, - "source": [ - "# Evaluation" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "twelve-clone", - "metadata": {}, - "outputs": [], - "source": [ - "target_label_in = np.ones_like(train_label).astype(int)\n", - "target_label_out = np.zeros_like(eval_label).astype(int)\n", - "\n", - "probs = np.concatenate([target_prob, eval_prob])\n", - "label_in_out = np.concatenate([target_label_in, target_label_out])\n", - "true_label = np.concatenate([train_label, eval_label])" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "necessary-india", - "metadata": {}, - "outputs": [], - "source": [ - "in_out_label_pred = np.zeros_like(label_in_out).astype(int)\n", - "\n", - "for label, label_model in attack_model_dict.items():\n", - " label_idx = np.where(true_label == label)[0]\n", - " \n", - " predict_in_out_label = attack_model_dict[label].predict(probs[label_idx])\n", - " true_in_out_label = label_in_out[label_idx]\n", - " \n", - " in_out_label_pred[label_idx] = predict_in_out_label" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "tired-northern", - "metadata": {}, - "outputs": [], - "source": [ - "print(\"overall f1 score is \", metrics.f1_score(in_out_label_pred, label_in_out))\n", - "print(metrics.classification_report(in_out_label_pred, label_in_out))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "refined-market", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "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.9.1" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/example/model_inversion/draft/Untitled.ipynb b/example/model_inversion/draft/Untitled.ipynb deleted file mode 100644 index a7594920..00000000 --- a/example/model_inversion/draft/Untitled.ipynb +++ /dev/null @@ -1,334 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "id": "outside-strap", - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np\n", - "import pandas as pd\n", - "%matplotlib inline\n", - "from matplotlib import pyplot as plt\n", - "import cv2\n", - "\n", - "import torch\n", - "import torchvision\n", - "import torchvision.transforms as transforms\n", - "import torch.nn as nn\n", - "import torch.nn.functional as F\n", - "import torch.optim as optim\n", - "\n", - "from torch.utils.data.dataset import Dataset\n", - "from torch.utils.data import DataLoader\n", - "\n", - "from sklearn.model_selection import train_test_split\n", - "from sklearn.metrics import accuracy_score" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "decimal-novelty", - "metadata": {}, - "outputs": [], - "source": [ - "device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')\n", - "print(device)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "republican-leadership", - "metadata": {}, - "outputs": [], - "source": [ - "# INPUT PATHS:\n", - "BASE = 'data/'\n", - "\n", - "imgs = []\n", - "labels = []\n", - "for i in range(1, 41):\n", - " for j in range(1, 11):\n", - " img = cv2.imread(BASE + f's{i}/{j}.pgm', 0)\n", - " imgs.append(img)\n", - " labels.append(i-1)\n", - " \n", - "X = np.stack(imgs)\n", - "y = np.array(labels)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "fossil-calcium", - "metadata": {}, - "outputs": [], - "source": [ - "class DataSet(Dataset):\n", - " \"\"\"\n", - " This class allows you to convert numpy.array to torch.Dataset\n", - " \"\"\"\n", - "\n", - " def __init__(self, x, y, transform=None):\n", - " \"\"\"\n", - " Attriutes\n", - " x (np.array) :\n", - " y (np.array) :\n", - " transform (torch.transform)\n", - " \"\"\"\n", - " self.x = x\n", - " self.y = y\n", - " self.transform = transform\n", - "\n", - " def __getitem__(self, index):\n", - " x = self.x[index]\n", - " y = self.y[index]\n", - "\n", - " if self.transform is not None:\n", - " x = self.transform(x)\n", - " return x, y\n", - "\n", - " def __len__(self):\n", - " return len(self.x)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "applied-public", - "metadata": {}, - "outputs": [], - "source": [ - "# ToTensor:画像のグレースケール化(RGBの0~255を0~1の範囲に正規化)、Normalize:Z値化(RGBの平均と標準偏差を0.5で決め打ちして正規化)\n", - "transform = transforms.Compose([transforms.ToTensor(),\n", - " transforms.CenterCrop(64),\n", - " transforms.Normalize((0.5, ), (0.5, ))])\n", - "\n", - "trainset = DataSet(X, y, transform=transform)\n", - "trainloader = torch.utils.data.DataLoader(trainset, batch_size=4, shuffle=True, num_workers=2)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "dress-contractor", - "metadata": {}, - "outputs": [], - "source": [ - "class Net(nn.Module):\n", - " def __init__(self):\n", - " super(Net, self).__init__()\n", - " self.fla = nn.Flatten()\n", - " #self.fc = nn.Linear(112*92, 40)\n", - " self.fc = nn.Linear(64*64, 40)\n", - "\n", - " def forward(self, x):\n", - " x = self.fla(x)\n", - " x = self.fc(x)\n", - " x = F.softmax(x, dim=1)\n", - " return x\n", - " \n", - "net = Net()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "measured-poetry", - "metadata": {}, - "outputs": [], - "source": [ - "criterion = nn.CrossEntropyLoss()\n", - "optimizer = optim.SGD(net.parameters(), lr=0.005, momentum=0.9)\n", - "\n", - "for epoch in range(30): # loop over the dataset multiple times\n", - "\n", - " running_loss = 0.0\n", - " for i, data in enumerate(trainloader, 0):\n", - " # get the inputs; data is a list of [inputs, labels]\n", - " inputs, labels = data\n", - "\n", - " # zero the parameter gradients\n", - " optimizer.zero_grad()\n", - "\n", - " # forward + backward + optimize\n", - " outputs = net(inputs)\n", - " loss = criterion(outputs, labels)\n", - " loss.backward()\n", - " optimizer.step()\n", - "\n", - " # print statistics\n", - " #train_loss = loss.item()\n", - " #print('[%d, %5d] loss: %.3f' %\n", - " # (epoch + 1, i + 1, train_loss))\n", - "\n", - "print('Finished Training')\n", - "\n", - "\n", - "in_preds = []\n", - "in_label = []\n", - "with torch.no_grad():\n", - " for data in trainloader:\n", - " inputs, labels = data\n", - " outputs = net(inputs)\n", - " in_preds.append(outputs)\n", - " in_label.append(labels) \n", - " in_preds = torch.cat(in_preds)\n", - " in_label = torch.cat(in_label) \n", - "print(accuracy_score(np.array(torch.argmax(in_preds, axis=1)),\n", - " np.array(in_label)))\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "random-square", - "metadata": {}, - "outputs": [], - "source": [ - "class Inversion(nn.Module):\n", - " def __init__(self, nc, ngf, nz, truncation, c):\n", - " super(Inversion, self).__init__()\n", - "\n", - " self.nc = nc\n", - " self.ngf = ngf\n", - " self.nz = nz\n", - " self.truncation = truncation\n", - " self.c = c\n", - "\n", - " self.decoder = nn.Sequential(\n", - " # input is Z\n", - " nn.ConvTranspose2d(nz, ngf * 8, 4, 1, 0),\n", - " nn.BatchNorm2d(ngf * 8),\n", - " nn.Tanh(),\n", - " # state size. (ngf*8) x 4 x 4\n", - " nn.ConvTranspose2d(ngf * 8, ngf * 4, 4, 2, 1),\n", - " nn.BatchNorm2d(ngf * 4),\n", - " nn.Tanh(),\n", - " # state size. (ngf*4) x 8 x 8\n", - " nn.ConvTranspose2d(ngf * 4, ngf * 2, 4, 2, 1),\n", - " nn.BatchNorm2d(ngf * 2),\n", - " nn.Tanh(),\n", - " # state size. (ngf*2) x 16 x 16\n", - " nn.ConvTranspose2d(ngf * 2, ngf, 4, 2, 1),\n", - " nn.BatchNorm2d(ngf),\n", - " nn.Tanh(),\n", - " # state size. (ngf) x 32 x 32\n", - " nn.ConvTranspose2d(ngf, nc, 4, 2, 1),\n", - " nn.Sigmoid()\n", - " # state size. (nc) x 64 x 64\n", - " )\n", - "\n", - " def forward(self, x):\n", - " topk, indices = torch.topk(x, self.truncation)\n", - " topk = torch.clamp(torch.log(topk), min=-1000) + self.c\n", - " topk_min = topk.min(1, keepdim=True)[0]\n", - " topk = topk + F.relu(-topk_min)\n", - " x = torch.zeros(len(x), self.nz).scatter_(1, indices, topk)\n", - "\n", - " x = x.view(-1, self.nz, 1, 1)\n", - " x = self.decoder(x)\n", - " x = x.view(-1, 1, 64, 64)\n", - " return x" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "devoted-binding", - "metadata": {}, - "outputs": [], - "source": [ - "inversion = Inversion(nc = 1, ngf = 128, nz = 530, truncation=40, c = 50)\n", - "inversion = inversion.to(device)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "embedded-confirmation", - "metadata": {}, - "outputs": [], - "source": [ - "log_interval = 10\n", - "\n", - "net.eval()\n", - "inversion.train()\n", - "\n", - "optimizer = optimizer = optim.Adam(inversion.parameters(), lr=0.005, betas=(0.5, 0.999), amsgrad=True)\n", - "\n", - "epoch_loss = 0\n", - "for epoch in range(30):\n", - " \n", - " for batch_idx, (data, target) in enumerate(trainloader):\n", - " data, target = data.to(device), target.to(device)\n", - " optimizer.zero_grad()\n", - " with torch.no_grad():\n", - " prediction = net(data)\n", - " reconstruction = inversion(prediction)\n", - " loss = F.mse_loss(reconstruction, data)\n", - " loss.backward()\n", - " optimizer.step()\n", - " epoch_loss += loss.item()\n", - " if batch_idx % log_interval == 0:\n", - " print('Train Epoch: {} [{}/{}]\\tLoss: {:.6f}'.format(epoch,\n", - " batch_idx * len(data),\n", - " len(trainloader.dataset),\n", - " epoch_loss / log_interval))\n", - " epoch_loss = 0\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "documentary-neighborhood", - "metadata": {}, - "outputs": [], - "source": [ - "plt.imshow(data.cpu().detach().numpy()[2][0])" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "first-comfort", - "metadata": {}, - "outputs": [], - "source": [ - "plt.imshow(reconstruction.cpu().detach().numpy()[2][0]) " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "terminal-prediction", - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "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.9.1" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/example/model_inversion/example.ipynb b/example/model_inversion/model_inversion.ipynb similarity index 80% rename from example/model_inversion/example.ipynb rename to example/model_inversion/model_inversion.ipynb index 08b1682e..4fa0c1d0 100644 --- a/example/model_inversion/example.ipynb +++ b/example/model_inversion/model_inversion.ipynb @@ -3,7 +3,7 @@ { "cell_type": "code", "execution_count": null, - "id": "disabled-pathology", + "id": "competent-earth", "metadata": {}, "outputs": [], "source": [ @@ -33,7 +33,7 @@ { "cell_type": "code", "execution_count": null, - "id": "blessed-marks", + "id": "hourly-savage", "metadata": {}, "outputs": [], "source": [ @@ -55,42 +55,7 @@ { "cell_type": "code", "execution_count": null, - "id": "grateful-stanley", - "metadata": {}, - "outputs": [], - "source": [ - "class DataSet(Dataset):\n", - " \"\"\"\n", - " This class allows you to convert numpy.array to torch.Dataset\n", - " \"\"\"\n", - "\n", - " def __init__(self, x, y, transform=None):\n", - " \"\"\"\n", - " Attriutes\n", - " x (np.array) :\n", - " y (np.array) :\n", - " transform (torch.transform)\n", - " \"\"\"\n", - " self.x = x\n", - " self.y = y\n", - " self.transform = transform\n", - "\n", - " def __getitem__(self, index):\n", - " x = self.x[index]\n", - " y = self.y[index]\n", - "\n", - " if self.transform is not None:\n", - " x = self.transform(x)\n", - " return x, y\n", - "\n", - " def __len__(self):\n", - " return len(self.x)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "oriental-demonstration", + "id": "brave-adoption", "metadata": {}, "outputs": [], "source": [ @@ -104,7 +69,7 @@ { "cell_type": "code", "execution_count": null, - "id": "worth-family", + "id": "marked-advancement", "metadata": {}, "outputs": [], "source": [ @@ -126,14 +91,14 @@ { "cell_type": "code", "execution_count": null, - "id": "solid-calculator", + "id": "white-fundamentals", "metadata": {}, "outputs": [], "source": [ "criterion = nn.CrossEntropyLoss()\n", "optimizer = optim.SGD(net.parameters(), lr=0.005, momentum=0.9)\n", "\n", - "for epoch in range(30): # loop over the dataset multiple times\n", + "for epoch in range(10): # loop over the dataset multiple times\n", "\n", " running_loss = 0.0\n", " for i, data in enumerate(trainloader, 0):\n", @@ -145,9 +110,10 @@ "\n", " # forward + backward + optimize\n", " outputs = net(inputs)\n", - " loss = criterion(outputs, labels)\n", + " loss = criterion(outputs, labels.to(torch.int64))\n", " loss.backward()\n", " optimizer.step()\n", + " \n", "\n", " # print statistics\n", " #train_loss = loss.item()\n", @@ -174,7 +140,7 @@ { "cell_type": "code", "execution_count": null, - "id": "continent-entrepreneur", + "id": "therapeutic-scratch", "metadata": {}, "outputs": [], "source": [ @@ -191,7 +157,7 @@ { "cell_type": "code", "execution_count": null, - "id": "reduced-postage", + "id": "documented-breeding", "metadata": {}, "outputs": [], "source": [ @@ -209,7 +175,7 @@ "axes[1][1].imshow(x_result_2[0][0], cmap='gray')\n", "axes[1][1].axis('off')\n", "axes[1][1].set_title('extracted image')\n", - "plt.savefig(\"model_inversion.png\")\n", + "# plt.savefig(\"model_inversion.png\")\n", "plt.show()" ] } diff --git a/example/model_inversion/model_inversion.png b/example/model_inversion/model_inversion.png deleted file mode 100644 index 7984a48e..00000000 Binary files a/example/model_inversion/model_inversion.png and /dev/null differ diff --git a/secure_ml.egg-info/PKG-INFO b/secure_ml.egg-info/PKG-INFO index 6e2be56b..846dc721 100644 --- a/secure_ml.egg-info/PKG-INFO +++ b/secure_ml.egg-info/PKG-INFO @@ -1,10 +1,10 @@ Metadata-Version: 1.0 Name: secure-ml Version: 0.0.0 -Summary: UNKNOWN -Home-page: UNKNOWN -Author: UNKNOWN -Author-email: UNKNOWN -License: UNKNOWN +Summary: package to implemet secure machine learning algorythm +Home-page: https://github.com/Koukyosyumei/secure_ml +Author: Hideaki Takahashi +Author-email: koukyosyumei@hotmail.com +License: MIT Description: UNKNOWN Platform: UNKNOWN diff --git a/secure_ml.egg-info/SOURCES.txt b/secure_ml.egg-info/SOURCES.txt index 716f24c5..cefe78ca 100644 --- a/secure_ml.egg-info/SOURCES.txt +++ b/secure_ml.egg-info/SOURCES.txt @@ -2,7 +2,6 @@ README.md setup.py .ipynb_checkpoints/README-checkpoint.md -.ipynb_checkpoints/Untitled-checkpoint.ipynb example/adversarial_example/.ipynb_checkpoints/evasion_attack-checkpoint.py example/adversarial_example/.ipynb_checkpoints/example_evasion_attack_svm-checkpoint.ipynb example/adversarial_example/.ipynb_checkpoints/example_poison_attack-checkpoint.ipynb @@ -14,15 +13,11 @@ example/membership_inference/.ipynb_checkpoints/CIFAR10-checkpoint.ipynb example/membership_inference/.ipynb_checkpoints/membership_inference-checkpoint.py example/membership_inference/.ipynb_checkpoints/svm-checkpoint.ipynb example/membership_inference/__pycache__/membership_inference.cpython-38.pyc -example/membership_inference/notebook/membership_inference_CIFAR10.ipynb -example/membership_inference/notebook/.ipynb_checkpoints/membership_inference_CIFAR10-checkpoint.ipynb example/membership_inference/notebook/.ipynb_checkpoints/mnist-checkpoint.ipynb example/membership_inference/notebook/old/mnist.ipynb example/membership_inference/notebook/old/svm.ipynb -example/model_inversion/Untitled.ipynb example/model_inversion/example.ipynb example/model_inversion/model_inversion.png -example/model_inversion/.ipynb_checkpoints/Untitled-checkpoint.ipynb example/model_inversion/.ipynb_checkpoints/example-checkpoint.ipynb example/model_inversion/.ipynb_checkpoints/model_inversion-checkpoint.py example/model_inversion/__pycache__/model_inversion.cpython-38.pyc @@ -55,12 +50,18 @@ secure_ml.egg-info/PKG-INFO secure_ml.egg-info/SOURCES.txt secure_ml.egg-info/dependency_links.txt secure_ml.egg-info/entry_points.txt +secure_ml.egg-info/requires.txt secure_ml.egg-info/top_level.txt +secure_ml.egg-info/.ipynb_checkpoints/SOURCES-checkpoint.txt +secure_ml.egg-info/.ipynb_checkpoints/dependency_links-checkpoint.txt secure_ml/.ipynb_checkpoints/utils-checkpoint.py secure_ml/__pycache__/__init__.cpython-38.pyc secure_ml/__pycache__/utils.cpython-38.pyc secure_ml/attack/__init__.py +secure_ml/attack/base_attack.py secure_ml/attack/evasion_attack.py +secure_ml/attack/fsha.py +secure_ml/attack/fsha_mnist.py secure_ml/attack/membership_inference.py secure_ml/attack/model_inversion.py secure_ml/attack/poison_attack.py diff --git a/secure_ml.egg-info/requires.txt b/secure_ml.egg-info/requires.txt new file mode 100644 index 00000000..19df87a3 --- /dev/null +++ b/secure_ml.egg-info/requires.txt @@ -0,0 +1,3 @@ +numpy +sklearn +torch diff --git a/secure_ml/attack/__init__.py b/secure_ml/attack/__init__.py index e31399a9..3608271c 100644 --- a/secure_ml/attack/__init__.py +++ b/secure_ml/attack/__init__.py @@ -1,8 +1,9 @@ +from secure_ml.attack.base_attack import BaseAttacker from secure_ml.attack.evasion_attack import Evasion_attack_sklearn -from secure_ml.attack.membership_inference import AttackerModel -from secure_ml.attack.membership_inference import ShadowModel -from secure_ml.attack.membership_inference import Membership_Inference +from secure_ml.attack.fsha import FSHA +from secure_ml.attack.fsha_mnist import Decoder, Discriminator, Pilot, Resnet +from secure_ml.attack.membership_inference import (AttackerModel, + Membership_Inference, + ShadowModel) from secure_ml.attack.model_inversion import Model_inversion from secure_ml.attack.poison_attack import Poison_attack_sklearn -from secure_ml.attack.fsha import FSHA -from secure_ml.attack.fsha_mnist import Resnet, Decoder, Discriminator, Pilot diff --git a/secure_ml/attack/base_attack.py b/secure_ml/attack/base_attack.py new file mode 100644 index 00000000..44a77abc --- /dev/null +++ b/secure_ml/attack/base_attack.py @@ -0,0 +1,15 @@ +from abc import ABCMeta, abstractmethod + + +class BaseAttacker(metaclass=ABCMeta): + def __init__(self, target_model): + """attacker against ml model + + Args: + target_model: target ML model + """ + self.target_model = target_model + + @abstractmethod + def attack(self): + pass diff --git a/secure_ml/attack/evasion_attack.py b/secure_ml/attack/evasion_attack.py index 87397c88..4fbd74e9 100644 --- a/secure_ml/attack/evasion_attack.py +++ b/secure_ml/attack/evasion_attack.py @@ -1,10 +1,13 @@ +import copy + import numpy as np import sklearn -import copy +from ..attack.base_attack import BaseAttacker -class Evasion_attack_sklearn: - def __init__(self, clf, X_minus_1, + +class Evasion_attack_sklearn(BaseAttacker): + def __init__(self, target_model, X_minus_1, dmax, max_iter, gamma, lam, t, h, distance="L1", kde_type="L1"): @@ -12,7 +15,7 @@ def __init__(self, clf, X_minus_1, reference https://arxiv.org/abs/1708.06131 Args: - clf (sklearn): sklearn classifier + target_model (sklearn): sklearn classifier X_minus_1 (numpy.array): datasets that contains only the class you want to misclasssify dmax (float): max distance between the adversarial example @@ -26,7 +29,7 @@ def __init__(self, clf, X_minus_1, kde_type (str): type of kernel density estimator Attributes: - clf (sklearn): sklearn classifier + target_model (sklearn): sklearn classifier X_minus_1 (numpy.array): datasets that contains only the class you want to misclasssify dmax (float): max distance between the adversarial example @@ -42,12 +45,16 @@ def __init__(self, clf, X_minus_1, delta_g (func): deviation of he discriminant function of a surrogate classifier f learnt on D + Raises: + ValueError: if given distance is not supported. + Usage: # datasets which contains only "3" X_minus_1 = X_train[np.where(y_train == "3")] # Attack_sklearn automatically detect the type of the classifier - attacker = Attack_sklearn(clf = clf, X_minus_1 = X_minus_1, + attacker = Attack_sklearn(target_model = target_model, + X_minus_1 = X_minus_1, dmax = (5000 / 255) * 2.5, max_iter = 300, gamma = 1 / (X_train.shape[1] * @@ -57,8 +64,8 @@ def __init__(self, clf, X_minus_1, # x0 is the intial ponint ("7") xm, log = attacker.attack(x0) """ + super().__init__(target_model) - self.clf = clf self.X_minus_1 = X_minus_1 self.dmax = dmax self.max_iter = max_iter @@ -90,34 +97,37 @@ def _detect_type_of_classifier(self): ValueError : if target classifier is not supported """ - target_type = type(self.clf) + target_type = type(self.target_model) if target_type == sklearn.svm._classes.SVC: - params = self.clf.get_params() + params = self.target_model.get_params() kernel_type = params["kernel"] if kernel_type == "rbf": - def kernel(xm): return np.exp(-self.gamma * - ((xm - self.clf.support_vectors_) - ** 2)) + def kernel(xm): return np.exp( + -self.gamma * + ((xm - + self.target_model.support_vectors_) + ** 2)) def delta_kernel(xm): return (-2 * self.gamma)\ * kernel(xm)\ - * (xm - self.clf.support_vectors_) + * (xm - self.target_model.support_vectors_) elif kernel_type == "linear": - def delta_kernel(xm): return self.clf.support_vectors_ + def delta_kernel(xm): return self.target_model.support_vectors_ elif kernel_type == "poly": p = params["degree"] - c = self.clf.intercept_ + c = self.target_model.intercept_ def delta_kernel(xm): return p *\ - (((xm * self.clf.support_vectors_) + c) ** (p - 1))\ - * self.clf.support_vectors_ + (((xm * self.target_model.support_vectors_) + + c) ** (p - 1))\ + * self.target_model.support_vectors_ else: raise ValueError(f"kernel type {kernel_type} is not supported") - self.delta_g = lambda xm: self.clf.dual_coef_.dot( + self.delta_g = lambda xm: self.target_model.dual_coef_.dot( delta_kernel(xm)) else: @@ -188,6 +198,7 @@ def attack(self, x0): if d > self.dmax: xm = x0 + ((xm - x0) / d) * self.dmax - g_list.append(self.clf.decision_function(xm.reshape(1, -1))) + g_list.append( + self.target_model.decision_function(xm.reshape(1, -1))) return xm, g_list diff --git a/secure_ml/attack/membership_inference.py b/secure_ml/attack/membership_inference.py index cdd0bcb3..d1e70a36 100644 --- a/secure_ml/attack/membership_inference.py +++ b/secure_ml/attack/membership_inference.py @@ -2,7 +2,9 @@ import torch import torch.nn as nn import torch.optim as optim -from secure_ml.utils import try_gpu, DataSet +from secure_ml.utils import DataSet, try_gpu + +from ..attack.base_attack import BaseAttacker class ShadowModel: @@ -58,7 +60,7 @@ def fit_transform(self, X, y, num_itr=100): y (np.array): target label num_itr (int): number of iteration for training - Return: + Returns: result_dict (dict) : key is each class value is (shadow_data, shadow_label) """ @@ -224,7 +226,7 @@ def __init__(self, models): reference https://arxiv.org/abs/1610.05820 Args: - models + models: models of attacker Attriutes: _init_models @@ -294,20 +296,23 @@ def predict_proba(self, y_pred_prob, y_labels): return in_out_pred -class Membership_Inference: +class Membership_Inference(BaseAttacker): def __init__(self, + target_model, shadow_models, attack_models, shadow_data_size, shadow_transform): - """implementation of membership inference + """Implementation of membership inference reference https://arxiv.org/abs/1610.05820 Args: - shadow_models - attack_models - shadow_data_size - shadow_transform + target_model: the model of the victim + shadow_models: shadow model for attack + attack_models: attacker model for attack + shadow_data_size: the size of datasets for + training the shadow models + shadow_transform: the transformation function for shadow datasets Attributes: shadow_models @@ -318,6 +323,7 @@ def __init__(self, shadow_result am """ + super().__init__(target_model) self.shadow_models = shadow_models self.attack_models = attack_models self.shadow_data_size = shadow_data_size @@ -327,7 +333,7 @@ def __init__(self, self.shadow_result = None self.am = None - def shadow(self, X, y, num_itr): + def train_shadow(self, X, y, num_itr): """train shadow models Args: @@ -340,14 +346,28 @@ def shadow(self, X, y, num_itr): shadow_transform=self.shadow_trasform) self.shadow_result = self.sm.fit_transform(X, y, num_itr=num_itr) - def attack(self): - """train attack models + def train_attacker(self): + """Train attacker models """ self.am = AttackerModel(self.attack_models) self.am.fit(self.shadow_result) + def attack(self, x, y, proba=False): + """Attack victim model + + Args: + x: target datasets which the attacker wants to classify + y: target labels which the attacker wants to classify + proba: the format of the output + """ + prediction_of_taregt_model = self.target_model(x) + if proba: + return self.predit_proba(prediction_of_taregt_model, y) + else: + return self.predit(prediction_of_taregt_model, y) + def predict(self, pred, label): - """predict whether the given prediction came from training data or not + """Predict whether the given prediction came from training data or not Args: pred (torch.Tensor): predicted probabilities on the data diff --git a/secure_ml/attack/model_inversion.py b/secure_ml/attack/model_inversion.py index fb16664e..6eb38614 100644 --- a/secure_ml/attack/model_inversion.py +++ b/secure_ml/attack/model_inversion.py @@ -1,27 +1,30 @@ import torch +from ..attack.base_attack import BaseAttacker -class Model_inversion: - def __init__(self, torch_model, input_shape): + +class Model_inversion(BaseAttacker): + def __init__(self, target_model, input_shape): """implementation of model inversion attack reference https://dl.acm.org/doi/pdf/10.1145/2810103.2813677 Args: - model - input_shape + target_model: model of the victim + input_shape: input shapes of taregt model Attributes: - model - input_shape + target_model: model of the victim + input_shape: input shapes of taregt model """ - self.model = torch_model + super().__init__(target_model) self.input_shape = input_shape def attack(self, target_label, lam, num_itr, process_func=lambda x: x): - """ + """Execute the model inversion attack on the target model. + Args: - target_label (int) + target_label (int): taregt label lam (float) : step size num_itr (int) : number of iteration process_func (function) : default is identity function @@ -33,7 +36,7 @@ def attack(self, target_label, log = [] x = torch.zeros(self.input_shape, requires_grad=True) for i in range(num_itr): - c = process_func(1 - self.model(x)[:, [target_label]]) + c = process_func(1 - self.target_model(x)[:, [target_label]]) c.backward() grad = x.grad with torch.no_grad(): diff --git a/secure_ml/attack/poison_attack.py b/secure_ml/attack/poison_attack.py index b0356279..2348913d 100644 --- a/secure_ml/attack/poison_attack.py +++ b/secure_ml/attack/poison_attack.py @@ -1,32 +1,36 @@ +import copy + import numpy as np import sklearn -import copy from tqdm import tqdm +from ..attack.base_attack import BaseAttacker + -class Poison_attack_sklearn: +class Poison_attack_sklearn(BaseAttacker): def __init__(self, - clf, + target_model, X_train, y_train, t=0.5): """implementation of poison attack for sklearn classifier reference https://arxiv.org/abs/1206.6389 Args: - clf: sklean classifier - X_train: training data for clf - y_train: training label for clf + target_model: sklean classifier + X_train: training data for target_model + y_train: training label for target_model t: step size Attributes: - clf: sklean classifier + target_model: sklean classifier X_train: y_train: t: step size kernel delta_kernel """ - self.clf = clf + super().__init__(target_model) + self.X_train = X_train self.y_train = y_train self.t = t @@ -41,11 +45,14 @@ def _detect_type_of_classifier(self): Returns: return true if no error occurs + + Raises: + ValueError: if given kernel type is not supported. """ - target_type = type(self.clf) + target_type = type(self.target_model) if target_type == sklearn.svm._classes.SVC: - params = self.clf.get_params() + params = self.target_model.get_params() kernel_type = params["kernel"] if kernel_type == "linear": self.kernel = lambda xa, xb: xa.dot(xb.T) @@ -59,16 +66,17 @@ def _detect_type_of_classifier(self): return True def _delta_q(self, xi, xc, yi, yc): - """culculate deviation of q + """Culculate deviation of q Q = yy.T * K denotes the label - annotated version of K, and α denotes the SVM’s dual variables corresponding to each training point. Args: - xi: - xc: - yi: - yc: + xi: intermidiate results of the generation of adversarial example + xc: initial attack point + yi: the labels of intermidiate results of the generation + of adversarial example + yc: true label of initial attack point Returns: dq: @@ -81,18 +89,18 @@ def _delta_q(self, xi, xc, yi, yc): def attack(self, xc, yc, X_valid, y_valid, num_iterations=200): - """create an adversarial example for poison attack + """Create an adversarial example for poison attack Args: xc: initial attack point yc: true label of initial attack point - x_valid: validation data for target clf - y_valid: validation label for target clf - num_iteration: (default = 200) + X_valid: validation data for target_model + y_valid: validation label for target_model + num_iterations: (default = 200) Returns: xc: created adversarial example - log: log of score of target clf under attack + log: log of score of target_model under attack """ # flip the class label yc *= -1 @@ -106,18 +114,18 @@ def attack(self, xc, yc, for i in tqdm(range(num_iterations)): - clf_ = copy.copy(self.clf) - clf_.__init__() - clf_.set_params(**self.clf.get_params()) - # clf_ = sklearn.svm.SVC(kernel="linear", C=1) + target_model_ = copy.copy(self.target_model) + target_model_.__init__() + target_model_.set_params(**self.target_model.get_params()) + # target_model_ = sklearn.svm.SVC(kernel="linear", C=1) # add poinsoned data - clf_.fit(np.concatenate([X_train_poisoned, - xc.reshape(1, -1)]), - np.concatenate([y_train_poisoned, - [yc]])) + target_model_.fit(np.concatenate([X_train_poisoned, + xc.reshape(1, -1)]), + np.concatenate([y_train_poisoned, + [yc]])) - score_temp = clf_.score(X_valid, y_valid) + score_temp = target_model_.score(X_valid, y_valid) log.append(score_temp) # if score_temp < best_score: # best_score = score_temp @@ -125,9 +133,9 @@ def attack(self, xc, yc, # best_itr = i # ------------------------ # - xs = clf_.support_vectors_ + xs = target_model_.support_vectors_ ys = np.concatenate([y_train_poisoned, - [yc]])[clf_.support_] + [yc]])[target_model_.support_] Qks = y_valid.reshape(-1, 1).dot(ys.reshape(-1, 1).T)\ @@ -145,7 +153,7 @@ def attack(self, xc, yc, # α denotes the SVM’s dual variables corresponding to each # training point - alpha = clf_.decision_function([xc]) + alpha = target_model_.decision_function([xc]) # the desired gradient used for optimizing our attack: delta_L = np.sum(((Mk.dot(delta_Qsc) + delta_Qkc) * alpha),