{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Handle changes in prediction during robustness evaluation.\n", "[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/understandable-machine-intelligence-lab/Quantus/main?labpath=tutorials%2FTutorial_Handle_Changes_In_Predictions.ipynb)\n", "\n", "\n", "Typically, during robustness evaluation, we want model prediction to stay the same.\n", "This behaviour is, however, very sensitive to perturbation function and its hyperparameter choices.\n", "In this notebook we demonstrate how this could be handled in `quantus` using a simple motivating example with Average Sensitivity Metric." ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[PhysicalDevice(name='/physical_device:CPU:0', device_type='CPU')]" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Import dependencies.\n", "import pandas as pd\n", "import tensorflow as tf\n", "import tensorflow_datasets as tfds\n", "import quantus\n", "\n", "tf.config.list_physical_devices()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 1) Preliminaries\n", "\n", "### 1.1 Load ImageNet subset." ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(32, 224, 224, 3)" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "IMG_SIZE = 224\n", "\n", "ds = tfds.load(\n", " \"imagenet_v2\",\n", " split=[\"test\"],\n", " as_supervised=True,\n", " try_gcs=True,\n", " batch_size=32,\n", " data_dir=\"/tmp/tensorflow_datasets/\",\n", ")\n", "\n", "x_batch, y_batch = ds[0].take(1).as_numpy_iterator().next()\n", "x_batch = tf.image.resize(x_batch, (IMG_SIZE, IMG_SIZE)).numpy()\n", "x_batch.shape" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 1.2. Load pre-trained model." ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "model = tf.keras.applications.MobileNetV2()\n", "model.input" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 1.3. Generate batch of predictions and explanations using baseline method \"IntegratedGradients\"." ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(32, 224, 224)" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "y_predicted = model.predict(x_batch).argmax(axis=1)\n", "a_batch_intgrad = quantus.explain(\n", " model, x_batch, y_predicted, method=\"IntegratedGradients\"\n", ")\n", "a_batch_intgrad.shape" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 2) Quantitative evaluation with Quantus\n", "\n", "We can evaluate the robustness of our explanations on a variety of quantitative criteria, but as a motivating example we test the Average Sensitivity (Yeh at el., 2019) of the explanations. This metric tests how the explanations change on average while subject to slight perturbations.\n", "\n", "All robustness metrics accept constructor keyword argument `return_nan_when_prediction_changes`, as the name suggests,\n", "when set to true, the metric will be evaluated to NaN if the prediction changes after the perturbation is applied." ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "47a0ef0f36824da0b4430a53dd56e3e5", "version_major": 2, "version_minor": 0 }, "text/plain": [ " 0%| | 0/1 [00:00\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
0123456789...22232425262728293031
No Prediction Change Check0.0032740.0032580.0080440.0051170.0076980.0044860.0039260.002260.0046410.009831...0.0056730.00550.0042420.0073230.0059930.0077630.0094050.0123470.0043980.011894
Nan On Prediction ChangeNaNNaN0.0080440.0051170.0076990.004486NaNNaNNaN0.009832...0.0056730.0055NaN0.0073230.0059960.0077630.0094050.012347NaNNaN
\n

2 rows × 32 columns

\n" }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "pd.DataFrame(\n", " [\n", " results[\"IntegratedGradients\"][\"DefaultAvgSensitivity\"],\n", " results[\"IntegratedGradients\"][\"AvgSensitivityWithNan\"],\n", " ],\n", " index=[\"No Prediction Change Check\", \"Nan On Prediction Change\"],\n", ")" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "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.8.12" } }, "nbformat": 4, "nbformat_minor": 1 }