7.4. PixelDP#

Lecuyer, Mathias, et al. "Certified robustness to adversarial examples with differential privacy." 2019 IEEE symposium on security and privacy (SP). IEEE, 2019.

import cv2
import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
import torchvision.transforms as transforms
from torch.utils.data import TensorDataset
from matplotlib import pyplot as plt
import glob
from sklearn.metrics import accuracy_score

from aijack.defense.crobustness import PixelDP
from aijack.utils import NumpyDataset

BASE = "data/"
torch.manual_seed(42)
/usr/local/lib/python3.10/dist-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html
  from .autonotebook import tqdm as notebook_tqdm
/usr/local/lib/python3.10/dist-packages/torchvision/io/image.py:13: UserWarning: Failed to load image Python extension: '/usr/local/lib/python3.10/dist-packages/torchvision/image.so: undefined symbol: _ZN3c104cuda20CUDACachingAllocator9allocatorE'If you don't plan on using image functionality from `torchvision.io`, you can ignore this warning. Otherwise, there might be something wrong with your environment. Did you have `libjpeg` or `libpng` installed before building `torchvision` from source?
  warn(
<torch._C.Generator at 0x7f9f89b4fdf0>
class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.fla = nn.Flatten()
        self.fc = nn.Linear(112 * 92, 40)

    def forward(self, x):
        x = self.fla(x)
        x = self.fc(x)
        x = F.softmax(x, dim=1)
        return x
pdp = PixelDP(
    Net(),
    40,
    L=0.01,
    eps=0.3,
    delta=1e-5,
    n_population_mc=100,
    batch_size_mc=32,
    mode="gaussian",
)
imgs = []
labels = []
for i in range(1, 41):
    for j in range(1, 11):
        img = cv2.imread(BASE + f"s{i}/{j}.pgm", 0)
        imgs.append(img)
        labels.append(i - 1)

X = np.stack(imgs)
y = np.array(labels)

# ToTensor:画像のグレースケール化(RGBの0~255を0~1の範囲に正規化)、Normalize:Z値化(RGBの平均と標準偏差を0.5で決め打ちして正規化)
transform = transforms.Compose(
    [transforms.ToTensor(), transforms.Normalize((0.5,), (0.5,))]
)
trainset = NumpyDataset(X, y, transform=transform)
trainloader = torch.utils.data.DataLoader(
    trainset, batch_size=4, shuffle=True, num_workers=2
)

criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(pdp.parameters(), lr=0.005, momentum=0.9)
for epoch in range(10):  # loop over the dataset multiple times
    running_loss = 0
    data_size = 0
    for i, data in enumerate(trainloader, 0):
        # get the inputs; data is a list of [inputs, labels]
        inputs, labels = data

        # zero the parameter gradients
        optimizer.zero_grad()

        # forward + backward + optimize
        outputs = pdp(inputs)
        loss = criterion(outputs, labels.to(torch.int64))
        loss.backward()
        optimizer.step()

        running_loss += loss.item()
        data_size += inputs.shape[0]

    print(f"epoch {epoch}: loss is {running_loss/data_size}")


in_preds = []
in_label = []
with torch.no_grad():
    for data in trainloader:
        inputs, labels = data
        outputs = pdp(inputs)
        in_preds.append(outputs)
        in_label.append(labels)
    in_preds = torch.cat(in_preds)
    in_label = torch.cat(in_label)
print(
    "Test Accuracy is: ",
    accuracy_score(np.array(torch.argmax(in_preds, axis=1)), np.array(in_label)),
)
epoch 0: loss is 0.9139378321170807
epoch 1: loss is 0.8554459440708161
epoch 2: loss is 0.8069418483972549
epoch 3: loss is 0.7713756114244461
epoch 4: loss is 0.7584735369682312
epoch 5: loss is 0.75129163980484
epoch 6: loss is 0.7420633500814438
epoch 7: loss is 0.731513864994049
epoch 8: loss is 0.7287486070394515
epoch 9: loss is 0.7276095592975617
Test Accuracy is:  0.845
pdp.eval()
expected_pred, counts = pdp(data[0][[0]])
expected_pred, counts
(tensor([9.6808e-04, 1.6266e-02, 8.4722e+00, 2.2943e-02, 8.0590e-04, 6.2990e-06,
         2.2331e-02, 6.8285e-04, 1.1202e-03, 5.9374e-03, 8.0079e-03, 5.8963e-01,
         1.9559e+01, 1.4635e-03, 1.6586e-02, 2.5163e-03, 2.7637e-04, 4.3312e-02,
         1.5605e-02, 2.8981e-03, 2.0027e-02, 2.2794e-01, 1.0082e-02, 2.5106e-04,
         1.3825e-02, 1.5252e+01, 3.3047e-02, 5.0347e+01, 2.1533e-03, 1.3620e-08,
         2.0145e-03, 2.7776e-04, 2.3923e-05, 4.3114e-04, 2.0491e-01, 2.7598e-03,
         1.8949e-02, 3.8814e-03, 1.9326e-03, 5.0761e+00]),
 tensor([  0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,
           0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,
           0.,   0.,   0., 100.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,
           0.,   0.,   0.,   0.]))
pdp.certify(counts)
0.06263168938608399