diff --git a/dianna/methods/kernelshap_tabular.py b/dianna/methods/kernelshap_tabular.py new file mode 100644 index 00000000..d2bf47e3 --- /dev/null +++ b/dianna/methods/kernelshap_tabular.py @@ -0,0 +1,84 @@ +from typing import List +from typing import Optional +from typing import Union +import numpy as np +import shap +from shap import KernelExplainer +from dianna import utils + + +class KERNELSHAPTabular: + """Wrapper around the SHAP Kernel explainer for tabular data.""" + + def __init__( + self, + training_data: np.array, + mode: str = "classification", + feature_names: List[int] = None, + training_data_kmeans: Optional[int] = None, + ) -> None: + """Initializer of KERNELSHAPTabular. + + Training data must be provided for the explainer to estimate the expected + values. + + More information can be found in the API guide: + https://github.com/shap/shap/blob/master/shap/explainers/_kernel.py + + Arguments: + training_data (np.array): training data, which should be numpy 2d array + mode (str, optional): "classification" or "regression" + feature_names (list(str), optional): list of names corresponding to the columns + in the training data. + training_data_kmeans(int, optional): summarize the whole training set with + weighted kmeans + """ + if training_data_kmeans: + self.training_data = shap.kmeans(training_data, training_data_kmeans) + else: + self.training_data = training_data + self.feature_names = feature_names + self.mode = mode + self.explainer: KernelExplainer + + def explain( + self, + model_or_function: Union[str, callable], + input_tabular: np.array, + link: str = "identity", + **kwargs, + ) -> np.array: + """Run the KernelSHAP explainer. + + Args: + model_or_function (callable or str): The function that runs the model to be explained + or the path to a ONNX model on disk. + input_tabular (np.ndarray): Data to be explained. + link (str): A generalized linear model link to connect the feature importance values + to the model. Must be either "identity" or "logit". + kwargs: These parameters are passed on + + Other keyword arguments: see the documentation for KernelExplainer: + https://github.com/shap/shap/blob/master/shap/explainers/_kernel.py + + Returns: + explanation: An Explanation object containing the KernelExplainer explanations + for each class. + """ + init_instance_kwargs = utils.get_kwargs_applicable_to_function( + KernelExplainer, kwargs + ) + self.explainer = KernelExplainer( + model_or_function, self.training_data, link, **init_instance_kwargs + ) + + explain_instance_kwargs = utils.get_kwargs_applicable_to_function( + self.explainer.shap_values, kwargs + ) + + saliency = self.explainer.shap_values(input_tabular, **explain_instance_kwargs) + + if self.mode == 'regression': + return saliency[0] + + return saliency diff --git a/dianna/methods/lime_tabular.py b/dianna/methods/lime_tabular.py index d72bbc22..59fe5c40 100644 --- a/dianna/methods/lime_tabular.py +++ b/dianna/methods/lime_tabular.py @@ -119,11 +119,11 @@ def explain( **explain_instance_kwargs, ) - if self.mode == "regression": + if self.mode == 'regression': local_exp = sorted(explanation.local_exp[1]) saliency = [i[1] for i in local_exp] - elif self.mode == "classification": + elif self.mode == 'classification': # extract scores from lime explainer saliency = [] for i in range(self.top_labels): diff --git a/tests/methods/test_shap_tabular.py b/tests/methods/test_shap_tabular.py new file mode 100644 index 00000000..f2ecc7fe --- /dev/null +++ b/tests/methods/test_shap_tabular.py @@ -0,0 +1,35 @@ +"""Test LIME tabular method.""" +from unittest import TestCase +import numpy as np +import dianna +from dianna.methods.kernelshap_tabular import KERNELSHAPTabular +from tests.utils import run_model + + +class LIMEOnTabular(TestCase): + """Suite of LIME tests for the tabular case.""" + + def test_shap_tabular_classification_correct_output_shape(self): + """Test whether the output of explainer has the correct shape.""" + training_data = np.random.random((10, 2)) + input_data = np.random.random(2) + feature_names = ["feature_1", "feature_2"] + explainer = KERNELSHAPTabular(training_data, + mode ='classification', + feature_names=feature_names,) + exp = explainer.explain( + run_model, + input_data, + ) + assert len(exp[0]) == len(feature_names) + + def test_shap_tabular_regression_correct_output_shape(self): + """Test whether the output of explainer has the correct length.""" + training_data = np.random.random((10, 2)) + input_data = np.random.random(2) + feature_names = ["feature_1", "feature_2"] + exp = dianna.explain_tabular(run_model, input_tabular=input_data, method='kernelshap', + mode ='regression', training_data = training_data, + training_data_kmeans = 2, feature_names=feature_names) + + assert len(exp) == len(feature_names) diff --git a/tutorials/kernelshap_tabular_penguin.ipynb b/tutorials/kernelshap_tabular_penguin.ipynb new file mode 100644 index 00000000..ffcc5ab7 --- /dev/null +++ b/tutorials/kernelshap_tabular_penguin.ipynb @@ -0,0 +1,434 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\"Logo_ER10\"\n", + "\n", + "### Model Interpretation using KernelSHAP for penguin dataset classifier\n", + "This notebook demonstrates the use of DIANNA with the SHAP Kernel explainer method for tabular data on the penguins dataset." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Colab setup" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "running_in_colab = 'google.colab' in str(get_ipython())\n", + "if running_in_colab:\n", + " # install dianna\n", + " !python3 -m pip install dianna[notebooks]\n", + " \n", + " # download data used in this demo\n", + " import os \n", + " base_url = 'https://raw.githubusercontent.com/dianna-ai/dianna/main/tutorials/'\n", + " paths_to_download = ['models/penguin_model.onnx']\n", + " for path in paths_to_download:\n", + " !wget {base_url + path} -P {os.path.dirname(path)}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Import libraries" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "import dianna\n", + "import numpy as np\n", + "import pandas as pd\n", + "import seaborn as sns\n", + "from sklearn.model_selection import train_test_split\n", + "from dianna.utils.onnx_runner import SimpleModelRunner\n", + "\n", + "from numba.core.errors import NumbaDeprecationWarning\n", + "import warnings\n", + "# silence the Numba deprecation warnings in shap\n", + "warnings.simplefilter('ignore', category=NumbaDeprecationWarning)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 1 - Loading the data\n", + "Load penguins dataset." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "penguins = sns.load_dataset('penguins')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Prepare the data" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\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", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
bill_length_mmbill_depth_mmflipper_length_mmbody_mass_g
039.118.7181.03750.0
139.517.4186.03800.0
240.318.0195.03250.0
436.719.3193.03450.0
539.320.6190.03650.0
...............
33847.213.7214.04925.0
34046.814.3215.04850.0
34150.415.7222.05750.0
34245.214.8212.05200.0
34349.916.1213.05400.0
\n", + "

342 rows × 4 columns

\n", + "
" + ], + "text/plain": [ + " bill_length_mm bill_depth_mm flipper_length_mm body_mass_g\n", + "0 39.1 18.7 181.0 3750.0\n", + "1 39.5 17.4 186.0 3800.0\n", + "2 40.3 18.0 195.0 3250.0\n", + "4 36.7 19.3 193.0 3450.0\n", + "5 39.3 20.6 190.0 3650.0\n", + ".. ... ... ... ...\n", + "338 47.2 13.7 214.0 4925.0\n", + "340 46.8 14.3 215.0 4850.0\n", + "341 50.4 15.7 222.0 5750.0\n", + "342 45.2 14.8 212.0 5200.0\n", + "343 49.9 16.1 213.0 5400.0\n", + "\n", + "[342 rows x 4 columns]" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Remove categorial columns and NaN values\n", + "penguins_filtered = penguins.drop(columns=['island', 'sex']).dropna()\n", + "\n", + "# Get the species\n", + "species = penguins['species'].unique()\n", + "\n", + "# Extract inputs and target\n", + "input_features = penguins_filtered.drop(columns=['species'])\n", + "target = pd.get_dummies(penguins_filtered['species'])\n", + "\n", + "# Let's explore the features of the dataset\n", + "input_features" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The data-set currently has four features that were used to train the model: bill length, bill depth, flipper length, and body mass. These features were used to classify the different species." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Training, validation, and test data split." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "X_train, X_test, y_train, y_test = train_test_split(input_features, target, test_size=0.2,\n", + " random_state=0, shuffle=True, stratify=target)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Get an instance to explain." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "# get an instance from test data\n", + "data_instance = X_test.iloc[10].to_numpy()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 2. Loading ONNX model\n", + "DIANNA supports ONNX models. Here we demonstrate the use of KernelSHAP explainer for tabular data with a pre-trained ONNX model, which is a MLP classifier for the penguins dataset.
\n", + "\n", + "The model is trained following this notebook:
\n", + "https://github.com/dianna-ai/dianna-exploration/blob/main/example_data/model_generation/penguin_species/generate_model.ipynb" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'Gentoo'" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# load onnx model and check the prediction with it\n", + "model_path = './models/penguin_model.onnx'\n", + "loaded_model = SimpleModelRunner(model_path)\n", + "predictions = loaded_model(data_instance.reshape(1,-1).astype(np.float32))\n", + "species[np.argmax(predictions)]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "A runner function is created to prepare data for the ONNX inference session." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "import onnxruntime as ort\n", + "\n", + "def run_model(data):\n", + " # get ONNX predictions\n", + " sess = ort.InferenceSession(model_path)\n", + " input_name = sess.get_inputs()[0].name\n", + " output_name = sess.get_outputs()[0].name\n", + "\n", + " onnx_input = {input_name: data.astype(np.float32)}\n", + " pred_onnx = sess.run([output_name], onnx_input)[0]\n", + " \n", + " return pred_onnx" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 3. Applying KernelSHAP with DIANNA\n", + "The simplest way to run DIANNA on image data is with `dianna.explain_tabular`.\n", + "\n", + "DIANNA requires input in numpy format, so the input data is converted into a numpy array.\n", + "\n", + "Note that the training data is also required since KernelSHAP needs it to generate proper perturbation. But here we can summarize the whole training set with weighted Kmeans to reduce the computational cost. This has been implemented in `shap` and here we just need to set the number of clusters, for instance `training_data_kmeans = 5`." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n" + ] + } + ], + "source": [ + "explanation = dianna.explain_tabular(run_model, input_tabular=data_instance, method='kernelshap',\n", + " mode ='classification', training_data = X_train,\n", + " training_data_kmeans = 5, feature_names=input_features.columns)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 4. Visualization\n", + "The output can be visualized with the DIANNA built-in visualization function. It shows the importance of each feature contributing to the prediction.\n", + "\n", + "The prediction is \"Gentoo\", so let's visualize the feature importance scores for \"Gentoo\".\n", + "\n", + "It can be noticed that the body mass feature has the biggest weight in the prediction." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAqMAAAGwCAYAAACdNWzAAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAAA7FklEQVR4nO3de1xVVf7/8fcR5CL3VAgLOTqooUmijoZ5qyzT8qvWTzMbb13UEi9j41jfNDUrzcnEsXIKy0uT2sU0s7wnjXfNwJxkCAlHS9SZVBDvwPr90deTJ9QAgaXwej4e+/E4e+219/7slXre7dtxGGOMAAAAAAuq2C4AAAAAlRdhFAAAANYQRgEAAGANYRQAAADWEEYBAABgDWEUAAAA1hBGAQAAYI2n7QKAyykoKNCBAwcUEBAgh8NhuxwAAFAExhgdP35ctWrVUpUqlz/3SRjFVe3AgQOKiIiwXQYAACiB/fv368Ybb7xsH8IormoBAQGSfv7DHBgYaLkaAABQFDk5OYqIiHB9j18OYRRXtfOX5gMDAwmjAABcY4pyix0PMAEAAMAawigAAACsIYwCAADAGsIoAAAArCGMAgAAwBrCKAAAAKwhjAIAAMAawigAAACsIYwCAADAGsIoAAAArCGMAgAAwBrCKAAAAKwhjAIAAMAawigAAACsIYwCAADAGsIoAAAArCGMAgAAwBrCKAAAAKwhjAIAAMAawigAAACsIYwCAADAGsIoAAAArCGMAgAAwBrCKAAAAKwhjAIAAMAawigAAACsIYwCAADAGsIoAAAArCGMAgAAwBrCKAAAAKwhjAIAAMAawigAAACsIYwCAADAGsIoAAAArCGMAgAAwBrCKAAAAKwhjAIAAMAawigAAACsIYwCAADAGsIoAAAArCGMAgAAwBrCKAAAAKwhjAIAAMAawigAAACsIYwCAADAmkoVRtu3b68RI0ZccrnT6VRCQoJr3uFwaMmSJZKkvXv3yuFwKCUlpUT7TkpKksPh0LFjx0q0fnGMHz9eTZo0KfP9AAAAXClP2wVcTbZv3y4/Pz/bZRSLw+HQ4sWL1a1bN9ulAAAAFBth9AI1a9a0XQIAAEClUqku00tSXl6e4uPjFRQUpBo1amjs2LEyxkgqfJn+Snz++eeqX7++fH19dfvtt2vv3r2F+mzYsEFt2rSRr6+vIiIiNGzYMJ04ccK13Ol0auLEiXrooYfk5+enG264Qa+//rrbcknq3r27HA6Ha/68d999V06nU0FBQerVq5eOHz9epNrbt2+voUOHasSIEQoJCVFYWJgSExN14sQJDRgwQAEBAYqKitLy5ctd65y/DWHlypWKjY2Vr6+v7rjjDh0+fFjLly9XdHS0AgMD1bt3b508efKS+z5z5oxycnLcJgAAUHFVujA6d+5ceXp6atu2bZo+fbpeffVVzZo1q1T3sX//ft1///3q0qWLUlJS9Nhjj+npp59265ORkaF77rlHDzzwgL755hu9//772rBhg+Lj4936/eUvf9Ett9yi5ORkPf300xo+fLhWr14t6efbCiRp9uzZysrKcs2f3/6SJUu0bNkyLVu2TF9++aUmT55c5GOYO3euatSooW3btmno0KF64okn1KNHD7Vq1Upff/217r77bvXp06dQsBw/frxee+01bdq0Sfv371fPnj2VkJCg+fPn67PPPtOqVas0Y8aMS+530qRJCgoKck0RERFFrhkAAFyDTCXSrl07Ex0dbQoKClxto0ePNtHR0cYYYyIjI820adNcyySZxYsXG2OMyczMNJJMcnLyb+7nmWeeMQ0bNnRrGz16tJFkjh49aowx5tFHHzUDBw5067N+/XpTpUoVc+rUKVc999xzj1ufBx980HTq1OmiNZ43btw4U61aNZOTk+NqGzVqlGnZsuVv1m7Mz+PUunVr13xeXp7x8/Mzffr0cbVlZWUZSWbz5s3GGGPWrVtnJJk1a9a4+kyaNMlIMhkZGa62QYMGmY4dO15y36dPnzbZ2dmuaf/+/UaSyc7OLlLtAADAvuzs7CJ/f1e6M6O33nqrHA6Haz4uLk7p6enKz88vtX2kpqaqZcuWbm1xcXFu8zt37tScOXPk7+/vmjp27KiCggJlZmZecr24uDilpqb+Zg1Op1MBAQGu+fDwcB0+fLjIxxATE+P67OHhoerVq6tx48autrCwMEkqtM0L1wsLC1O1atVUt25dt7bL1eHt7a3AwEC3CQAAVFw8wGRJbm6uBg0apGHDhhVaVrt27SveftWqVd3mHQ6HCgoKrmj9C9vOB/pfb/PXfa60DgAAULFVujC6detWt/ktW7aoXr168vDwKLV9REdHa+nSpYX2c6GmTZtq9+7dioqKuuy2fr3eli1bFB0d7ZqvWrVqqZ7VBQAAKE+V7jL9vn37NHLkSKWlpWnBggWaMWOGhg8fXqr7GDx4sNLT0zVq1CilpaVp/vz5mjNnjluf0aNHa9OmTYqPj1dKSorS09P1ySefFHqAaePGjZoyZYq+++47vf766/rwww/d6nU6nVq7dq0OHjyoo0ePlupxAAAAlLVKF0b79u2rU6dOqUWLFhoyZIiGDx+ugQMHluo+ateurUWLFmnJkiW65ZZb9Le//U0vvfSSW5+YmBh9+eWX+u6779SmTRvFxsbqueeeU61atdz6PfXUU/rqq68UGxurF154Qa+++qo6duzoWj516lStXr1aERERio2NLdXjAAAAKGsOY/7vJZu46jidTo0YMeKyP2Fa0eXk5CgoKEjZ2dk8zAQAwDWiON/fle7MKAAAAK4ehNESGDx4sNsrmS6cBg8ebLu8y9q3b98la/f399e+fftslwgAACoRLtOXwOHDhy/5M5WBgYEKDQ0t54qKLi8v76I/TXqe0+mUp+fV85IFLtMDAHDtKc7399WTOq4hoaGhV3XgvBxPT8/ffJ0UAABAeeEyPQAAAKwhjAIAAMAawigAAACsIYwCAADAGsIoAAAArCGMAgAAwBrCKAAAAKwhjAIAAMAawigAAACsIYwCAADAGsIoAAAArCGMAgAAwBrCKAAAAKwhjAIAAMAawigAAACsIYwCAADAGsIoAAAArCGMAgAAwBrCKAAAAKwhjAIAAMAawigAAACsIYwCAADAGsIoAAAArCGMAgAAwBrCKAAAAKwhjAIAAMAawigAAACsIYwCAADAGsIoAAAArCGMAgAAwBrCKAAAAKwhjAIAAMAawigAAACsIYwCAADAGsIoAAAArCGMAgAAwBrCKAAAAKwhjAIAAMAawigAAACsIYwCAADAGsIoAAAArPG0XQBwTXA4fvlsjL06AACoYDgzCgAAAGsIowAAALCGMAoAAABrCKMAAACwhjAKAAAAawijAAAAsIYwCgAAAGsIowAAALCGMAoAAABrCKMAAACwhjAKAAAAawijAAAAsIYwCgAAAGsIowAAALCGMAoAAABrCKMAAACwhjAKAAAAawijAAAAsIYwCgAAAGsIowAAALCGMAoAAABrCKMAAACwhjAKAAAAawijAAAAsIYwCgAAAGsIowAAALCGMAoAAABrCKMAAACwhjAKAAAAawijAAAAsKZCh9H27dtrxIgR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a9a4+kyaNMlIMhkZGa62QYMGmY4dO15y36dPnzbZ2dmu6fx/m+zs7CLVXlxS0SYAAFB02dnZRf7+tnrPaEnExcUVmk9JSblkH09PTzVv3tx19nTnzp1at26d/P39C207IyND9evXlyQ1a9asxDXu3LlTe/bsUUBAgFv76dOnlZGR4Zpv1KiRPDw8XPPh4eHatWuXJCktLU2enp5q2rSpa3lUVJRCQkKKVIPT6XTbf3h4uNtZ1d8SExPj+uzh4aHq1aurcePGrrawsDBJKrTNC9cLCwtTtWrVVLduXbe2bdu2XXK/3t7e8vb2LnKdAADg2nbNhdErlZubqy5duujll18utCw8PNz12c/P74r20axZM7333nuFll34UFbVqlXdljkcDhUUFJR4vxe60m1fbP0L2xwOhyQV2uav+5TlMQIAgGvfNffS+y1bthSaj46OvmSfvLw87dixw9WnadOm+vbbb+V0OhUVFeU2XUkAvVDTpk2Vnp6u0NDQQvsICgoq0jYaNGigvLw8JScnu9r27Nmjo0ePuvWrWrWq8vPzS6VuAACA8nbNhdEPP/xQ77zzjr777juNGzdO27ZtU3x8vFuf119/XYsXL9a//vUvDRkyREePHtUjjzwiSRoyZIiOHDmihx56SNu3b1dGRoZWrlypAQMGlFqoe/jhh1WjRg117dpV69evV2ZmppKSkjRs2DD98MMPRdrGTTfdpA4dOmjgwIHatm2bkpOTNXDgQPn6+rrOSko/X45fu3atDh48WCioAgAAXO2uuTA6YcIELVy4UDExMZo3b54WLFighg0buvWZPHmyJk+erFtuuUUbNmzQ0qVLVaNGDUlSrVq1tHHjRuXn5+vuu+9W48aNNWLECAUHB6tKldIZjmrVqukf//iHateurfvvv1/R0dF69NFHdfr0aQUGBhZ5O/PmzVNYWJjatm2r7t276/HHH1dAQIB8fHxcfaZOnarVq1crIiJCsbGxpVI/AABAeXEYY4ztIorK4XBo8eLF6tat20WX7927V3Xq1FFycnKF/DnMH374QREREVqzZo3uvPNO2+WUi5ycHAUFBSk7O7tYQb6oLjjJfFnXzt8SAADsK873d6V7gOla8sUXXyg3N1eNGzdWVlaW/vznP8vpdKpt27a2SwMAACgV19xlehvee+89+fv7X3Rq1KhRme333Llz+t///V81atRI3bt3V82aNZWUlFToCfXi2Ldv3yWPxd/fX/v27SvFIwAAALi8a+oyvS3Hjx/XoUOHLrqsatWqioyMLOeKSi4vL8/tZ0l/zel0ytPz6jlhzmV6AACuPVymL2UBAQGFXmB/rfL09FRUVJTtMgAAACRxmR4AAAAWEUYBAABgDWEUAAAA1hBGAQAAYA1hFAAAANYQRgEAAGANYRQAAADWEEYBAABgDWEUAAAA1hBGAQAAYA1hFAAAANYQRgEAAGANYRQAAADWEEYBAABgDWEUAAAA1hBGAQAAYA1hFAAAANYQRgEAAGANYRQAAADWEEYBAABgDWEUAAAA1hBGAQAAYA1hFAAAANYQRgEAAGCNp+0CAJuMsV0BAACVG2dGAQAAYA1hFAAAANYQRgEAAGANYRQAAADWEEYBAABgDWEUAAAA1hBGAQAAYA1hFAAAANYQRgEAAGANYRQAAADWEEYBAABgDWEUAAAA1hBGAQAAYA1hFAAAANYQRgEAAGANYRQAAADWeNouALgmOBy2KwAAoGwYY3X3nBkFAACANYRRAAAAWEMYBQAAgDWEUQAAAFhDGAUAAIA1hFEAAABYQxgFAACANYRRAAAAWEMYBQAAgDWEUQAAAFhDGAUAAIA1hFEAAABYQxgFAACANYRRAAAAWEMYBQAAgDWEUQAAAFhDGAUAAIA1hFEAAABYQxgFAACANYRRAAAAWEMYBQAAgDWEUQAAAFhDGAUAAIA1hFEAAABYQxgFAACANYRRAAAAWEMYBQAAgDWEUQAAAFhDGAUAAIA1hFEAAABYQxi9QPv27TVixIhS3eacOXMUHBxcqtsEAACoKAijAAAAsIYwCgAAAGsIo7+Sl5en+Ph4BQUFqUaNGho7dqyMMZKko0ePqm/fvgoJCVG1atXUqVMnpaenu60/Z84c1a5dW9WqVVP37t31008/uZbt3btXVapU0VdffeW2TkJCgiIjI1VQUHDZ2pKSkuRwOLRy5UrFxsbK19dXd9xxhw4fPqzly5crOjpagYGB6t27t06ePOlab8WKFWrdurWCg4NVvXp13XfffcrIyHAtP3v2rOLj4xUeHi4fHx9FRkZq0qRJkiRjjMaPH6/atWvL29tbtWrV0rBhw4o0lllZWbr33nvl6+urOnXqaP78+XI6nUpISCjS+gAAoOIjjP7K3Llz5enpqW3btmn69Ol69dVXNWvWLElS//799dVXX2np0qXavHmzjDHq3Lmzzp07J0naunWrHn30UcXHxyslJUW33367XnjhBde2nU6nOnTooNmzZ7vtc/bs2erfv7+qVCnaf47x48frtdde06ZNm7R//3717NlTCQkJmj9/vj777DOtWrVKM2bMcPU/ceKERo4cqa+++kpr165VlSpV1L17d1f4/etf/6qlS5fqgw8+UFpamt577z05nU5J0qJFizRt2jS9+eabSk9P15IlS9S4ceMi1dm3b18dOHBASUlJWrRokd566y0dPnz4suucOXNGOTk5bhMAAKjADFzatWtnoqOjTUFBgatt9OjRJjo62nz33XdGktm4caNr2X//+1/j6+trPvjgA2OMMQ899JDp3Lmz2zYffPBBExQU5Jp///33TUhIiDl9+rQxxpgdO3YYh8NhMjMzf7O+devWGUlmzZo1rrZJkyYZSSYjI8PVNmjQINOxY8dLbuc///mPkWR27dpljDFm6NCh5o477nA77vOmTp1q6tevb86ePfub9V0oNTXVSDLbt293taWnpxtJZtq0aZdcb9y4cUZSoSk7O7tY+y91EhMTExMTU8WcykB2drYp6vc3Z0Z/5dZbb5XD4XDNx8XFKT09Xbt375anp6datmzpWla9enU1aNBAqampkqTU1FS35efXv1C3bt3k4eGhxYsXS/r5sv7tt9/uOhNZFDExMa7PYWFhqlatmurWrevWduEZyPT0dD300EOqW7euAgMDXfvat2+fpJ/P+KakpKhBgwYaNmyYVq1a5Vq3R48eOnXqlOrWravHH39cixcvVl5e3m/WmJaWJk9PTzVt2tTVFhUVpZCQkMuu98wzzyg7O9s17d+//zf3BQAArl2E0XLm5eWlvn37avbs2Tp79qzmz5+vRx55pFjbqFq1quuzw+Fwmz/fduH9p126dNGRI0eUmJiorVu3auvWrZJ+vldUkpo2barMzExNnDhRp06dUs+ePfX//t//kyRFREQoLS1Nb7zxhnx9ffXkk0+qbdu2rlsTSpu3t7cCAwPdJgAAUHERRn/lfFA7b8uWLapXr54aNmyovLw8t+U//fST0tLS1LBhQ0lSdHT0Rdf/tccee0xr1qzRG2+8oby8PN1///1lcCTuNY4ZM0Z33nmnoqOjdfTo0UL9AgMD9eCDDyoxMVHvv/++Fi1apCNH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SU1NNePGjatQr3YqzlicOXPGJCcnm+TkZBMeHm7+9Kc/meTkZJOenm7rEEpNccdi8uTJxsvLy3z00Udur645fvy4rUMoNcUdi5deesmsWrXKZGRkmN27d5tXXnnFeHp6msTERFuHUGqKOxa/VpGepi/uWEyYMMGsXLnSZGRkmB07dphevXoZHx8f8+2339o6hFJT3LHYt2+fCQgIMPHx8SYtLc0sW7bMhIaGmhdeeMHWIVhFGAWMMTNmzDC1a9c2Xl5epkWLFmbLli2uZe3atTP9+vVz6//BBx+Y+vXrGy8vL9OoUSPz2WeflXPFZac4Y5GZmWkkFZratWtX/oWXgeKMRWRk5EXHYty4ceVfeBkozlg8++yzJioqyvj4+JiQkBATFxdnFi5caKHqslHcfy8uVJHCqDHFG4sRI0a4+oaFhZnOnTubr7/+2kLVZaO4fy42bdpkWrZsaby9vU3dunXNiy++aPLy8sq56quDwxhjbJ2VBQAAQOXGPaMAAACwhjAKAAAAawijAAAAsIYwCgAAAGsIowAAALCGMAoAAABrCKMAAACwhjAKAAAAawijAAAAsIYwCgBXmf79+6tbt262y7ikvXv3yuFwKCUlxXYpACoAwigAoMjOnj1ru4SrGuMDFB9hFACucu3bt9fQoUM1YsQIhYSEKCwsTImJiTpx4oQGDBiggIAARUVFafny5a51kpKS5HA49NlnnykmJkY+Pj669dZb9c9//tNt24sWLVKjRo3k7e0tp9OpqVOnui13Op2aOHGi+vbtq8DAQA0cOFB16tSRJMXGxsrhcKh9+/aSpO3bt+uuu+5SjRo1FBQUpHbt2unrr792257D4dCsWbPUvXt3VatWTfXq1dPSpUvd+nz77be67777FBgYqICAALVp00YZGRmu5bNmzVJ0dLR8fHx000036Y033rjs+H300Udq3LixfH19Vb16dXXo0EEnTpxwLX/nnXdcYxAeHq74+HjXsn379qlr167y9/dXYGCgevbsqUOHDrmWjx8/Xk2aNNGsWbNUp04d+fj4SJKOHTumxx57TDVr1lRgYKDuuOMO7dy587J1ApUVYRQArgFz585VjRo1tG3bNg0dOlRPPPGEevTooVatWunrr7/W3XffrT59+ujkyZNu640aNUpTp07V9u3bVbNmTXXp0kXnzp2TJO3YsUM9e/ZUr169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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from dianna.visualization import plot_tabular\n", + "\n", + "# get the scores for the target class\n", + "explanation = explanation[np.argmax(predictions)]\n", + "\n", + "_ = plot_tabular(explanation, X_test.columns, num_features=10)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "dianna", + "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.10.13" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/tutorials/kernelshap_tabular_weather.ipynb b/tutorials/kernelshap_tabular_weather.ipynb new file mode 100644 index 00000000..a239ee38 --- /dev/null +++ b/tutorials/kernelshap_tabular_weather.ipynb @@ -0,0 +1,280 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\"Logo_ER10\"\n", + "\n", + "### Model Interpretation using KernelSHAP for weather prediction regressor\n", + "This notebook demonstrates the use of DIANNA with the SHAP Kernel explainer method for tabular data on the weather dataset.\n", + "\n", + "https://shap.readthedocs.io/en/latest/example_notebooks/tabular_examples/model_agnostic/Diabetes%20regression.html" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Colab setup" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "running_in_colab = 'google.colab' in str(get_ipython())\n", + "if running_in_colab:\n", + " # install dianna\n", + " !python3 -m pip install dianna[notebooks]\n", + " \n", + " # download data used in this demo\n", + " import os\n", + " base_url = 'https://raw.githubusercontent.com/dianna-ai/dianna/main/tutorials/'\n", + " paths_to_download = ['models/sunshine_hours_regression_model.onnx']\n", + " for path in paths_to_download:\n", + " !wget {base_url + path} -P {os.path.dirname(path)}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Import libraries" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "import dianna\n", + "import numpy as np\n", + "import pandas as pd\n", + "from sklearn.model_selection import train_test_split\n", + "from dianna.utils.onnx_runner import SimpleModelRunner\n", + "\n", + "from numba.core.errors import NumbaDeprecationWarning\n", + "import warnings\n", + "# silence the Numba deprecation warnings in shap\n", + "warnings.simplefilter('ignore', category=NumbaDeprecationWarning)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 1 - Loading the data\n", + "Load weather prediction dataset." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "data = pd.read_csv(\"https://zenodo.org/record/5071376/files/weather_prediction_dataset_light.csv?download=1\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### Prepare the data\n", + "As the target, the sunshine hours for the next day in the data-set will be used. Therefore, we will remove the last data point as this has no target. A tabular regression model will be trained which does not require time-based data, therefore DATE and MONTH can be removed." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "X_data = data.drop(columns=['DATE', 'MONTH'])[:-1]\n", + "y_data = data.loc[1:][\"BASEL_sunshine\"]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Training, validation, and test data split." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "X_train, X_holdout, y_train, y_holdout = train_test_split(X_data, y_data, test_size=0.3, random_state=0)\n", + "X_val, X_test, y_val, y_test = train_test_split(X_holdout, y_holdout, test_size=0.5, random_state=0)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Get an instance to explain." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "# get an instance from test data\n", + "data_instance = X_test.iloc[10].to_numpy()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 2. Loading ONNX model\n", + "DIANNA supports ONNX models. Here we demonstrate the use of KernelSHAP explainer for tabular data with a pre-trained ONNX model, which is a MLP regressor for the weather dataset.
\n", + "\n", + "The model is trained following this notebook:
\n", + "https://github.com/dianna-ai/dianna-exploration/blob/main/example_data/model_generation/sunshine_prediction/generate_model.ipynb" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([[3.0719438]], dtype=float32)" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# load onnx model and check the prediction with it\n", + "model_path = './models/sunshine_hours_regression_model.onnx'\n", + "loaded_model = SimpleModelRunner(model_path)\n", + "predictions = loaded_model(data_instance.reshape(1,-1).astype(np.float32))\n", + "predictions" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "A runner function is created to prepare data for the ONNX inference session." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "import onnxruntime as ort\n", + "\n", + "def run_model(data):\n", + " # get ONNX predictions\n", + " sess = ort.InferenceSession(model_path)\n", + " input_name = sess.get_inputs()[0].name\n", + " output_name = sess.get_outputs()[0].name\n", + "\n", + " onnx_input = {input_name: data.astype(np.float32)}\n", + " pred_onnx = sess.run([output_name], onnx_input)[0]\n", + " \n", + " return pred_onnx" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 3. Applying KernelSHAP with DIANNA\n", + "The simplest way to run DIANNA on image data is with `dianna.explain_tabular`.\n", + "\n", + "DIANNA requires input in numpy format, so the input data is converted into a numpy array.\n", + "\n", + "Note that the training data is also required since KernelSHAP needs it to generate proper perturbation." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "The default value of `n_init` will change from 10 to 'auto' in 1.4. Set the value of `n_init` explicitly to suppress the warning\n" + ] + } + ], + "source": [ + "explanation = dianna.explain_tabular(run_model, input_tabular=data_instance, method='kernelshap',\n", + " mode ='regression', training_data = X_train, \n", + " training_data_kmeans = 5, feature_names=X_test.columns)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "#### 4. Visualization\n", + "The output can be visualized with the DIANNA built-in visualization function. It shows the top 10 importance of each feature contributing to the prediction." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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zw87d+6EhYUFACA9PR2vv/66TgMEgIiICKSnp+PcuXPYvn07wsLC8Oabb6J9+/bIz88vdz/37t1DmzZtoNVqsX79epw+fRpr1qxBQECA8nSUkydPIiIiAo0aNcK+fftw/PhxLFq0CEZGRsVW6U+fPo309HRVqVGjRrnjGTJkCNLT05GamopvvvkGfn5+6NWrF1577TVVu0WLFqFTp05o2rQpDh8+jF9//RW9evXC0KFDMWbMmGL97tq1C+np6di3bx9q1qyJ9u3b48qVK6o2/v7+xWJv0aJFuWMnIiIiojLIv1xkZKR06tSpWP3u3bsFgCxdulRERADIhg0byrw+MTFRAMi5c+dKHW/hwoXi7u5eZkx79uwRAHLjxo1S20RHR0tQUFCp50NDQ+XNN98sVr98+XIBIDt37hQRkQsXLoihoaG8/fbbxdp+/PHHAkAOHTokIiJpaWkCQBITE5U2v/76qwCQTZs2lTu2suYEQFX27NmjxNm9e3extrYWGxsb6dixo6SlpSnXFr0PM2fOlBo1aoi1tbVMnTpV7t27J2PGjBEbGxtxdnaW5cuXK9cUzSc+Pl5CQkLE2NhY/P39JSEhoVzxFr1PO3bskHr16omJiYmEhYXJlStXZNu2beLj4yOWlpbSu3dvuXXrlnLd9u3bpWnTpmJtbS22trbSrl07OXv2rHI+Li5OzM3N5ffff1fqhg0bJt7e3qp+yqLVagWAaLXacrUnEhEBWFgqV4hINyry+V3p52R/8cUXaNasGWrWrInz588DAD788ENs2rSp0gl/Rbz44osICgoqdXtFSezt7aGnp4d169aVunfc0dFRWQWuCpGRkbCxsVHmtW7dOty7d6/EFeuoqChYWFggPj6+xL5u376NlStXAgCMjIweOrYxY8agR48eyr8spKeno0mTJrh37x7Cw8NhaWmJ/fv348CBA7CwsEBERISyxQYAfvjhB1y+fBn79u3DBx98gOjoaLRv3x42NjY4fPgwhg4diqioKFy6dEk17tixYzF69GgkJiYiJCQEHTp0wLVr18od95QpU7B48WL89NNPuHjxInr06IEPP/wQX331FbZu3Yrvv/8eixYtUtrfunULb7/9No4ePYrdu3dDT08PXbp0UbYn9e/fHy+//DL69u2L/Px8bN26FcuWLcOqVatgZmZWYgx37txBVlaWqhAREdFT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YeDAgQ98/SIjI/Hee+9h8eLFGDduXHle8lINGTIECQkJaNSoEXJycrBnzx60bNkS+/btw/jx4/Gf//wH2dnZcHZ2RqtWrWBlZfVQ4wHAnDlzMGfOHCQlJcHDwwObN29G9erVH7rf0kyfPh329vaYPXs2/vjjD1SrVg0NGjTAu+++C+Dvp7okJiaiZ8+e0Gg06N27N15//XVs3779kcVERERETx+NiEhVB0HPnnPnzqF27dpITEws89szn1ZZWVmwtraGVqvVyR8rpHsPcX8y0b8OP+mJdKMin9//yj3ZRERERERPMibZz5D7H1v3z7J///6qDk9l6NChpcY6dOjQqg6PiIiIqEzcLvIMOXv2bKnnnJ2dYWpq+hijKVtmZmap34poZWWFGjVqPOaIdIvbRf79uF2Enib8pCfSjYp8flf5jY/0+Ojq2dmPQ40aNZ74RJqIiIieXdwuQkRERESkY0yyiYiIiIh0jNtFiIhKwD2sRET0MLiSTURERESkY0yyiYiIiIh0jEk2EREREZGOMckmIiIiItIxJtlERERERDrGJJuIiIiISMf4CD8iIqKnnUZT1REQPX5V/CxWrmQTEREREekYk2wiIiIiIh1jkk1EREREpGNMsomIiIiIdIxJNhERERGRjjHJJiIiIiLSMSbZREREREQ6xiSbiIiIiEjHmGQTEREREenYE5lkX716FcOGDUOtWrVgbGwMR0dHhIeH48CBA0qbn376CS+//DJsbGxgYmKCgIAAfPDBBygoKFD1pdFoYGJigvPnz6vqO3fujAEDBijHAwYMgEajwZw5c1TtNm7cCM1936SVkJAAjUajFFNTU/j7++O///2v6roBAwagc+fOpc7R3d0dH374oaouMTER3bt3h4ODA0xMTODp6YkhQ4bg999/BwCcO3cOGo0GSUlJyjXZ2dkICwuDn58fLl26VOp498d+8+bNMtsRERERUdmeyCS7a9euSExMRFxcHH7//Xds3rwZLVu2xLVr1wAAGzZsQGhoKFxcXLBnzx6cOnUKb775JmbMmIFevXpB/vE1mxqNBpMnT37guCYmJpg7dy5u3LjxwLanT59Geno6Tp48iaioKAwbNgy7d++u3IQBbNmyBS+88ALu3LmDVatWISUlBV9++SWsra0xadKkEq+5evUqwsLCcOvWLezfvx8uLi6VHp+IiIiIKkCe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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from dianna.visualization import plot_tabular\n", + "\n", + "_ = plot_tabular(explanation, X_test.columns, num_features=10)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "dianna", + "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.10.13" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/tutorials/lime_tabular_penguin.ipynb b/tutorials/lime_tabular_penguin.ipynb index f95730d6..09d4af1d 100644 --- a/tutorials/lime_tabular_penguin.ipynb +++ b/tutorials/lime_tabular_penguin.ipynb @@ -334,7 +334,6 @@ "\n", " onnx_input = {input_name: data.astype(np.float32)}\n", " pred_onnx = sess.run([output_name], onnx_input)[0]\n", - " pred_onnx\n", " \n", " return pred_onnx" ] diff --git a/tutorials/lime_tabular_weather.ipynb b/tutorials/lime_tabular_weather.ipynb index b7da342f..57f2a320 100644 --- a/tutorials/lime_tabular_weather.ipynb +++ b/tutorials/lime_tabular_weather.ipynb @@ -185,7 +185,6 @@ "\n", " onnx_input = {input_name: data.astype(np.float32)}\n", " pred_onnx = sess.run([output_name], onnx_input)[0]\n", - " pred_onnx\n", " \n", " return pred_onnx" ]