mirror of
https://github.com/IBM/ai-privacy-toolkit.git
synced 2026-04-26 13:26:21 +02:00
454 lines
44 KiB
Text
454 lines
44 KiB
Text
|
|
{
|
||
|
|
"cells": [
|
||
|
|
{
|
||
|
|
"cell_type": "markdown",
|
||
|
|
"metadata": {},
|
||
|
|
"source": [
|
||
|
|
"# Running membership inference attacks on the Nursery data and defending using differential privacy"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "markdown",
|
||
|
|
"metadata": {},
|
||
|
|
"source": [
|
||
|
|
"In this tutorial we will show how to run black-box membership attacks on both a vanilla model and models trained with differential privacy. The attacks are taken from the ART library's inference module (https://github.com/Trusted-AI/adversarial-robustness-toolbox) and the differentially private model implementation is taken fron the Differential Privacy Library (https://github.com/IBM/differential-privacy-library).\n",
|
||
|
|
"\n",
|
||
|
|
"This will be demonstrated on the Nursery dataset (original dataset can be found here: https://archive.ics.uci.edu/ml/datasets/nursery). "
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "markdown",
|
||
|
|
"metadata": {},
|
||
|
|
"source": [
|
||
|
|
"We have already preprocessed the dataset such that all categorical features are one-hot encoded, and the data was scaled using sklearn's StandardScaler."
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "markdown",
|
||
|
|
"metadata": {},
|
||
|
|
"source": [
|
||
|
|
"## Load data"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 8,
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [],
|
||
|
|
"source": [
|
||
|
|
"import os\n",
|
||
|
|
"import sys\n",
|
||
|
|
"sys.path.insert(0, os.path.abspath('..'))\n",
|
||
|
|
"\n",
|
||
|
|
"from art.utils import load_nursery\n",
|
||
|
|
"\n",
|
||
|
|
"train_size = 200\n",
|
||
|
|
"(x_train, y_train), (x_test, y_test), _, _ = load_nursery(test_set=0.5)\n",
|
||
|
|
"x_train = x_train[:train_size]\n",
|
||
|
|
"y_train = y_train[:train_size]\n",
|
||
|
|
"x_test = x_test[:train_size]\n",
|
||
|
|
"y_test = y_test[:train_size]"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "markdown",
|
||
|
|
"metadata": {},
|
||
|
|
"source": [
|
||
|
|
"## Train logistic regression model"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 9,
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [
|
||
|
|
{
|
||
|
|
"name": "stdout",
|
||
|
|
"output_type": "stream",
|
||
|
|
"text": [
|
||
|
|
"Base model accuracy: 0.91\n"
|
||
|
|
]
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"source": [
|
||
|
|
"from sklearn.linear_model import LogisticRegression\n",
|
||
|
|
"from art.estimators.classification.scikitlearn import ScikitlearnLogisticRegression\n",
|
||
|
|
"\n",
|
||
|
|
"model = LogisticRegression(solver=\"lbfgs\", max_iter=1000)\n",
|
||
|
|
"model.fit(x_train, y_train)\n",
|
||
|
|
"\n",
|
||
|
|
"art_classifier = ScikitlearnLogisticRegression(model)\n",
|
||
|
|
"base_model_accuracy = model.score(x_test, y_test)\n",
|
||
|
|
"\n",
|
||
|
|
"print('Base model accuracy: ', base_model_accuracy)"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "markdown",
|
||
|
|
"metadata": {},
|
||
|
|
"source": [
|
||
|
|
"## Attack\n",
|
||
|
|
"### Black-box attack\n",
|
||
|
|
"The black-box attack basically trains an additional classifier (called the attack model) to predict the membership status of a sample. It can use as input to the learning process probabilities/logits or losses, depending on the type of model and provided configuration.\n",
|
||
|
|
"#### Train attack model"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 10,
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [],
|
||
|
|
"source": [
|
||
|
|
"import numpy as np\n",
|
||
|
|
"from art.attacks.inference.membership_inference import MembershipInferenceBlackBox\n",
|
||
|
|
"\n",
|
||
|
|
"attack_train_ratio = 0.5\n",
|
||
|
|
"attack_train_size = int(len(x_train) * attack_train_ratio)\n",
|
||
|
|
"attack_test_size = int(len(x_test) * attack_train_ratio)\n",
|
||
|
|
"\n",
|
||
|
|
"attack = MembershipInferenceBlackBox(art_classifier, attack_model_type='rf') \n",
|
||
|
|
"\n",
|
||
|
|
"#train attack model\n",
|
||
|
|
"attack.fit(x_train[:attack_train_size], y_train[:attack_train_size],\n",
|
||
|
|
" x_test[:attack_test_size], y_test[:attack_test_size])"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "markdown",
|
||
|
|
"metadata": {},
|
||
|
|
"source": [
|
||
|
|
"#### Infer membership and check accuracy"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 11,
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [
|
||
|
|
{
|
||
|
|
"name": "stdout",
|
||
|
|
"output_type": "stream",
|
||
|
|
"text": [
|
||
|
|
"attack accuracy on training data: 0.5\n",
|
||
|
|
"attack accuracy on test data: 0.5800000000000001\n",
|
||
|
|
"overall attack accuracy: 0.54\n"
|
||
|
|
]
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"source": [
|
||
|
|
"# infer attacked feature\n",
|
||
|
|
"inferred_train = attack.infer(x_train[attack_train_size:], y_train[attack_train_size:])\n",
|
||
|
|
"inferred_test = attack.infer(x_test[attack_test_size:], y_test[attack_test_size:])\n",
|
||
|
|
"\n",
|
||
|
|
"# check accuracy\n",
|
||
|
|
"train_acc = np.sum(inferred_train) / len(inferred_train)\n",
|
||
|
|
"test_acc = 1 - (np.sum(inferred_test) / len(inferred_test))\n",
|
||
|
|
"acc = (train_acc * len(inferred_train) + test_acc * len(inferred_test)) / (len(inferred_train) + len(inferred_test))\n",
|
||
|
|
"print('attack accuracy on training data: ', train_acc)\n",
|
||
|
|
"print('attack accuracy on test data: ', test_acc)\n",
|
||
|
|
"print('overall attack accuracy: ', acc)"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "markdown",
|
||
|
|
"metadata": {},
|
||
|
|
"source": [
|
||
|
|
"This means that for 54% of the data, membership status is inferred correctly (a little better than a random coin flip)."
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 12,
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [
|
||
|
|
{
|
||
|
|
"name": "stdout",
|
||
|
|
"output_type": "stream",
|
||
|
|
"text": [
|
||
|
|
"precision and recall: (0.5434782608695652, 0.5)\n"
|
||
|
|
]
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"source": [
|
||
|
|
"def calc_precision_recall(predicted, actual, positive_value=1):\n",
|
||
|
|
" score = 0 # both predicted and actual are positive\n",
|
||
|
|
" num_positive_predicted = 0 # predicted positive\n",
|
||
|
|
" num_positive_actual = 0 # actual positive\n",
|
||
|
|
" for i in range(len(predicted)):\n",
|
||
|
|
" if predicted[i] == positive_value:\n",
|
||
|
|
" num_positive_predicted += 1\n",
|
||
|
|
" if actual[i] == positive_value:\n",
|
||
|
|
" num_positive_actual += 1\n",
|
||
|
|
" if predicted[i] == actual[i]:\n",
|
||
|
|
" if predicted[i] == positive_value:\n",
|
||
|
|
" score += 1\n",
|
||
|
|
" \n",
|
||
|
|
" if num_positive_predicted == 0:\n",
|
||
|
|
" precision = 1\n",
|
||
|
|
" else:\n",
|
||
|
|
" precision = score / num_positive_predicted # the fraction of predicted “Yes” responses that are correct\n",
|
||
|
|
" if num_positive_actual == 0:\n",
|
||
|
|
" recall = 1\n",
|
||
|
|
" else:\n",
|
||
|
|
" recall = score / num_positive_actual # the fraction of “Yes” responses that are predicted correctly\n",
|
||
|
|
"\n",
|
||
|
|
" return precision, recall\n",
|
||
|
|
"\n",
|
||
|
|
"# rule-based\n",
|
||
|
|
"print('precision and recall: ', calc_precision_recall(np.concatenate((inferred_train, inferred_test)), \n",
|
||
|
|
" np.concatenate((np.ones(len(inferred_train)), np.zeros(len(inferred_test))))))"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "markdown",
|
||
|
|
"metadata": {},
|
||
|
|
"source": [
|
||
|
|
"## Train differentially private model"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 15,
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [
|
||
|
|
{
|
||
|
|
"name": "stdout",
|
||
|
|
"output_type": "stream",
|
||
|
|
"text": [
|
||
|
|
"DP model accuracy: 0.56\n"
|
||
|
|
]
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"source": [
|
||
|
|
"import diffprivlib.models as dp\n",
|
||
|
|
"\n",
|
||
|
|
"dp_model = dp.LogisticRegression(epsilon=5, data_norm=5)\n",
|
||
|
|
"dp_model.fit(x_train, y_train)\n",
|
||
|
|
"# print('norm: ', np.linalg.norm(x_train) )\n",
|
||
|
|
"\n",
|
||
|
|
"dp_art_model = ScikitlearnLogisticRegression(dp_model)\n",
|
||
|
|
"print('DP model accuracy: ', dp_model.score(x_test, y_test))"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "markdown",
|
||
|
|
"metadata": {},
|
||
|
|
"source": [
|
||
|
|
"### Black-box attack"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 16,
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [
|
||
|
|
{
|
||
|
|
"name": "stdout",
|
||
|
|
"output_type": "stream",
|
||
|
|
"text": [
|
||
|
|
"attack accuracy on training data: 0.4\n",
|
||
|
|
"attack accuracy on test data: 0.62\n",
|
||
|
|
"overall attack accuracy: 0.51\n",
|
||
|
|
"precision and recall: (0.5128205128205128, 0.4)\n"
|
||
|
|
]
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"source": [
|
||
|
|
"dp_attack = MembershipInferenceBlackBox(dp_art_model, attack_model_type='rf')\n",
|
||
|
|
"\n",
|
||
|
|
"# train attack model\n",
|
||
|
|
"dp_attack.fit(x_train[:attack_train_size].astype(np.float32), y_train[:attack_train_size],\n",
|
||
|
|
" x_test[:attack_test_size].astype(np.float32), y_test[:attack_test_size])\n",
|
||
|
|
"\n",
|
||
|
|
"# infer \n",
|
||
|
|
"dp_inferred_train = dp_attack.infer(x_train.astype(np.float32)[attack_train_size:], y_train[attack_train_size:])\n",
|
||
|
|
"dp_inferred_test = dp_attack.infer(x_test.astype(np.float32)[attack_test_size:], y_test[attack_test_size:])\n",
|
||
|
|
"\n",
|
||
|
|
"# check accuracy\n",
|
||
|
|
"dp_train_acc = np.sum(dp_inferred_train) / len(dp_inferred_train)\n",
|
||
|
|
"dp_test_acc = 1 - (np.sum(dp_inferred_test) / len(dp_inferred_test))\n",
|
||
|
|
"dp_acc = (dp_train_acc * len(dp_inferred_train) + dp_test_acc * len(dp_inferred_test)) / (len(dp_inferred_train) + len(dp_inferred_test))\n",
|
||
|
|
"print('attack accuracy on training data: ', dp_train_acc)\n",
|
||
|
|
"print('attack accuracy on test data: ', dp_test_acc)\n",
|
||
|
|
"print('overall attack accuracy: ', dp_acc)\n",
|
||
|
|
"\n",
|
||
|
|
"print('precision and recall: ', calc_precision_recall(np.concatenate((dp_inferred_train, dp_inferred_test)), \n",
|
||
|
|
" np.concatenate((np.ones(len(dp_inferred_train)), np.zeros(len(dp_inferred_test))))))"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "markdown",
|
||
|
|
"metadata": {},
|
||
|
|
"source": [
|
||
|
|
"The differentially private model reduces the attack accuracy, but also completely ruins the model's accuracy.\n",
|
||
|
|
"Let's see if we can find a sweet spot where both acceptable accuracy and privacy can be acheived."
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 17,
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [
|
||
|
|
{
|
||
|
|
"name": "stdout",
|
||
|
|
"output_type": "stream",
|
||
|
|
"text": [
|
||
|
|
"0.01\n",
|
||
|
|
"0.1\n",
|
||
|
|
"0.5\n",
|
||
|
|
"1.0\n",
|
||
|
|
"5.0\n",
|
||
|
|
"10.0\n",
|
||
|
|
"25.0\n",
|
||
|
|
"75.0\n",
|
||
|
|
"100.0\n",
|
||
|
|
"200.0\n"
|
||
|
|
]
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"source": [
|
||
|
|
"accuracy = []\n",
|
||
|
|
"attack_accuracy = []\n",
|
||
|
|
"epsilons = [0.01, 0.1, 0.5, 1.0, 5.0, 10.0, 25.0, 75.0, 100.0, 200.0]\n",
|
||
|
|
"\n",
|
||
|
|
"for eps in epsilons:\n",
|
||
|
|
" print(eps)\n",
|
||
|
|
" dp_clf = dp.LogisticRegression(epsilon=eps, data_norm=5)\n",
|
||
|
|
" dp_clf.fit(x_train, y_train)\n",
|
||
|
|
" accuracy.append(dp_clf.score(x_test, y_test))\n",
|
||
|
|
" dp_art_classifier = ScikitlearnLogisticRegression(dp_clf)\n",
|
||
|
|
" dp_attack = MembershipInferenceBlackBox(dp_art_classifier, attack_model_type='rf')\n",
|
||
|
|
" dp_attack.fit(x_train[:attack_train_size].astype(np.float32), y_train[:attack_train_size].astype(np.float32),\n",
|
||
|
|
" x_test[:attack_test_size].astype(np.float32), y_test[:attack_test_size].astype(np.float32))\n",
|
||
|
|
" dp_inferred_train = dp_attack.infer(x_train.astype(np.float32)[attack_train_size:], y_train.astype(np.float32)[attack_train_size:])\n",
|
||
|
|
" dp_inferred_test = dp_attack.infer(x_test.astype(np.float32)[attack_train_size:], y_test.astype(np.float32)[attack_train_size:])\n",
|
||
|
|
" dp_train_acc = np.sum(dp_inferred_train) / len(dp_inferred_train)\n",
|
||
|
|
" dp_test_acc = 1 - (np.sum(dp_inferred_test) / len(dp_inferred_test))\n",
|
||
|
|
" dp_acc = (dp_train_acc * len(dp_inferred_train) + dp_test_acc * len(dp_inferred_test)) / (len(dp_inferred_train) + len(dp_inferred_test))\n",
|
||
|
|
" attack_accuracy.append(dp_acc)"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 18,
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [
|
||
|
|
{
|
||
|
|
"data": {
|
||
|
|
"image/png": "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
|
||
|
|
"text/plain": [
|
||
|
|
"<Figure size 432x288 with 1 Axes>"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
"metadata": {
|
||
|
|
"needs_background": "light"
|
||
|
|
},
|
||
|
|
"output_type": "display_data"
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"source": [
|
||
|
|
"import matplotlib.pyplot as plt\n",
|
||
|
|
"\n",
|
||
|
|
"plt.plot(epsilons, accuracy)\n",
|
||
|
|
"plt.plot(epsilons, np.ones_like(epsilons) * base_model_accuracy, dashes=[2,2], label=\"base model\")\n",
|
||
|
|
"plt.title(\"Differentially private logistic regression\")\n",
|
||
|
|
"plt.xlabel(\"epsilon\")\n",
|
||
|
|
"plt.ylabel(\"Model accuracy\")\n",
|
||
|
|
"plt.ylim(0, 1)\n",
|
||
|
|
"plt.xlim(0.1, 200)\n",
|
||
|
|
"plt.show()"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 19,
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [
|
||
|
|
{
|
||
|
|
"data": {
|
||
|
|
"image/png": "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
|
||
|
|
"text/plain": [
|
||
|
|
"<Figure size 432x288 with 1 Axes>"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
"metadata": {
|
||
|
|
"needs_background": "light"
|
||
|
|
},
|
||
|
|
"output_type": "display_data"
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"source": [
|
||
|
|
"plt.plot(epsilons, attack_accuracy)\n",
|
||
|
|
"plt.plot(epsilons, np.ones_like(epsilons) * acc, dashes=[2,2], label=\"base model\")\n",
|
||
|
|
"plt.title(\"Differentially private logistic regression\")\n",
|
||
|
|
"plt.xlabel(\"epsilon\")\n",
|
||
|
|
"plt.ylabel(\"Attack accuracy\")\n",
|
||
|
|
"plt.ylim(0, 1)\n",
|
||
|
|
"plt.xlim(0.1, 200)\n",
|
||
|
|
"plt.show()"
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "markdown",
|
||
|
|
"metadata": {},
|
||
|
|
"source": [
|
||
|
|
"Looks like epsilon=25 is a good choice."
|
||
|
|
]
|
||
|
|
},
|
||
|
|
{
|
||
|
|
"cell_type": "code",
|
||
|
|
"execution_count": 21,
|
||
|
|
"metadata": {},
|
||
|
|
"outputs": [
|
||
|
|
{
|
||
|
|
"name": "stdout",
|
||
|
|
"output_type": "stream",
|
||
|
|
"text": [
|
||
|
|
"DP model accuracy with eps=100: 0.795\n",
|
||
|
|
"DP model attack accuracy with eps=100: 0.52\n"
|
||
|
|
]
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"source": [
|
||
|
|
"dp_model = dp.LogisticRegression(epsilon=25, data_norm=5)\n",
|
||
|
|
"dp_model.fit(x_train, y_train)\n",
|
||
|
|
"\n",
|
||
|
|
"dp_art_classifier = ScikitlearnLogisticRegression(dp_model)\n",
|
||
|
|
"print('DP model accuracy with eps=100: ', dp_model.score(x_test, y_test))\n",
|
||
|
|
"\n",
|
||
|
|
"dp_attack = MembershipInferenceBlackBox(dp_art_classifier, attack_model_type='rf')\n",
|
||
|
|
"dp_attack.fit(x_train[:attack_train_size].astype(np.float32), y_train[:attack_train_size].astype(np.float32),\n",
|
||
|
|
" x_test[:attack_test_size].astype(np.float32), y_test[:attack_test_size].astype(np.float32))\n",
|
||
|
|
"dp_inferred_train = dp_attack.infer(x_train.astype(np.float32)[attack_train_size:], y_train.astype(np.float32)[attack_train_size:])\n",
|
||
|
|
"dp_inferred_test = dp_attack.infer(x_test.astype(np.float32)[attack_test_size:], y_test.astype(np.float32)[attack_test_size:])\n",
|
||
|
|
"dp_train_acc = np.sum(dp_inferred_train) / len(dp_inferred_train)\n",
|
||
|
|
"dp_test_acc = 1 - (np.sum(dp_inferred_test) / len(dp_inferred_test))\n",
|
||
|
|
"dp_acc = (dp_train_acc * len(dp_inferred_train) + dp_test_acc * len(dp_inferred_test)) / (len(dp_inferred_train) + len(dp_inferred_test))\n",
|
||
|
|
" \n",
|
||
|
|
"print('DP model attack accuracy with eps=100: ', dp_acc)"
|
||
|
|
]
|
||
|
|
}
|
||
|
|
],
|
||
|
|
"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.8.3"
|
||
|
|
}
|
||
|
|
},
|
||
|
|
"nbformat": 4,
|
||
|
|
"nbformat_minor": 2
|
||
|
|
}
|