{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "### Contrastive explanation on MNIST (PyTorch)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This is an example of `ContrastiveExplainer` on MNIST with a PyTorch model. `ContrastiveExplainer` is an optimization based method for generating explanations (pertinent negatives and pertinent positives), supporting classification tasks only. If using this explainer, please cite the original work: https://arxiv.org/abs/1802.07623." ] }, { "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.6 %\n", "Accuracy for class 1 is: 99.8 %\n", "Accuracy for class 2 is: 99.7 %\n", "Accuracy for class 3 is: 98.9 %\n", "Accuracy for class 4 is: 99.5 %\n", "Accuracy for class 5 is: 99.3 %\n", "Accuracy for class 6 is: 98.2 %\n", "Accuracy for class 7 is: 99.1 %\n", "Accuracy for class 8 is: 99.0 %\n", "Accuracy for class 9 is: 97.5 %\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 ContrastiveExplainer\n", "\n", "explainer = ContrastiveExplainer(\n", " model=model,\n", " preprocess_function=preprocess\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can simply call `explainer.explain` to generate explanations 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[4]`." ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Binary step: 5 |----------------------------------------| 0.6% " ] }, { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAArwAAAH0CAYAAADfWf7fAAAgAElEQVR4Xu3dC7RkVXkn8MOjhUa6QSAgEhVEY0wkiZhEfCA+RqMSgaWoIBhhMqMSI68AQQQxGkBAUB5iNAICEZuI4EiUZTQoceJ7klk6EZNJyIhEVN7aAuE5qy6hG6lT3LPPV1V3731+vVZWltV7n9r79321z7+LunXXue++++5r/CFAgAABAgQIECBQqcA6Am+llbUtAgQIECBAgACBBQGBVyMQIECAAAECBAhULSDwVl1emyNAgAABAgQIEBB49QABAgQIECBAgEDVAgJv1eW1OQIECBAgQIAAAYFXDxAgQIAAAQIECFQtIPBWXV6bI0CAAAECBAgQEHj1AAECBAgQIECAQNUCAm/V5bU5AgQIECBAgAABgVcPECBAgAABAgQIVC0g8FZdXpsjQIAAAQIECBAQePUAAQIECBAgQIBA1QICb9XltTkCBAgQIECAAAGBVw8QIECAAAECBAhULSDwVl1emyNAgAABAgQIEBB49QABAgQIECBAgEDVAgJv1eW1OQIECBAgQIAAAYFXDxAgQIAAAQIECFQtIPBWXV6bI0CAAAECBAgQEHj1AAECBAgQIECAQNUCAm/V5bU5AgQIECBAgAABgVcPECBAgAABAgQIVC0g8FZdXpsjQIAAAQIECBAQePUAAQIECBAgQIBA1QICb9XltTkCBAgQIECAAAGBVw8QIECAAAECBAhULSDwVl1emyNAgAABAgQIEBB49QABAgQIECBAgEDVAgJv1eW1OQIECBAgQIAAAYFXDxAgQIAAAQIECFQtIPBWXV6bI0CAAAECBAgQEHj1AAECBAgQIECAQNUCAm/V5bU5AgQIECBAgAABgVcPECBAgAABAgQIVC0g8FZdXpsjQIAAAQIECBAQePUAAQIECBAgQIBA1QICb9XltTkCBAgQIECAAAGBVw8QIECAAAECBAhULSDwVl1emyNAgAABAgQIEBB49QABAgQIECBAgEDVAgJv1eW1OQIECBAgQIAAAYFXDxAgQIAAAQIECFQtIPBWXV6bI0CAAAECBAgQEHj1AAECBAgQIECAQNUCAm/V5bU5AgQIECBAgAABgVcPECBAgAABAgQIVC0g8FZdXpsjQIAAAQIECBAQePUAAQIECBAgQIBA1QICb9XltTkCBAgQ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" }, "metadata": {}, "output_type": "display_data" } ], "source": [ "explanations = explainer.explain(x_test[4])\n", "explanations.ipython_plot(index=0)" ] } ], "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 }