Raw capture โ raw/jacobian-lens.md
url: https://github.com/anthropics/jacobian-lens title: jlens โ Jacobian lens author: Anthropic PBC date_fetched: 2026-07-08 date_published: 2026-06
Reference implementation for the paper "Verbalizable Representations Form a Global Workspace in Language Models" (https://transformer-circuits.pub/2026/workspace/index.html).
Reference implementation. Not maintained and not accepting contributions.
The Jacobian lens reads out what an internal activation is disposed to make the model say. It linearly transports a residual-stream vector at any layer and position into the final-layer basis, then decodes it with the model's own unembedding into a ranked list of vocabulary tokens.
Core formula:
lens_l(h) = unembed( J_l @ h ), J_l = E[โh_final / โh_l]
The expectation is over prompts, source positions, and all current-and-future target positions in a generic web-text corpus.
jlens/
__init__.py โ public API surface (12 exports)
lens.py โ JacobianLens class: apply, transport, save/load, merge
fitting.py โ fit(), jacobian_for_prompt(): the Jacobian estimator
protocol.py โ LensModel Protocol: model-agnostic interface
hooks.py โ ActivationRecorder: forward-hook context manager
hf.py โ HuggingFace adapter (HFLensModel, from_hf, Layout)
vis.py โ Interactive slice visualization (compute_slice, build_page)
examples.py โ Bundled example prompts, WikiText loader
_logging.py โ stderr logging with elapsed/delta timestamps
data/
slice_vis.html โ D3-based interactive HTML template
blackmail.json โ Agentic Misalignment scenario prompt
tests/
tiny.py โ Tiny CPU decoder (4-layer, d_model=8) for tests
test_fitting.py โ Jacobian estimation, fit/save/load round-trip, merge, resume
test_compute_slice.py โ Visualization computation end-to-end
test_ranks_of.py โ Chunked rank computation correctness
test_vis_modes.py โ Page rendering (embed vs fetch modes)
test_hf_layout.py โ HF model layout auto-detection
data/
evaluations/ โ 6 prompt distributions for lens-quality evaluation
experiments/ โ 11 experiment prompt sets (probe-swap, verbal-introspection, etc.)
The project is ~600 lines of Python across 6 core modules, designed as a model-agnostic library through a Protocol-based interface.
The central design pattern: LensModel is a Protocol (structural subtyping, no inheritance required). Any model can be plugged in by implementing:
- n_layers, d_model โ model dimensions
- layers โ sequence of residual blocks (forward-hook targets)
- tokenizer โ tokenizer with .decode() method
- encode(text) โ tokenize to input_ids tensor
- forward(input_ids) โ run residual stack (no LM head), must build autograd graph
- unembed(residual) โ final norm + LM head, maps [..., d_model] โ [..., vocab_size]
The HuggingFace adapter (hf.py) implements this by auto-detecting the layout of the text decoder inside common HF architecture families (Llama, Qwen, Mistral, Gemma, OLMo, Phi, GPT-2, GPT-NeoX/Pythia). tests/tiny.py provides a minimal from-scratch TinyDecoder that satisfies LensModel for testing without transformers.
The lens fitting (fitting.py) computes the average input-output Jacobian:
Per-prompt estimator (jacobian_for_prompt):
- Replicate the prompt dim_batch times along the batch axis
- Run one forward pass, retain the autograd graph
- Loop ceil(d_model / dim_batch) times:
dim_batch output dimensionstorch.autograd.grad with retain_graph=True (except last pass)dim_batch rows of J_l at oncesum_{p' >= p} dh_final[p'] / dh_l[p] โ the sum over all later target positionsMulti-prompt accumulation (fit):
- Iterates over prompts, accumulates per-prompt Jacobians as a running mean
- Supports checkpointing (atomic saves, resume on restart)
- Tracks per-prompt diagnostics: Jacobian norm (flags heavy-tailed outliers) and relative shift in running mean (tracks convergence)
- Skips too-short prompts elegantly (tracks next_idx separately from n_done to avoid double-counting on resume)
- merge() classmethod combines lenses fitted on disjoint prompt subsets via n_prompts-weighted mean
ActivationRecorder (hooks.py) is a context manager that registers forward hooks on specific residual blocks. Key design:
- Hooks store output tensors without detaching them, so they can be used directly in torch.autograd.grad
- start_graph_at option marks one captured tensor with requires_grad_(True), making it the leaf that roots the autograd graph โ essential when model parameters have requires_grad=False
- Handles HF blocks that return tuples (hidden, present_kv, ...) by extracting the first tensor
- Cleans up hooks on __exit__, with rollback on failed __enter__
vis.py produces a position ร layer HTML heatmap showing the lens's top-1 token at each cell, with:
- Superscript showing rank over the full vocabulary
- Click-to-pin tokens with rank-tracking charts
- Bottom row showing the model's actual output (J=I at final layer)
- Two modes: "embed" (self-contained single file, d3 inlined, rank data base64-embedded) and "fetch" (sidecar files, lazy loading, CDN d3)
- Chunked rank computation to avoid full-vocab argsort at long sequence lengths
- mask_display option to restrict displayed tokens to word-like ones (ranks remain full-vocab)
- English gloss support for non-Latin tokens (alt_token)
dim_batch times so one backward pass computes dim_batch rows of each J_l simultaneouslychunk_size so peak memory is one [chunk_size, vocab] sort bufferp' >= p), not just the next token โ this is the reduction used in the paperdict[int, Tensor[d_model, d_model]] โ one [d_model, d_model] matrix per layerceil(d_model / dim_batch) backward passes per promptfit() on disjoint prompt slices and merging with JacobianLens.merge()torch.compile per-block (not whole-module, which would bypass hooks)tests/tiny.py: A 4-layer CPU decoder with h + 0.1 * linear(h) residual blocks. The small gain keeps the Jacobian well-conditioned, and the block structure means J_2 == I + 0.1*W_3 exactly โ giving tests a mathematical ground truth to assert againsttests/test_fitting.py: 10 tests covering the full fitting pipeline including a regression test for a desync bug where skipped prompts caused double-counting on resumetests/test_compute_slice.py: End-to-end visualization tests including tracked rank columns matching _ranks_of outputtorch โ core computationtransformers >= 5.5 โ HuggingFace model loadinghuggingface_hub โ downloading pre-fitted lenses from the Hubnumpy โ visualization array operationsdatasets (WikiText loading), pytest, ruffjlens.examples.EXAMPLESNo model weights or text corpora are bundled.