These examples show how to use torchxai explainers on a minimal image classification model. Each section covers one input pattern — the minimal set of arguments that pattern of explainer requires. Each pattern uses the shared compare() helper to run single-target sequentially, then multi-target in one call, verify they match, and report timing.

Setup

import time

import torch
import torch.nn as nn

from torchxai.data_types import SingleTargetAcrossBatch


class TinyCNN(nn.Module):
    def __init__(self, num_classes=10):
        super().__init__()
        self.features = nn.Sequential(
            nn.Conv2d(3, 16, 3, padding=1),
            nn.ReLU(),
            nn.MaxPool2d(2),
            nn.Conv2d(16, 32, 3, padding=1),
            nn.ReLU(),
            nn.AdaptiveAvgPool2d((4, 4)),
        )
        self.classifier = nn.Linear(32 * 4 * 4, num_classes)

    def forward(self, x):
        return self.classifier(self.features(x).flatten(1))


torch.manual_seed(0)
model = TinyCNN().eval()
inputs = torch.randn(1, 3, 32, 32)  # single 3-channel 32x32 image
baseline = torch.zeros_like(inputs)  # zero baseline (used where required)

# Targets for all 10 output classes
targets = [SingleTargetAcrossBatch(index=i) for i in range(10)]


def compare(explainer_cls, model, explain_kwargs, targets, delta: float = 1.0e-8, **init_kwargs):
    """Compare sequential single-target calls vs one multi-target call.
    Verifies results match and reports timing and attribution shape.
    """
    explainer = explainer_cls(model, multi_target=False, **init_kwargs)
    t0 = time.perf_counter()
    attrs = [explainer.explain(**explain_kwargs, target=t) for t in targets]
    elapsed_single = time.perf_counter() - t0
    attrs_tensor = torch.stack(attrs)

    explainer_mt = explainer_cls(model, multi_target=True, **init_kwargs)
    t0 = time.perf_counter()
    attrs_mt = explainer_mt.explain(**explain_kwargs, target=targets)
    elapsed_mt = time.perf_counter() - t0
    attrs_mt_tensor = torch.stack(attrs_mt)

    assert torch.allclose(attrs_tensor, attrs_mt_tensor, atol=delta), (
        "Results differ between single-target and multi-target"
    )
    speedup = elapsed_single / elapsed_mt if elapsed_mt > 0 else float("inf")
    print(f"shape  : {attrs_mt_tensor.shape}")
    print(
        f"single : {elapsed_single:.3f}s  |  multi : {elapsed_mt:.3f}s  |  speedup : {speedup:.1f}x"
    )

Explainer Input Requirements

Explainer baselines feature_mask sliding_window_shapes
SaliencyExplainer
InputXGradientExplainer
GuidedBackpropExplainer
RandomExplainer
FeatureAblationExplainer optional
LimeExplainer optional
KernelShapExplainer optional
IntegratedGradientsExplainer
DeepLiftExplainer
InputXBaselineGradientExplainer
DeepLiftShapExplainer ✓ distribution
GradientShapExplainer ✓ distribution
OcclusionExplainer

Pattern A — inputs + target

No baseline or mask required. Applies to: SaliencyExplainer, InputXGradientExplainer, GuidedBackpropExplainer, RandomExplainer, FeatureAblationExplainer, LimeExplainer, KernelShapExplainer.

from torchxai.explainers import SaliencyExplainer

# Replace SaliencyExplainer with any Pattern-A explainer

compare(SaliencyExplainer, model, {"inputs": inputs}, targets)

Pattern B — inputs + baseline + target

A single reference tensor (same shape as inputs) is required. Applies to: IntegratedGradientsExplainer, DeepLiftExplainer, InputXBaselineGradientExplainer.

from torchxai.explainers import IntegratedGradientsExplainer

# Replace with DeepLiftExplainer or InputXBaselineGradientExplainer as needed

compare(IntegratedGradientsExplainer, model, {"inputs": inputs, "baselines": baseline}, targets)

Pattern C — inputs + baseline distribution + target

baselines is a stacked set of reference samples rather than a single tensor. Applies to: DeepLiftShapExplainer, GradientShapExplainer.

Note

GradientShap randomly samples a baseline from the distribution on each call, so results may vary slightly between single-target runs and the multi-target call. Use delta=1e-3.

from torchxai.explainers import GradientShapExplainer

# Replace with DeepLiftShapExplainer as needed

baselines_dist = baseline.expand(5, -1, -1, -1)   # (5, 3, 32, 32) reference distribution
compare(GradientShapExplainer, model, {"inputs": inputs, "baselines": baselines_dist}, targets, delta=1e-3, n_samples=100)

Pattern D — inputs + feature_mask + target

A feature_mask groups input elements into segments so the explainer scores whole regions rather than individual pixels. Applies to: FeatureAblationExplainer, LimeExplainer, KernelShapExplainer.

The same explainer class works with or without a mask; the mask is optional. Pixel-level attribution uses no mask; segment-level attribution passes one.

from torchxai.explainers import FeatureAblationExplainer

# Replace with LimeExplainer or KernelShapExplainer as needed

# 8x8 super-pixel grid — 64 segments over a 32x32 image
grid = 8
cell_size = 32 // grid
feature_mask = torch.zeros(1, 1, 32, 32, dtype=torch.long)
for i in range(grid):
    for j in range(grid):
        feature_mask[0, 0, i*cell_size:(i+1)*cell_size, j*cell_size:(j+1)*cell_size] = i * grid + j

print("Without feature mask (pixel-level):")
compare(FeatureAblationExplainer, model, {"inputs": inputs}, targets)

print("\nWith feature mask (segment-level):")
compare(FeatureAblationExplainer, model, {"inputs": inputs, "feature_mask": feature_mask}, targets)

Pattern E — inputs + sliding_window_shapes + target

OcclusionExplainer patches out rectangular windows instead of using a feature mask. The sliding_window_shapes tuple specifies the window size per input channel.

from torchxai.explainers import OcclusionExplainer

compare(OcclusionExplainer, model, {"inputs": inputs, "sliding_window_shapes": (1, 8, 8)}, targets)