# SIGNed explanations: Unveiling relevant features by reducing bias
This repository and python package has been published alongside the following journal article:
https://doi.org/10.1016/j.inffus.2023.101883
If you use the code from this repository in your work, please cite:
```bibtex
@article{Gumpfer2023SIGN,
title = {SIGNed explanations: Unveiling relevant features by reducing bias},
author = {Nils Gumpfer and Joshua Prim and Till Keller and Bernhard Seeger and Michael Guckert and Jennifer Hannig},
journal = {Information Fusion},
pages = {101883},
year = {2023},
issn = {1566-2535},
doi = {https://doi.org/10.1016/j.inffus.2023.101883},
url = {https://www.sciencedirect.com/science/article/pii/S1566253523001999}
}
```
<img src="https://ars.els-cdn.com/content/image/1-s2.0-S1566253523001999-ga1_lrg.jpg" title="Graphical Abstract" width="900px"/>
## Setup
To install the package in your environment, run:
```shell
pip3 install signxai
```
## Usage
### VGG16
The below example illustrates the usage of the ```signxai``` package in combination with a VGG16 model trained on imagenet:
```python
import numpy as np
import matplotlib.pyplot as plt
from tensorflow.keras.applications.vgg16 import VGG16
from signxai.methods.wrappers import calculate_relevancemap
from signxai.utils.utils import (load_image, aggregate_and_normalize_relevancemap_rgb, download_image,
calculate_explanation_innvestigate)
# Load model
model = VGG16(weights='imagenet')
# Remove last layer's softmax activation (we need the raw values!)
model.layers[-1].activation = None
# Load example image
path = 'example.jpg'
download_image(path)
img, x = load_image(path)
# Calculate relevancemaps
R1 = calculate_relevancemap('lrpz_epsilon_0_1_std_x', np.array(x), model)
R2 = calculate_relevancemap('lrpsign_epsilon_0_1_std_x', np.array(x), model)
# Equivalent relevance maps as for R1 and R2, but with direct access to innvestigate and parameters
R3 = calculate_explanation_innvestigate(model, x, method='lrp.stdxepsilon', stdfactor=0.1, input_layer_rule='Z')
R4 = calculate_explanation_innvestigate(model, x, method='lrp.stdxepsilon', stdfactor=0.1, input_layer_rule='SIGN')
# Visualize heatmaps
fig, axs = plt.subplots(ncols=3, nrows=2, figsize=(18, 12))
axs[0][0].imshow(img)
axs[1][0].imshow(img)
axs[0][1].matshow(aggregate_and_normalize_relevancemap_rgb(R1), cmap='seismic', clim=(-1, 1))
axs[0][2].matshow(aggregate_and_normalize_relevancemap_rgb(R2), cmap='seismic', clim=(-1, 1))
axs[1][1].matshow(aggregate_and_normalize_relevancemap_rgb(R3), cmap='seismic', clim=(-1, 1))
axs[1][2].matshow(aggregate_and_normalize_relevancemap_rgb(R4), cmap='seismic', clim=(-1, 1))
plt.show()
```
(Image credit for example used in this code: Greg Gjerdingen from Willmar, USA)
### MNIST
The below example illustrates the usage of the ```signxai``` package in combination with a dense model trained on MNIST:
```python
import numpy as np
from matplotlib import pyplot as plt
from tensorflow.python.keras.datasets import mnist
from tensorflow.python.keras.models import load_model
from signxai.methods.wrappers import calculate_relevancemap
from signxai.utils.utils import normalize_heatmap, download_model
# Load train and test data
(x_train, y_train), (x_test, y_test) = mnist.load_data()
# Scale images to the [-1, 0] range
x_train = x_train.astype("float32") / -255.0
x_test = x_test.astype("float32") / -255.0
x_train = -(np.ones_like(x_train) + x_train)
x_test = -(np.ones_like(x_test) + x_test)
# Load model
path = 'model.h5'
download_model(path)
model = load_model(path)
# Remove softmax
model.layers[-1].activation = None
# Calculate relevancemaps
x = x_test[231]
R1 = calculate_relevancemap('gradient_x_input', np.array(x), model, neuron_selection=3)
R2 = calculate_relevancemap('gradient_x_sign_mu_neg_0_5', np.array(x), model, neuron_selection=3)
R3 = calculate_relevancemap('gradient_x_input', np.array(x), model, neuron_selection=8)
R4 = calculate_relevancemap('gradient_x_sign_mu_neg_0_5', np.array(x), model, neuron_selection=8)
# Visualize heatmaps
fig, axs = plt.subplots(ncols=3, nrows=2, figsize=(18, 12))
axs[0][0].imshow(x, cmap='seismic', clim=(-1, 1))
axs[1][0].imshow(x, cmap='seismic', clim=(-1, 1))
axs[0][1].matshow(normalize_heatmap(R1), cmap='seismic', clim=(-1, 1))
axs[0][2].matshow(normalize_heatmap(R2), cmap='seismic', clim=(-1, 1))
axs[1][1].matshow(normalize_heatmap(R3), cmap='seismic', clim=(-1, 1))
axs[1][2].matshow(normalize_heatmap(R4), cmap='seismic', clim=(-1, 1))
plt.show()
```
## Experiments
To reproduce the experiments from our paper, please find a detailed description on https://github.com/nilsgumpfer/SIGN.
Raw data
{
"_id": null,
"home_page": "https://github.com/nilsgumpfer/SIGN-XAI",
"name": "signxai",
"maintainer": "Nils Gumpfer",
"docs_url": null,
"requires_python": null,
"maintainer_email": "nils.gumpfer@kite.thm.de",
"keywords": "XAI, SIGN, LRP",
"author": "Nils Gumpfer",
"author_email": "nils.gumpfer@kite.thm.de",
"download_url": "https://files.pythonhosted.org/packages/fa/fd/5ec60baa32314f2e5e553e101bb2d017ac2210242c1575e9e3404a820bf2/signxai-1.1.7.tar.gz",
"platform": null,
"description": "# SIGNed explanations: Unveiling relevant features by reducing bias\n\nThis repository and python package has been published alongside the following journal article:\nhttps://doi.org/10.1016/j.inffus.2023.101883\n\nIf you use the code from this repository in your work, please cite:\n```bibtex\n @article{Gumpfer2023SIGN,\n title = {SIGNed explanations: Unveiling relevant features by reducing bias},\n author = {Nils Gumpfer and Joshua Prim and Till Keller and Bernhard Seeger and Michael Guckert and Jennifer Hannig},\n journal = {Information Fusion},\n pages = {101883},\n year = {2023},\n issn = {1566-2535},\n doi = {https://doi.org/10.1016/j.inffus.2023.101883},\n url = {https://www.sciencedirect.com/science/article/pii/S1566253523001999}\n}\n```\n\n<img src=\"https://ars.els-cdn.com/content/image/1-s2.0-S1566253523001999-ga1_lrg.jpg\" title=\"Graphical Abstract\" width=\"900px\"/>\n\n## Setup\n\nTo install the package in your environment, run:\n\n```shell\n pip3 install signxai\n```\n\n\n## Usage\n\n### VGG16\n\nThe below example illustrates the usage of the ```signxai``` package in combination with a VGG16 model trained on imagenet:\n\n```python\nimport numpy as np\nimport matplotlib.pyplot as plt\nfrom tensorflow.keras.applications.vgg16 import VGG16\nfrom signxai.methods.wrappers import calculate_relevancemap\nfrom signxai.utils.utils import (load_image, aggregate_and_normalize_relevancemap_rgb, download_image, \n calculate_explanation_innvestigate)\n\n# Load model\nmodel = VGG16(weights='imagenet')\n\n# Remove last layer's softmax activation (we need the raw values!)\nmodel.layers[-1].activation = None\n\n# Load example image\npath = 'example.jpg'\ndownload_image(path)\nimg, x = load_image(path)\n\n# Calculate relevancemaps\nR1 = calculate_relevancemap('lrpz_epsilon_0_1_std_x', np.array(x), model)\nR2 = calculate_relevancemap('lrpsign_epsilon_0_1_std_x', np.array(x), model)\n\n# Equivalent relevance maps as for R1 and R2, but with direct access to innvestigate and parameters\nR3 = calculate_explanation_innvestigate(model, x, method='lrp.stdxepsilon', stdfactor=0.1, input_layer_rule='Z')\nR4 = calculate_explanation_innvestigate(model, x, method='lrp.stdxepsilon', stdfactor=0.1, input_layer_rule='SIGN')\n\n# Visualize heatmaps\nfig, axs = plt.subplots(ncols=3, nrows=2, figsize=(18, 12))\naxs[0][0].imshow(img)\naxs[1][0].imshow(img)\naxs[0][1].matshow(aggregate_and_normalize_relevancemap_rgb(R1), cmap='seismic', clim=(-1, 1))\naxs[0][2].matshow(aggregate_and_normalize_relevancemap_rgb(R2), cmap='seismic', clim=(-1, 1))\naxs[1][1].matshow(aggregate_and_normalize_relevancemap_rgb(R3), cmap='seismic', clim=(-1, 1))\naxs[1][2].matshow(aggregate_and_normalize_relevancemap_rgb(R4), cmap='seismic', clim=(-1, 1))\n\nplt.show()\n```\n(Image credit for example used in this code: Greg Gjerdingen from Willmar, USA)\n\n### MNIST\n\nThe below example illustrates the usage of the ```signxai``` package in combination with a dense model trained on MNIST:\n\n```python\nimport numpy as np\nfrom matplotlib import pyplot as plt\nfrom tensorflow.python.keras.datasets import mnist\nfrom tensorflow.python.keras.models import load_model\n\nfrom signxai.methods.wrappers import calculate_relevancemap\nfrom signxai.utils.utils import normalize_heatmap, download_model\n\n# Load train and test data\n(x_train, y_train), (x_test, y_test) = mnist.load_data()\n\n# Scale images to the [-1, 0] range\nx_train = x_train.astype(\"float32\") / -255.0\nx_test = x_test.astype(\"float32\") / -255.0\nx_train = -(np.ones_like(x_train) + x_train)\nx_test = -(np.ones_like(x_test) + x_test)\n\n# Load model\npath = 'model.h5'\ndownload_model(path)\nmodel = load_model(path)\n\n# Remove softmax\nmodel.layers[-1].activation = None\n\n# Calculate relevancemaps\nx = x_test[231]\nR1 = calculate_relevancemap('gradient_x_input', np.array(x), model, neuron_selection=3)\nR2 = calculate_relevancemap('gradient_x_sign_mu_neg_0_5', np.array(x), model, neuron_selection=3)\nR3 = calculate_relevancemap('gradient_x_input', np.array(x), model, neuron_selection=8)\nR4 = calculate_relevancemap('gradient_x_sign_mu_neg_0_5', np.array(x), model, neuron_selection=8)\n\n# Visualize heatmaps\nfig, axs = plt.subplots(ncols=3, nrows=2, figsize=(18, 12))\naxs[0][0].imshow(x, cmap='seismic', clim=(-1, 1))\naxs[1][0].imshow(x, cmap='seismic', clim=(-1, 1))\naxs[0][1].matshow(normalize_heatmap(R1), cmap='seismic', clim=(-1, 1))\naxs[0][2].matshow(normalize_heatmap(R2), cmap='seismic', clim=(-1, 1))\naxs[1][1].matshow(normalize_heatmap(R3), cmap='seismic', clim=(-1, 1))\naxs[1][2].matshow(normalize_heatmap(R4), cmap='seismic', clim=(-1, 1))\n\nplt.show()\n```\n\n## Experiments\n\nTo reproduce the experiments from our paper, please find a detailed description on https://github.com/nilsgumpfer/SIGN.\n",
"bugtrack_url": null,
"license": "BSD 2-Clause License",
"summary": "SIGNed explanations: Unveiling relevant features by reducing bias",
"version": "1.1.7",
"project_urls": {
"Homepage": "https://github.com/nilsgumpfer/SIGN-XAI"
},
"split_keywords": [
"xai",
" sign",
" lrp"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "6456b4c903d6e73468ce7322fa2f32511decbae192048e2634345d025f09d667",
"md5": "637de5c69ed6c2049b9f89adb4b570b3",
"sha256": "1004aa8f86497c9c15e71abb1ff6a9978c2a10b964b1429a1156c9659a4691ec"
},
"downloads": -1,
"filename": "signxai-1.1.7-py3-none-any.whl",
"has_sig": false,
"md5_digest": "637de5c69ed6c2049b9f89adb4b570b3",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": null,
"size": 110103,
"upload_time": "2024-04-11T12:39:29",
"upload_time_iso_8601": "2024-04-11T12:39:29.148832Z",
"url": "https://files.pythonhosted.org/packages/64/56/b4c903d6e73468ce7322fa2f32511decbae192048e2634345d025f09d667/signxai-1.1.7-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "fafd5ec60baa32314f2e5e553e101bb2d017ac2210242c1575e9e3404a820bf2",
"md5": "2dbe59c8dd9fe483b5772e89ba1e9195",
"sha256": "2a3b1d2aa0176c0df013b76550e7a9757caa050cb9f4d4d866312cdd38fdbc9f"
},
"downloads": -1,
"filename": "signxai-1.1.7.tar.gz",
"has_sig": false,
"md5_digest": "2dbe59c8dd9fe483b5772e89ba1e9195",
"packagetype": "sdist",
"python_version": "source",
"requires_python": null,
"size": 85892,
"upload_time": "2024-04-11T12:39:31",
"upload_time_iso_8601": "2024-04-11T12:39:31.205720Z",
"url": "https://files.pythonhosted.org/packages/fa/fd/5ec60baa32314f2e5e553e101bb2d017ac2210242c1575e9e3404a820bf2/signxai-1.1.7.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-04-11 12:39:31",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "nilsgumpfer",
"github_project": "SIGN-XAI",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"requirements": [
{
"name": "matplotlib",
"specs": [
[
"~=",
"3.7.2"
]
]
},
{
"name": "tensorflow",
"specs": [
[
"~=",
"2.8.4"
]
]
},
{
"name": "setuptools",
"specs": [
[
"~=",
"68.2.2"
]
]
},
{
"name": "version-parser",
"specs": [
[
"~=",
"1.0.1"
]
]
}
],
"lcname": "signxai"
}