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


jlens โ€” Jacobian lens

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.

What it does

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.

Project structure

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

Architecture

The project is ~600 lines of Python across 6 core modules, designed as a model-agnostic library through a Protocol-based interface.

Protocol-based model abstraction

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.

Fitting algorithm

The lens fitting (fitting.py) computes the average input-output Jacobian:

  1. 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:

  2. Multi-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

Activation recording

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__

Interactive visualization

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)

Computation patterns

Implementation details

Test infrastructure

Dependencies

Data included

No model weights or text corpora are bundled.