{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "### L2X (learning to explain) on MNIST" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This is an example of the L2X explainer on image classification. Different from gradient-based methods, L2X trains a separate explanation model. The advantage of L2X is that it generates explanations fast after the explanation model is trained. The disadvantage is that the quality of the explanations highly depend on the trained explanation model, which can be affected by multiple factors, e.g., the network structure of the explanation model, the training parameters.\n", "\n", "For image data, we implement the default explanation model in `omnixai.explainers.vision.agnostic.l2x`. One may implement other models by following the same interface. Please refer to the docs for more details. If using this explainer, please cite the original work: \"Learning to Explain: An Information-Theoretic Perspective on Model Interpretation, Jianbo Chen, Le Song, Martin J. Wainwright, Michael I. Jordan, https://arxiv.org/abs/1802.07814\"." ] }, { "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", "\n", "from omnixai.data.image import Image\n", "from omnixai.explainers.vision import L2XImage" ] }, { "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", "train_imgs, train_labels = Image(train_data.data, batched=True), train_data.targets\n", "test_imgs, test_labels = Image(test_data.data, batched=True), test_data.targets" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The predictions function takes an `Image` instance as its input and outputs the class probabilities or logits for classification tasks." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "device = \"cuda\" if torch.cuda.is_available() else \"cpu\"\n", "# 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])\n", "# The prediction function\n", "predict_function = lambda ims: model(preprocess(ims).to(device)).detach().cpu().numpy()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We now train the CNN model defined above and evaluate its performance." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Accuracy for class 0 is: 99.6 %\n", "Accuracy for class 1 is: 99.7 %\n", "Accuracy for class 2 is: 98.8 %\n", "Accuracy for class 3 is: 98.5 %\n", "Accuracy for class 4 is: 99.4 %\n", "Accuracy for class 5 is: 99.1 %\n", "Accuracy for class 6 is: 98.4 %\n", "Accuracy for class 7 is: 99.4 %\n", "Accuracy for class 8 is: 98.7 %\n", "Accuracy for class 9 is: 96.4 %\n" ] } ], "source": [ "learning_rate=1e-3\n", "batch_size=32\n", "num_epochs=5\n", "\n", "train_loader = DataLoader(\n", " dataset=InputData(preprocess(train_imgs), train_labels),\n", " batch_size=batch_size,\n", " shuffle=True\n", ")\n", "test_loader = DataLoader(\n", " dataset=InputData(preprocess(test_imgs), test_labels),\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 `L2XImage`, we need to set the following parameters:\n", " \n", " - `training_data`: The data used to train the explainer. `training_data` should be the training dataset for training the machine learning model.\n", " - `predict_function`: The prediction function corresponding to the model to explain. When the model is for classification, the outputs of the `predict_function` are the class probabilities. When the model is for regression, the outputs of the `predict_function` are the estimated values.\n", " - `mode`: The task type, e.g., `classification` or `regression`.\n", " - `selection_model`: A pytorch model class for estimating P(S|X) in L2X. If `selection_model = None`, a default model `DefaultSelectionModel` will be used.\n", " - `prediction_model`: A pytorch model class for estimating Q(X_S) in L2X. If `prediction_model = None`, a default model `DefaultPredictionModel` will be used." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "Default upsampling behavior when mode=bilinear is changed to align_corners=False since 0.4.0. Please specify align_corners=True if the old behavior is desired. See the documentation of nn.Upsample for details.\n" ] }, { "name": "stdout", "output_type": "stream", "text": [ " |████████████████████████████████████████| 100.0% Complete, Loss 0.2665\n", "L2X prediction model accuracy: 0.8901166666666667\n" ] } ], "source": [ "explainer = L2XImage(\n", " training_data=train_imgs,\n", " predict_function=predict_function,\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We 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 `test_imgs[0:5]`." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "Default upsampling behavior when mode=bilinear is changed to align_corners=False since 0.4.0. Please specify align_corners=True if the old behavior is desired. See the documentation of nn.Upsample for details.\n" ] }, { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAArwAAAH0CAYAAADfWf7fAAAgAElEQVR4Xu3dd7guVXk34EVvCmJBjb1HY4mJoqIYjYrYIiAgSuyJvaGioiIqaiJEEYgYvhhsYENUki+iscTEJCp2saFGI6IgFhCpIvBd8/qdkwP7PXstZk19zr3/yWX2KjP3rHnWjzmz33ejyy+//PLkhwABAgQIECBAgEBQgY0E3qBX1mkRIECAAAECBAgsBAReC4EAAQIECBAgQCC0gMAb+vI6OQIECBAgQIAAAYHXGiBAgAABAgQIEAgtIPCGvrxOjgABAgQIECBAQOC1BggQIECAAAECBEILCLyhL6+TI0CAAAECBAgQEHitAQIECBAgQIAAgdACAm/oy+vkCBAgQIAAAQIEBF5rgAABAgQIECBAILSAwBv68jo5AgQIECBAgAABgdcaIECAAAECBAgQCC0g8Ia+vE6OAAECBAgQIEBA4LUGCBAgQIAAAQIEQgsIvKEvr5MjQIAAAQIECBAQeK0BAgQIECBAgACB0AICb+jL6+QIECBAgAABAgQEXmuAAAECBAgQIEAgtIDAG/ryOjkCBAgQIECAAAGB1xogQIAAAQIECBAILSDwhr68To4AAQIECBAgQEDgtQYIECBAgAABAgRCCwi8oS+vkyNAgAABAgQIEBB4rQECBAgQIECAAIHQAgJv6Mvr5AgQIECAAAECBARea4AAAQIECBAgQCC0gMAb+vI6OQIECBAgQIAAAYHXGiBAgAABAgQIEAgtIPCGvrxOjgABAgQIECBAQOC1BggQIECAAAECBEILCLyhL6+TI0CAAAECBAgQEHitAQIECBAgQIAAgdACAm/oy+vkCBAgQIAAAQIEBF5rgAABAgQIECBAILSAwBv68jo5AgQIECBAgAABgdcaIECAAAECBAgQCC0g8Ia+vE6OAAECBAgQIEBA4LUGCBAgQIAAAQIEQgsIvKEvr5MjQIAAAQIECBAQeK0BAgQIECBAgACB0AICb+jL6+QIECBAgAABAgQEXmuAAAECBAgQIEAgtIDAG/ryOjkCBAgQIECAAAGB1xogQIAAAQIECBAILSDwhr68To4AAQIECBAgQEDgtQYIECBAgAABAgRCCwi8oS+vkyNAgAABAgQIEBB4rQECBAgQIECAAIHQAgJv6Mvr5AgQIECAAAECBARea4AAAQIECBAgQCC0gMAb+vI6OQIECBAgQIAAAYHXGiBAgAABAgQIEAgtIPCGvrxOjgABAgQIECBAQOC1BggQIECAAAECBEILCLyhL6+TI0CAAAECBAgQEHitAQIECBAgQIAAgdACAm/oy+vkCBAgQIAAAQIEBF5rgAABAgQIECBAILSAwBv68jo5AgQIECBAgAABgdcaIECAAAECBAgQCC0g8Ia+vE6OAAECBAgQIEBA4LUGCBAgQIAAAQIEQgsIvKEvr5MjQIAAAQIECBAQeK0BAgQIECBAgACB0AICb+jL6+QIECBAgAABAgQEXmuAAAECBAgQIEAgtIDAG/ryOjkCBAgQIECAAAGB1xogQIAAAQIECBAILSDwhr68To4AAQIECBAgQEDgtQYIECBAgAABAgRCCwi8oS+vkyNAgAABAgQIEBB4rQECBAgQIECAAIHQAgJv6Mvr5AgQIECAAAECBARea4AAAQIECBAgQCC0gMAb+vI6OQIECBAgQIAAAYHXGiBAgAABAgQIEAgtIPCGvrxOjgABAgQIECBAQOC1BggQIECAAAECBEILCLyhL6+TI0CAAAECBAgQEHitAQIECBAgQIAAgdACAm/oyxv/5D72719I7/7gJ9I3v/vDdNHFv0nX3+Ga6U/v9Ufpyfs+LG237TaDAbzkr/4+XXDhxemNr3rmYHOaiACB6Qoc94GPp9cecezaA9z2alun293mpunxez8o7Xy3O3R64Ice9Z706/MvSK/a/4mrjvvIp7wy7fuI+6c/2+Wenc5vMAJzEBB453CVHONSgTcc/b701veelB7x4D9J99npD9M2W2+ZfnDaGentx380XXbZZekdR7wkXeda1xhET+AdhNkkBGYj0ATeN73tg+mYN7woXfLbS9NPf/bL9P7/+2/pP04+Jf3d656X7rVjd6H3+P/7qXTRRb9Jj9lzl4XPj35yVmpq0juPfOkVvF79xnemXf7krmnHO//+bBwdKIGuBATeriSNM6jAyV/+dnrCfn+dXvPiv0i77XqvK8x93vkXpkc//eB00xtfLx1x8LMHOS6BdxBmkxCYjUATeI9+5z+mf//gEWuP+bLLLk97Pfmg9HvXvVY68jXP6e1c3vqek9In/uNL6di/vWLg7W1CAxOYgYDAO4OL5BBXCjzvFUel03780/T+v3/lUp5/+bcvpP0O+tv08fe+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" }, "metadata": {}, "output_type": "display_data" } ], "source": [ "explanations = explainer.explain(test_imgs[0:5])\n", "explanations.ipython_plot(index=1)" ] } ], "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 }