Lecture Notes · AI Master's

Explainable AI

From Shapley values to saliency maps to mechanistic interpretability — a working primer focused on deep learning, computer vision, and LLMs.

Why XAI, and what counts as an explanation

Motivation, taxonomy, and the central tension.

A modern deep neural network can have tens of billions of parameters and produce outputs that humans accept, reject, or deploy in safety-critical settings — medical triage, credit scoring, autonomous driving, content moderation. Explainable AI (XAI) is the body of techniques that produces auxiliary information allowing a human to reason about why a model produced a given output, or how it behaves overall.

The motivation is not only philosophical. Concrete drivers include:

The interpretability — accuracy tradeoff (and why it's overstated)

Classical wisdom: simpler models (linear regression, shallow decision trees) are interpretable but inaccurate; deep models are accurate but opaque. Recent work, especially Cynthia Rudin's "Stop Explaining Black Box Models" (2019), argues this tradeoff is exaggerated in many tabular domains — interpretable models can often match black-box accuracy when designed carefully. The tradeoff is real for high-dimensional perceptual tasks (vision, language), which is why XAI for deep models is an active field rather than a closed one.

A taxonomy of explanation methods

Four orthogonal distinctions structure almost every paper in the field:

AxisOptionsExample
Stage Intrinsic / Post-hoc A logistic regression is intrinsically interpretable; SHAP on a ResNet is post-hoc.
Specificity Model-specific / Model-agnostic TreeSHAP only works on trees. LIME works on any classifier.
Scope Local / Global "Why this prediction?" (local) vs. "How does the model behave overall?" (global).
Output type Feature attribution / Counterfactual / Example-based / Rule extraction SHAP gives attributions; "if income had been €5k higher, the loan would have been approved" is a counterfactual.

What does it mean for an explanation to be good?

Two desiderata that often conflict:

A faithful explanation may be unintelligible (e.g., a 4096-dimensional gradient vector). A plausible explanation may be a confabulation. The honest framing of any XAI method is: which of these two properties does it actually deliver, and how do we evaluate that?

Sanity check

Adebayo et al. (2018) showed that several popular saliency methods produce essentially the same heatmap even when the model's weights are randomized. Methods that pass this "model parameter randomization test" are faithful; those that don't are visualizing the input, not the model.

Pointers

  1. Rudin, C. (2019). Stop explaining black box machine learning models for high stakes decisions. Nature Machine Intelligence.
  2. Doshi-Velez & Kim (2017). Towards a rigorous science of interpretable machine learning.
  3. Adebayo et al. (2018). Sanity checks for saliency maps. NeurIPS.

Shapley Values & SHAP

Cooperative game theory as a unified framework for feature attribution.

The origin: a fair division problem

Lloyd Shapley (1953) asked: given a coalition of players that together earn some payout, how should the payout be split fairly? He defined four axioms (efficiency, symmetry, dummy, linearity) and proved there exists a unique attribution rule satisfying all four. That rule is the Shapley value.

The translation to machine learning, due to Štrumbelj & Kononenko (2014) and made canonical by Lundberg & Lee's SHAP (NeurIPS 2017), is:

Cooperative gameML interpretation
Set of players $N$Set of features
Coalition $S \subseteq N$Subset of features present
Value function $v(S)$Model prediction given only features in $S$
Shapley value $\phi_i$Attribution of feature $i$ to the prediction

The formula

The Shapley value of feature $i$ is the weighted average of its marginal contributions across all possible coalitions:

$$\phi_i(v) = \sum_{S \subseteq N \setminus \{i\}} \frac{|S|!\,(n - |S| - 1)!}{n!} \bigl[\, v(S \cup \{i\}) - v(S) \,\bigr]$$

Read this as: for every subset $S$ that does not contain feature $i$, measure how much adding $i$ changes the value ($v(S \cup \{i\}) - v(S)$), and average these marginal contributions, weighted so each "coalition size" contributes equally.

The four axioms (and why uniqueness matters)

  1. Efficiency. $\sum_i \phi_i = v(N) - v(\emptyset)$. The attributions exactly account for the prediction relative to the empty baseline.
  2. Symmetry. If two features always contribute equally ($v(S \cup \{i\}) = v(S \cup \{j\})$ for all $S$), then $\phi_i = \phi_j$.
  3. Dummy. A feature that never changes the prediction gets attribution zero.
  4. Linearity. Attributions are additive across composable games: $\phi_i(v_1 + v_2) = \phi_i(v_1) + \phi_i(v_2)$.

These axioms uniquely determine the formula above. Any feature-attribution method satisfying all four must compute Shapley values. This is the central appeal of SHAP: it isn't one of many possible attribution methods; among methods with these properties, it is the only one.

Why we can't just compute it

The sum has $2^{n-1}$ coalitions. For a model with 50 features that is $\approx 5.6 \times 10^{14}$ evaluations per prediction. Worse, evaluating $v(S)$ requires marginalizing out the missing features, which typically means averaging the model's prediction over a sample of values for the absent features — adding another factor.

All practical SHAP variants are approximations or model-specific exact algorithms:

VariantApplies toHow
KernelSHAPAny modelWeighted local linear regression on sampled coalitions; recovers Shapley values in the limit.
TreeSHAPTree ensembles (XGBoost, LightGBM, sklearn)Exact, in polynomial time. Lundberg et al. (2020).
DeepSHAPDeep neural networksCombines DeepLIFT propagation rules with Shapley reference values.
GradientSHAPDifferentiable modelsStochastic estimator combining Integrated Gradients with Shapley sampling.
PartitionSHAPHigh-dim structured inputs (text, images)Hierarchical Shapley: cluster features, attribute clusters, recurse.

The baseline problem

"Marginalize out missing features" is harder than it sounds. SHAP needs a notion of $v(S)$ when only the features in $S$ are present — but neural networks don't accept partial inputs. Two common choices:

Janzing et al. (2020) argue that the choice of baseline encodes implicit causal assumptions, and different baselines yield meaningfully different attributions. This is not a solved problem.

Conceptual warning

SHAP values are attributions to the model's output, not causal effects on the underlying phenomenon. If the model is wrong, SHAP will faithfully explain its wrongness. SHAP cannot tell you what the true causal drivers are — only what the model is using.

Pointers

  1. Lundberg & Lee (2017). A unified approach to interpreting model predictions. NeurIPS.
  2. Lundberg et al. (2020). From local explanations to global understanding with explainable AI for trees. Nature Machine Intelligence.
  3. Janzing, Minorics, Blöbaum (2020). Feature relevance quantification in explainable AI. AISTATS.
  4. Štrumbelj & Kononenko (2014). Explaining prediction models with feature contributions. KAIS.

XAI for Computer Vision

Saliency maps, class activation, integrated gradients, occlusion.

For a vision model, the natural form of a local explanation is a heatmap over the input image highlighting which pixels (or regions) drove the prediction. The methods below differ in how they compute that heatmap, and crucially, in whether the heatmap actually reflects the model's reasoning.

Vanilla saliency (Simonyan et al., 2013)

The simplest idea: compute the gradient of the predicted class score with respect to the input pixels. Pixels whose small perturbations most change the output are the "salient" ones.

$$M_{ij} = \left| \frac{\partial y_c}{\partial x_{ij}} \right|$$

Cheap (one backward pass). Often noisy. Tends to highlight edges in the image rather than semantically meaningful regions.

Grad-CAM (Selvaraju et al., 2017)

Currently the standard baseline for CNN interpretability. The insight: instead of using gradients with respect to pixels, use gradients with respect to the last convolutional layer's feature maps. Those maps still carry spatial structure (a 14×14 grid for ResNet-50 with 224×224 input) and are semantically richer than raw pixels.

Let $A^k \in \mathbb{R}^{H \times W}$ be the $k$-th feature map of the target conv layer, and $y^c$ be the score for class $c$. Compute channel weights by global-average-pooling the gradients:

$$\alpha_k^c = \frac{1}{Z} \sum_{i,j} \frac{\partial y^c}{\partial A^k_{ij}}$$

Then form a weighted sum of feature maps, gated by ReLU to keep only positively-contributing regions:

$$L^c_{\text{Grad-CAM}} = \text{ReLU}\!\left( \sum_k \alpha_k^c \, A^k \right)$$

The result is a low-resolution heatmap that you upsample to image size. Class-discriminative: different classes produce different maps. Survives the sanity check in Adebayo et al. (2018).

Integrated Gradients (Sundararajan et al., 2017)

A theoretically principled feature-attribution method for any differentiable model. Given an input $x$ and a baseline $x'$ (typically a black image), integrate the gradient along the straight-line path from $x'$ to $x$:

$$\text{IG}_i(x) = (x_i - x'_i) \cdot \int_{\alpha = 0}^{1} \frac{\partial F(x' + \alpha(x - x'))}{\partial x_i} \, d\alpha$$

In practice the integral is approximated by a Riemann sum over 20–50 steps. IG satisfies completeness ($\sum_i \text{IG}_i = F(x) - F(x')$, the same property as Shapley efficiency) and implementation invariance (functionally equivalent models give the same attributions). The choice of baseline matters: zero image, blur, or random noise yield different attributions.

LIME for images (Ribeiro et al., 2016)

Partition the image into ~50 superpixels (e.g., via SLIC). Generate ~1000 perturbed versions by randomly masking subsets of superpixels with a neutral color. Get the model's predictions on all perturbations, then fit a sparse linear model that predicts these outputs from the binary mask. The coefficients of the linear model are the superpixel attributions.

LIME is model-agnostic and gives intuitive region-level explanations. It's also slow (1000 forward passes per explanation) and unstable: re-running LIME on the same image with a different perturbation seed can produce visibly different heatmaps.

Occlusion sensitivity (Zeiler & Fergus, 2014)

Slide an opaque gray patch over the image; for each position, record how much the predicted class probability drops. Drops in probability map directly to importance. Intuitive, no gradients needed, very slow (one forward pass per patch position), and conflates the model's reliance on a region with the OOD-ness of the occluded image.

The honest comparison

MethodFaithful?ResolutionCost
Vanilla saliencyMixed — fails some sanity checksPixel1 backward pass
Grad-CAMPasses sanity checksCoarse (feature-map grid)1 fwd + 1 bwd
Integrated GradientsTheoretically principledPixel20–50 fwd + bwd
LIMELocal approximation, unstableSuperpixel~1000 fwd
OcclusionOOD-confoundedPatch grid~hundreds fwd

For most CNN interpretability work today, the default is Grad-CAM for quick visual checks and Integrated Gradients when you need theoretical guarantees. SHAP (via the DeepExplainer or GradientExplainer) is also viable and ties the analysis to the Shapley framework introduced in Tab 2.

Pointers

  1. Selvaraju et al. (2017). Grad-CAM: Visual Explanations from Deep Networks via Gradient-based Localization. ICCV.
  2. Sundararajan, Taly, Yan (2017). Axiomatic attribution for deep networks. ICML.
  3. Simonyan, Vedaldi, Zisserman (2013). Deep Inside Convolutional Networks. ICLR workshop.
  4. Ribeiro, Singh, Guestrin (2016). "Why Should I Trust You?": Explaining the Predictions of Any Classifier. KDD.
  5. Zeiler & Fergus (2014). Visualizing and understanding convolutional networks. ECCV.

Code: Grad-CAM in PyTorch

A minimal-but-real implementation in ~50 lines.

The implementation below loads a pretrained ResNet-50, registers forward and backward hooks on its last convolutional block, runs Grad-CAM on an input image, and returns a normalized heatmap. No external XAI libraries — just PyTorch and torchvision.

import torch
import torch.nn.functional as F
from torchvision import models, transforms
from PIL import Image
import numpy as np

# 1. Load a pretrained model and set it to eval mode.
model = models.resnet50(weights=models.ResNet50_Weights.DEFAULT)
model.eval()

# 2. Pick the target layer. For ResNet-50, the last conv block is layer4.
target_layer = model.layer4[-1]

# 3. Register hooks to capture the layer's activations and gradients.
activations = {}
gradients   = {}

def fwd_hook(module, inp, out):
    activations['value'] = out

def bwd_hook(module, grad_in, grad_out):
    gradients['value'] = grad_out[0]

target_layer.register_forward_hook(fwd_hook)
target_layer.register_full_backward_hook(bwd_hook)

# 4. Preprocess an input image (ImageNet normalization).
preprocess = transforms.Compose([
    transforms.Resize(256),
    transforms.CenterCrop(224),
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.485, 0.456, 0.406],
                         std=[0.229, 0.224, 0.225]),
])

img = Image.open('cat.jpg').convert('RGB')
x   = preprocess(img).unsqueeze(0)                  # shape [1, 3, 224, 224]

# 5. Forward pass; pick the predicted class.
logits     = model(x)
pred_class = logits.argmax(dim=1).item()

# 6. Backward pass on the predicted class score.
model.zero_grad()
logits[0, pred_class].backward()

# 7. Grad-CAM: weight feature maps by channel-averaged gradients, ReLU, upsample.
A      = activations['value']                       # [1, 2048, 7, 7]
grad_A = gradients['value']                         # [1, 2048, 7, 7]

alpha  = grad_A.mean(dim=(2, 3), keepdim=True)      # [1, 2048, 1, 1]
cam    = F.relu((alpha * A).sum(dim=1, keepdim=True))   # [1, 1, 7, 7]

cam    = F.interpolate(cam, size=(224, 224),
                       mode='bilinear', align_corners=False)
cam    = cam.squeeze().detach().numpy()
cam    = (cam - cam.min()) / (cam.max() - cam.min() + 1e-8)

# `cam` is a 224x224 array in [0, 1]. Overlay on the image with matplotlib:
# plt.imshow(img); plt.imshow(cam, alpha=0.5, cmap='jet')

What's happening in each step

Production-ready alternative

For real projects, use a maintained library rather than rolling your own:

from pytorch_grad_cam import GradCAM
from pytorch_grad_cam.utils.model_targets import ClassifierOutputTarget

cam = GradCAM(model=model, target_layers=[model.layer4[-1]])
heatmap = cam(input_tensor=x,
              targets=[ClassifierOutputTarget(pred_class)])[0]

The pytorch-grad-cam package also implements Grad-CAM++, ScoreCAM, AblationCAM, EigenCAM, and others — useful for comparing methods on your own model.

Using SHAP on a CNN

import shap

# Pick a small background set (50–100 images from the training set)
background = train_images[:100]

# DeepExplainer uses DeepLIFT-style propagation with Shapley baselines
explainer   = shap.DeepExplainer(model, background)
shap_values = explainer.shap_values(test_images[:5])

# Visualize per-class pixel attributions
shap.image_plot(shap_values, test_images[:5])
Practical note

DeepExplainer is fast but only works with TF/Keras and PyTorch with specific layer types. For arbitrary architectures, shap.GradientExplainer is more flexible (uses GradientSHAP). For exhaustive coverage, shap.KernelExplainer works on any model but is extremely slow on images.

Can SHAP Be Used With LLMs?

Yes — with significant caveats, and not as the right tool for every question.

The short answer: SHAP is well-defined for LLMs, the shap library has dedicated explainers for text models, and it produces useful attributions for classification-style tasks. But the obstacles that make SHAP awkward on images become severe on language, and for the deepest questions about LLM behavior the field is moving toward different techniques entirely.

Why LLMs are hard for SHAP

  1. Input dimensionality. A 2000-token prompt with a 100k vocabulary is a vastly higher-dimensional input than even a 224×224×3 image. The coalition sum has $2^{2000}$ terms.
  2. Cost per coalition. Each coalition evaluation is a full LLM forward pass, which already costs hundreds of milliseconds. Sampling enough coalitions for stable attributions costs seconds to minutes per explanation.
  3. The baseline problem, intensified. What is a "missing" token? Replace with [MASK], with a random token from the vocabulary, or simply delete it and shorten the sequence? Each choice yields different SHAP values and encodes different counterfactual semantics.
  4. High-dimensional output. For generation, the "output" isn't a single score but a distribution over thousands of vocabulary items at every position. Which scalar do you attribute? The probability of the actual completion? The logit of a specific token?
  5. Compositionality and context dependence. A token's contribution depends heavily on neighboring tokens. The Shapley axiom of linearity is violated in spirit — meaning isn't additive over tokens.

Where SHAP works well on text

Short-text classification with a frozen model. Sentiment analysis, NLI, hate-speech detection, intent classification. The shap library's PartitionExplainer (the default for text) uses hierarchical Shapley: tokens are grouped, attributions are computed at the group level, and the tree is recursively refined where attributions are large. This brings $2^n$ down to something tractable.

import shap
import transformers

# A short-text classification pipeline
pipe = transformers.pipeline(
    "sentiment-analysis",
    model="distilbert-base-uncased-finetuned-sst-2-english"
)

explainer   = shap.Explainer(pipe)
shap_values = explainer(["The film was a delight, but ran far too long."])

# Renders an HTML visualization with each token colored by attribution
shap.plots.text(shap_values)

This works well, runs in a few seconds, and produces interpretable per-token attributions. It is the right tool when the question is "which words in this short input drove this classification?"

Where SHAP struggles or breaks

What practitioners reach for instead

Gradient-based attribution on embeddings

Integrated Gradients still works on LLMs if applied to token embeddings rather than tokens themselves. The captum library (PyTorch) and transformers-interpret wrap this conveniently. Faster than SHAP, often comparable quality for short inputs.

Attention attribution

Transformers expose attention weights for free. Visualizing them is tempting and common — but Jain & Wallace (2019) and Wiegreffe & Pinter (2019) demonstrated that attention weights are not reliable explanations: alternative attention patterns can produce the same output. Treat attention visualizations as suggestive heuristics, not faithful explanations.

Mechanistic interpretability

The emerging research frontier for LLMs. Rather than asking "which input tokens mattered," ask "which internal computations does the model perform, and what do they encode?" Active sub-areas:

Influence functions

"Which training examples most affected this prediction?" Mathematically elegant but computationally brutal; recent approximations (TRAK, Park et al. 2023) make it feasible on large models.

Self-explanation and chain-of-thought

Ask the model to explain itself. Plausible and cheap. Often unfaithful: stated reasons may not match actual computation. Recent work (Turpin et al., 2023) shows LLMs can produce convincing chain-of-thought explanations that have no relation to their actual decision process when an artificial bias is introduced.

Field reality

There is no single XAI method that gives faithful, scalable, semantically rich explanations of arbitrary LLM behavior. For classification, use SHAP or IG. For mechanistic questions, use causal tracing and SAEs. For behavioral audits, use evaluations and red-teaming. The right method depends on the question.

Pointers

  1. Jain & Wallace (2019). Attention is not Explanation. NAACL.
  2. Wiegreffe & Pinter (2019). Attention is not not Explanation. EMNLP.
  3. Wang et al. (2022). Interpretability in the Wild: a Circuit for Indirect Object Identification in GPT-2 small.
  4. Templeton et al. (2024). Scaling Monosemanticity: Extracting Interpretable Features from Claude 3 Sonnet. Anthropic.
  5. Turpin et al. (2023). Language Models Don't Always Say What They Think. NeurIPS.
  6. Park et al. (2023). TRAK: Attributing Model Behavior at Scale. ICML.