Phase A · neuroscience battery

A5 · Local field potentials

cf. Jonas & Kording 2017

← back to the method catalogue

What it does?

The local field potential is a pooled, low-resolution signal. In neuroscience it is the summed electrical activity of many neurons near an electrode, and its power spectrum, the strength of each oscillation frequency, is studied as a marker of brain state. We build the analogue on the VCS by pooling the activity of a region of memory into one aggregate signal and taking its power spectrum. The idea is that rhythms in this pooled signal reflect the computation. The problem we test is whether those rhythms are real computation or just the machine's clocks showing through. The VCS is driven by a frame clock and a scanline clock, and their fixed rhythms dominate any pooled signal. So much of the spectrum is epiphenomenal: it is the timing of the hardware, not the work the program does. This is a known danger for field potentials in neuroscience too, where a strong oscillation can reflect a global pacemaker rather than local processing. The method is easy to compute and produces impressive-looking spectra, but on a machine whose clocks we know exactly we can show how little of that structure is actually computational.

A5 · Local field potentials result

Left: the frame. Right: this method's per-cell/per-component result against the ground-truth importance, with the RAM cells labelled. A5_global_pool_clock_explained_variance_fraction_epiphenomenal = 0.752 — this example only (pong, state gameplay(seed=0,prefix=90)+256); the audit aggregate is below.

Neuroscience battery · pooled signals and their rhythms

Learn the method — a beginner's guide

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.

The idea in plain words

Put a microphone in a busy restaurant. You cannot follow any single conversation, but you still hear something: a loud hum that swells and fades. Neuroscientists do the same with the brain. An electrode in brain tissue records the local field potential (LFP): the summed electrical activity of thousands of nearby neurons. Nobody sees a single cell. What people study instead is the rhythm of this hum: how strong the slow waves are, how strong the fast ones. That breakdown of a signal into rhythms is called its power spectrum, and LFP bands such as “theta” or “gamma” are read as windows onto what the region computes.

The worry is simple. A strong rhythm might be the computation. Or it might be a pacemaker: a global clock that ticks everywhere and makes every part of the system hum at the same beat, whether or not that part does useful work. Activity that is caused by the clock but carries no computation is called epiphenomenal. In a brain you cannot easily tell the two apart. On the Atari you can, because we know every clock of the machine exactly. A5 measures how much of the “LFP” spectrum is just those clocks.

How it works on a neural network

Neuroscience origin. The LFP is a mesoscale signal: coarser than a single neuron, finer than an EEG over the whole skull. It is the analysis you can run when single-cell access is impossible. Jonas & Kording (2017) recorded the analogous “LFP” of a simulated 6502 chip and found rich rhythms that said nothing about the program it ran.

Deep-learning analogue. In a network, the LFP corresponds to pooled or aggregate activation statistics: the mean activation of a layer, the norm of a block's output, or the average over a group of units, tracked over time steps (tokens, video frames, RL steps). Write the activation of unit \(i\) at time \(t\) as \(a_i(t)\). Standardise each unit (subtract its mean, divide by its standard deviation: a z-score \(z_i\)) and average over a region \(R\):

\[ L(t) \;=\; \frac{1}{|R|}\sum_{i\in R} z_i(t), \qquad P(f_k) \;=\; \Big|\sum_{t=0}^{T-1} L(t)\,w(t)\,e^{-2\pi i k t/T}\Big|^2 . \]

\(L(t)\) is the pooled signal, \(w(t)\) a smooth window that tapers the ends, and \(P(f_k)\) the power at frequency \(f_k = k/T\) cycles per step (the discrete Fourier transform). A peak in \(P\) at period \(p = 1/f\) means the pooled activity repeats every \(p\) steps.

Toy example. Take two units over \(T=8\) steps. Unit 1 is a counter that flips every step: \(z_1 = (+1,-1,+1,-1,+1,-1,+1,-1)\). Unit 2 holds a real variable that jumps once: \(z_2 = (-1,-1,-1,-1,+1,+1,+1,+1)\). Their pool is \(L = (0,-1,0,-1,1,0,1,0)\). Its spectrum has a peak at period 2 (from unit 1) and a slow component at period 8 (from unit 2). If we know unit 1 is a clock, we can fit sin/cos waves of period 2 to \(L\) and ask what fraction of \(L\)'s energy they explain. Here it is exactly half (energy 2 of 4): half of this “LFP” is pure clock, however striking the period-2 peak looks.

Recipe

  1. Record the activity of every unit over \(T\) time steps (here: all 128 RAM bytes, once per video frame).
  2. Choose regions: one global pool of every unit that varies, plus smaller pools of related units.
  3. Z-score each varying unit and average per time step: this is the region's pooled signal \(L(t)\).
  4. Remove the mean and the linear trend, multiply by a Hann window, and take the DFT power spectrum.
  5. Report the dominant periods. Then build a basis of the known clocks (sin/cos at their periods and harmonics).
  6. Project \(L\) onto that clock basis: the fraction of its energy captured is the clock-explained, epiphenomenal fraction.

From a neural network to the Atari

Neurons in a brain region / units in a layerThe 128 bytes of the VCS's RAM (random-access memory: the program's working variables, e.g. ball position, score, timers), read once per frame (one full TV picture, 1/60 s).
The LFP: pooled, z-scored activityThe mean z-scored value of a set of RAM bytes per frame: the global pool (every byte that changes) and one regional pool per game-variable family (all score bytes, all enemy bytes, …).
Theta / gamma bandsPeaks in the per-frame power spectrum, reported as periods in frames (a period-2 blink, a period-8 animation cycle, …).
A global pacemakerThe machine's known clocks: the frame cadence itself, plus every RAM byte that is an exact free-running counter (it ticks by a fixed step, or repeats with a fixed short period). Games use these as animation and blink timers.
“Is this rhythm computation?”Answered exactly: the fraction of the pooled signal's energy that lies in the span of the known-clock waves. That part is causally inert timing, not game logic.

How we apply it to the VCS

The runner A5_lfp.jl follows the recipe on the real, bit-exact emulator. Concretely:

  1. The trajectory. It builds the study's shared gameplay state: a seeded stream of random joystick actions (90 frames of play, then a 15-frame horizon). It drives the game with that stream and keeps going with NOOP (no button pressed) until the trajectory is long enough for a spectrum (256 frames for most games). Two fresh runs from power-on must give byte-identical RAM and screen, or the runner refuses to analyse. Then a5_record_ram calls env_step! and get_ram once per frame to fill a \(T\times128\) tape.
  2. Finding the clocks without labels. detect_clock_cells scans each RAM byte. A byte is a ramp if its frame-to-frame difference (mod 256) is one constant non-zero step: a frame counter. It is periodic if it repeats exactly with some period between 2 and 64 frames: a blink or animation timer. No game knowledge is used.
  3. The clock basis. clock_basis stacks sin/cos waves at two slow frame-cadence periods (\(T\) and \(T/2\), always present) plus the first three harmonics of every detected clock period. Each wave goes through the same detrend and window as the data. A QR factorisation makes the basis orthonormal.
  4. Pooling and spectra. pool_region builds the global pool and one pool per variable family from the candidate-cause list. dft_power computes a plain \(O(T^2)\) DFT (no FFT package is added to the emulator environment). The headline number is the global pool's clock-explained fraction, from variance_explained_by.
  5. Controls. The self-test projects a pure clock wave (must score above 0.9) and a mid-band sinusoid placed between frequency bins (must score below 0.5). So a high clock fraction is a measurement, not a basis that explains everything.

Where we differ from the neuroscience original. We sample once per frame. The VCS also has a scanline clock (262 TV lines per frame) and a CPU clock, but those tick far faster than our sampling rate and cannot appear in a per-frame spectrum. The clocks A5 actually removes are the frame cadence and the frame-driven counter bytes. A5 is also descriptive. It never intervenes; the oracle is used only to build and gate the shared gameplay state. Its score asks “how much of this signal is known-inert timing?”, not “does it find the causes of an output?”.

Read the code

XAI the interpretability method   substrate the bit-exact emulator it runs on (jutari, Julia).

Reading the result

The figure shows the global pool's power spectrum in cycles per frame. Expect most of the power at the lowest frequencies, slow sweeps over the whole recording (periods of \(T\) or \(T/2\) frames), and in some games sharp peaks at short integer periods: these look like the “brain rhythms” of the game. Then compare them with the clock basis. The slow sweeps are the frame cadence, the short peaks sit on a detected timer period or its harmonics, and in most games the clock-explained fraction is large. The rich-looking spectrum is mostly the machine's timing. Regional pools for real game variables (score, enemies) are often just as clock-dominated, or flat when their bytes never change; either way the spectrum cannot tell you what they compute or what causes them. The live faithfulness number is in the audit box below.

Pitfalls

Try it yourself

julia --project=jutari tools/xai_study/phaseA_kording/A5_lfp.jl --games core

Writes A5_<game>.json/.npz (pooled signal, spectrum, clock cells, per-region clock fractions) into tools/xai_study/phaseA_kording/out/. Add --selftest to run the controls on the first game without writing. A few minutes per game on one CPU core, most of it building the shared gameplay state.

Original papers & further reading

Read next: A4 · Pairwise correlations · A6 · Granger causality · A7 · Dimensionality reduction (NMF/PCA) · A2 · Single-unit lesions

How it's scored

The score is the fraction of the pooled-activity power spectrum that the known clocks explain. We pool a region of memory into one signal, take its power spectrum, and measure how much of that spectrum is accounted for by the frame clock and the scanline clock, whose frequencies we know exactly. Faithfulness is one minus that clock-explained fraction, because the part of the spectrum that is just the hardware's timing is epiphenomenal, not computation. A high clock-explained fraction means the impressive-looking spectrum is mostly the machine's pacemaker, so the method's faithfulness is low. The grading is always against the intervention oracle, which certifies what is truly computational. There is no sprite-position hard-case here; the output is a spectrum, not a coordinate. This method is a calibration baseline: it shows how a standard neuroscience signal can look rich while carrying little of the real computation. The audit box reports the measured faithfulness across the scored games, so the number reflects the whole scored set rather than one game where the clocks happen to dominate more or less.

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.

How F, S, M are computed here

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_phaseA.json.

AxisFormula (as computed) What it measuresMatches §3?
F
faithfulness
—No faithfulness score. A5 is declared a descriptive method: it reports the pooled-activity spectral structure it reveals (headline = global-pool clock-explained variance fraction), not an F vs the oracle.— n/a Runner A5_lfp.jl explicitly sets method_kind='descriptive (no oracle F/S/M)',; metric_name=A5_global_pool_clock_explained_variance_fraction_epiphenomenal, value=gp.clock_var_fraction. Record out/A5_pong.json has no triad.
S
sufficiency
—Not computed; A5 emits no S.— n/a No S/held-out estimator in A5_lfp.jl; descriptive method by design.
M
minimality
—Not computed; A5 emits no M.— n/a No minimality set in A5_lfp.jl; descriptive method by design.

✓ 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).

In the audit

This is the method's entry in the actual cross-method audit — scored on the paper's correctness triad, each axis a mean over 42 of the 44 scored games (42 committed §R records), not the single example shown above. Tradition: correlational. The example figure (Pong) is one of those records.

0.394F — faithfulness vs oracle (mean over 42 games, ±0.056 CI95)
n/aS — sufficiency: held-out predictive (n/a where the paper does not define this axis)
n/aM — minimality: true-minimal-set / named-set (n/a otherwise)
42committed records aggregated
0.00human-plausibility proxy

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.

Results per game

This method's faithfulness on each of the 42 scored games (all-regime F; this method has no content-vs-position split (see the note below)). Click a header to sort. Every number is read from site_data.json (methods.A5_lfp.per_game).

content-F and position-F are n/a for this method. The content-vs-position split applies only to pixel-attribution methods — those that produce an attribution map over the framebuffer, whose score can be read separately on the smooth content outputs and the discrete position outputs (where the naive gradient is provably zero). This method does not attribute to a pixel output; it is graded by its own fidelity metric (A5_global_pool_clock_explained_variance_fraction_epiphenomenal), reported as the F column, so there is no content or position regime to separate.

GameF (all)content-Fposition-FSMNote
Kung-Fu Master0.774n/an/an/an/a
Jamesbond0.743n/an/an/an/a
Asterix0.703n/an/an/an/a
Assault0.701n/an/an/an/a
Video Pinball0.625n/an/an/an/a
Yars' Revenge0.607n/an/an/an/a
Riverraid0.604n/an/an/an/a
Alien0.581n/an/an/an/a
Fishing Derby0.573n/an/an/an/a
Atlantis0.544n/an/an/an/a
Gopher0.529n/an/an/an/a
Enduro0.523n/an/an/an/a
Space Invaders0.506n/an/an/an/a
Skiing0.475n/an/an/an/a
Private Eye0.458n/an/an/an/a
Freeway0.445n/an/an/an/a
Chopper Command0.439n/an/an/an/a
Name This Game0.424n/an/an/an/a
Pitfall0.415n/an/an/an/a
Ice Hockey0.410n/an/an/an/a
Montezuma's Revenge0.402n/an/an/an/a
Tennis0.395n/an/an/an/a
Road Runner0.383n/an/an/an/a
Demon Attack0.342n/an/an/an/a
Q*bert0.330n/an/an/an/a
Phoenix0.307n/an/an/an/a
Seaquest0.306n/an/an/an/a
Bowling0.297n/an/an/an/a
Bank Heist0.284n/an/an/an/a
Venture0.270n/an/an/an/a
Pong0.248n/an/an/an/a
Boxing0.229n/an/an/an/a
Air Raid0.226n/an/an/an/a
Double Dunk0.225n/an/an/an/a
Pacman0.213n/an/an/an/a
Ms. Pac-Man0.194n/an/an/an/a
Breakout0.186n/an/an/an/a
Krull0.148n/an/an/an/a
Frostbite0.139n/an/an/an/a
Kangaroo0.133n/an/an/an/a
Centipede0.101n/an/an/an/a
Berzerk0.089n/an/an/an/a

Call stack — how it runs on jutari / jaxtari

The path from this method's runner (compute_game) into the bit-exact VCS substrate, and the computation it involves. Every step links to the exact source on main. From callstack_phaseA.json.

Applied on the substrate

  1. assemble the shared gameplay-state testbed + cause-density gate — build_a5_shared_state(game) -> build_shared_testbed(game; ...) runner
  2. build_shared_testbed definition: booted checkpoint + shared output + gate — function build_shared_testbed(game; ...) runner
  3. cause-density gate counts causes with |Delta_y|>floor via the oracle — cause_density = count(>(floor), deltas) runner
  4. record a (frames x 128) RAM tape by stepping the ROM with A5's per-game settings — a5_record_ram(game, frames, actions) runner
  5. step the real emulator one frame per action while recording — env_step!(env, Int(actions[t])) jutari
  6. read RAM into the tape each frame — get_ram(env) jutari

The computation

  1. detect periodic clock cells (basis of the clock-explained fraction) over the tape — detect_clock_cells(tape; p_max=64) runner
  2. LFP analysis (method under test): pool RAM cells into a region, detrend + window, DFT power spectrum, dominant period/band + clock-explained fraction — analyse_region(name, cells, tape, B, win) runner

Scored against the exact intervention oracle Δy(u): run_intervention(checkpoint, actions, target_frame, horizon, cause).

Implementation
tools/xai_study/phaseA_kording/A5_lfp.jl
Reference
cf. Jonas & Kording 2017
Record
A5_pong.json
All records
phaseA_kording/out

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.