4.1. Memership Inference#

from sklearn.metrics import roc_auc_score
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.svm import SVC
from sklearn.metrics import accuracy_score
import numpy as np
import torch
import torch.nn as nn
import torch.optim as optim

from aijack.attack.membership import ShadowMembershipInferenceAttack
from aijack.utils.utils import TorchClassifier, NumpyDataset
np.random.seed(42)
torch.manual_seed(42)

df = pd.read_csv("/content/sample_data/mnist_train_small.csv", header=None)

X = df[range(1, 785)].values.astype("float64") / 255
y = df[0].values

# We use the train dataset to train the victim model. The attacker utilize shadow dataset to
# prepare membership inference attack. The test dataset is used to evaluate the result of attack.
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=1 / 3, random_state=42
)
X_train, X_shadow, y_train, y_shadow = train_test_split(
    X_train, y_train, test_size=1 / 2, random_state=42
)
# We simulate the situation where the distribution of training dataset is different from the test/shadow datasets.
X_test = 0.5 * X_test + 0.5 * np.random.normal(size=(X_test.shape))

4.1.1. sklearn#

# Train the victim

clf = SVC(probability=True)
clf.fit(X_train, y_train)
clf.score(X_train, y_train), clf.score(X_test, y_test)
(0.9848484848484849, 0.11054447277636119)
# Train the attacker

shadow_models = [SVC(probability=True) for _ in range(2)]
attack_models = [SVC(probability=True) for _ in range(10)]

attacker = ShadowMembershipInferenceAttack(clf, shadow_models, attack_models)
attacker.fit(X_shadow, y_shadow)
# Get the attack result of membership inference
in_result = attacker.predict(clf.predict_proba(X_train), y_train)
out_result = attacker.predict(clf.predict_proba(X_test), y_test)

in_label = np.ones(in_result.shape[0])
out_label = np.zeros(out_result.shape[0])

accuracy_score(
    np.concatenate([in_label, out_label]), np.concatenate([in_result, out_result])
)
0.9738243456086402

4.1.2. PyTorch#

class LM(nn.Module):
    def __init__(self):
        super(LM, self).__init__()
        self.lin1 = nn.Linear(28 * 28, 10)

    def forward(self, x):
        out = self.lin1(x)
        return out
# Train the victim
device = torch.device("cuda:0") if torch.cuda.is_available() else torch.device("cpu")

criterion = nn.CrossEntropyLoss()
net = LM().to(torch.double).to(device)
optimizer = optim.Adam(net.parameters(), lr=0.001)
# You need to wrap the torch module with TorchClassifier
clf = TorchClassifier(
    net, criterion, optimizer, batch_size=64, epoch=100, device=device
)

clf.fit(X_train, y_train)
clf.score(X_train, y_train), clf.score(X_test, y_test)
(0.974947494749475, 0.3077846107694615)
# Train the attacker


def create_clf():
    _net = LM().to(torch.double).to(device)
    _optimizer = optim.Adam(_net.parameters(), lr=0.001)
    return TorchClassifier(
        _net, criterion, _optimizer, batch_size=64, epoch=100, device=device
    )


shadow_models = [create_clf() for _ in range(2)]
attack_models = [SVC(probability=True) for _ in range(10)]

attacker = ShadowMembershipInferenceAttack(clf, shadow_models, attack_models)
attacker.fit(X_shadow, y_shadow)
# Get the attack result of membership inference
in_result = attacker.predict(clf.predict_proba(X_train), y_train)
out_result = attacker.predict(clf.predict_proba(X_test), y_test)

in_label = np.ones(in_result.shape[0])
out_label = np.zeros(out_result.shape[0])

accuracy_score(
    np.concatenate([in_label, out_label]), np.concatenate([in_result, out_result])
)
0.6735168379209481