Sundararajan et al. 2017
Integrated Gradients attributes the output to inputs by integrating the gradient along a straight path from a chosen baseline to the actual input. Instead of the gradient at a single point, which can be misleading if the output has saturated, it accumulates the gradient over the whole path. This gives the method its completeness property: the attributions add up exactly to the difference between the output at the input and the output at the baseline. The attribution depends on which baseline is chosen, an all-black image, a mean image, and so on, so we sweep several baselines and report the behaviour. We apply it to the VCS by integrating each cause's gradient from a baseline state to the live state and correlating with the true causal map. On smooth content outputs it behaves like a stronger saliency and concentrates mass on the true causal byte. On a sprite's position the completeness property does not save it: the position is a discrete strobe-timed step, so the naive gradient along the whole path is zero, and the integral of zero is zero. The baseline choice moves the magnitude of the attribution but not its correlation with the truth. Integrated Gradients is an axiomatic, much-cited method, which makes it an important reference point for what completeness can and cannot fix on discrete outputs.
Top row (image domain, as in Paper 1): the game frame, then the oracle's true causal region and this method's attributed region — each painted onto the frame through the screen footprint of the RAM cells it implicates (brighter = more important). A faithful method's heat matches the oracle's. Bottom: per-cell importance — oracle (green) vs method (blue) — and the deletion/insertion faithfulness curves (perturb the ranked causes and watch the output move). Note: the image-domain overlay footprints are illustrative, computed on the pre-redesign boot frame; the bars, curves and all reported numbers come from the re-run records on the shared gameplay states. pearson_corr_with_oracle = 0.464 — this example only (pong, state f90+15); the audit aggregate is below.
This example explains the content of RAM $36 (byte 54) — the most causally-active concept byte at this state. Its strongest true-causes are: RAM $36 (the play area — ball / paddles); RAM $31 (17% of its footprint sits in the score band, the rest in the play area). The score digits appear in the region because RAM $31 reaches them: perturbing it over the 30-frame NOOP window changes the game outcome, and hence the score — a downstream effect, not direct rendering.
New to explainable AI? This block explains the method as it is used on neural networks, then how we run the very same method on an Atari 2600, where — unlike for a network — we know the right answer. Every implementation step links to the code. See also the XAI primer for the shared vocabulary.
Vanilla saliency has a blind spot called saturation. Picture a network that is already 99.9 % sure the photo shows a dog. Making the dog's ear a bit brighter cannot raise the score much more, so the gradient there is almost zero. Yet the ear is a big reason the score is high. The gradient only sees the flat top of the curve, not the climb that got there.
Integrated Gradients (IG) looks at the whole climb. It chooses a baseline: an input that means “nothing”, such as a black image. It walks in a straight line from the baseline to the real input, adds up the gradients along the way, and multiplies by how far each input moved. The payoff is completeness: the attributions add up exactly to the output at the input minus the output at the baseline. The price is that the answer depends on which baseline you pick. So our runner tries four baselines and reports how much the result moves.
With \(y = f(x)\) and a baseline \(x^0\), IG assigns input \(i\)
\[ \mathrm{IG}_i(x; x^0) \;=\; (x_i - x^0_i)\int_0^1 \frac{\partial f}{\partial x_i}\big(x^0 + \alpha\,(x - x^0)\big)\,d\alpha . \]The integral is a line integral of the gradient along the straight path. By the gradient theorem (the fundamental theorem of calculus for paths) the pieces sum to the total change: \(\sum_i \mathrm{IG}_i = f(x) - f(x^0)\). In practice the integral is a Riemann sum over \(K\) points, e.g. midpoints \(\alpha_k = (k - \tfrac12)/K\).
Toy example (2 inputs). \(f(x_1, x_2) = x_1 x_2\) at \(x = (2, 3)\), baseline \(x^0 = (0, 0)\). On the path \(x(\alpha) = (2\alpha, 3\alpha)\) the gradient is \((3\alpha, 2\alpha)\). Then
\[ \mathrm{IG}_1 = 2\int_0^1 3\alpha\,d\alpha = 3, \qquad \mathrm{IG}_2 = 3\int_0^1 2\alpha\,d\alpha = 3, \qquad 3 + 3 = 6 = f(x) - f(x^0). \]Completeness holds. Compare: saliency gives \((3, 2)\), and Grad×Input gives \((6, 6)\), which sums to 12, twice the real change.
Saturation. Let \(f(x) = \min(1, x)\) at \(x = 2\). The gradient is 0, so saliency says “irrelevant”. IG from \(x^0 = 0\) integrates slope 1 over the first half of the path: \(\mathrm{IG} = 2 \cdot \tfrac12 = 1 = f(2) - f(0)\). IG sees the climb.
Baseline dependence. Back to \(x_1 x_2\), now with baseline \(x^0 = (2, 0)\). \(x_1\) does not move, so \(\mathrm{IG}_1 = 0\), and \(\mathrm{IG}_2 = 3 \cdot 2 = 6\). Same model, same input: all the credit moved to \(x_2\). The baseline defines the question being answered.
| The network \(f\) | The Atari 2600 VCS running the ROM, emulated bit-exactly by jutari; its differentiable twin is JuTari.Diff. |
|---|---|
| The input \(x\) | The 128 RAM bytes at the intervention frame \(f^*\) (after 90 frames of seeded random play). |
| The baseline \(x^0\) | Four choices: all-zeros RAM (headline), every byte set to the mean of \(x\), one uniform-random RAM vector, and the real RAM at an earlier frame (\(f^*/2\)) of the same game. |
| Points on the path | \(K = 64\) midpoint RAM vectors. They hold fractional byte values the real machine cannot execute; only the differentiable read is evaluated there. |
| The output \(y\) | A content output (one RAM byte read one-hot) and a position output (screen pixels changed versus the un-intervened frame, made differentiable by the bilinear sampler). |
| “Is the attribution right?” | The intervention oracle: poke each cause, re-run the real ROM, measure \(|\Delta y|\). |
The runner integrates the gradient over the RAM vector with \(K = 64\) Riemann midpoints, for each of four baselines, and scores each IG map against the oracle. It also records each baseline's completeness error. The headline number uses the all-zeros baseline; the sweep sits beside it.
soft_ram_peek or the bilinear sampler), which is
defined for any real number. The machine itself only runs during the oracle and the
deletion/insertion curves, always on integer pokes. As in vanilla saliency, the 15 frames between
\(f^*\) and the readout are not differentiated.zeros is the classic “absent” input.
mean_ram fills all 128 bytes with one number, the mean of the current RAM.
random is one seeded uniform draw in 0–255. real_alt is the genuine RAM at
frame \(f^*/2\) of the same seeded run. It is the only baseline that is itself a reachable game state.XAI the interpretability method substrate the bit-exact emulator it runs on (jutari, Julia).
ig_baseline_sweep.jl:365 — The method: \(K\) midpoint gradients along the path, times \((x - x^0)\), plus the completeness error.ig_baseline_sweep.jl:372 — The interpolated RAM vector: fractional bytes, fed only to the differentiable read.ig_baseline_sweep.jl:337 — The four baselines of the sweep: zeros, mean_ram, random, real_alt.ig_baseline_sweep.jl:560 — The real-state baseline: the genuine RAM at half the intervention frame.ig_baseline_sweep.jl:403 — Scores one baseline's IG against the oracle (correlation, precision@k, deletion/insertion, completeness).ig_baseline_sweep.jl:250 — Deletion/insertion curves: occlude or restore the top-ranked causes and re-run the real ROM.SoftStep.jl:106 — The linear one-hot read: the same gradient at every point of the path.shared_testbed_impl.jl:357 — The bilinear sampler: defined for any real RAM value, so IG can integrate along the path.oracle_intervene.jl:242 — The ground truth: poke a cause (integer value), re-run the real ROM, read the output.StellaEnvironment.jl:259 — One frame of the bit-exact machine.The headline bars use the zeros baseline. On the content output you see one spike at the read byte, as in vanilla saliency. Its height is the byte's distance from the baseline. Across the baseline sweep the spike grows or shrinks, but the correlation with the oracle barely moves. It drops to nothing only when a baseline equals the byte. The completeness error is essentially zero throughout. On the position output, agreement with the oracle stays low for every baseline. Completeness is a bookkeeping guarantee about the total; it does not make IG notice the several causes the oracle finds over 15 frames.
julia --project=jutari tools/xai_study/phaseB_attribution/ig_baseline_sweep.jl --games core --baseline-sweep
Writes ig_baseline_sweep_<game>_{content,ball_pixel}.json/.npz (the sweep is under extra.baseline_sweep) and ig_baseline_sweep_core_summary.json into tools/xai_study/phaseB_attribution/out/. Use --ig-steps N to change \(K\) and --baseline zeros|mean_ram|random|real_alt to run a single baseline.
Read next: Expected Gradients · Grad×Input / DeepLIFT · Vanilla gradient (saliency) · KernelSHAP / Shapley
The score is the Pearson correlation of the Integrated-Gradients attribution with the oracle's exact causal map, reported raw, at the headline baseline, with the baseline swept to show the dependence. Faithfulness for this method is that correlation, graded always against the intervention oracle. On smooth content outputs it behaves like a stronger saliency and scores well, and sweeping the baseline moves the magnitude of the attribution but not its correlation with the truth, because the constant one-hot Jacobian keeps the mass on the same byte. The hard case is a sprite's position. The position is a discrete strobe-timed step, so the naive gradient along the whole integration path is zero, and the integral of zero is zero; completeness does not rescue it. The audit turns on the differentiable sampler to give the method a fair chance on position, but the restored gradient is faithful on only a minority of games, so the position score stays low. The audit box reports the all-regime faithfulness, which averages the strong content result and the weak position result across the scored games. This makes Integrated Gradients a key reference for what the completeness axiom can and cannot fix on discrete outputs.
The score is measured against the §1 intervention oracle — never against another interpretability method. F (faithful) is always vs the oracle; see the execution stack. How each of F / S / M is actually computed for this method (and whether it matches the paper) is in the box just below; the numbers are in the In the audit box under it.
The exact formula this method uses for each score, read from its runner, and
whether it matches the paper's §3 (F ∧ S ∧ M triad) definition.
From the committed audit
fsm_math_phaseB.json.
| Axis | Formula (as computed) | What it measures | Matches §3? |
|---|---|---|---|
| F faithfulness | \(F = \rho_{\mathrm{Pearson}}\!\left(\mathrm{attr},\ |\Delta y(u)|\right)\) | Raw Pearson correlation between the method's per-cause attribution magnitudes and the oracle's true absolute causal effects |Delta_y(u)|, scored separately for the content and position output regimes. | ✓ matches ig_baseline_sweep.jl: pr = pearson(attr, odelta); headline value = content-path corr at zeros baseline; triad_extra_dict(hs.pearson, hs.attr_per_cause, f.oracle_abs_delta). Record: out/ig_baseline_sweep_air_raid_content.json (value=0.79). Scorer pilot_ig_vs_oracle.jl pearson() (raw Statistics.cor, zero-variance->0); F = pearson(attr, oracle_abs_delta) where oracle_abs_delta = abs.(cmap.delta) (true |Delta_y| per cause). Also reports spearman, precision@k, deletion/insertion AUC (paper's auxiliary F metrics). Per-regime split: separate *_content.json and *_position.json records, each carrying its own extra.triad.{F,S,M}. how it's measured — call stack:
|
| S sufficiency | \(S = \dfrac{\#\{\,u_{\mathrm{held}}:\ |\hat{y}-y|\le\varepsilon\,\}}{|\mathrm{held\text{-}out}|}\in[0,1]\) | Fit Delta_y = a*attr + b on a calibration half of the do(u) causes, predict the disjoint held-out half, and report the fraction of held-out causes whose predicted output lands within an epsilon band of the oracle's bit-exact re-run. | ✓ matches common/triad_sm.jl sufficiency_score() (interleaved calib/held split by seed, least-squares 1-D fit Delta_y~a*attr+b on calib, epsilon = max(0.5, 0.10*heldout_spread)); assembled in triad_extra_dict(). The new §3 (sec:triad) admits the fraction-within-tolerance [0,1] special case of the held-out predictive test, which this held-out do(u) fit-then-predict estimator satisfies, so it matches. (Detail: epsilon is a self-scaled band 0.10*spread; the [-1,1] correlation form is available but this method reports the [0,1] hit fraction.) how it's measured — call stack:
|
| M minimality | \(M = |U^{\star}| / |\hat{U}| \in (0,1]\quad U^{\star}=\{u:\Delta y(u)>0\},\ \hat{U}=\{u:|\mathrm{attr}(u)|>\tau\}\) | Ratio of the number of oracle causal movers (causes with nonzero true Delta_y) to the number of cells the method names above 1e-6 of its own max attribution; null when the oracle finds no mover or the method names nothing. | ✓ matches common/triad_sm.jl minimality_score() with name_frac=1e-6, mover_floor=0.0; the above-threshold named set is used (topk kept but not passed), see triad_extra_dict(). This is the paper's M = |U*|/|U_hat| in (0,1] (standardized everywhere), so it matches the new §3. (Detail: |U*| is taken as all oracle movers with Delta_y>0, an upper bound on the strictly-smallest reproducing subset, so M can be optimistic.) how it's measured — call stack:
|
✓ matches = the same quantity as §3; ◐ partial = the same kind of estimator but a differing detail; ✗ does not match = a different quantity (see the note). Definitions: F = agreement with the oracle's true causal effects Δy(u); S = held-out predictive score in [−1, 1]; M = |U*|/|Û| (true-minimal-set size / named-set size).
This is the method's entry in the actual cross-method audit — scored on the paper's correctness triad, each axis a mean over 44 of the 44 scored games (88 committed §R records), not the single example shown above. Tradition: gradient. The example figure (Pong) is one of those records.
F faithfulness (scored vs the oracle for every method) · S sufficiency (held-out predictive score in [−1, 1]; a negative value means the explanation predicts held-out interventions worse than the unperturbed baseline; reported for the predictive methods across all three phases where the calibration/held-out split is defined) · M minimality (true-minimal-set / named-set; where the method names a cause set) — n/a otherwise, per the paper's F ∧ S ∧ M triad.
Source: leaderboard.json · the whole leaderboard is on the
methods page and the
Paper 2 audit.
This method's faithfulness on each of the 44 scored games (all-regime F, and the content vs position split). Click a header to
sort. Every number is read from site_data.json
(methods.ig_baseline_sweep.per_game).
| Game | F (all) | content-F | position-F | S | M | Note |
|---|---|---|---|---|---|---|
| Krull | 0.804 | 1.000 | 0.608 | 0.538 | 1.000 | |
| Gopher | 0.761 | 0.776 | 0.746 | 0.929 | 1.000 | |
| Pacman | 0.629 | 0.776 | 0.481 | 0.611 | 1.000 | |
| Bowling | 0.518 | 0.688 | 0.348 | 0.905 | 1.000 | |
| Enduro | 0.500 | 1.000 | 0.000 | 0.500 | 1.000 | position gradient vanishes |
| Space Invaders | 0.500 | 1.000 | 0.000 | 0.556 | 1.000 | position gradient vanishes |
| Tennis | 0.500 | 1.000 | 0.000 | 0.531 | 1.000 | position gradient vanishes |
| Montezuma's Revenge | 0.500 | 1.000 | 0.000 | 0.938 | 1.000 | position gradient vanishes |
| Riverraid | 0.500 | 1.000 | 0.000 | 0.522 | 1.000 | position gradient vanishes |
| Kangaroo | 0.500 | 0.999 | 0.000 | 0.500 | 1.000 | position gradient vanishes |
| Q*bert | 0.500 | 0.999 | 0.000 | 0.500 | 1.000 | position gradient vanishes |
| Boxing | 0.487 | 0.817 | 0.156 | 0.542 | 1.000 | |
| Ice Hockey | 0.477 | 0.767 | 0.188 | 0.545 | 1.000 | |
| Demon Attack | 0.477 | 0.955 | 0.000 | 0.875 | 1.000 | position gradient vanishes |
| Fishing Derby | 0.474 | 0.948 | 0.000 | 0.500 | 1.000 | position gradient vanishes |
| Video Pinball | 0.465 | 0.770 | 0.160 | 0.500 | 1.000 | |
| Phoenix | 0.455 | 0.909 | 0.000 | 0.577 | 1.000 | position gradient vanishes |
| Bank Heist | 0.450 | 0.900 | 0.000 | 0.833 | 1.000 | position gradient vanishes |
| Ms. Pac-Man | 0.405 | 0.810 | 0.000 | 0.475 | 1.000 | position gradient vanishes |
| Skiing | 0.405 | 0.810 | 0.000 | 0.450 | 1.000 | position gradient vanishes |
| Double Dunk | 0.399 | 0.797 | 0.000 | 0.538 | 1.000 | position gradient vanishes |
| Freeway | 0.398 | 0.747 | 0.049 | 0.500 | 1.000 | |
| Name This Game | 0.394 | 0.788 | 0.000 | 0.417 | 1.000 | position gradient vanishes |
| Alien | 0.390 | 0.779 | 0.000 | 0.500 | 1.000 | position gradient vanishes |
| Jamesbond | 0.388 | 0.747 | 0.028 | 0.893 | 1.000 | |
| Atlantis | 0.386 | 0.773 | 0.000 | 0.400 | 1.000 | position gradient vanishes |
| Yars' Revenge | 0.385 | 0.771 | 0.000 | 0.464 | 1.000 | position gradient vanishes |
| Private Eye | 0.380 | 0.758 | 0.003 | 0.960 | 1.000 | position gradient vanishes |
| Breakout | 0.375 | 0.750 | 0.000 | 0.550 | 1.000 | position gradient vanishes |
| Kung-Fu Master | 0.372 | 0.745 | 0.000 | 0.800 | 1.000 | position gradient vanishes |
| Venture | 0.372 | 0.743 | 0.000 | 0.474 | 1.000 | position gradient vanishes |
| Pong | 0.371 | 0.464 | 0.278 | 0.444 | 1.000 | |
| Seaquest | 0.355 | 0.000 | 0.710 | 0.479 | 1.000 | holds up on position |
| Air Raid | 0.294 | 0.360 | 0.228 | 0.036 | 1.000 | |
| Frostbite | 0.272 | 0.484 | 0.059 | 0.150 | 1.000 | |
| Berzerk | 0.048 | 0.096 | 0.000 | 0.481 | 1.000 | position gradient vanishes |
| Assault | 0.000 | 0.000 | 0.000 | 0.905 | 1.000 | position gradient vanishes |
| Asterix | 0.000 | 0.000 | 0.000 | 0.100 | 1.000 | position gradient vanishes |
| Carnival | 0.000 | 0.000 | 0.000 | 0.526 | 1.000 | position gradient vanishes |
| Centipede | 0.000 | 0.000 | 0.000 | 0.500 | 1.000 | position gradient vanishes |
| Chopper Command | 0.000 | 0.000 | 0.000 | 0.452 | 1.000 | position gradient vanishes |
| Hero | 0.000 | 0.000 | 0.000 | 0.444 | 0.750 | position gradient vanishes |
| Pitfall | 0.000 | 0.000 | 0.000 | 0.882 | 1.000 | position gradient vanishes |
| Road Runner | 0.000 | 0.000 | 0.000 | 0.105 | 0.500 | position gradient vanishes |
The path from this method's runner (main) into the bit-exact VCS substrate, and the
computation it involves. Every step links to the exact source on main. From
callstack_phaseB.json.
env_reset! / env_step! jutaribuild_shared_testbed jutaricontent_read -> soft_ram_peek jutari-diff call site tools/xai_study/phaseB_attribution/ig_baseline_sweep.jl:294make_baseline runnerig_over_ram runnerZygote.gradient(readf, xalpha) Zygote_st_sampler_position_read runner-diffScored against the exact intervention oracle Δy(u): run_intervention.
On jaxtari (JAX / GPU): the same differentiable path has a bit-exact JAX sibling (Theorem 1, forward-exact) for batched GPU runs — JAX-equivalent differentiable path (bit-exact per Theorem 1, for GPU batching): jaxtari/jaxtari/diff/soft_step.py, soft_mem.py, straight_through.py
The figure is generated from the committed record by
docs/gen_method_figures.py; the game frame
and each RAM cell's screen footprint are produced by
render_scenes.jl /
cell_footprints.jl.