{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "### Counterfactual explanation on MNIST (PyTorch)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This is an example of `CounterfactualExplainer` on MNIST with a PyTorch model. `CounterfactualExplainer` is an optimization based method for generating counterfactual examples, supporting classification tasks only. If using this explainer, please cite the paper \"Counterfactual Explanations without Opening the Black Box: Automated Decisions and the GDPR, Sandra Wachter, Brent Mittelstadt, Chris Russell, https://arxiv.org/abs/1711.00399\"." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "# This default renderer is used for sphinx docs only. Please delete this cell in IPython.\n", "import plotly.io as pio\n", "pio.renderers.default = \"png\"" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "import torch\n", "import torch.nn as nn\n", "import torchvision\n", "import torchvision.transforms as transforms\n", "from torch.utils.data import Dataset\n", "from torch.utils.data import DataLoader\n", "import matplotlib.pyplot as plt\n", "from omnixai.data.image import Image" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The model is a simple convolutional neural network with two convolutional layers and one dense hidden layer." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "class InputData(Dataset):\n", "\n", " def __init__(self, images, labels):\n", " self.images = images\n", " self.labels = labels\n", "\n", " def __len__(self):\n", " return self.images.shape[0]\n", "\n", " def __getitem__(self, index):\n", " return self.images[index], self.labels[index]\n", "\n", "\n", "class MNISTNet(nn.Module):\n", "\n", " def __init__(self):\n", " super().__init__()\n", " self.conv_layers = nn.Sequential(\n", " nn.Conv2d(1, 10, kernel_size=5),\n", " nn.MaxPool2d(2),\n", " nn.ReLU(),\n", " nn.Conv2d(10, 20, kernel_size=5),\n", " nn.Dropout(),\n", " nn.MaxPool2d(2),\n", " nn.ReLU(),\n", " )\n", " self.fc_layers = nn.Sequential(\n", " nn.Linear(320, 50),\n", " nn.ReLU(),\n", " nn.Dropout(),\n", " nn.Linear(50, 10)\n", " )\n", "\n", " def forward(self, x):\n", " x = self.conv_layers(x)\n", " x = torch.flatten(x, 1)\n", " x = self.fc_layers(x)\n", " return x" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The following code loads the training and test datasets. We recommend using `Image` to represent a batch of images. `Image` can be constructed from a numpy array or a Pillow image. In this example, `Image` is constructed from a numpy array containing a batch of digit images." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "# Load the training and test datasets\n", "train_data = torchvision.datasets.MNIST(root='../data', train=True, download=True)\n", "test_data = torchvision.datasets.MNIST(root='../data', train=False, download=True)\n", "train_data.data = train_data.data.numpy()\n", "test_data.data = test_data.data.numpy()\n", "\n", "class_names = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9)\n", "# Use `Image` objects to represent the training and test datasets\n", "x_train, y_train = Image(train_data.data, batched=True), train_data.targets\n", "x_test, y_test = Image(test_data.data, batched=True), test_data.targets" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The preprocessing function takes an `Image` instance as its input and outputs the processed features that the ML model consumes. In this example, the `Image` object is converted into a torch tensor via the defined `transform`." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "device = \"cuda\" if torch.cuda.is_available() else \"cpu\"\n", "# Build the CNN model\n", "model = MNISTNet().to(device)\n", "# The preprocessing function\n", "transform = transforms.Compose([transforms.ToTensor()])\n", "preprocess = lambda ims: torch.stack([transform(im.to_pil()) for im in ims])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We now train the CNN model defined above and evaluate its performance." ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Accuracy for class 0 is: 99.7 %\n", "Accuracy for class 1 is: 99.8 %\n", "Accuracy for class 2 is: 99.3 %\n", "Accuracy for class 3 is: 99.2 %\n", "Accuracy for class 4 is: 99.5 %\n", "Accuracy for class 5 is: 99.2 %\n", "Accuracy for class 6 is: 98.6 %\n", "Accuracy for class 7 is: 98.4 %\n", "Accuracy for class 8 is: 99.2 %\n", "Accuracy for class 9 is: 97.7 %\n" ] } ], "source": [ "learning_rate=1e-3\n", "batch_size=128\n", "num_epochs=10\n", "\n", "train_loader = DataLoader(\n", " dataset=InputData(preprocess(x_train), y_train),\n", " batch_size=batch_size,\n", " shuffle=True\n", ")\n", "test_loader = DataLoader(\n", " dataset=InputData(preprocess(x_test), y_test),\n", " batch_size=batch_size,\n", " shuffle=False\n", ")\n", "optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)\n", "loss_func = nn.CrossEntropyLoss()\n", "\n", "model.train()\n", "for epoch in range(num_epochs):\n", " for i, (x, y) in enumerate(train_loader):\n", " x, y = x.to(device), y.to(device)\n", " loss = loss_func(model(x), y)\n", " optimizer.zero_grad()\n", " loss.backward()\n", " optimizer.step()\n", "\n", "correct_pred = {name: 0 for name in class_names}\n", "total_pred = {name: 0 for name in class_names}\n", "\n", "model.eval()\n", "for x, y in test_loader:\n", " images, labels = x.to(device), y.to(device)\n", " outputs = model(images)\n", " _, predictions = torch.max(outputs, 1)\n", " for label, prediction in zip(labels, predictions):\n", " if label == prediction:\n", " correct_pred[class_names[label]] += 1\n", " total_pred[class_names[label]] += 1\n", "\n", "for name, correct_count in correct_pred.items():\n", " accuracy = 100 * float(correct_count) / total_pred[name]\n", " print(\"Accuracy for class {} is: {:.1f} %\".format(name, accuracy))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To initialize `CounterfactualExplainer`, we need to set the following parameters:\n", " \n", " - `model`: The ML model to explain, e.g., `torch.nn.Module` or `tf.keras.Model`.\n", " - `preprocess_function`: The preprocessing function that converts the raw data (a `Image` instance) into the inputs of `model`.\n", " - \"optimization parameters\": e.g., `binary_search_steps`, `num_iterations`. Please refer to the docs for more details." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "from omnixai.explainers.vision import CounterfactualExplainer\n", "\n", "explainer = CounterfactualExplainer(\n", " model=model,\n", " preprocess_function=preprocess\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can simply call `explainer.explain` to generate counterfactual examples for this classification task. `ipython_plot` plots the generated explanations in IPython. Parameter `index` indicates which instance to plot, e.g., `index = 0` means plotting the first instance in `x_test[0:5]`." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Binary step: 5 |███████████████████████████████████████-| 99.9% " ] }, { "data": { "image/png": "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za4JECBAgAABAgQiBQTeSChlBAgQIECAAAECdQoIvHX2za4JECBAgAABAgQiBQTeSChlBAgQIECAAAECdQoIvHX2za4JECBAgAABAgQiBQTeSChlBAgQIECAAAECdQoIvHX2za4JECBAgAABAgQiBQTeSChlBAgQIECAAAECdQoIvHX2za4JECBAgAABAgQiBQTeSChlBAgQIECAAAECdQoIvHX2za4JECBAgAABAgQiBQTeSChlBAgQIECAAAECdQoIvHX2za4JECBAgAABAgQiBQTeSChlBAgQIECAAAECdQoIvHX2za4JECBAgAABAgQiBQTeSChlBAgQIECAAAECdQoIvHX2za4JECBAgAABAgQiBQTeSChlBAgQIECAAAECdQoIvHX2za4JECBAgAABAgQiBQTeSChlBAgQIECAAAECdQoIvHX2za4JECBAgAABAgQiBQTeSChlBAgQIECAAAECdQoIvHX2za4JECBAgAABAgQiBQTeSChlBAgQIECAAAECdQoIvHX2za4JECBAgAABAgQiBQTeSChlBAgQIECAAAECdQoIvHX2za4JECBAgAABAgQiBQTeSChlBAgQIECAAAECdQoIvHX2za4JECBAgAABAgQiBQTeSChlBAgQIECAAAECdQoIvHX2za4JECBAgAABAgQiBQTeSChlBAgQIECAAAECdQoIvHX2za4JECBAgAABAgQiBQTeSChlBAgQIECAAAECdQoIvHX2za4JECBAgAABAgQiBQTeSChlBAgQIECAAAECdQoIvHX2za4JECBAgAABAgQiBQTeSChlBAgQIECAAAECdQoIvHX2za4JECBAgAABAgQiBQTeSChlBAgQIECAAAECdQoIvHX2za4JECBAgAABAgQiBQTeSChlBAgQIECAAAECdQoIvHX2za4JECBAgAABAgQiBQTeSChlBAgQIECAAAECdQoIvHX2za4JECBAgAABAgQiBQTeSChlBAgQIECAAAECdQoIvHX2za4JECBAgAABAgQiBQTeSChlBAgQIECAAAECdQoIvHX2za4JECBAgAABAgQiBQTeSChlBAgQIECAAAECdQoIvHX2za4JECBAgAABAgQiBQTeSChlBAgQIECAAAECdQoIvHX2za4JECBAgAABAgQiBQTeSChlBAgQIECAAAECdQoIvHX2za4JECBAgAAB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IEAgSUDgTeJSTIAAAQIECBAgUJuAwFtbx+yXAAECBAgQIEAgSUDgTeJSTIAAAQIECBAgUJuAwFtbx+yXAAECBAgQIEAgSUDgTeJSTIAAAQIECBAgUJuAwFtbx+yXAAECBAgQIEAgSUDgTeJSTIAAAQIECBAgUJuAwFtbx+yXAAECBAgQIEAgSUDgTeJSTIAAAQIECBAgUJuAwFtbx+yXAAECBAgQIEAgSUDgTeJSTIAAAQIECBAgUJuAwFtbx+yXAAECBAgQIEAgSUDgTeJSTIAAAQIECBAgUJuAwFtbx+yXAAECBAgQIEAgSUDgTeJSTIAAAQIECBAgUJuAwFtbx+yXAAECBAgQIEAgSUDgTeJSTIAAAQIECBAgUJuAwFtbx+yXAAECBAgQIEAgSUDgTeJSTIAAAQIECBAgUJuAwFtbx+yXAAECBAgQIEAgSUDgTeJSTIAAAQIECBAgUJuAwFtbx+yXAAECBAgQIEAgSUDgTeJSTIAAAQIECBAgUJuAwFtbx+yXAAECBAgQIEAgSUDgTeJSTIAAAQIECBAgUJuAwFtbx+yXAAECBAgQIEAgSUDgTeJSTIAAAQIECBAgUJuAwFtbx+yXAAECBAgQIEAgSUDgTeJSTIAAAQIECBAgUJuAwFtbx+yXAAECBAgQIEAgSUDgTeJSTIAAAQIECBAgUJuAwFtbx+yXAAECBAgQIEAgSUDgTeJSTIAAAQIECBAgUJuAwFtbx+yXAAECBAgQIEAgSUDgTeJSTIAAAQIECBAgUJuAwFtbx+yXAAECBAgQIEAgSUDgTeJSTIAAAQIECBAgUJuAwFtbx+yXAAECBAgQIEAgSUDgTeJSTIAAAQIECBAgUJuAwFtbx+yXAAECBAgQIEAgSUDgTeJSTIAAAQIECBAgUJuAwFtbx+yXAAECBAgQIEAgSUDgTeJSTIAAAQIECBAgUJuAwFtbx+yXAAECBAgQIEAgSUDgTeJSTIAAAQIECBAgUJuAwFtbx+yXAAECBAgQIEAgSUDgTeJSTIAAAQIECBAgUJuAwFtbx+yXAAECBAgQIEAgSUDgTeJSTIAAAQIECBAgUJuAwFtbx+yXAAECBAgQIEAgSUDgTeJSTIAAAQIECBAgUJuAwFtbx+yXAAECBAgQIEAgSUDgTeJSTIAAAQIECBAgUJuAwFtbx+yXAAECBAgQIEAgSUDgTeJSTIAAAQIECBAgUJuAwFtbx+yXAAECBAgQIEAgSUDgTeJSTIAAAQIECBAgUJuAwFtbx+yXAAECBAgQIEAgSUDgTeJSTIAAAQIECBAgUJuAwFtbx+yXAAECBAgQIEAgSUDgTeJSTIAAAQIECBAgUJuAwFtbx+yXAAECBAgQIEAgSUDgTeJSTIAAAQIECBAgUJuAwFtbx+yXAAECBAgQIEAgSUDgTeJSTIAAAQIECBAgUJuAwFtbx+yXAAECBAgQIEAgSUDgTeJSTIAAAQIECBAgUJuAwFtbx+yXAAECBAgQIEAgSUDgTeJSTIAAAQIEMPhKhAAAAuJJREFUCBAgUJuAwFtbx+yXAAECBAgQIEAgSUDgTeJSTIAAAQIECBAgUJuAwFtbx+yXAAECBAgQIEAgSUDgTeJSTIAAAQIECBAgUJuAwFtbx+yXAAECBAgQIEAgSUDgTeJSTIAAAQIECBAgUJuAwFtbx+yXAAECBAgQIEAgSUDgTeJSTIAAAQIECBAgUJuAwFtbx+yXAAECBAgQIEAgSUDgTeJSTIAAAQIECBAgUJuAwFtbx+yXAAECBAgQIEAgSUDgTeJSTIAAAQIECBAgUJuAwFtbx+yXAAECBAgQIEAgSUDgTeJSTIAAAQIECBAgUJuAwFtbx+yXAAECBAgQIEAgSUDgTeJSTIAAAQIECBAgUJuAwFtbx+yXAAECBAgQIEAgSUDgTeJSTIAAAQIECBAgUJuAwFtbx+yXAAECBAgQIEAgSUDgTeJSTIAAAQIECBAgUJuAwFtbx+yXAAECBAgQIEAgSUDgTeJSTIAAAQIECBAgUJuAwFtbx+yXAAECBAgQIEAgSUDgTeJSTIAAAQIECBAgUJuAwFtbx+yXAAECBAgQIEAgSUDgTeJSTIAAAQIECBAgUJuAwFtbx+yXAAECBAgQIEAgSUDgTeJSTIAAAQIECBAgUJuAwFtbx+yXAAECBAgQIEAgSUDgTeJSTIAAAQIECBAgUJuAwFtbx+yXAAECBAgQIEAgSUDgTeJSTIAAAQIECBAgUJuAwFtbx+yXAAECBAgQIEAgSUDgTeJSTIAAAQIECBAgUJuAwFtbx+yXAAECBAgQIEAgSUDgTeJSTIAAAQIECBAgUJuAwFtbx+yXAAECBAgQIEAgSUDgTeJSTIAAAQIECBAgUJuAwFtbx+yXAAECBAgQIEAgSUDgTeJSTIAAAQIECBAgUJuAwFtbx+yXAAECBAgQIEAgSUDgTeJSTIAAAQIECBAgUJuAwFtbx+yXAAECBAgQIEAgSUDgTeJSTIAAAQIECBAgUJvA/wcMQTFBiwcWjQAAAABJRU5ErkJggg==" }, "metadata": {}, "output_type": "display_data" } ], "source": [ "explanations = explainer.explain(x_test[0:5])\n", "explanations.ipython_plot(index=4)" ] } ], "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.7.5" } }, "nbformat": 4, "nbformat_minor": 2 }