From a64865c72067bcd81af9e6090f495c6356f38553 Mon Sep 17 00:00:00 2001 From: janmenjayap Date: Sun, 13 Sep 2026 11:20:16 +0530 Subject: [PATCH 1/7] feat(analysis): causal-swap benchmark corpus and answer metrics --- ...est_jacobian_lens_causal_swap_benchmark.py | 72 +++++++++++ .../jacobian_lens_causal_swap_benchmark.py | 115 ++++++++++++++++++ 2 files changed, 187 insertions(+) create mode 100644 tests/unit/tools/test_jacobian_lens_causal_swap_benchmark.py create mode 100644 transformer_lens/tools/analysis/jacobian_lens_causal_swap_benchmark.py diff --git a/tests/unit/tools/test_jacobian_lens_causal_swap_benchmark.py b/tests/unit/tools/test_jacobian_lens_causal_swap_benchmark.py new file mode 100644 index 0000000000..34a8ba2168 --- /dev/null +++ b/tests/unit/tools/test_jacobian_lens_causal_swap_benchmark.py @@ -0,0 +1,72 @@ +"""Unit tests for the causal coordinate-swap benchmark's corpus schema and answer metrics. + +Model-free: these exercise the prompt-corpus cross product and the rank/margin metric +directly on plain tensors, so no model is loaded. +""" + +import pytest +import torch + +from transformer_lens.tools.analysis.jacobian_lens_causal_swap_benchmark import ( + BenchmarkCorpus, + FunctionSpec, + compute_answer_metrics, + iter_prompt_trials, +) + + +def test_iter_prompt_trials_yields_ordered_pairs_per_function() -> None: + corpus = BenchmarkCorpus( + name="toy", + concepts=("A", "B", "C"), + functions=( + FunctionSpec( + name="f", + template="{arg} implies", + answers={"A": "a", "B": "b", "C": "c"}, + ), + ), + ) + trials = list(iter_prompt_trials(corpus)) + assert len(trials) == 6 # 3 * 2 ordered pairs, one function + assert all(t.source != t.target for t in trials) + assert {(t.source, t.target) for t in trials} == { + ("A", "B"), + ("A", "C"), + ("B", "A"), + ("B", "C"), + ("C", "A"), + ("C", "B"), + } + sample = next(t for t in trials if t.source == "A" and t.target == "B") + assert sample.prompt == "A implies" + assert sample.source_answer == "a" and sample.target_answer == "b" + + +def test_compute_answer_metrics_matches_hand_computed_rank_and_margin() -> None: + logits = torch.tensor([1.0, 5.0, 3.0, 3.0]) # target id 2 ties with id 3 for second place + metrics = compute_answer_metrics(logits, target_token_id=2) + assert metrics.top1_token_id == 1 + assert metrics.target_rank == 2 # exactly one logit (id 1) strictly greater + assert metrics.target_is_top1 is False + assert metrics.target_tied_for_top is False # not tied for the *maximum*, only for 2nd place + # Margin is against the best competitor overall (id 1, the actual top1), not the nearer tie. + assert metrics.target_logit_margin == pytest.approx(3.0 - 5.0) + + +def test_compute_answer_metrics_rejects_non_finite_or_out_of_range_target() -> None: + with pytest.raises(ValueError, match="finite"): + compute_answer_metrics(torch.tensor([1.0, float("nan")]), target_token_id=0) + with pytest.raises(ValueError, match="one-dimensional"): + compute_answer_metrics(torch.zeros(2, 2), target_token_id=0) + with pytest.raises(ValueError, match="vocabulary"): + compute_answer_metrics(torch.tensor([1.0, 2.0]), target_token_id=5) + + +def test_compute_answer_metrics_pins_deterministic_argmax_tie_semantics() -> None: + # A target tied for the global maximum: target_is_top1 follows argmax's own tie-break + # (first index), target_tied_for_top is true, and margin against itself is zero. + metrics = compute_answer_metrics(torch.tensor([3.0, 1.0, 3.0]), target_token_id=2) + assert metrics.target_rank == 1 + assert metrics.target_is_top1 is False + assert metrics.target_tied_for_top is True diff --git a/transformer_lens/tools/analysis/jacobian_lens_causal_swap_benchmark.py b/transformer_lens/tools/analysis/jacobian_lens_causal_swap_benchmark.py new file mode 100644 index 0000000000..0988f51f7a --- /dev/null +++ b/transformer_lens/tools/analysis/jacobian_lens_causal_swap_benchmark.py @@ -0,0 +1,115 @@ +"""Causal coordinate-swap benchmark for ``JacobianLens.coordinate_patch_hooks``. + +Measures whether an anchored J-space coordinate edit installed live inside a forward pass +via ``coordinate_patch_hooks`` causes a directional change in model output, under three +controls: baseline-capability filtering (only intervene on prompts the model already +answers correctly), norm-matched random-atom controls (isolate "this concept mattered" +from "any edit of similar magnitude would have mattered"), and bootstrap uncertainty on +every reported rate. + +This module is layered bottom-up and built out across several stages. This stage is +model-free: it establishes the prompt corpus schema and the rank/margin metric shared by +every later stage (baseline filtering, control-token selection, the trial runner, and +artifact serialization). +""" + +from __future__ import annotations + +import itertools +from dataclasses import dataclass +from typing import Dict, Iterator, Sequence + +import torch + + +@dataclass(frozen=True) +class FunctionSpec: + """A templated prompt function evaluated over a shared set of concepts. + + ``template`` takes a single ``{arg}`` placeholder, e.g. ``"The capital of {arg} is"``. + ``answers`` maps each concept to its answer word under this function, e.g. + ``{"France": "Paris"}``. + """ + + name: str + template: str + answers: Dict[str, str] + + +@dataclass(frozen=True) +class BenchmarkCorpus: + """A named set of concepts and the prompt functions evaluated over them.""" + + name: str + concepts: Sequence[str] + functions: Sequence[FunctionSpec] + + +@dataclass(frozen=True) +class PromptTrialSpec: + """One (function, ordered source/target concept pair) prompt instance.""" + + function: str + source: str + target: str + prompt: str + source_answer: str + target_answer: str + + +def iter_prompt_trials(corpus: BenchmarkCorpus) -> Iterator[PromptTrialSpec]: + """Yields one spec per (function, ordered source/target concept pair). + + Ordered pairs are every element of ``itertools.permutations(corpus.concepts, 2)``, the + same cross product Jacobian_Lens_Demo.ipynb's country benchmark already uses, now as + tested library code instead of a notebook cell. + """ + for function in corpus.functions: + for source, target in itertools.permutations(corpus.concepts, 2): + yield PromptTrialSpec( + function=function.name, + source=source, + target=target, + prompt=function.template.format(arg=source), + source_answer=function.answers[source], + target_answer=function.answers[target], + ) + + +@dataclass(frozen=True) +class AnswerMetrics: + """Rank/margin/tie metrics for one target token against one next-token logit vector.""" + + top1_token_id: int + target_rank: int + target_is_top1: bool + target_tied_for_top: bool + target_logit_margin: float + + +def compute_answer_metrics(logits: torch.Tensor, target_token_id: int) -> AnswerMetrics: + """Computes rank/margin/tie metrics for ``target_token_id`` against ``logits``. + + Ports Jacobian_Lens_Demo.ipynb's ``_target_metrics`` cell verbatim (arithmetic + unchanged, only renamed and restructured into a dataclass), so results stay directly + comparable with that notebook's already-reviewed success/rank definitions. + """ + if logits.ndim != 1 or logits.numel() < 2: + raise ValueError("expected one-dimensional next-token logits") + if not 0 <= target_token_id < logits.shape[0]: + raise ValueError("target token id is outside the vocabulary") + if not torch.isfinite(logits).all(): + raise ValueError("logits must be finite") + + target_logit = logits[target_token_id] + top_logit = logits.max() + top1_token_id = int(logits.argmax().item()) + top_logit_tie_count = int((logits == top_logit).sum().item()) + competitors = torch.cat((logits[:target_token_id], logits[target_token_id + 1 :])) + return AnswerMetrics( + top1_token_id=top1_token_id, + target_rank=int((logits > target_logit).sum().item()) + 1, + target_is_top1=top1_token_id == target_token_id, + target_tied_for_top=bool(target_logit == top_logit) and top_logit_tie_count > 1, + target_logit_margin=float((target_logit - competitors.max()).item()), + ) From a5e33b7b150880ea255219e52b6a65eac5e9473e Mon Sep 17 00:00:00 2001 From: janmenjayap Date: Sun, 13 Sep 2026 11:35:05 +0530 Subject: [PATCH 2/7] feat(analysis): baseline-capability filter --- ...est_jacobian_lens_causal_swap_benchmark.py | 31 +++++++++++++++++++ .../jacobian_lens_causal_swap_benchmark.py | 28 ++++++++++++++++- 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/tests/unit/tools/test_jacobian_lens_causal_swap_benchmark.py b/tests/unit/tools/test_jacobian_lens_causal_swap_benchmark.py index 34a8ba2168..25551a1ad7 100644 --- a/tests/unit/tools/test_jacobian_lens_causal_swap_benchmark.py +++ b/tests/unit/tools/test_jacobian_lens_causal_swap_benchmark.py @@ -8,9 +8,12 @@ import torch from transformer_lens.tools.analysis.jacobian_lens_causal_swap_benchmark import ( + AnswerMetrics, + BaselineRecord, BenchmarkCorpus, FunctionSpec, compute_answer_metrics, + filter_baseline_capable, iter_prompt_trials, ) @@ -70,3 +73,31 @@ def test_compute_answer_metrics_pins_deterministic_argmax_tie_semantics() -> Non assert metrics.target_rank == 1 assert metrics.target_is_top1 is False assert metrics.target_tied_for_top is True + + +def test_filter_baseline_capable_splits_by_deterministic_argmax() -> None: + correct = BaselineRecord("f", "A", "p1", AnswerMetrics(0, 1, True, False, 2.0)) + wrong = BaselineRecord("f", "B", "p2", AnswerMetrics(3, 5, False, False, -1.0)) + capable, excluded = filter_baseline_capable([correct, wrong]) + assert capable == [correct] + assert excluded == [wrong] + + +def test_filter_baseline_capable_all_wrong_excludes_every_record() -> None: + wrong = BaselineRecord("currency", "France", "p", AnswerMetrics(9, 4, False, False, -3.0)) + capable, excluded = filter_baseline_capable([wrong, wrong]) + assert capable == [] + assert len(excluded) == 2 + + +def test_filter_baseline_capable_preserves_order_and_does_not_mutate_input() -> None: + records = [ + BaselineRecord("f", "A", "p1", AnswerMetrics(0, 1, True, False, 2.0)), + BaselineRecord("f", "B", "p2", AnswerMetrics(3, 5, False, False, -1.0)), + BaselineRecord("f", "C", "p3", AnswerMetrics(0, 1, True, False, 1.0)), + ] + original = list(records) + capable, excluded = filter_baseline_capable(records) + assert [r.source for r in capable] == ["A", "C"] + assert [r.source for r in excluded] == ["B"] + assert records == original diff --git a/transformer_lens/tools/analysis/jacobian_lens_causal_swap_benchmark.py b/transformer_lens/tools/analysis/jacobian_lens_causal_swap_benchmark.py index 0988f51f7a..ee89059f47 100644 --- a/transformer_lens/tools/analysis/jacobian_lens_causal_swap_benchmark.py +++ b/transformer_lens/tools/analysis/jacobian_lens_causal_swap_benchmark.py @@ -17,7 +17,7 @@ import itertools from dataclasses import dataclass -from typing import Dict, Iterator, Sequence +from typing import Dict, Iterator, List, Sequence, Tuple import torch @@ -113,3 +113,29 @@ def compute_answer_metrics(logits: torch.Tensor, target_token_id: int) -> Answer target_tied_for_top=bool(target_logit == top_logit) and top_logit_tie_count > 1, target_logit_margin=float((target_logit - competitors.max()).item()), ) + + +@dataclass(frozen=True) +class BaselineRecord: + """A source prompt's own-answer metrics under the unperturbed baseline forward pass.""" + + function: str + source: str + prompt: str + metrics: AnswerMetrics + + +def filter_baseline_capable( + baselines: Sequence[BaselineRecord], +) -> Tuple[List[BaselineRecord], List[BaselineRecord]]: + """Splits baseline records into (capable, excluded) prompts. + + A prompt is baseline-capable when the model's own deterministic argmax already matches + the source's answer (``metrics.target_is_top1``); only such prompts are eligible for + later intervention trials, so an edit's effect is never measured against a prompt the + unperturbed model already gets wrong. Order-preserving in both outputs; never mutates + ``baselines``. + """ + capable = [record for record in baselines if record.metrics.target_is_top1] + excluded = [record for record in baselines if not record.metrics.target_is_top1] + return capable, excluded From 8b4f0b2a0c68608f688f4b68ff04083d2914f358 Mon Sep 17 00:00:00 2001 From: janmenjayap Date: Sun, 13 Sep 2026 13:32:26 +0530 Subject: [PATCH 3/7] feat(analysis): norm-matched control-token selection --- ...est_jacobian_lens_causal_swap_benchmark.py | 49 +++++++++++++++++++ .../jacobian_lens_causal_swap_benchmark.py | 44 ++++++++++++++++- 2 files changed, 92 insertions(+), 1 deletion(-) diff --git a/tests/unit/tools/test_jacobian_lens_causal_swap_benchmark.py b/tests/unit/tools/test_jacobian_lens_causal_swap_benchmark.py index 25551a1ad7..f1e3c48adb 100644 --- a/tests/unit/tools/test_jacobian_lens_causal_swap_benchmark.py +++ b/tests/unit/tools/test_jacobian_lens_causal_swap_benchmark.py @@ -15,6 +15,7 @@ compute_answer_metrics, filter_baseline_capable, iter_prompt_trials, + select_norm_matched_control_token, ) @@ -101,3 +102,51 @@ def test_filter_baseline_capable_preserves_order_and_does_not_mutate_input() -> assert [r.source for r in capable] == ["A", "C"] assert [r.source for r in excluded] == ["B"] assert records == original + + +def test_select_norm_matched_control_token_is_deterministic_given_seed() -> None: + torch.manual_seed(0) + dictionary = torch.randn(20, 4) + first = select_norm_matched_control_token( + dictionary, target_token_id=5, excluded_ids=set(), seed=1 + ) + second = select_norm_matched_control_token( + dictionary, target_token_id=5, excluded_ids=set(), seed=1 + ) + assert first == second + + +def test_select_norm_matched_control_token_respects_tolerance_and_exclusions() -> None: + dictionary = torch.zeros(5, 3) + dictionary[0] = torch.tensor([1.0, 0.0, 0.0]) # norm 1, target + dictionary[1] = torch.tensor([1.05, 0.0, 0.0]) # norm 1.05, within 10% + dictionary[2] = torch.tensor([2.0, 0.0, 0.0]) # norm 2, outside tolerance + dictionary[3] = torch.tensor([0.98, 0.0, 0.0]) # norm 0.98, within 10%, but excluded + dictionary[4] = torch.tensor([5.0, 0.0, 0.0]) # far outside tolerance + chosen = select_norm_matched_control_token( + dictionary, target_token_id=0, excluded_ids={3}, tolerance=0.1, seed=0 + ) + assert chosen == 1 + + +def test_select_norm_matched_control_token_raises_when_no_candidate_survives() -> None: + dictionary = torch.eye(3) * torch.tensor([1.0, 10.0, 100.0]).unsqueeze(1) + with pytest.raises(ValueError, match="no candidate token"): + select_norm_matched_control_token( + dictionary, target_token_id=0, excluded_ids=set(), tolerance=0.01, seed=0 + ) + + +def test_select_norm_matched_control_token_always_excludes_the_target_itself() -> None: + dictionary = torch.ones( + 3, 2 + ) # every atom has an identical norm -- target would trivially "match" itself + chosen = select_norm_matched_control_token( + dictionary, target_token_id=1, excluded_ids=set(), seed=0 + ) + assert chosen != 1 + + +def test_select_norm_matched_control_token_rejects_non_2d_dictionary() -> None: + with pytest.raises(ValueError, match="2-D"): + select_norm_matched_control_token(torch.ones(3), target_token_id=0, excluded_ids=set()) diff --git a/transformer_lens/tools/analysis/jacobian_lens_causal_swap_benchmark.py b/transformer_lens/tools/analysis/jacobian_lens_causal_swap_benchmark.py index ee89059f47..ba52d62c6f 100644 --- a/transformer_lens/tools/analysis/jacobian_lens_causal_swap_benchmark.py +++ b/transformer_lens/tools/analysis/jacobian_lens_causal_swap_benchmark.py @@ -17,7 +17,7 @@ import itertools from dataclasses import dataclass -from typing import Dict, Iterator, List, Sequence, Tuple +from typing import Container, Dict, Iterator, List, Sequence, Tuple import torch @@ -139,3 +139,45 @@ def filter_baseline_capable( capable = [record for record in baselines if record.metrics.target_is_top1] excluded = [record for record in baselines if not record.metrics.target_is_top1] return capable, excluded + + +def select_norm_matched_control_token( + dictionary: torch.Tensor, + target_token_id: int, + excluded_ids: Container[int], + *, + tolerance: float = 0.1, + seed: int = 0, +) -> int: + """Deterministically selects a norm-matched control token id. + + A candidate token id ``t`` qualifies when its ``dictionary`` atom norm is within + ``tolerance`` (relative to the target token's atom norm) and ``t`` is neither + ``target_token_id`` nor a member of ``excluded_ids``. One qualifying candidate is picked + with a seeded ``torch.Generator`` so the same ``seed`` always yields the same control + token. Raises ``ValueError`` if no candidate qualifies; the tolerance is never silently + widened and selection never falls back to the globally nearest atom. + """ + if dictionary.ndim != 2: + raise ValueError( + f"dictionary must be 2-D [num_atoms, d_model], got shape {tuple(dictionary.shape)}" + ) + atom_norms = dictionary.float().norm(dim=1) + target_norm = atom_norms[target_token_id] + within_tolerance = (atom_norms - target_norm).abs() <= tolerance * target_norm + candidates = [ + token_id + for token_id in range(dictionary.shape[0]) + if token_id != target_token_id + and token_id not in excluded_ids + and bool(within_tolerance[token_id]) + ] + if not candidates: + raise ValueError( + "no candidate token within relative tolerance " + f"{tolerance} of target_token_id={target_token_id}'s atom norm " + f"({float(target_norm):.4f})" + ) + generator = torch.Generator(device=dictionary.device).manual_seed(seed) + pick = int(torch.randint(len(candidates), (1,), generator=generator).item()) + return candidates[pick] From 348d5f41b2b1d33e87cc3ee8b2f53888393b3ee7 Mon Sep 17 00:00:00 2001 From: janmenjayap Date: Sun, 13 Sep 2026 13:50:34 +0530 Subject: [PATCH 4/7] feat(analysis): coordinate-patch causal-swap trial runner --- ...obian_lens_causal_swap_benchmark_trials.py | 228 +++++++++++++++++ .../jacobian_lens_causal_swap_benchmark.py | 235 +++++++++++++++++- 2 files changed, 458 insertions(+), 5 deletions(-) create mode 100644 tests/unit/tools/test_jacobian_lens_causal_swap_benchmark_trials.py diff --git a/tests/unit/tools/test_jacobian_lens_causal_swap_benchmark_trials.py b/tests/unit/tools/test_jacobian_lens_causal_swap_benchmark_trials.py new file mode 100644 index 0000000000..3c75d2d565 --- /dev/null +++ b/tests/unit/tools/test_jacobian_lens_causal_swap_benchmark_trials.py @@ -0,0 +1,228 @@ +"""Trial-runner tests for the causal coordinate-swap benchmark. + +Unlike the corpus/metrics/filter/control-token tests, these exercise real forward passes and +real ``model.hooks(fwd_hooks=...)`` installs against the shared ``_ToyBridge`` fixture -- a real +``TransformerBridge`` subclass, no Hugging Face download required. +""" + +from typing import Dict, Tuple + +import pytest +import torch + +from tests.unit.tools.conftest import D_MODEL, D_VOCAB, _ToyBridge +from transformer_lens.tools.analysis import JacobianLens +from transformer_lens.tools.analysis.jacobian_lens_causal_swap_benchmark import ( + BenchmarkCorpus, + FunctionSpec, + PromptTrialSpec, + run_causal_swap_benchmark, + run_causal_swap_trial, +) +from transformer_lens.tools.analysis.jacobian_lens_decomposition import ( + JSpaceDecomposition, +) + +# ``coordinate_patch_hooks`` always warns once per call, naming the layer/position counts that +# will perform a live vocabulary-scale solve; this is expected and already covered by its own +# tests (test_jacobian_lens_coordinate_patch_hooks.py), so it is not re-asserted here. +pytestmark = pytest.mark.filterwarnings("ignore::UserWarning") + +PROMPT = "a toy prompt" +SOLVE_K = 8 +# Generous on purpose: these tests exercise runner mechanics (cache sharing, skip recording, +# baseline filtering, determinism), not tolerance-matching precision, which +# test_jacobian_lens_causal_swap_benchmark.py already covers directly. +CONTROL_TOLERANCE = 4.0 + + +def _word_for_token_id(token_id: int) -> str: + """Builds a word that resolves back to ``token_id`` under the toy bridge's length-based + tokenizer (``to_single_token(s) == len(s) % D_VOCAB``, so a " "-prefixed word of length + ``token_id - 1`` (mod ``D_VOCAB``) resolves to ``token_id``).""" + length = (token_id - 1) % D_VOCAB + if length == 0: + length = D_VOCAB + return "x" * length + + +@pytest.fixture(scope="module") +def toy_bridge() -> _ToyBridge: + return _ToyBridge() + + +@pytest.fixture(scope="module") +def toy_lens() -> JacobianLens: + return JacobianLens( + {0: torch.eye(D_MODEL), 1: torch.eye(D_MODEL), 2: torch.eye(D_MODEL)}, + n_prompts=1, + d_model=D_MODEL, + ) + + +def _spec_with_active_source(lens: JacobianLens, model: _ToyBridge, layer: int) -> PromptTrialSpec: + """Builds a spec whose source concept is a real active atom in ``layer``'s support for + ``PROMPT`` -- discovered via a real decomposition rather than guessed, since the toy model's + activations are not hand-computable in advance.""" + support = lens.decompose(model, PROMPT, layer=layer, position=-1, k=SOLVE_K).support + source_id = int(support[0]) + target_id = (source_id + 1) % D_VOCAB + source_answer_id = (source_id + 2) % D_VOCAB + target_answer_id = (source_id + 3) % D_VOCAB + return PromptTrialSpec( + function="f", + source=_word_for_token_id(source_id), + target=_word_for_token_id(target_id), + prompt=PROMPT, + source_answer=_word_for_token_id(source_answer_id), + target_answer=_word_for_token_id(target_answer_id), + ) + + +def _spec_with_inactive_source( + lens: JacobianLens, model: _ToyBridge, layer: int +) -> PromptTrialSpec: + """Builds a spec whose source concept is provably absent from ``layer``'s active support + for ``PROMPT`` -- ``k=SOLVE_K < D_VOCAB`` guarantees at least one token id is left out.""" + support = { + int(token) + for token in lens.decompose(model, PROMPT, layer=layer, position=-1, k=SOLVE_K).support + } + source_id = next(token_id for token_id in range(D_VOCAB) if token_id not in support) + target_id = (source_id + 1) % D_VOCAB + source_answer_id = (source_id + 2) % D_VOCAB + target_answer_id = (source_id + 3) % D_VOCAB + return PromptTrialSpec( + function="f", + source=_word_for_token_id(source_id), + target=_word_for_token_id(target_id), + prompt=PROMPT, + source_answer=_word_for_token_id(source_answer_id), + target_answer=_word_for_token_id(target_answer_id), + ) + + +def test_run_causal_swap_trial_shares_decomposition_cache_between_real_and_control( + toy_lens: JacobianLens, toy_bridge: _ToyBridge +) -> None: + spec = _spec_with_active_source(toy_lens, toy_bridge, layer=1) + cache: Dict[Tuple[int, int, int], JSpaceDecomposition] = {} + result = run_causal_swap_trial( + toy_lens, + toy_bridge, + spec, + layer=1, + decomposition_cache=cache, + control_tolerance=CONTROL_TOLERANCE, + k=SOLVE_K, + ) + assert result.status == "ok" + assert len(cache) == 1 # one (layer, batch, position) key, reused by the control call + + +def test_run_causal_swap_trial_records_skip_without_raising_on_inactive_source( + toy_lens: JacobianLens, toy_bridge: _ToyBridge +) -> None: + spec = _spec_with_inactive_source(toy_lens, toy_bridge, layer=2) + result = run_causal_swap_trial( + toy_lens, + toy_bridge, + spec, + layer=2, + control_tolerance=CONTROL_TOLERANCE, + k=SOLVE_K, + ) + assert result.status == "skipped_source_inactive" + assert result.real_target_metrics is None + assert result.control_target_metrics is None + assert result.error is not None + + +def test_run_causal_swap_trial_populates_baseline_regardless_of_status( + toy_lens: JacobianLens, toy_bridge: _ToyBridge +) -> None: + spec = _spec_with_inactive_source(toy_lens, toy_bridge, layer=2) + result = run_causal_swap_trial( + toy_lens, + toy_bridge, + spec, + layer=2, + control_tolerance=CONTROL_TOLERANCE, + k=SOLVE_K, + ) + # The baseline forward pass has no hooks installed, so it is unaffected by the source + # being inactive for the (unrelated) intervention conditions. + assert result.baseline is not None + + +def _rigged_corpus(model: _ToyBridge) -> BenchmarkCorpus: + """One function, two concepts: "correct"'s own baseline answer is rigged to be the model's + actual top1 (baseline-capable); "wrong"'s is rigged to not be (baseline-incapable).""" + template = "prompt {arg} end" + correct_concept = "AAAA" + wrong_concept = "BBBBBB" + + def _actual_top1(concept: str) -> int: + prompt = template.format(arg=concept) + tokens = model.to_tokens(prompt) + with torch.no_grad(): + logits = model(tokens)[0, -1] + return int(logits.argmax().item()) + + correct_answer = _word_for_token_id(_actual_top1(correct_concept)) + wrong_answer = _word_for_token_id((_actual_top1(wrong_concept) + 1) % D_VOCAB) + return BenchmarkCorpus( + name="toy", + concepts=(correct_concept, wrong_concept), + functions=( + FunctionSpec( + name="f", + template=template, + answers={correct_concept: correct_answer, wrong_concept: wrong_answer}, + ), + ), + ) + + +def test_run_causal_swap_benchmark_excludes_baseline_incapable_prompts( + toy_lens: JacobianLens, toy_bridge: _ToyBridge +) -> None: + corpus = _rigged_corpus(toy_bridge) + trials, excluded = run_causal_swap_benchmark( + toy_lens, + toy_bridge, + corpus, + layers=[1], + control_tolerance=CONTROL_TOLERANCE, + k=SOLVE_K, + ) + assert len(excluded) == 1 + assert excluded[0].function == "f" and excluded[0].source == "BBBBBB" + assert all(not (t.function == "f" and t.source == "BBBBBB") for t in trials) + assert all(t.function == "f" and t.source == "AAAA" for t in trials) + + +def test_run_causal_swap_benchmark_is_deterministic_given_seed( + toy_lens: JacobianLens, toy_bridge: _ToyBridge +) -> None: + corpus = _rigged_corpus(toy_bridge) + first, first_excluded = run_causal_swap_benchmark( + toy_lens, + toy_bridge, + corpus, + layers=[1], + control_tolerance=CONTROL_TOLERANCE, + control_seed=7, + k=SOLVE_K, + ) + second, second_excluded = run_causal_swap_benchmark( + toy_lens, + toy_bridge, + corpus, + layers=[1], + control_tolerance=CONTROL_TOLERANCE, + control_seed=7, + k=SOLVE_K, + ) + assert first == second + assert first_excluded == second_excluded diff --git a/transformer_lens/tools/analysis/jacobian_lens_causal_swap_benchmark.py b/transformer_lens/tools/analysis/jacobian_lens_causal_swap_benchmark.py index ba52d62c6f..47fbec03d1 100644 --- a/transformer_lens/tools/analysis/jacobian_lens_causal_swap_benchmark.py +++ b/transformer_lens/tools/analysis/jacobian_lens_causal_swap_benchmark.py @@ -7,20 +7,36 @@ from "any edit of similar magnitude would have mattered"), and bootstrap uncertainty on every reported rate. -This module is layered bottom-up and built out across several stages. This stage is -model-free: it establishes the prompt corpus schema and the rank/margin metric shared by -every later stage (baseline filtering, control-token selection, the trial runner, and -artifact serialization). +This module is layered bottom-up and built out across several stages: the model-free prompt +corpus and rank/margin metric, baseline-capability filtering, norm-matched control-token +selection, and this stage's per-trial runner, which wires the first three together with real +``coordinate_patch_hooks`` calls against a live model. """ from __future__ import annotations import itertools from dataclasses import dataclass -from typing import Container, Dict, Iterator, List, Sequence, Tuple +from typing import ( + Any, + Container, + Dict, + Iterator, + List, + Literal, + MutableMapping, + Optional, + Sequence, + Tuple, +) import torch +from transformer_lens.tools.analysis.jacobian_lens import DEFAULT_K, JacobianLens +from transformer_lens.tools.analysis.jacobian_lens_decomposition import ( + JSpaceDecomposition, +) + @dataclass(frozen=True) class FunctionSpec: @@ -181,3 +197,212 @@ def select_norm_matched_control_token( generator = torch.Generator(device=dictionary.device).manual_seed(seed) pick = int(torch.randint(len(candidates), (1,), generator=generator).item()) return candidates[pick] + + +def _resolve_answer_token_id(model: Any, word: str) -> int: + """Resolves a concept or answer word to the token id it maps to as a continuation. + + Prepends a leading space so the id matches how the word tokenizes when it follows + other prompt text (e.g. " Paris", not "Paris"), the same convention the corpus + templates themselves rely on. + """ + return int(model.to_single_token(f" {word}")) + + +@dataclass(frozen=True) +class TrialResult: + """One ``(function, source, target, layer)`` causal-swap trial's full record.""" + + function: str + source: str + target: str + layer: int + status: Literal["ok", "skipped_source_inactive"] + baseline: AnswerMetrics + real_target_metrics: Optional[AnswerMetrics] + control_token_id: Optional[int] + control_target_metrics: Optional[AnswerMetrics] + error: Optional[str] + + +def run_causal_swap_trial( + lens: JacobianLens, + model: Any, + trial_spec: PromptTrialSpec, + layer: int, + *, + decomposition_cache: Optional[MutableMapping[Tuple[int, int, int], JSpaceDecomposition]] = None, + control_tolerance: float = 0.1, + control_seed: int = 0, + alpha: float = 1.0, + k: int = DEFAULT_K, +) -> TrialResult: + """Runs one causal-swap trial: baseline, then real and control coordinate-patch conditions. + + A baseline forward pass scores the prompt's own (unperturbed) source answer. A + norm-matched control token is then selected from ``layer``'s lens-vector dictionary, + excluding the source token, the real target token, and both prompts' answer tokens. The + real and control conditions each install ``coordinate_patch_hooks`` at ``layer`` and + position ``-1``, sharing one ``decomposition_cache`` so only the first of the two performs + the vocabulary-scale decomposition; both are scored against the target's own answer token, + so a real-vs-control gap isolates "swapping toward this concept mattered" from "any + edit of this magnitude would have mattered." + + If either condition's ``coordinate_patch_hooks`` call raises ``ValueError`` (the source is + not in the active support at this layer), the trial is recorded with + ``status="skipped_source_inactive"`` and the caught message in ``error``, rather than + propagating the exception -- ``coordinate_patch_hooks`` itself stays fail-fast; only this + harness catches the failure. ``coordinate_patch_hooks``'s own ``UserWarning``s (both the + per-call install notice and any solver-side conditioning warning) are not suppressed here + and propagate to the caller unchanged. + + Args: + lens: The fitted lens. + model: The model to run trials against. + trial_spec: The prompt, source/target concepts, and their answer words. + layer: The single layer to patch at. + decomposition_cache: Shared cache passed to both the real and control + ``coordinate_patch_hooks`` calls. A fresh cache is used if omitted. + control_tolerance: Relative tolerance for the norm-matched control token. + control_seed: Seed for the control token's deterministic selection. + alpha: Interpolation strength forwarded to ``coordinate_patch_hooks``. + k: Sparse-solver upper bound forwarded to ``coordinate_patch_hooks``. + + Returns: + The trial's :class:`TrialResult`. + """ + if decomposition_cache is None: + decomposition_cache = {} + tokens = model.to_tokens(trial_spec.prompt) + source_id = _resolve_answer_token_id(model, trial_spec.source) + target_id = _resolve_answer_token_id(model, trial_spec.target) + source_answer_id = _resolve_answer_token_id(model, trial_spec.source_answer) + target_answer_id = _resolve_answer_token_id(model, trial_spec.target_answer) + + with torch.no_grad(): + baseline_logits = model(tokens)[0, -1].float() + baseline_metrics = compute_answer_metrics(baseline_logits, source_answer_id) + + dictionary = lens.lens_vector_dictionary(model, layer) + control_token_id = select_norm_matched_control_token( + dictionary, + target_id, + excluded_ids={source_id, source_answer_id, target_answer_id}, + tolerance=control_tolerance, + seed=control_seed, + ) + + def _condition_metrics(condition_target_id: int) -> AnswerMetrics: + hooks = lens.coordinate_patch_hooks( + model, + source_id, + condition_target_id, + layers=[layer], + positions=[-1], + decomposition_cache=decomposition_cache, + k=k, + alpha=alpha, + ) + with model.hooks(fwd_hooks=hooks), torch.no_grad(): + condition_logits = model(tokens)[0, -1].float() + return compute_answer_metrics(condition_logits, target_answer_id) + + try: + real_metrics = _condition_metrics(target_id) + control_metrics = _condition_metrics(control_token_id) + except ValueError as exc: + return TrialResult( + function=trial_spec.function, + source=trial_spec.source, + target=trial_spec.target, + layer=layer, + status="skipped_source_inactive", + baseline=baseline_metrics, + real_target_metrics=None, + control_token_id=control_token_id, + control_target_metrics=None, + error=str(exc), + ) + + return TrialResult( + function=trial_spec.function, + source=trial_spec.source, + target=trial_spec.target, + layer=layer, + status="ok", + baseline=baseline_metrics, + real_target_metrics=real_metrics, + control_token_id=control_token_id, + control_target_metrics=control_metrics, + error=None, + ) + + +def run_causal_swap_benchmark( + lens: JacobianLens, + model: Any, + corpus: BenchmarkCorpus, + layers: Sequence[int], + **trial_kwargs: Any, +) -> Tuple[List[TrialResult], List[BaselineRecord]]: + """Runs the full causal-swap sweep: baseline filtering, then every surviving trial. + + Each ``(function, source)`` prompt's baseline is computed once -- it does not depend on + ``layer`` -- and only prompts that survive :func:`filter_baseline_capable` proceed to + :func:`run_causal_swap_trial`, once per remaining ``layer``. Each trial gets its own fresh + ``decomposition_cache``: the cache key is ``(layer, batch_idx, position)``, which collides + across different prompts run as independent single-example forward passes, so a cache may + only be reused within one trial's real/control pair, never across trials. + + Args: + lens: The fitted lens. + model: The model to run trials against. + corpus: The prompt corpus to sweep. + layers: Layers to sweep as an independent trial dimension. + **trial_kwargs: Forwarded to :func:`run_causal_swap_trial` (``control_tolerance``, + ``control_seed``, ``alpha``, ``k``; ``decomposition_cache`` is not accepted here + since each trial always uses its own). + + Returns: + ``(trials, excluded_baselines)``. + """ + all_specs = list(iter_prompt_trials(corpus)) + specs_by_prompt: Dict[Tuple[str, str], List[PromptTrialSpec]] = {} + baselines: List[BaselineRecord] = [] + for spec in all_specs: + prompt_key = (spec.function, spec.source) + if prompt_key not in specs_by_prompt: + specs_by_prompt[prompt_key] = [] + tokens = model.to_tokens(spec.prompt) + with torch.no_grad(): + baseline_logits = model(tokens)[0, -1].float() + source_answer_id = _resolve_answer_token_id(model, spec.source_answer) + baselines.append( + BaselineRecord( + function=spec.function, + source=spec.source, + prompt=spec.prompt, + metrics=compute_answer_metrics(baseline_logits, source_answer_id), + ) + ) + specs_by_prompt[prompt_key].append(spec) + + capable, excluded = filter_baseline_capable(baselines) + capable_prompt_keys = {(record.function, record.source) for record in capable} + + trials: List[TrialResult] = [] + for layer in layers: + for prompt_key, specs in specs_by_prompt.items(): + if prompt_key not in capable_prompt_keys: + continue + for spec in specs: + trials.append( + run_causal_swap_trial( + lens, + model, + spec, + layer, + **trial_kwargs, + ) + ) + return trials, excluded From eb2de5756201db6b57b8472c6026d451e2b96735 Mon Sep 17 00:00:00 2001 From: janmenjayap Date: Sun, 13 Sep 2026 14:07:35 +0530 Subject: [PATCH 5/7] feat(analysis): bootstrap CI and frozen artifact schema --- ...est_jacobian_lens_causal_swap_benchmark.py | 144 ++++++++++++++++ .../jacobian_lens_causal_swap_benchmark.py | 158 +++++++++++++++++- 2 files changed, 301 insertions(+), 1 deletion(-) diff --git a/tests/unit/tools/test_jacobian_lens_causal_swap_benchmark.py b/tests/unit/tools/test_jacobian_lens_causal_swap_benchmark.py index f1e3c48adb..d60a5c0b22 100644 --- a/tests/unit/tools/test_jacobian_lens_causal_swap_benchmark.py +++ b/tests/unit/tools/test_jacobian_lens_causal_swap_benchmark.py @@ -4,18 +4,30 @@ directly on plain tensors, so no model is loaded. """ +import dataclasses +import hashlib +import json +from typing import Any, Dict, List + import pytest import torch from transformer_lens.tools.analysis.jacobian_lens_causal_swap_benchmark import ( + SCHEMA_VERSION, AnswerMetrics, BaselineRecord, BenchmarkCorpus, FunctionSpec, + TrialResult, + bootstrap_success_rate_ci, + build_protocol_manifest, compute_answer_metrics, filter_baseline_capable, + fingerprint_manifest, iter_prompt_trials, + load_artifact, select_norm_matched_control_token, + serialize_artifact, ) @@ -150,3 +162,135 @@ def test_select_norm_matched_control_token_always_excludes_the_target_itself() - def test_select_norm_matched_control_token_rejects_non_2d_dictionary() -> None: with pytest.raises(ValueError, match="2-D"): select_norm_matched_control_token(torch.ones(3), target_token_id=0, excluded_ids=set()) + + +def test_bootstrap_success_rate_ci_bounds_bracket_point_estimate_and_lie_in_unit_interval() -> None: + successes = [True, True, False, True, False, True, True, False] + result = bootstrap_success_rate_ci(successes, n_resamples=2000, seed=0) + assert result.ci_low <= result.point_estimate <= result.ci_high + assert 0.0 <= result.ci_low and result.ci_high <= 1.0 + assert result.point_estimate == pytest.approx(sum(successes) / len(successes)) + + +def test_bootstrap_success_rate_ci_is_deterministic_given_seed() -> None: + successes = [True, False, True] + first = bootstrap_success_rate_ci(successes, seed=3) + second = bootstrap_success_rate_ci(successes, seed=3) + assert first == second + + +def test_bootstrap_success_rate_ci_rejects_empty_input() -> None: + with pytest.raises(ValueError, match="empty"): + bootstrap_success_rate_ci([]) + + +def test_fingerprint_manifest_matches_the_notebook_recipe() -> None: + manifest = {"b": 2, "a": 1} + expected = hashlib.sha256( + json.dumps(manifest, sort_keys=True, separators=(",", ":")).encode() + ).hexdigest() + assert fingerprint_manifest(manifest) == expected + + +def test_build_protocol_manifest_rejects_missing_required_field() -> None: + with pytest.raises(ValueError, match="model_id"): + build_protocol_manifest(model_revision="x") + + +def _full_manifest_fields(**overrides: Any) -> Dict[str, Any]: + fields: Dict[str, Any] = dict( + model_id="gpt2", + model_revision="x", + lens_repo="r", + lens_file="f", + lens_revision="y", + corpus_name="toy", + layers=[1], + alpha=1.0, + k=8, + control_tolerance=0.1, + control_seed=0, + success_definition="target token id equals deterministic argmax token id", + baseline_definition="source answer token id equals deterministic argmax token id", + rank_definition="1 + count(logits strictly greater than target logit)", + ) + fields.update(overrides) + return fields + + +def test_serialize_then_load_artifact_round_trips(tmp_path) -> None: + manifest = build_protocol_manifest(**_full_manifest_fields()) + trials: List[TrialResult] = [] + excluded: List[BaselineRecord] = [] + real_ci = bootstrap_success_rate_ci([True, False]) + control_ci = bootstrap_success_rate_ci([False, False]) + artifact = serialize_artifact(manifest, trials, excluded, real_ci, control_ci) + path = tmp_path / "artifact.json" + path.write_text(json.dumps(artifact)) + loaded = load_artifact(path) + assert loaded["protocol_fingerprint"] == artifact["protocol_fingerprint"] + assert loaded["schema_version"] == SCHEMA_VERSION + + +def test_serialize_artifact_round_trips_trial_and_baseline_records(tmp_path) -> None: + manifest = build_protocol_manifest(**_full_manifest_fields(layers=[6])) + trial = TrialResult( + function="capital", + source="France", + target="China", + layer=6, + status="ok", + baseline=AnswerMetrics(0, 1, True, False, 2.0), + real_target_metrics=AnswerMetrics(1, 1, True, False, 0.5), + control_token_id=42, + control_target_metrics=AnswerMetrics(2, 3, False, False, -0.1), + error=None, + ) + excluded = [ + BaselineRecord("currency", "Egypt", "prompt", AnswerMetrics(9, 4, False, False, -3.0)) + ] + real_ci = bootstrap_success_rate_ci([True]) + control_ci = bootstrap_success_rate_ci([False]) + artifact = serialize_artifact(manifest, [trial], excluded, real_ci, control_ci) + path = tmp_path / "artifact.json" + path.write_text(json.dumps(artifact)) + loaded = load_artifact(path) + assert loaded["trials"] == [dataclasses.asdict(trial)] + assert loaded["excluded_baselines"] == [dataclasses.asdict(excluded[0])] + + +def test_load_artifact_rejects_tampered_fingerprint(tmp_path) -> None: + manifest = build_protocol_manifest(**_full_manifest_fields(layers=[1])) + artifact = serialize_artifact( + manifest, [], [], bootstrap_success_rate_ci([True]), bootstrap_success_rate_ci([False]) + ) + artifact["protocol_manifest"]["layers"] = [2] + path = tmp_path / "bad.json" + path.write_text(json.dumps(artifact)) + with pytest.raises(ValueError, match="fingerprint"): + load_artifact(path) + + +def test_load_artifact_rejects_wrong_schema_version(tmp_path) -> None: + manifest = build_protocol_manifest(**_full_manifest_fields()) + artifact = serialize_artifact( + manifest, [], [], bootstrap_success_rate_ci([True]), bootstrap_success_rate_ci([False]) + ) + artifact["schema_version"] = SCHEMA_VERSION + 1 + artifact["protocol_fingerprint"] = fingerprint_manifest(artifact["protocol_manifest"]) + path = tmp_path / "bad_version.json" + path.write_text(json.dumps(artifact)) + with pytest.raises(ValueError, match="schema_version"): + load_artifact(path) + + +def test_load_artifact_rejects_missing_required_key(tmp_path) -> None: + manifest = build_protocol_manifest(**_full_manifest_fields()) + artifact = serialize_artifact( + manifest, [], [], bootstrap_success_rate_ci([True]), bootstrap_success_rate_ci([False]) + ) + del artifact["excluded_baselines"] + path = tmp_path / "bad_missing.json" + path.write_text(json.dumps(artifact)) + with pytest.raises(ValueError, match="excluded_baselines"): + load_artifact(path) diff --git a/transformer_lens/tools/analysis/jacobian_lens_causal_swap_benchmark.py b/transformer_lens/tools/analysis/jacobian_lens_causal_swap_benchmark.py index 47fbec03d1..43a5c88890 100644 --- a/transformer_lens/tools/analysis/jacobian_lens_causal_swap_benchmark.py +++ b/transformer_lens/tools/analysis/jacobian_lens_causal_swap_benchmark.py @@ -15,8 +15,11 @@ from __future__ import annotations +import hashlib import itertools -from dataclasses import dataclass +import json +from dataclasses import asdict, dataclass +from pathlib import Path from typing import ( Any, Container, @@ -30,6 +33,7 @@ Tuple, ) +import numpy as np import torch from transformer_lens.tools.analysis.jacobian_lens import DEFAULT_K, JacobianLens @@ -406,3 +410,155 @@ def run_causal_swap_benchmark( ) ) return trials, excluded + + +@dataclass(frozen=True) +class BootstrapResult: + """A percentile-bootstrap confidence interval around a success rate.""" + + point_estimate: float + ci_low: float + ci_high: float + n_resamples: int + confidence: float + + +def bootstrap_success_rate_ci( + successes: Sequence[bool], + *, + n_resamples: int = 10_000, + confidence: float = 0.95, + seed: int = 0, +) -> BootstrapResult: + """Computes a seeded percentile-bootstrap confidence interval for a success rate. + + Resamples trial indices with replacement ``n_resamples`` times using + ``numpy.random.default_rng(seed)`` (the reproducibility convention + :func:`~transformer_lens.tools.analysis.jacobian_lens_decomposition.estimate_occupancy` + already uses for its own random controls), and reports the ``confidence`` central + interval of the resampled success rates around the observed point estimate. + + Raises: + ValueError: If ``successes`` is empty. + """ + if len(successes) == 0: + raise ValueError("successes must be a non-empty sequence") + values = np.asarray([bool(success) for success in successes], dtype=np.float64) + n = values.shape[0] + point_estimate = float(values.mean()) + rng = np.random.default_rng(seed) + resample_indices = rng.integers(0, n, size=(n_resamples, n)) + resample_rates = values[resample_indices].mean(axis=1) + tail = (1.0 - confidence) / 2.0 + ci_low = float(np.quantile(resample_rates, tail)) + ci_high = float(np.quantile(resample_rates, 1.0 - tail)) + return BootstrapResult( + point_estimate=point_estimate, + ci_low=ci_low, + ci_high=ci_high, + n_resamples=n_resamples, + confidence=confidence, + ) + + +_REQUIRED_MANIFEST_FIELDS = ( + "model_id", + "model_revision", + "lens_repo", + "lens_file", + "lens_revision", + "corpus_name", + "layers", + "alpha", + "k", + "control_tolerance", + "control_seed", + "success_definition", + "baseline_definition", + "rank_definition", +) + + +def build_protocol_manifest(**fields: Any) -> Dict[str, Any]: + """Assembles a protocol manifest, requiring the benchmark's fixed field set. + + Requires at least :data:`_REQUIRED_MANIFEST_FIELDS`, the same key set (and, where they + overlap, the same string values) as ``Jacobian_Lens_Demo.ipynb``'s existing + ``protocol_manifest`` cell. + + Raises: + ValueError: If any required field is missing, naming the missing field(s). + """ + missing = [name for name in _REQUIRED_MANIFEST_FIELDS if name not in fields] + if missing: + raise ValueError(f"protocol manifest is missing required field(s): {', '.join(missing)}") + return dict(fields) + + +def fingerprint_manifest(manifest: Dict[str, Any]) -> str: + """Fingerprints a protocol manifest with the recipe ``Jacobian_Lens_Demo.ipynb`` uses.""" + return hashlib.sha256( + json.dumps(manifest, sort_keys=True, separators=(",", ":")).encode() + ).hexdigest() + + +SCHEMA_VERSION = 1 + + +def serialize_artifact( + manifest: Dict[str, Any], + trials: Sequence[TrialResult], + excluded_baselines: Sequence[BaselineRecord], + real_ci: BootstrapResult, + control_ci: BootstrapResult, +) -> Dict[str, Any]: + """Assembles a JSON-serializable artifact dict from a benchmark run's results.""" + return { + "schema_version": SCHEMA_VERSION, + "protocol_manifest": manifest, + "protocol_fingerprint": fingerprint_manifest(manifest), + "trials": [asdict(trial) for trial in trials], + "excluded_baselines": [asdict(record) for record in excluded_baselines], + "real_success_ci": asdict(real_ci), + "control_success_ci": asdict(control_ci), + } + + +_REQUIRED_ARTIFACT_FIELDS = ( + "schema_version", + "protocol_manifest", + "protocol_fingerprint", + "trials", + "excluded_baselines", + "real_success_ci", + "control_success_ci", +) + + +def load_artifact(path: Path) -> Dict[str, Any]: + """Reads and validates a frozen artifact produced by :func:`serialize_artifact`. + + Validates that every required top-level key is present, that ``schema_version`` + matches :data:`SCHEMA_VERSION`, and that ``protocol_fingerprint`` matches a fresh + :func:`fingerprint_manifest` of the loaded ``protocol_manifest`` -- catching a + hand-edited or corrupted artifact rather than trusting the stored fingerprint blindly. + + Raises: + ValueError: Naming the missing or mismatched field. + """ + artifact = json.loads(Path(path).read_text()) + missing = [name for name in _REQUIRED_ARTIFACT_FIELDS if name not in artifact] + if missing: + raise ValueError(f"artifact is missing required field(s): {', '.join(missing)}") + if artifact["schema_version"] != SCHEMA_VERSION: + raise ValueError( + f"artifact schema_version {artifact['schema_version']!r} does not match the " + f"expected {SCHEMA_VERSION!r}" + ) + expected_fingerprint = fingerprint_manifest(artifact["protocol_manifest"]) + if artifact["protocol_fingerprint"] != expected_fingerprint: + raise ValueError( + "artifact protocol_fingerprint does not match a freshly computed fingerprint of " + "its protocol_manifest (the manifest may have been hand-edited or corrupted)" + ) + return artifact From 9ab12539f41c637c8ae5825302d8e87e35497689 Mon Sep 17 00:00:00 2001 From: janmenjayap Date: Sat, 19 Sep 2026 11:38:12 +0530 Subject: [PATCH 6/7] docs(notebook): causal-swap benchmark for coordinate_patch_hooks Add the generation entry point (module main()), a cached-GPT-2 integration smoke test, the frozen GPT-2-small benchmark artifact, and a notebook that loads that artifact only and never calls the model. Establish demos/data/ as the directory for notebook-adjacent frozen data files. Register the new notebook in the nbval CI matrix, the docs make_docs copy list, and the docs index, and add a Causal-swap benchmark subsection to jacobian_lens_fitting.md with the interpretation caveats. Export run_causal_swap_benchmark, BenchmarkCorpus, FunctionSpec, bootstrap_success_rate_ci, and load_artifact from the analysis package. The artifact is regenerable with: uv run python -m transformer_lens.tools.analysis.jacobian_lens_causal_swap_benchmark --- .github/workflows/checks.yml | 1 + ...Lens_Coordinate_Patch_Benchmark_Demo.ipynb | 639 +++ ...obian_lens_causal_swap_benchmark_gpt2.json | 3806 +++++++++++++++++ docs/make_docs.py | 1 + docs/source/content/jacobian_lens_fitting.md | 18 + docs/source/index.md | 1 + ...est_jacobian_lens_causal_swap_benchmark.py | 100 + transformer_lens/tools/analysis/__init__.py | 16 + .../jacobian_lens_causal_swap_benchmark.py | 145 +- 9 files changed, 4723 insertions(+), 4 deletions(-) create mode 100644 demos/Jacobian_Lens_Coordinate_Patch_Benchmark_Demo.ipynb create mode 100644 demos/data/jacobian_lens_causal_swap_benchmark_gpt2.json create mode 100644 tests/integration/test_jacobian_lens_causal_swap_benchmark.py diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 3cb3384936..450c4e01ee 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -436,6 +436,7 @@ jobs: # - "Grokking_Demo" - "Head_Detector_Demo" # - "Interactive_Neuroscope" + - "Jacobian_Lens_Coordinate_Patch_Benchmark_Demo" - "Main_Demo" # - "No_Position_Experiment" - "Othello_GPT" diff --git a/demos/Jacobian_Lens_Coordinate_Patch_Benchmark_Demo.ipynb b/demos/Jacobian_Lens_Coordinate_Patch_Benchmark_Demo.ipynb new file mode 100644 index 0000000000..63ef06211a --- /dev/null +++ b/demos/Jacobian_Lens_Coordinate_Patch_Benchmark_Demo.ipynb @@ -0,0 +1,639 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "db1e254e", + "metadata": {}, + "source": [ + "\"Open" + ] + }, + { + "cell_type": "markdown", + "id": "d2e56114", + "metadata": {}, + "source": [ + "# Coordinate-patch causal-swap benchmark\n", + "\n", + "`JacobianLens.coordinate_patch_hooks` installs an anchored J-space coordinate edit live\n", + "inside a forward pass. This notebook asks whether that edit causes a directional change in\n", + "model output, under three controls:\n", + "\n", + "- **Baseline-capability filtering.** A prompt only enters the intervention trials if the\n", + " unperturbed model already answers it correctly; a swap is never scored against a prompt\n", + " the model already gets wrong.\n", + "- **Norm-matched random-atom control.** Every real trial (patch toward the actual target\n", + " concept) is paired with a control trial that patches toward a token whose lens-dictionary\n", + " atom norm matches the real target's within a fixed relative tolerance. This isolates\n", + " \"swapping toward this concept mattered\" from \"any coordinate edit of this magnitude would\n", + " have mattered.\"\n", + "- **Bootstrap confidence intervals.** Every reported success rate carries a seeded\n", + " percentile-bootstrap interval, not a bare point estimate.\n", + "\n", + "Each trial installs `coordinate_patch_hooks` at exactly **one** layer and the final prompt\n", + "position -- a single-layer intervention, not a multi-layer band. A trial whose source concept\n", + "is not active in that layer's support is recorded as skipped, not silently dropped and not\n", + "counted as a failure.\n", + "\n", + "**This notebook loads a frozen artifact and never calls the model.** The artifact was\n", + "generated once, out-of-band, by running this module as a script; see its `main()` docstring\n", + "for the exact command. Re-running the sweep is a separate, explicit step, not something this\n", + "notebook triggers." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "8a272a14", + "metadata": { + "execution": { + "iopub.execute_input": "2026-09-13T09:18:45.508917Z", + "iopub.status.busy": "2026-09-13T09:18:45.508832Z", + "iopub.status.idle": "2026-09-13T09:18:45.606558Z", + "shell.execute_reply": "2026-09-13T09:18:45.606012Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Running as a Jupyter notebook - intended for development only!\n" + ] + } + ], + "source": [ + "# NBVAL_IGNORE_OUTPUT\n", + "import os\n", + "\n", + "DEVELOPMENT_MODE = False\n", + "IN_GITHUB = os.getenv(\"GITHUB_ACTIONS\") == \"true\"\n", + "try:\n", + " import google.colab\n", + "\n", + " IN_COLAB = True\n", + " print(\"Running as a Colab notebook\")\n", + "except ImportError:\n", + " IN_COLAB = False\n", + " print(\"Running as a Jupyter notebook - intended for development only!\")\n", + " DEVELOPMENT_MODE = True\n", + " from IPython import get_ipython\n", + "\n", + " ipython = get_ipython()\n", + " ipython.run_line_magic(\"load_ext\", \"autoreload\")\n", + " ipython.run_line_magic(\"autoreload\", \"2\")\n", + "\n", + "if IN_COLAB or IN_GITHUB:\n", + " %pip install transformer_lens" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "bc924b1c", + "metadata": { + "execution": { + "iopub.execute_input": "2026-09-13T09:18:45.607950Z", + "iopub.status.busy": "2026-09-13T09:18:45.607851Z", + "iopub.status.idle": "2026-09-13T09:18:48.738394Z", + "shell.execute_reply": "2026-09-13T09:18:48.737884Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "schema_version=1\n", + "protocol_fingerprint=deae49a4df19fb44f8bed71db87b6bd6c09e5ca5c0e5531ba8bb3926b5a46b7d\n", + "model=gpt2 lens=neuronpedia/jacobian-lens/gpt2-small/jlens/Salesforce-wikitext/gpt2_jacobian_lens.pt @a4114d7752d11eb546e6cf372213d7e75526d3a1\n", + "corpus=countries layers=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] alpha=1.0\n" + ] + } + ], + "source": [ + "from pathlib import Path\n", + "\n", + "import numpy as np\n", + "import pandas as pd\n", + "\n", + "import transformer_lens\n", + "from transformer_lens.tools.analysis import bootstrap_success_rate_ci, load_artifact\n", + "\n", + "REPO_ROOT = Path(transformer_lens.__file__).resolve().parents[1]\n", + "ARTIFACT_PATH = REPO_ROOT / \"demos\" / \"data\" / \"jacobian_lens_causal_swap_benchmark_gpt2.json\"\n", + "\n", + "artifact = load_artifact(ARTIFACT_PATH)\n", + "manifest = artifact[\"protocol_manifest\"]\n", + "print(f\"schema_version={artifact['schema_version']}\")\n", + "print(f\"protocol_fingerprint={artifact['protocol_fingerprint']}\")\n", + "print(\n", + " f\"model={manifest['model_id']} lens={manifest['lens_repo']}/{manifest['lens_file']} \"\n", + " f\"@{manifest['lens_revision']}\"\n", + ")\n", + "print(f\"corpus={manifest['corpus_name']} layers={manifest['layers']} alpha={manifest['alpha']}\")" + ] + }, + { + "cell_type": "markdown", + "id": "7f469199", + "metadata": {}, + "source": [ + "## Baseline coverage and per-function success\n", + "\n", + "The unconditional country/function corpus is reused from the existing `swap_hooks`\n", + "country-swap demo; here it runs against GPT-2-small rather than gemma-2-2b, and only prompts\n", + "that survive the baseline-capability filter reach the intervention trials below.\n", + "\n", + "`ok_trials` counts trials where the source concept was active in the patched layer's support\n", + "(so a real and control condition both ran); every other surviving-baseline trial was skipped\n", + "because the source concept was inactive there. A function with no `ok_trials` still has its\n", + "excluded-baseline count reported -- it is not silently omitted." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "1feb4158", + "metadata": { + "execution": { + "iopub.execute_input": "2026-09-13T09:18:48.739662Z", + "iopub.status.busy": "2026-09-13T09:18:48.739505Z", + "iopub.status.idle": "2026-09-13T09:18:48.814685Z", + "shell.execute_reply": "2026-09-13T09:18:48.814251Z" + } + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
functionexcluded_baseline_promptsok_trialsreal_successcontrol_success
0capital30n/an/a
1continent260% [0%, 0%]0% [0%, 0%]
2currency40n/an/a
3language10n/an/a
4overall1060% [0%, 0%]0% [0%, 0%]
\n", + "
" + ], + "text/plain": [ + " function excluded_baseline_prompts ok_trials real_success \\\n", + "0 capital 3 0 n/a \n", + "1 continent 2 6 0% [0%, 0%] \n", + "2 currency 4 0 n/a \n", + "3 language 1 0 n/a \n", + "4 overall 10 6 0% [0%, 0%] \n", + "\n", + " control_success \n", + "0 n/a \n", + "1 0% [0%, 0%] \n", + "2 n/a \n", + "3 n/a \n", + "4 0% [0%, 0%] " + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "trials_df = pd.DataFrame(artifact[\"trials\"])\n", + "excluded_df = pd.DataFrame(artifact[\"excluded_baselines\"])\n", + "\n", + "ok_df = trials_df[trials_df[\"status\"] == \"ok\"].copy()\n", + "ok_df[\"real_success\"] = ok_df[\"real_target_metrics\"].apply(lambda m: m[\"target_is_top1\"])\n", + "ok_df[\"control_success\"] = ok_df[\"control_target_metrics\"].apply(lambda m: m[\"target_is_top1\"])\n", + "ok_df[\"baseline_rank\"] = ok_df[\"baseline\"].apply(lambda m: m[\"target_rank\"])\n", + "ok_df[\"real_rank\"] = ok_df[\"real_target_metrics\"].apply(lambda m: m[\"target_rank\"])\n", + "ok_df[\"control_rank\"] = ok_df[\"control_target_metrics\"].apply(lambda m: m[\"target_rank\"])\n", + "\n", + "functions = sorted(set(trials_df[\"function\"]) | set(excluded_df[\"function\"]))\n", + "\n", + "\n", + "def _rate_with_ci(successes):\n", + " ci = bootstrap_success_rate_ci(successes)\n", + " return f\"{ci.point_estimate:.0%} [{ci.ci_low:.0%}, {ci.ci_high:.0%}]\"\n", + "\n", + "\n", + "summary_rows = []\n", + "for function in functions:\n", + " n_excluded = int((excluded_df[\"function\"] == function).sum()) if len(excluded_df) else 0\n", + " subset = ok_df[ok_df[\"function\"] == function]\n", + " summary_rows.append(\n", + " {\n", + " \"function\": function,\n", + " \"excluded_baseline_prompts\": n_excluded,\n", + " \"ok_trials\": len(subset),\n", + " \"real_success\": (\n", + " _rate_with_ci(subset[\"real_success\"].tolist()) if len(subset) else \"n/a\"\n", + " ),\n", + " \"control_success\": (\n", + " _rate_with_ci(subset[\"control_success\"].tolist()) if len(subset) else \"n/a\"\n", + " ),\n", + " }\n", + " )\n", + "\n", + "overall_real_ci = artifact[\"real_success_ci\"]\n", + "overall_control_ci = artifact[\"control_success_ci\"]\n", + "summary_rows.append(\n", + " {\n", + " \"function\": \"overall\",\n", + " \"excluded_baseline_prompts\": len(excluded_df),\n", + " \"ok_trials\": len(ok_df),\n", + " \"real_success\": (\n", + " f\"{overall_real_ci['point_estimate']:.0%} \"\n", + " f\"[{overall_real_ci['ci_low']:.0%}, {overall_real_ci['ci_high']:.0%}]\"\n", + " ),\n", + " \"control_success\": (\n", + " f\"{overall_control_ci['point_estimate']:.0%} \"\n", + " f\"[{overall_control_ci['ci_low']:.0%}, {overall_control_ci['ci_high']:.0%}]\"\n", + " ),\n", + " }\n", + ")\n", + "\n", + "summary_table = pd.DataFrame(summary_rows)\n", + "summary_table" + ] + }, + { + "cell_type": "markdown", + "id": "b6a3a97f", + "metadata": {}, + "source": [ + "## Visual summary\n", + "\n", + "Real (patch toward the actual target concept) versus control (patch toward a norm-matched\n", + "random token) success by function. A function with no surviving active-support trials is\n", + "marked **n/a** rather than plotted as zero." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "c74c1711", + "metadata": { + "execution": { + "iopub.execute_input": "2026-09-13T09:18:48.816090Z", + "iopub.status.busy": "2026-09-13T09:18:48.815995Z", + "iopub.status.idle": "2026-09-13T09:18:50.454182Z", + "shell.execute_reply": "2026-09-13T09:18:50.453757Z" + } + }, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAxYAAAG+CAYAAAAObpINAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjgsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvwVt1zgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAYINJREFUeJzt3QeUE9X7//GH3nsVREBBUHovShFBEBSxIqIgNlBRxIJgQ1DBhqKCoiLYKSoqKhZEFBAEBUX0S7HQBelVpW3+53P/Z/JLstndZLPL7ibv1zmBzWQyuZncmbnPbZPL5/P5DAAAAABikDuWNwMAAAAAgQUAAACADEGLBQAAAICYEVgAAAAAiBmBBQAAAICYEVgAAAAAiBmBBQAAAICYEVgAAAAAiBmBBQAAAICYEVgg21i3bp3lypXLXn31Vf+yBx980C1LBPqe+r5IXNWqVbPzzjsv0z/n77//tksuucTKlCnj8t3YsWMtO7r66qvdPskqS5Yssfz589v69euz5PP13bUPkNiUB4oWLXpcPitR81y48sfQoUOtRYsWWZqunIjAIkpr1661gQMH2qmnnmqFCxd2j9NPP91uvvlm+/nnn4PW9QrF3sNb97777rN9+/a5dQJfT+3x9ddfJ0tLUlKSOwi6d+9uVapUsSJFiljdunXt4Ycftv/++y+WfAEgjg0ePNg+//xzGzZsmL3xxhvWpUuXLEvLX3/95c6VP/30k2U39957r/Xq1cuqVq2a1UlBDpad83hO8r///c/tRwUBx8Ntt91my5cvt5kzZx6Xz4sXebM6ATnJxx9/bD179rS8efNa7969rUGDBpY7d25btWqVzZgxw1544QUXeIRehLRctQ0HDhywL774wh555BH76quv7Ntvv3UX9UCvv/66zZ49O9ny0047LVl6/vnnH+vXr5+1bNnSBgwYYOXLl7dFixbZ8OHDbc6cOe4zEqW2H0DkdG644IIL7M4778wWha4RI0a4mtKGDRsGvfbyyy+7CpSsoELgl19+aQsXLsySz0f8SC2PI7rAQvuxffv2x6Uls2LFiu48+eSTT7oKXESGwCJCf/zxh11++eUuaFCh/YQTTgh6/bHHHrPnn3/eBRqh1OWgbNmy7m8FABdffLELRL777ju78sorg9bVMgUWocvDURO9gpPWrVv7l11//fXugPOCi44dO0b6FQEkiG3btlnJkiUtu8uXL1+WffbkyZPtpJNOchU3qfH5fK6FuFChQsctbYni4MGDriUeiFZGHZeXXXaZXXrppfbnn3/aySefzA8RAbpCRejxxx93JzldbEKDClErxq233uq6JKWlQ4cO7n+1bsRCgUVgUOG58MIL3f8rV65McxtHjhxxNQA1a9a0ggULuj7XZ555pgtuQvt3btiwwfX/1t+VK1e28ePHu9dXrFjhvpMuAAq83n777aDP2LVrl6sZrVevnntv8eLF7dxzz3VNjBlp8eLF1rVrVytVqpRLS/369e2ZZ57xv66uavouOjnou6o24pprrrGdO3dG1K873HgP7SftLxXS9N1q1apl99xzj//1w4cP2wMPPGBNmjSxEiVKuHS1adPG5s6dm+7vuXXrVtdSdeKJJ1qBAgVcflStitc8fPvtt7vfUSdWzy233OLS/uyzzwb1s9cytahFk1avL6pqcZ5++mn3m+vk3a5dO/vll18yJM+pRkqPUOF+G9Vo63dW/tL2ypUr57r2/PDDD0Hrvfnmm9a8eXPXJVF5pG3btq4FMdCnn37qvrO+e7Fixaxbt27266+/RrX/RZ/duXNnV6GgfVO9enWX1yKldKlmU99H3SdVEeHRBU77X/s+lGrX9dqUKVPCblddJ/W68oaOX6+rZWrjmbz3BH4/byzIggUL3D5VOnVcqcU11J49e1zXK71H+0v7rU+fPrZjxw7XxbNZs2ZuPe1TLz1eP+dwv7fOw3fccYc712p7OuaUFwPzu2g76rb6wQcfuC6iWrdOnTr22WefWST0Pp3XQveJ993Vlaxp06bu933xxRf931XdJ7y01ahRw1U6hba6KL06dyvv6/065t59912Llo6l0qVLu30XSt1t9bsEtko999xzbh94x4DSH3q+jlQ0+/fHH39053yd+3WePPvss10lWrh89s0339hNN93kWuCVV0TnAn2GzuE6zyj92rfePtN71Bde+1L5QS1NkTge17a08ngk1y7P5s2brUePHu6zdJ7TZx87dixoHeU1jZnSb6Hfv0KFCta/f3/bvXt30Ho6XtRtWvtY+/Oss85Kdq5LTSTn3aNHj9pDDz1kp5xyissfOnZ0fTx06FDQtiI5n2h/qYAvSmtoN/HUjkudM/VeHSv6rqos+OSTTyL6nl7l7Icffhjxvkl0BBZRdIPSiSwjBvKo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zn3HGTNm2FlnneW+W4MGDdx+lK+//tr69etne/fu9e8P73uF+30jyRfHA4EFAABANpAnTx4bNWqUPffcc7Zp06aw6+gu1pdddpldfvnltmLFClfYvP/++13gEOjJJ590BdUff/zRvS4KIp599lmbOnWqK+Sq8HrhhRfarFmz3OONN95wAcO7776bZlq9gu1PP/1ktWvXtiuuuMK1tAwbNsx++OEH8/l8NnDgQP/6Bw4csK5du9qcOXNcmrp06WLnn3++bdiwwb2uArYK4SqMb9myxT1E2z/77LPt9NNPd4XuBQsWuPcFBj8KjBTMLF682B5//HG3jdmzZ/tfv/TSS23btm326aefuv3XuHFjt81du3a516dPn+72o/a90n7CCSfY888/n+r337x5s7Vt29YV4r/66iu33WuuucaOHj3qXn/mmWdcwV6/w88//+yCoe7du9tvv/0WtJ17773X7rzzTvc9Tz31VOvVq5fbhgIzdQtT4ODtD62X0u8bab7IdL4Es3fvXp++tv4HAAAJYnjx4/uIUt++fX0XXHCB+7tly5a+a665xv39/vvvu3KL54orrvB16tQp6L133XWX7/TTT/c/r1q1qq9Hjx5B60yePNlt5/fff/cv69+/v69w4cK+/fv3+5d17tzZLU+NtnPffff5ny9atMgte+WVV/zLpkyZ4itYsGCq26lTp47vueeeC0r3008/HbROr169fGeccUaK22jXrp3vzDPPDFrWrFkz39133+3+nj9/vq948eK+//77L2idU045xffiiy+6v1u1auW76aabgl5v0aKFr0GDBil+7rBhw3zVq1f3HT58OOzrlSpV8j3yyCPJ0uV9ztq1a90+mzhxov/1X3/91S1buXKl/zcrUaJEsm2H+30jzReh+zejy860WAAAAGQjGmehWviVK1cme03LzjjjjKBleq6a8MBa/KZNmyZ7r7rbnHLKKf7n6vqjLjPqmhS4TLX7ohp8veY9vNYFqV+/ftB7pF69ekHL1J1o3759/hYL1bir25S6ZGl7+i6B2wzHa7FITWBaRC0O3ndQlyd9dpkyZYK+y9q1a/3dlpSOFi1aBG2jVatWaaZLXZ/y5cuX7LV9+/bZX3/9FfZ3Cv1NA9OudIuX9tSE/r6R5ovMxuBtAACAbERdbNR1Rt2KNFtUeqhrUKjQQrD67YdbpvEBMmDA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skKFCrm/Fy1aZOPGjbPHH3/cypYta4MHD86MNAIAAACIt65QGzdudOMp5IMPPrBLLrnEbrjhBjvjjDOsffv2mZFGAAAAAPHWYlG0aFHbuXOn+/uLL76wTp06ub8LFixo//77b8anEAAAAED8tVgokLjuuuusUaNGtmbNGuvatatb/uuvv1q1atUyI40AAAAA4q3FYvz48daqVSvbvn27vffee1amTBm3fOnSpdarV6/MSCMAAACAbC6XT3e3SyC6c3iJEiVs7969Vrx48axODgAAABAXZeeoWywAAAAAIBSBBQAAAICcH1hozIYGfWtWqRYtWtiSJUtSXX/Pnj1288032wknnGAFChSwU0891WbNmnXc0gsAAAAgA2aFykjTpk2z22+/3SZMmOCCirFjx1rnzp1t9erVVr58+WTrHz582M1Kpdfeffddq1y5srvbt+78DQAAACAHtVisWrUqxdc+//zzqLb11FNP2fXXX2/9+vWz008/3QUYhQsXtkmTJoVdX8t37drlbsynG/KppaNdu3bWoEGDaL8GAAAAgKwMLBo3buy6LwU6dOiQDRw40C644IKIt6PWB01R27Fjx/9LTO7c7vmiRYvCvmfmzJluqlt1hapQoYLVrVvXRo0aZceOHYv2awAAAADIyq5Qr776qt144432ySef2OTJk23Lli12xRVXWFJSks2fPz/i7ezYscMFBAoQAul5Sq0if/75p3311VfWu3dvN67i999/t5tuusmOHDliw4cPD/seBT16BE6ZJUqvHgAAAADCi6a8HHVgcdlll1nr1q1d96U6derYwYMH7eqrr7YxY8a4bkyZ/cU0vuKll16yPHnyWJMmTWzz5s32xBNPpBhYjB492kaMGJFs+e7du+3o0aOZml4AAAAgJ9u/f3/mD95WVya1OOihGZo0q1M0ypYt64KDv//+O2i5nlesWDHse/Q5+fLlc+/znHbaabZ161aXnvz58yd7z7Bhw9wA8cAWiypVqlipUqW4QR4AAACQirx582ZeYDF16lTXFapNmza2Zs0a++mnn1zrhQZuv/HGG3byySdHtB0FAWpxmDNnjvXo0cPfIqHnGq8RjgZsv/322249jccQpUEBR7igQjQlrR6h9H5vGwAAAACSi6a8HHXJ+tprr3UDpjWQuly5cm761xUrVripXxs2bBjVttSS8PLLL9tr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jRw50o4cOeKe58qVy42tuPvuu+3iiy/OjDQCAAAAiLfAYsyYMXbgwAErX768/fvvv9auXTurUaOGFStWzB555JHMSSUAAACA+JoVSrNBzZ4927799ltbvny5CzIaN27sZooCAAAAkJiiDiw0nWzPnj3tjDPOcA/P4cOHberUqdanT5+MTiMAAACAeLvzdp48eWzLli2uK1SgnTt3umXHjh2z7Iw7bwMAAADZ4M7bikM0YDvUpk2b3IcCAAAASDwRd4Vq1KiRCyj0OPvssy1v3v97q1op1q5da126dMmsdAIAAACIh8CiR48e7v+ffvrJOnfubEWLFvW/lj9/fqtWrRrTzQIAAAAJKuLAYvjw4e5/BRAavF2wYMHMTBcAAACAHCTqMRZ9+/a1//77zyZOnGjDhg2zXbt2ueXLli2zzZs3Z0YaAQAAAMTbdLM///yzu2eFBmqvW7fOrr/+eitdurTNmDHD3YFb09ECAAAASCxRt1gMHjzYrr76avvtt9+CukN17drV5s2bl9HpAwAAABCPLRY//PCDvfTSS8mWV65c2bZu3ZpR6QIAAAAQzy0WBQoUcDfKCLVmzRorV65cRqULAAAAQDwHFt27d7eRI0fakSNH3HPd10JjK+6+++50Tzc7fvx4N9uUula1aNHClixZkuK6L7/8srVp08ZKlSrlHhrvkdr6AAAAALJhYDFmzBg7cOCAlS9f3v79919r166d1ahRw4oVK2aPPPJI1AmYNm2a3X777W46W80s1aBBA3efjG3btoVd/+uvv7ZevXrZ3LlzbdGiRValShU755xzmJEKAAAAyEK5fD6fLz1vXLBggZshSkFG48aNXctBeqiFolmzZjZu3Dj3PCkpyQULt9xyiw0dOjTN9+uu32q50Pv79OmT5vrqxqUZrfbu3WvFixdPV5oBAACARLAvirJz1IO3PWeeeaZ7xOLw4cO2dOlSdz8MT+7cuV2QotaISPzzzz+uW5amvA3n0KFD7uHxxocogNEDAAAAQHjRlJfzRrvhV1991d2zQvew0PiK6tWr2yWXXGJXXXWVex6NHTt2uBaHChUqBC3X81WrVkW0DY3tqFSpUootJqNHj7YRI0YkW7579247evRoVOkFAAAAEsn+/fszPrBQjykN3J41a5YbB1GvXj23bOXKle6+Fgo2PvjgAzueHn30UZs6daobdxF4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6dPHKleu7MZKyKBBg6xdu3Y2ZswY69atm02dOtV++OEHe+mll7L4mwAAAACJK8sDC00fu337dnvggQfcAGxNG/vZZ5/5B2hv2LDBzRTlad26tb399tvupmv33HOP1axZ080IVbdu3Sz8FoiEuqTpfiWhXdOAnID8i5yOPIycjjyc/WX5fSwAAAAA5HxZfudtAAAAADkfgQUAAACAmBFYAAAAAIgZgQWyzIMPPugG62eX7QCp+frrr91NNffs2cOOAgAgDAILhKUZum655RY7+eST3SwMumP2+eefn+weIrG48847g7Z39dVXW48ePfhFkOV5s3379nbbbbcFLdOMdFu2bIn4JkEZ5dVXX+WmnnHqeORlICNxnUa2n24W2c+6devsjDPOcIWZJ554wurVq2dHjhyxzz//3G6++WZbtWpVhnxO0aJF3QPIbnkzpRt6VqxYkR8L2TYva5LHY8eOWd68wZf2w4cPu/wLAJlO080Cgc4991xf5cqVfQcOHEi2Y3bv3u3+HzNmjK9u3bq+woUL+0488UTfjTfe6Nu/f79/vcmTJ/tKlCjhe//99301atTwFShQwHfOOef4NmzY4F9n+PDhvgYNGvj/VnYMfMydO9e9NmTIEF/NmjV9hQoV8lWvXt133333+Q4fPhx2O4hvkeTN9evX+7p37+4rUqSIr1ixYr5LL73Ut3Xr1mT55fXXX/dVrVrVV7x4cV/Pnj19+/btc6/37ds3WV5cu3aty4/62/scL49/9tlnvtq1a7vP69y5s++vv/4KStfLL7/sXtcxUKtWLd/48eP9r2m72uZ7773na9++vcvj9evX9y1cuNC97n1m4EPpR/znZS9v/Pjjj0HLA8+NXv6YNWuWr3Hjxr58+fK5Ze3atfPdfPPNvkGDBvnKlCnj8pasWLHC16VLF5dXy5cv77vyyit927dv929f77vlllt8d911l69UqVK+ChUqJMtvSsMNN9zg3q88XadOHd9HH33kvoeOt3feeSdofV0DdJ3wji/kbDo/XnDBBWFfi7RckNo588iRIy4Par3SpUu763+fPn2CPlPn7aeffjros3VOD8yraaVFXnrpJfeazrs9evRw79HnBvrggw98jRo1cnld5Y8HH3zQpREpoysUguzatcvdoFA1ZkWKFEm2d1S7Jrpp4bPPPmu//vqrvfbaa/bVV1/ZkCFDgtb9559/7JFHHrHXX3/dvv32W9c3/fLLL0+xW9Rll11mXbp0cd1N9FDXEylWrJjrDvK///3PnnnmGXv55Zft6aef5pdLMJHkzaSkJLvgggvcut98843Nnj3b/vzzT3cjzkB//PGHu7Hmxx9/7B5a99FHH3WvKY+1atXKrr/+en9eVBeVcJTHn3zySXvjjTds3rx57oaeysuet956y938U8fBypUrbdSoUXb//fe7YybQvffe6973008/2amnnmq9evWyo0ePumNg7NixVrx4cX9aAreP+D7PRmro0KEu/yqP1a9f3y1THlMrhc69EyZMcOffDh06WKNGjeyHH35wn//333+7824gvU9pWrx4sT3++OM2cuRIdxyJjq9zzz3XbfPNN99052R9bp48edx7dH6fPHly0Pb0/JJLLnHnccS3SMsFqZ0zH3vsMXfeVL5RPtu3b587V2d0WrTtAQMG2KBBg9x5t1OnTu48HWj+/PnWp08ft47y+osvvujKIqHrIUQqQQcS0OLFi10N2IwZM6J6n2qpVDMWWDOh7Xz33Xf+ZStXrnTL9BnhWhpSqwkJ9MQTT/iaNGnif06LRWKIJG9+8cUXvjx58gS1jP3666/ufUuWLPHnl9AaVNXQtmjRIqjmVrW9gcK1WOj577//7l9HrRGq5fWccsopvrfffjtoOw899JCvVatW7m+vVnrixInJ0qvjxfuc0Fo0xH9ejqbFQrWqgZR/Vcsamu/Uahxo48aN7v2rV6/2v+/MM88MWqdZs2a+u+++2/39+eef+3Lnzu1fP9z30vHn1UD//fffvrx58/q+/vrriPYLsr9Ir9OplQtSO2fqb13jPUePHvWddNJJUbdYpJUWtVJ369YtaJ3evXsHnWvPPvts36hRo4LWeeONN3wnnHBCRN8/UdFigdBAM6I98uWXX9rZZ59tlStXdjVRV111le3cudPVRnjUz7dZs2b+57Vr13Y1capVi8a0adNcX2T1b9eYjPvuu8/VciCxRJI3lbfUuhDYwnD66acny3fVqlULqkE94YQTbNu2bVGnqXDhwnbKKaeE3c7Bgwddy8i1117rH0+kx8MPP+yWB/Jqmb1tSHrSg/g6z0aqadOmyZY1adIk6Pny5ctt7ty5QXlR52QJzI+BeTE0T6tm98QTT3StauE0b97c6tSp42+RU6tG1apVrW3bthnwLZHdRVIuSO2cuXfvXteKpnzkUWtYaF7OiLSsXr066HMk9LmOGbXYBR4zXkt24HdCMAILBKlZs6abUjO1gYMadHjeeee5C9B7771nS5cutfHjx/sHCWakRYsWWe/eva1r166uy8qPP/7ouo1k9OcgPvJmpPLlyxf0XNtVN4+M2I5XaDxw4ID7X133VCDzHr/88ot99913KW5H25D0pAfxk5fVlSM0CNHg7nDCdacKXab8qBmnAvOiHr/99ltQwT+1Y6NQoUJpfrfrrrvOdRcRdWfp16+fP08jfkVaLkjtnBkpHRuh7wk8NjKqjKJjZsSIEUHHy4oVK9wxU7BgwajSnEgILBCkdOnS1rlzZ3cQqsY1lPrp6iDVhWbMmDHWsmVLV3v1119/JVtXfcTVl9ejGgK9/7TTTgu719UfWDOaBFq4cKGr8VIwoVo5XZDXr1/Pr5aAIsmbylsbN250D4/6xuo1tVxEKlxejFaFChWsUqVKboxHjRo1gh7Vq1c/rmlBzsvL5cqVc3+rdtSjgk16NW7c2PU3V2tdaH4MF5iEo4Lapk2bbM2aNSmuc+WVV7pztPq369jr27dvutOMnCPSckFqNJW3zpvff/+9f5nOfcuWLQtaT8dG4HGhcRhr166NKi21atUK+hwJfa5jRuWW0ONFDy/wR3LsGSSji50OZjULKtpXdK5uJLpQaFCrDirVDjz33HOu0KRBWBocGEo1E5qjXYMAdaBr/msd5KHNjR5d8H7++Wd3IO/YscN9hgIJdXuaOnWqa65XGt5//31+tQSVVt7s2LGjm7ZTrVy6GC1ZssQNvmvXrl3Y7iIpUV5UvlXNl/JielsPVNs1evRolz4VxlTbpVrcp556Kqq0qOZM9zZQWmiCT4y8rNYBnS+9QdmaYEDdQNNLA8U1aFwTA6gApfOpprZVi0KkgauOI7VuXHzxxW5Atwpzn376qRsI7ilVqpRddNFFdtddd9k555zjuk4hvqjLUmjLV9myZSMqF6RFZQadMz/88ENXFtDA6d27dwe1emkSAm1fg6t1TlXwqi5TnkjKKPqcWbNmuXOxjj0NzFZeDvwcTbyhyWd0HldQruNQZZFYjsOEkNWDPJA9afCdpivUIKn8+fO7aRE1hac3aPCpp55yA5g0TZumi9PUneGm4tQ0mieffLKbqq1jx45uKtCUBl1v27bN16lTJ1/RokWDBihqYK0GXWm5Blxp0FbgACsGbyeWtPJmpNPNBlKe0vY8GpzasmVLl7/Tmm42dGrN0NPqW2+95WvYsKFLq6bwbNu2rX/QbiQDdGXAgAHuGGC62cTKy//73//cQH/lQ+UhTU4QbvC2lydTm3xA1qxZ47vwwgt9JUuWdNvUlJ+33XabLykpKcX3adCsBux6du7c6evXr5/LjwULFnRTen788cdB75kzZ45L1/Tp0zNwbyE7CDcdtx7XXnttxOWC1M6Zmsp14MCBbhpwnS81cYDO4Zdffrl/nb1797qygNapUqWK79VXX002eDuttHjTzeqY86abffjhh30VK1YMSp+mxm3durVbR5/XvHlz9z6kLJf+yergBvFHfWx152I16QMAEodqiAcPHuy6n3BjPsRCrcXq4qppkR966KFM3ZkamK1xT2oJQfpx520AABAzddNT33d13+rfvz9BBaKm8TlffPGF63Z36NAhGzdunOtyd8UVV2T43tT9NHT/Co0xUjcozWb2/PPP86vFiDEWAAAgZrqhnqaw1dTgw4YNY48i+kJp7tyux4Omqtc08xpDoaljU5r0JRYag6fAQuPyNAZD45s0qxliQ1coAAAAADGjxQIAAABAzAgsAAAAAMSMwAIAAABAzAgsAAAAAMSMwAIAAABAzAgsAAAAAMSMwAIAAABAzAgsAAAAAMSMwAIAAACAxer/AcJh9iOUfGWPAAAAAElFTkSuQmCC", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import matplotlib.pyplot as plt\n", + "\n", + "plot_functions = [row[\"function\"] for row in summary_rows if row[\"function\"] != \"overall\"]\n", + "x = np.arange(len(plot_functions))\n", + "width = 0.35\n", + "\n", + "real_values = []\n", + "real_errs = [[], []]\n", + "control_values = []\n", + "control_errs = [[], []]\n", + "has_data = []\n", + "for function in plot_functions:\n", + " subset = ok_df[ok_df[\"function\"] == function]\n", + " if len(subset) == 0:\n", + " has_data.append(False)\n", + " real_values.append(0.0)\n", + " control_values.append(0.0)\n", + " real_errs[0].append(0.0)\n", + " real_errs[1].append(0.0)\n", + " control_errs[0].append(0.0)\n", + " control_errs[1].append(0.0)\n", + " continue\n", + " has_data.append(True)\n", + " real_ci = bootstrap_success_rate_ci(subset[\"real_success\"].tolist())\n", + " control_ci = bootstrap_success_rate_ci(subset[\"control_success\"].tolist())\n", + " real_values.append(real_ci.point_estimate)\n", + " real_errs[0].append(real_ci.point_estimate - real_ci.ci_low)\n", + " real_errs[1].append(real_ci.ci_high - real_ci.point_estimate)\n", + " control_values.append(control_ci.point_estimate)\n", + " control_errs[0].append(control_ci.point_estimate - control_ci.ci_low)\n", + " control_errs[1].append(control_ci.ci_high - control_ci.point_estimate)\n", + "\n", + "fig, ax = plt.subplots(figsize=(8, 4.5))\n", + "real_bars = ax.bar(\n", + " x - width / 2, real_values, width, yerr=real_errs, capsize=3, label=\"Real target\"\n", + ")\n", + "control_bars = ax.bar(\n", + " x + width / 2, control_values, width, yerr=control_errs, capsize=3, label=\"Norm-matched control\"\n", + ")\n", + "for i, present in enumerate(has_data):\n", + " if not present:\n", + " ax.annotate(\n", + " \"n/a\", (x[i], 0.02), ha=\"center\", fontsize=9, color=\"black\"\n", + " )\n", + "ax.set(\n", + " ylabel=\"Deterministic-argmax success rate\",\n", + " xticks=x,\n", + " xticklabels=[f.title() for f in plot_functions],\n", + " ylim=(0, 1.05),\n", + ")\n", + "ax.legend(frameon=False)\n", + "ax.grid(axis=\"y\", alpha=0.25)\n", + "fig.suptitle(\"GPT-2-small causal-swap success by function (real vs. norm-matched control)\")\n", + "fig.tight_layout()\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "id": "99c9e1dd", + "metadata": {}, + "source": [ + "## Per-trial detail\n", + "\n", + "Every trial that survived baseline filtering and had its source concept active in the\n", + "patched layer's support (`ok_trials` above). `control_token_id` is the raw vocabulary index\n", + "of the norm-matched control token; this notebook does not load a tokenizer, so it is not\n", + "decoded to text here." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "dedef2ac", + "metadata": { + "execution": { + "iopub.execute_input": "2026-09-13T09:18:50.455449Z", + "iopub.status.busy": "2026-09-13T09:18:50.455292Z", + "iopub.status.idle": "2026-09-13T09:18:50.475336Z", + "shell.execute_reply": "2026-09-13T09:18:50.474886Z" + } + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
functionsourcetargetlayerbaseline_rankreal_rankreal_successcontrol_token_idcontrol_rankcontrol_success
0continentEgyptCanada915False69185False
1continentEgyptChina914False16324False
2continentEgyptFrance913False47713False
3continentEgyptCanada1015False42685False
4continentEgyptChina1014False151854False
5continentEgyptFrance1013False120533False
\n", + "
" + ], + "text/plain": [ + " function source target layer baseline_rank real_rank real_success \\\n", + "0 continent Egypt Canada 9 1 5 False \n", + "1 continent Egypt China 9 1 4 False \n", + "2 continent Egypt France 9 1 3 False \n", + "3 continent Egypt Canada 10 1 5 False \n", + "4 continent Egypt China 10 1 4 False \n", + "5 continent Egypt France 10 1 3 False \n", + "\n", + " control_token_id control_rank control_success \n", + "0 6918 5 False \n", + "1 1632 4 False \n", + "2 4771 3 False \n", + "3 4268 5 False \n", + "4 15185 4 False \n", + "5 12053 3 False " + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "detail_columns = [\n", + " \"function\",\n", + " \"source\",\n", + " \"target\",\n", + " \"layer\",\n", + " \"baseline_rank\",\n", + " \"real_rank\",\n", + " \"real_success\",\n", + " \"control_token_id\",\n", + " \"control_rank\",\n", + " \"control_success\",\n", + "]\n", + "ok_df[detail_columns].sort_values([\"function\", \"layer\", \"source\", \"target\"]).reset_index(drop=True)" + ] + }, + { + "cell_type": "markdown", + "id": "dfc8ece0", + "metadata": {}, + "source": [ + "## Interpretation and caveats\n", + "\n", + "- This is a **directional causal-effect** measurement under the stated controls, not proof of\n", + " unique causal mediation: a successful swap shows the edit moved the output the predicted\n", + " way relative to a norm-matched random edit, nothing stronger.\n", + "- Results are reported for **GPT-2-small only**; no claim is made about closed-weight models,\n", + " and no claim about other open-weight models is implied.\n", + "- The corpus is the fixed reused country/function set; this is not an exhaustive-coverage\n", + " claim over concepts or functions.\n", + "- Every trial is a **single-layer** intervention (one layer, the final prompt position). This\n", + " says nothing about a multi-layer band protocol, which `coordinate_patch_hooks` was not\n", + " designed for (stacking hooked layers is order-dependent and can raise).\n", + "- This notebook is independent of the existing `swap_hooks` country-swap benchmark elsewhere\n", + " in this repository: different mechanism, different model, different protocol. Neither\n", + " supersedes the other." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.14" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/demos/data/jacobian_lens_causal_swap_benchmark_gpt2.json b/demos/data/jacobian_lens_causal_swap_benchmark_gpt2.json new file mode 100644 index 0000000000..4ce656a1a6 --- /dev/null +++ b/demos/data/jacobian_lens_causal_swap_benchmark_gpt2.json @@ -0,0 +1,3806 @@ +{ + "control_success_ci": { + "ci_high": 0.0, + "ci_low": 0.0, + "confidence": 0.95, + "n_resamples": 10000, + "point_estimate": 0.0 + }, + "excluded_baselines": [ + { + "function": "capital", + "metrics": { + "target_is_top1": false, + "target_logit_margin": -0.2864990234375, + "target_rank": 2, + "target_tied_for_top": false, + "top1_token_id": 6586 + }, + "prompt": "The capital of Canada is the city of", + "source": "Canada" + }, + { + "function": "capital", + "metrics": { + "target_is_top1": false, + "target_logit_margin": -0.7241363525390625, + "target_rank": 2, + "target_tied_for_top": false, + "top1_token_id": 20834 + }, + "prompt": "The capital of China is the city of", + "source": "China" + }, + { + "function": "capital", + "metrics": { + "target_is_top1": false, + "target_logit_margin": -1.7487869262695312, + "target_rank": 7, + "target_tied_for_top": false, + "top1_token_id": 27872 + }, + "prompt": "The capital of Egypt is the city of", + "source": "Egypt" + }, + { + "function": "language", + "metrics": { + "target_is_top1": false, + "target_logit_margin": -1.105224609375, + "target_rank": 5, + "target_tied_for_top": false, + "top1_token_id": 257 + }, + "prompt": "Most people in China speak", + "source": "China" + }, + { + "function": "continent", + "metrics": { + "target_is_top1": false, + "target_logit_margin": -1.9497413635253906, + "target_rank": 5, + "target_tied_for_top": false, + "top1_token_id": 262 + }, + "prompt": "Canada is a country on the continent of", + "source": "Canada" + }, + { + "function": "continent", + "metrics": { + "target_is_top1": false, + "target_logit_margin": -0.6490402221679688, + "target_rank": 3, + "target_tied_for_top": false, + "top1_token_id": 262 + }, + "prompt": "China is a country on the continent of", + "source": "China" + }, + { + "function": "currency", + "metrics": { + "target_is_top1": false, + "target_logit_margin": -1.9744873046875, + "target_rank": 7, + "target_tied_for_top": false, + "top1_token_id": 366 + }, + "prompt": "The single-word name for the currency now used in France is the", + "source": "France" + }, + { + "function": "currency", + "metrics": { + "target_is_top1": false, + "target_logit_margin": -4.760887145996094, + "target_rank": 38, + "target_tied_for_top": false, + "top1_token_id": 5398 + }, + "prompt": "The single-word name for the currency now used in Canada is the", + "source": "Canada" + }, + { + "function": "currency", + "metrics": { + "target_is_top1": false, + "target_logit_margin": -2.1355819702148438, + "target_rank": 6, + "target_tied_for_top": false, + "top1_token_id": 34847 + }, + "prompt": "The single-word name for the currency now used in China is the", + "source": "China" + }, + { + "function": "currency", + "metrics": { + "target_is_top1": false, + "target_logit_margin": -5.075996398925781, + "target_rank": 116, + "target_tied_for_top": false, + "top1_token_id": 14075 + }, + "prompt": "The single-word name for the currency now used in Egypt is the", + "source": "Egypt" + } + ], + "protocol_fingerprint": "deae49a4df19fb44f8bed71db87b6bd6c09e5ca5c0e5531ba8bb3926b5a46b7d", + "protocol_manifest": { + "alpha": 1.0, + "baseline_definition": "source answer token id equals deterministic argmax token id", + "control_seed": 0, + "control_tolerance": 0.1, + "corpus_name": "countries", + "k": 25, + "layers": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "lens_file": "gpt2-small/jlens/Salesforce-wikitext/gpt2_jacobian_lens.pt", + "lens_repo": "neuronpedia/jacobian-lens", + "lens_revision": "a4114d7752d11eb546e6cf372213d7e75526d3a1", + "model_id": "gpt2", + "model_revision": "n/a", + "rank_definition": "1 + count(logits strictly greater than target logit)", + "success_definition": "target token id equals deterministic argmax token id" + }, + "real_success_ci": { + "ci_high": 0.0, + "ci_low": 0.0, + "confidence": 0.95, + "n_resamples": 10000, + "point_estimate": 0.0 + }, + "schema_version": 1, + "trials": [ + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.08658599853515625, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 6342 + }, + "control_target_metrics": null, + "control_token_id": 5518, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "capital", + "layer": 0, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Canada" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.08658599853515625, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 6342 + }, + "control_target_metrics": null, + "control_token_id": 7035, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "capital", + "layer": 0, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.08658599853515625, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 6342 + }, + "control_target_metrics": null, + "control_token_id": 39809, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "capital", + "layer": 0, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Egypt" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.5519790649414062, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 4141 + }, + "control_target_metrics": null, + "control_token_id": 1133, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "language", + "layer": 0, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Canada" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.5519790649414062, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 4141 + }, + "control_target_metrics": null, + "control_token_id": 7035, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "language", + "layer": 0, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.5519790649414062, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 4141 + }, + "control_target_metrics": null, + "control_token_id": 10445, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "language", + "layer": 0, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Egypt" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7837142944335938, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 3594 + }, + "control_target_metrics": null, + "control_token_id": 4942, + "error": "source_idx=3340 is not in the decomposition's active support", + "function": "language", + "layer": 0, + "real_target_metrics": null, + "source": "Canada", + "status": "skipped_source_inactive", + "target": "France" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7837142944335938, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 3594 + }, + "control_target_metrics": null, + "control_token_id": 7035, + "error": "source_idx=3340 is not in the decomposition's active support", + "function": "language", + "layer": 0, + "real_target_metrics": null, + "source": "Canada", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7837142944335938, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 3594 + }, + "control_target_metrics": null, + "control_token_id": 10445, + "error": "source_idx=3340 is not in the decomposition's active support", + "function": "language", + "layer": 0, + "real_target_metrics": null, + "source": "Canada", + "status": "skipped_source_inactive", + "target": "Egypt" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.41039276123046875, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 17526 + }, + "control_target_metrics": null, + "control_token_id": 7037, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "language", + "layer": 0, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "France" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.41039276123046875, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 17526 + }, + "control_target_metrics": null, + "control_token_id": 554, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "language", + "layer": 0, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "Canada" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.41039276123046875, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 17526 + }, + "control_target_metrics": null, + "control_token_id": 6928, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "language", + "layer": 0, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.39803314208984375, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 2031 + }, + "control_target_metrics": null, + "control_token_id": 5519, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "continent", + "layer": 0, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Canada" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.39803314208984375, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 2031 + }, + "control_target_metrics": null, + "control_token_id": 7035, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "continent", + "layer": 0, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.39803314208984375, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 2031 + }, + "control_target_metrics": null, + "control_token_id": 39809, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "continent", + "layer": 0, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Egypt" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7269477844238281, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 5478 + }, + "control_target_metrics": null, + "control_token_id": 7037, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "continent", + "layer": 0, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "France" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7269477844238281, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 5478 + }, + "control_target_metrics": null, + "control_token_id": 554, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "continent", + "layer": 0, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "Canada" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7269477844238281, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 5478 + }, + "control_target_metrics": null, + "control_token_id": 9505, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "continent", + "layer": 0, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.08658599853515625, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 6342 + }, + "control_target_metrics": null, + "control_token_id": 5041, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "capital", + "layer": 1, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Canada" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.08658599853515625, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 6342 + }, + "control_target_metrics": null, + "control_token_id": 4343, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "capital", + "layer": 1, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.08658599853515625, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 6342 + }, + "control_target_metrics": null, + "control_token_id": 32814, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "capital", + "layer": 1, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Egypt" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.5519790649414062, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 4141 + }, + "control_target_metrics": null, + "control_token_id": 7840, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "language", + "layer": 1, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Canada" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.5519790649414062, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 4141 + }, + "control_target_metrics": null, + "control_token_id": 4345, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "language", + "layer": 1, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.5519790649414062, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 4141 + }, + "control_target_metrics": null, + "control_token_id": 17967, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "language", + "layer": 1, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Egypt" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7837142944335938, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 3594 + }, + "control_target_metrics": null, + "control_token_id": 5303, + "error": "source_idx=3340 is not in the decomposition's active support", + "function": "language", + "layer": 1, + "real_target_metrics": null, + "source": "Canada", + "status": "skipped_source_inactive", + "target": "France" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7837142944335938, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 3594 + }, + "control_target_metrics": null, + "control_token_id": 4346, + "error": "source_idx=3340 is not in the decomposition's active support", + "function": "language", + "layer": 1, + "real_target_metrics": null, + "source": "Canada", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7837142944335938, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 3594 + }, + "control_target_metrics": null, + "control_token_id": 17967, + "error": "source_idx=3340 is not in the decomposition's active support", + "function": "language", + "layer": 1, + "real_target_metrics": null, + "source": "Canada", + "status": "skipped_source_inactive", + "target": "Egypt" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.41039276123046875, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 17526 + }, + "control_target_metrics": null, + "control_token_id": 8287, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "language", + "layer": 1, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "France" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.41039276123046875, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 17526 + }, + "control_target_metrics": null, + "control_token_id": 12537, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "language", + "layer": 1, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "Canada" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.41039276123046875, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 17526 + }, + "control_target_metrics": null, + "control_token_id": 13961, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "language", + "layer": 1, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.39803314208984375, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 2031 + }, + "control_target_metrics": null, + "control_token_id": 7840, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "continent", + "layer": 1, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Canada" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.39803314208984375, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 2031 + }, + "control_target_metrics": null, + "control_token_id": 4345, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "continent", + "layer": 1, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.39803314208984375, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 2031 + }, + "control_target_metrics": null, + "control_token_id": 32814, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "continent", + "layer": 1, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Egypt" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7269477844238281, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 5478 + }, + "control_target_metrics": null, + "control_token_id": 8287, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "continent", + "layer": 1, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "France" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7269477844238281, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 5478 + }, + "control_target_metrics": null, + "control_token_id": 12537, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "continent", + "layer": 1, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "Canada" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7269477844238281, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 5478 + }, + "control_target_metrics": null, + "control_token_id": 9934, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "continent", + "layer": 1, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.08658599853515625, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 6342 + }, + "control_target_metrics": null, + "control_token_id": 11776, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "capital", + "layer": 2, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Canada" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.08658599853515625, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 6342 + }, + "control_target_metrics": null, + "control_token_id": 809, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "capital", + "layer": 2, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.08658599853515625, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 6342 + }, + "control_target_metrics": null, + "control_token_id": 24970, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "capital", + "layer": 2, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Egypt" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.5519790649414062, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 4141 + }, + "control_target_metrics": null, + "control_token_id": 6829, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "language", + "layer": 2, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Canada" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.5519790649414062, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 4141 + }, + "control_target_metrics": null, + "control_token_id": 8117, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "language", + "layer": 2, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.5519790649414062, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 4141 + }, + "control_target_metrics": null, + "control_token_id": 35809, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "language", + "layer": 2, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Egypt" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7837142944335938, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 3594 + }, + "control_target_metrics": null, + "control_token_id": 13059, + "error": "source_idx=3340 is not in the decomposition's active support", + "function": "language", + "layer": 2, + "real_target_metrics": null, + "source": "Canada", + "status": "skipped_source_inactive", + "target": "France" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7837142944335938, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 3594 + }, + "control_target_metrics": null, + "control_token_id": 809, + "error": "source_idx=3340 is not in the decomposition's active support", + "function": "language", + "layer": 2, + "real_target_metrics": null, + "source": "Canada", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7837142944335938, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 3594 + }, + "control_target_metrics": null, + "control_token_id": 35809, + "error": "source_idx=3340 is not in the decomposition's active support", + "function": "language", + "layer": 2, + "real_target_metrics": null, + "source": "Canada", + "status": "skipped_source_inactive", + "target": "Egypt" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.41039276123046875, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 17526 + }, + "control_target_metrics": null, + "control_token_id": 8287, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "language", + "layer": 2, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "France" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.41039276123046875, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 17526 + }, + "control_target_metrics": null, + "control_token_id": 543, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "language", + "layer": 2, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "Canada" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.41039276123046875, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 17526 + }, + "control_target_metrics": null, + "control_token_id": 8225, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "language", + "layer": 2, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.39803314208984375, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 2031 + }, + "control_target_metrics": null, + "control_token_id": 6829, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "continent", + "layer": 2, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Canada" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.39803314208984375, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 2031 + }, + "control_target_metrics": null, + "control_token_id": 809, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "continent", + "layer": 2, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.39803314208984375, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 2031 + }, + "control_target_metrics": null, + "control_token_id": 24970, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "continent", + "layer": 2, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Egypt" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7269477844238281, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 5478 + }, + "control_target_metrics": null, + "control_token_id": 8287, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "continent", + "layer": 2, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "France" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7269477844238281, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 5478 + }, + "control_target_metrics": null, + "control_token_id": 543, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "continent", + "layer": 2, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "Canada" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7269477844238281, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 5478 + }, + "control_target_metrics": null, + "control_token_id": 4430, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "continent", + "layer": 2, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.08658599853515625, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 6342 + }, + "control_target_metrics": null, + "control_token_id": 9817, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "capital", + "layer": 3, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Canada" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.08658599853515625, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 6342 + }, + "control_target_metrics": null, + "control_token_id": 4802, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "capital", + "layer": 3, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.08658599853515625, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 6342 + }, + "control_target_metrics": null, + "control_token_id": 20411, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "capital", + "layer": 3, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Egypt" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.5519790649414062, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 4141 + }, + "control_target_metrics": null, + "control_token_id": 1974, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "language", + "layer": 3, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Canada" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.5519790649414062, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 4141 + }, + "control_target_metrics": null, + "control_token_id": 4803, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "language", + "layer": 3, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.5519790649414062, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 4141 + }, + "control_target_metrics": null, + "control_token_id": 16327, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "language", + "layer": 3, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Egypt" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7837142944335938, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 3594 + }, + "control_target_metrics": null, + "control_token_id": 11202, + "error": "source_idx=3340 is not in the decomposition's active support", + "function": "language", + "layer": 3, + "real_target_metrics": null, + "source": "Canada", + "status": "skipped_source_inactive", + "target": "France" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7837142944335938, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 3594 + }, + "control_target_metrics": null, + "control_token_id": 4805, + "error": "source_idx=3340 is not in the decomposition's active support", + "function": "language", + "layer": 3, + "real_target_metrics": null, + "source": "Canada", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7837142944335938, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 3594 + }, + "control_target_metrics": null, + "control_token_id": 16327, + "error": "source_idx=3340 is not in the decomposition's active support", + "function": "language", + "layer": 3, + "real_target_metrics": null, + "source": "Canada", + "status": "skipped_source_inactive", + "target": "Egypt" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.41039276123046875, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 17526 + }, + "control_target_metrics": null, + "control_token_id": 12308, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "language", + "layer": 3, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "France" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.41039276123046875, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 17526 + }, + "control_target_metrics": null, + "control_token_id": 9322, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "language", + "layer": 3, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "Canada" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.41039276123046875, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 17526 + }, + "control_target_metrics": null, + "control_token_id": 8129, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "language", + "layer": 3, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.39803314208984375, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 2031 + }, + "control_target_metrics": null, + "control_token_id": 9817, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "continent", + "layer": 3, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Canada" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.39803314208984375, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 2031 + }, + "control_target_metrics": null, + "control_token_id": 4803, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "continent", + "layer": 3, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.39803314208984375, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 2031 + }, + "control_target_metrics": null, + "control_token_id": 20411, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "continent", + "layer": 3, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Egypt" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7269477844238281, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 5478 + }, + "control_target_metrics": null, + "control_token_id": 11202, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "continent", + "layer": 3, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "France" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7269477844238281, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 5478 + }, + "control_target_metrics": null, + "control_token_id": 9322, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "continent", + "layer": 3, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "Canada" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7269477844238281, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 5478 + }, + "control_target_metrics": null, + "control_token_id": 592, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "continent", + "layer": 3, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.08658599853515625, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 6342 + }, + "control_target_metrics": null, + "control_token_id": 5348, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "capital", + "layer": 4, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Canada" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.08658599853515625, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 6342 + }, + "control_target_metrics": null, + "control_token_id": 8748, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "capital", + "layer": 4, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.08658599853515625, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 6342 + }, + "control_target_metrics": null, + "control_token_id": 13468, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "capital", + "layer": 4, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Egypt" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.5519790649414062, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 4141 + }, + "control_target_metrics": null, + "control_token_id": 13092, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "language", + "layer": 4, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Canada" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.5519790649414062, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 4141 + }, + "control_target_metrics": null, + "control_token_id": 8748, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "language", + "layer": 4, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.5519790649414062, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 4141 + }, + "control_target_metrics": null, + "control_token_id": 12572, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "language", + "layer": 4, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Egypt" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7837142944335938, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 3594 + }, + "control_target_metrics": null, + "control_token_id": 8966, + "error": "source_idx=3340 is not in the decomposition's active support", + "function": "language", + "layer": 4, + "real_target_metrics": null, + "source": "Canada", + "status": "skipped_source_inactive", + "target": "France" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7837142944335938, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 3594 + }, + "control_target_metrics": null, + "control_token_id": 8748, + "error": "source_idx=3340 is not in the decomposition's active support", + "function": "language", + "layer": 4, + "real_target_metrics": null, + "source": "Canada", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7837142944335938, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 3594 + }, + "control_target_metrics": null, + "control_token_id": 12572, + "error": "source_idx=3340 is not in the decomposition's active support", + "function": "language", + "layer": 4, + "real_target_metrics": null, + "source": "Canada", + "status": "skipped_source_inactive", + "target": "Egypt" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.41039276123046875, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 17526 + }, + "control_target_metrics": null, + "control_token_id": 7209, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "language", + "layer": 4, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "France" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.41039276123046875, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 17526 + }, + "control_target_metrics": null, + "control_token_id": 8329, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "language", + "layer": 4, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "Canada" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.41039276123046875, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 17526 + }, + "control_target_metrics": null, + "control_token_id": 6602, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "language", + "layer": 4, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.39803314208984375, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 2031 + }, + "control_target_metrics": null, + "control_token_id": 5350, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "continent", + "layer": 4, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Canada" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.39803314208984375, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 2031 + }, + "control_target_metrics": null, + "control_token_id": 8748, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "continent", + "layer": 4, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.39803314208984375, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 2031 + }, + "control_target_metrics": null, + "control_token_id": 13468, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "continent", + "layer": 4, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Egypt" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7269477844238281, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 5478 + }, + "control_target_metrics": null, + "control_token_id": 8966, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "continent", + "layer": 4, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "France" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7269477844238281, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 5478 + }, + "control_target_metrics": null, + "control_token_id": 8329, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "continent", + "layer": 4, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "Canada" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7269477844238281, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 5478 + }, + "control_target_metrics": null, + "control_token_id": 5713, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "continent", + "layer": 4, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.08658599853515625, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 6342 + }, + "control_target_metrics": null, + "control_token_id": 607, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "capital", + "layer": 5, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Canada" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.08658599853515625, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 6342 + }, + "control_target_metrics": null, + "control_token_id": 6082, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "capital", + "layer": 5, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.08658599853515625, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 6342 + }, + "control_target_metrics": null, + "control_token_id": 250, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "capital", + "layer": 5, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Egypt" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.5519790649414062, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 4141 + }, + "control_target_metrics": null, + "control_token_id": 67, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "language", + "layer": 5, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Canada" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.5519790649414062, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 4141 + }, + "control_target_metrics": null, + "control_token_id": 6090, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "language", + "layer": 5, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.5519790649414062, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 4141 + }, + "control_target_metrics": null, + "control_token_id": 15187, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "language", + "layer": 5, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Egypt" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7837142944335938, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 3594 + }, + "control_target_metrics": null, + "control_token_id": 15671, + "error": "source_idx=3340 is not in the decomposition's active support", + "function": "language", + "layer": 5, + "real_target_metrics": null, + "source": "Canada", + "status": "skipped_source_inactive", + "target": "France" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7837142944335938, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 3594 + }, + "control_target_metrics": null, + "control_token_id": 299, + "error": "source_idx=3340 is not in the decomposition's active support", + "function": "language", + "layer": 5, + "real_target_metrics": null, + "source": "Canada", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7837142944335938, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 3594 + }, + "control_target_metrics": null, + "control_token_id": 15187, + "error": "source_idx=3340 is not in the decomposition's active support", + "function": "language", + "layer": 5, + "real_target_metrics": null, + "source": "Canada", + "status": "skipped_source_inactive", + "target": "Egypt" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.41039276123046875, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 17526 + }, + "control_target_metrics": null, + "control_token_id": 9817, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "language", + "layer": 5, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "France" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.41039276123046875, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 17526 + }, + "control_target_metrics": null, + "control_token_id": 1805, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "language", + "layer": 5, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "Canada" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.41039276123046875, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 17526 + }, + "control_target_metrics": null, + "control_token_id": 6090, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "language", + "layer": 5, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.39803314208984375, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 2031 + }, + "control_target_metrics": null, + "control_token_id": 607, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "continent", + "layer": 5, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Canada" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.39803314208984375, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 2031 + }, + "control_target_metrics": null, + "control_token_id": 6090, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "continent", + "layer": 5, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.39803314208984375, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 2031 + }, + "control_target_metrics": null, + "control_token_id": 250, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "continent", + "layer": 5, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Egypt" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7269477844238281, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 5478 + }, + "control_target_metrics": null, + "control_token_id": 9817, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "continent", + "layer": 5, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "France" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7269477844238281, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 5478 + }, + "control_target_metrics": null, + "control_token_id": 1805, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "continent", + "layer": 5, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "Canada" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7269477844238281, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 5478 + }, + "control_target_metrics": null, + "control_token_id": 4281, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "continent", + "layer": 5, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.08658599853515625, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 6342 + }, + "control_target_metrics": null, + "control_token_id": 5832, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "capital", + "layer": 6, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Canada" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.08658599853515625, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 6342 + }, + "control_target_metrics": null, + "control_token_id": 5938, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "capital", + "layer": 6, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.08658599853515625, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 6342 + }, + "control_target_metrics": null, + "control_token_id": 23431, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "capital", + "layer": 6, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Egypt" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.5519790649414062, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 4141 + }, + "control_target_metrics": null, + "control_token_id": 8284, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "language", + "layer": 6, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Canada" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.5519790649414062, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 4141 + }, + "control_target_metrics": null, + "control_token_id": 5940, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "language", + "layer": 6, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.5519790649414062, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 4141 + }, + "control_target_metrics": null, + "control_token_id": 2913, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "language", + "layer": 6, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Egypt" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7837142944335938, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 3594 + }, + "control_target_metrics": null, + "control_token_id": 8478, + "error": "source_idx=3340 is not in the decomposition's active support", + "function": "language", + "layer": 6, + "real_target_metrics": null, + "source": "Canada", + "status": "skipped_source_inactive", + "target": "France" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7837142944335938, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 3594 + }, + "control_target_metrics": null, + "control_token_id": 3629, + "error": "source_idx=3340 is not in the decomposition's active support", + "function": "language", + "layer": 6, + "real_target_metrics": null, + "source": "Canada", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7837142944335938, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 3594 + }, + "control_target_metrics": null, + "control_token_id": 2913, + "error": "source_idx=3340 is not in the decomposition's active support", + "function": "language", + "layer": 6, + "real_target_metrics": null, + "source": "Canada", + "status": "skipped_source_inactive", + "target": "Egypt" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.41039276123046875, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 17526 + }, + "control_target_metrics": null, + "control_token_id": 5420, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "language", + "layer": 6, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "France" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.41039276123046875, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 17526 + }, + "control_target_metrics": null, + "control_token_id": 16981, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "language", + "layer": 6, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "Canada" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.41039276123046875, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 17526 + }, + "control_target_metrics": null, + "control_token_id": 5940, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "language", + "layer": 6, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.39803314208984375, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 2031 + }, + "control_target_metrics": null, + "control_token_id": 5833, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "continent", + "layer": 6, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Canada" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.39803314208984375, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 2031 + }, + "control_target_metrics": null, + "control_token_id": 5940, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "continent", + "layer": 6, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.39803314208984375, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 2031 + }, + "control_target_metrics": null, + "control_token_id": 23431, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "continent", + "layer": 6, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Egypt" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7269477844238281, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 5478 + }, + "control_target_metrics": null, + "control_token_id": 8478, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "continent", + "layer": 6, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "France" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7269477844238281, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 5478 + }, + "control_target_metrics": null, + "control_token_id": 16981, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "continent", + "layer": 6, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "Canada" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7269477844238281, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 5478 + }, + "control_target_metrics": null, + "control_token_id": 12460, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "continent", + "layer": 6, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.08658599853515625, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 6342 + }, + "control_target_metrics": null, + "control_token_id": 14104, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "capital", + "layer": 7, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Canada" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.08658599853515625, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 6342 + }, + "control_target_metrics": null, + "control_token_id": 521, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "capital", + "layer": 7, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.08658599853515625, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 6342 + }, + "control_target_metrics": null, + "control_token_id": 6998, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "capital", + "layer": 7, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Egypt" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.5519790649414062, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 4141 + }, + "control_target_metrics": null, + "control_token_id": 9667, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "language", + "layer": 7, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Canada" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.5519790649414062, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 4141 + }, + "control_target_metrics": null, + "control_token_id": 4245, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "language", + "layer": 7, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.5519790649414062, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 4141 + }, + "control_target_metrics": null, + "control_token_id": 16292, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "language", + "layer": 7, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Egypt" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7837142944335938, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 3594 + }, + "control_target_metrics": null, + "control_token_id": 9234, + "error": "source_idx=3340 is not in the decomposition's active support", + "function": "language", + "layer": 7, + "real_target_metrics": null, + "source": "Canada", + "status": "skipped_source_inactive", + "target": "France" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7837142944335938, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 3594 + }, + "control_target_metrics": null, + "control_token_id": 521, + "error": "source_idx=3340 is not in the decomposition's active support", + "function": "language", + "layer": 7, + "real_target_metrics": null, + "source": "Canada", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7837142944335938, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 3594 + }, + "control_target_metrics": null, + "control_token_id": 16292, + "error": "source_idx=3340 is not in the decomposition's active support", + "function": "language", + "layer": 7, + "real_target_metrics": null, + "source": "Canada", + "status": "skipped_source_inactive", + "target": "Egypt" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.41039276123046875, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 17526 + }, + "control_target_metrics": null, + "control_token_id": 288, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "language", + "layer": 7, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "France" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.41039276123046875, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 17526 + }, + "control_target_metrics": null, + "control_token_id": 7593, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "language", + "layer": 7, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "Canada" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.41039276123046875, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 17526 + }, + "control_target_metrics": null, + "control_token_id": 10117, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "language", + "layer": 7, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.39803314208984375, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 2031 + }, + "control_target_metrics": null, + "control_token_id": 14104, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "continent", + "layer": 7, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Canada" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.39803314208984375, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 2031 + }, + "control_target_metrics": null, + "control_token_id": 521, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "continent", + "layer": 7, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.39803314208984375, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 2031 + }, + "control_target_metrics": null, + "control_token_id": 16293, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "continent", + "layer": 7, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Egypt" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7269477844238281, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 5478 + }, + "control_target_metrics": null, + "control_token_id": 3730, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "continent", + "layer": 7, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "France" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7269477844238281, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 5478 + }, + "control_target_metrics": null, + "control_token_id": 7593, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "continent", + "layer": 7, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "Canada" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7269477844238281, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 5478 + }, + "control_target_metrics": null, + "control_token_id": 8315, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "continent", + "layer": 7, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.08658599853515625, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 6342 + }, + "control_target_metrics": null, + "control_token_id": 4473, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "capital", + "layer": 8, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Canada" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.08658599853515625, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 6342 + }, + "control_target_metrics": null, + "control_token_id": 5982, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "capital", + "layer": 8, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.08658599853515625, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 6342 + }, + "control_target_metrics": null, + "control_token_id": 17945, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "capital", + "layer": 8, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Egypt" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.5519790649414062, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 4141 + }, + "control_target_metrics": null, + "control_token_id": 9564, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "language", + "layer": 8, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Canada" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.5519790649414062, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 4141 + }, + "control_target_metrics": null, + "control_token_id": 8072, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "language", + "layer": 8, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.5519790649414062, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 4141 + }, + "control_target_metrics": null, + "control_token_id": 13572, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "language", + "layer": 8, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Egypt" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7837142944335938, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 3594 + }, + "control_target_metrics": null, + "control_token_id": 9686, + "error": "source_idx=3340 is not in the decomposition's active support", + "function": "language", + "layer": 8, + "real_target_metrics": null, + "source": "Canada", + "status": "skipped_source_inactive", + "target": "France" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7837142944335938, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 3594 + }, + "control_target_metrics": null, + "control_token_id": 5984, + "error": "source_idx=3340 is not in the decomposition's active support", + "function": "language", + "layer": 8, + "real_target_metrics": null, + "source": "Canada", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7837142944335938, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 3594 + }, + "control_target_metrics": null, + "control_token_id": 13572, + "error": "source_idx=3340 is not in the decomposition's active support", + "function": "language", + "layer": 8, + "real_target_metrics": null, + "source": "Canada", + "status": "skipped_source_inactive", + "target": "Egypt" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.41039276123046875, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 17526 + }, + "control_target_metrics": null, + "control_token_id": 18842, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "language", + "layer": 8, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "France" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.41039276123046875, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 17526 + }, + "control_target_metrics": null, + "control_token_id": 986, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "language", + "layer": 8, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "Canada" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.41039276123046875, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 17526 + }, + "control_target_metrics": null, + "control_token_id": 4783, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "language", + "layer": 8, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.39803314208984375, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 2031 + }, + "control_target_metrics": null, + "control_token_id": 4474, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "continent", + "layer": 8, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Canada" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.39803314208984375, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 2031 + }, + "control_target_metrics": null, + "control_token_id": 5984, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "continent", + "layer": 8, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.39803314208984375, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 2031 + }, + "control_target_metrics": null, + "control_token_id": 13574, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "continent", + "layer": 8, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Egypt" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7269477844238281, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 5478 + }, + "control_target_metrics": null, + "control_token_id": 4965, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "continent", + "layer": 8, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "France" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7269477844238281, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 5478 + }, + "control_target_metrics": null, + "control_token_id": 986, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "continent", + "layer": 8, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "Canada" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7269477844238281, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 5478 + }, + "control_target_metrics": null, + "control_token_id": 4156, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "continent", + "layer": 8, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.08658599853515625, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 6342 + }, + "control_target_metrics": null, + "control_token_id": 7518, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "capital", + "layer": 9, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Canada" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.08658599853515625, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 6342 + }, + "control_target_metrics": null, + "control_token_id": 2005, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "capital", + "layer": 9, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.08658599853515625, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 6342 + }, + "control_target_metrics": null, + "control_token_id": 17343, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "capital", + "layer": 9, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Egypt" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.5519790649414062, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 4141 + }, + "control_target_metrics": null, + "control_token_id": 7518, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "language", + "layer": 9, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Canada" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.5519790649414062, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 4141 + }, + "control_target_metrics": null, + "control_token_id": 2863, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "language", + "layer": 9, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.5519790649414062, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 4141 + }, + "control_target_metrics": null, + "control_token_id": 18003, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "language", + "layer": 9, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Egypt" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7837142944335938, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 3594 + }, + "control_target_metrics": null, + "control_token_id": 14582, + "error": "source_idx=3340 is not in the decomposition's active support", + "function": "language", + "layer": 9, + "real_target_metrics": null, + "source": "Canada", + "status": "skipped_source_inactive", + "target": "France" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7837142944335938, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 3594 + }, + "control_target_metrics": null, + "control_token_id": 2863, + "error": "source_idx=3340 is not in the decomposition's active support", + "function": "language", + "layer": 9, + "real_target_metrics": null, + "source": "Canada", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7837142944335938, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 3594 + }, + "control_target_metrics": null, + "control_token_id": 18003, + "error": "source_idx=3340 is not in the decomposition's active support", + "function": "language", + "layer": 9, + "real_target_metrics": null, + "source": "Canada", + "status": "skipped_source_inactive", + "target": "Egypt" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.41039276123046875, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 17526 + }, + "control_target_metrics": null, + "control_token_id": 8060, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "language", + "layer": 9, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "France" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.41039276123046875, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 17526 + }, + "control_target_metrics": null, + "control_token_id": 6918, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "language", + "layer": 9, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "Canada" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.41039276123046875, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 17526 + }, + "control_target_metrics": null, + "control_token_id": 1614, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "language", + "layer": 9, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.39803314208984375, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 2031 + }, + "control_target_metrics": null, + "control_token_id": 7518, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "continent", + "layer": 9, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Canada" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.39803314208984375, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 2031 + }, + "control_target_metrics": null, + "control_token_id": 2005, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "continent", + "layer": 9, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.39803314208984375, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 2031 + }, + "control_target_metrics": null, + "control_token_id": 18003, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "continent", + "layer": 9, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Egypt" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7269477844238281, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 5478 + }, + "control_target_metrics": { + "target_is_top1": false, + "target_logit_margin": -1.921661376953125, + "target_rank": 3, + "target_tied_for_top": false, + "top1_token_id": 5478 + }, + "control_token_id": 4771, + "error": null, + "function": "continent", + "layer": 9, + "real_target_metrics": { + "target_is_top1": false, + "target_logit_margin": -1.9085540771484375, + "target_rank": 3, + "target_tied_for_top": false, + "top1_token_id": 5478 + }, + "source": "Egypt", + "status": "ok", + "target": "France" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7269477844238281, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 5478 + }, + "control_target_metrics": { + "target_is_top1": false, + "target_logit_margin": -2.8730621337890625, + "target_rank": 5, + "target_tied_for_top": false, + "top1_token_id": 5478 + }, + "control_token_id": 6918, + "error": null, + "function": "continent", + "layer": 9, + "real_target_metrics": { + "target_is_top1": false, + "target_logit_margin": -2.825183868408203, + "target_rank": 5, + "target_tied_for_top": false, + "top1_token_id": 5478 + }, + "source": "Egypt", + "status": "ok", + "target": "Canada" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7269477844238281, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 5478 + }, + "control_target_metrics": { + "target_is_top1": false, + "target_logit_margin": -2.7609634399414062, + "target_rank": 4, + "target_tied_for_top": false, + "top1_token_id": 5478 + }, + "control_token_id": 1632, + "error": null, + "function": "continent", + "layer": 9, + "real_target_metrics": { + "target_is_top1": false, + "target_logit_margin": -2.7115440368652344, + "target_rank": 4, + "target_tied_for_top": false, + "top1_token_id": 5478 + }, + "source": "Egypt", + "status": "ok", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.08658599853515625, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 6342 + }, + "control_target_metrics": null, + "control_token_id": 4266, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "capital", + "layer": 10, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Canada" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.08658599853515625, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 6342 + }, + "control_target_metrics": null, + "control_token_id": 15185, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "capital", + "layer": 10, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.08658599853515625, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 6342 + }, + "control_target_metrics": null, + "control_token_id": 454, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "capital", + "layer": 10, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Egypt" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.5519790649414062, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 4141 + }, + "control_target_metrics": null, + "control_token_id": 11361, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "language", + "layer": 10, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Canada" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.5519790649414062, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 4141 + }, + "control_target_metrics": null, + "control_token_id": 2669, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "language", + "layer": 10, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.5519790649414062, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 4141 + }, + "control_target_metrics": null, + "control_token_id": 35113, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "language", + "layer": 10, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Egypt" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7837142944335938, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 3594 + }, + "control_target_metrics": null, + "control_token_id": 5650, + "error": "source_idx=3340 is not in the decomposition's active support", + "function": "language", + "layer": 10, + "real_target_metrics": null, + "source": "Canada", + "status": "skipped_source_inactive", + "target": "France" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7837142944335938, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 3594 + }, + "control_target_metrics": null, + "control_token_id": 2669, + "error": "source_idx=3340 is not in the decomposition's active support", + "function": "language", + "layer": 10, + "real_target_metrics": null, + "source": "Canada", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7837142944335938, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 3594 + }, + "control_target_metrics": null, + "control_token_id": 26821, + "error": "source_idx=3340 is not in the decomposition's active support", + "function": "language", + "layer": 10, + "real_target_metrics": null, + "source": "Canada", + "status": "skipped_source_inactive", + "target": "Egypt" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.41039276123046875, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 17526 + }, + "control_target_metrics": null, + "control_token_id": 3866, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "language", + "layer": 10, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "France" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.41039276123046875, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 17526 + }, + "control_target_metrics": null, + "control_token_id": 13206, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "language", + "layer": 10, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "Canada" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.41039276123046875, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 17526 + }, + "control_target_metrics": null, + "control_token_id": 10357, + "error": "source_idx=6365 is not in the decomposition's active support", + "function": "language", + "layer": 10, + "real_target_metrics": null, + "source": "Egypt", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.39803314208984375, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 2031 + }, + "control_target_metrics": null, + "control_token_id": 11361, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "continent", + "layer": 10, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Canada" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.39803314208984375, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 2031 + }, + "control_target_metrics": null, + "control_token_id": 2670, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "continent", + "layer": 10, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "China" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.39803314208984375, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 2031 + }, + "control_target_metrics": null, + "control_token_id": 35113, + "error": "source_idx=4881 is not in the decomposition's active support", + "function": "continent", + "layer": 10, + "real_target_metrics": null, + "source": "France", + "status": "skipped_source_inactive", + "target": "Egypt" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7269477844238281, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 5478 + }, + "control_target_metrics": { + "target_is_top1": false, + "target_logit_margin": -1.8690147399902344, + "target_rank": 3, + "target_tied_for_top": false, + "top1_token_id": 5478 + }, + "control_token_id": 12053, + "error": null, + "function": "continent", + "layer": 10, + "real_target_metrics": { + "target_is_top1": false, + "target_logit_margin": -1.7807693481445312, + "target_rank": 3, + "target_tied_for_top": false, + "top1_token_id": 5478 + }, + "source": "Egypt", + "status": "ok", + "target": "France" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7269477844238281, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 5478 + }, + "control_target_metrics": { + "target_is_top1": false, + "target_logit_margin": -2.7808380126953125, + "target_rank": 5, + "target_tied_for_top": false, + "top1_token_id": 5478 + }, + "control_token_id": 4268, + "error": null, + "function": "continent", + "layer": 10, + "real_target_metrics": { + "target_is_top1": false, + "target_logit_margin": -2.749217987060547, + "target_rank": 5, + "target_tied_for_top": false, + "top1_token_id": 5478 + }, + "source": "Egypt", + "status": "ok", + "target": "Canada" + }, + { + "baseline": { + "target_is_top1": true, + "target_logit_margin": 0.7269477844238281, + "target_rank": 1, + "target_tied_for_top": false, + "top1_token_id": 5478 + }, + "control_target_metrics": { + "target_is_top1": false, + "target_logit_margin": -2.6646461486816406, + "target_rank": 4, + "target_tied_for_top": false, + "top1_token_id": 5478 + }, + "control_token_id": 15185, + "error": null, + "function": "continent", + "layer": 10, + "real_target_metrics": { + "target_is_top1": false, + "target_logit_margin": -2.54638671875, + "target_rank": 4, + "target_tied_for_top": false, + "top1_token_id": 5478 + }, + "source": "Egypt", + "status": "ok", + "target": "China" + } + ] +} diff --git a/docs/make_docs.py b/docs/make_docs.py index f80c32ce58..6f87b734bb 100644 --- a/docs/make_docs.py +++ b/docs/make_docs.py @@ -752,6 +752,7 @@ def copy_demos(_app: Optional[Any] = None): copy_to_dir = GENERATED_DIR / "demos" notebooks_to_copy = [ "Exploratory_Analysis_Demo.ipynb", + "Jacobian_Lens_Coordinate_Patch_Benchmark_Demo.ipynb", "Jacobian_Lens_Decomposition_Demo.ipynb", "Main_Demo.ipynb", ] diff --git a/docs/source/content/jacobian_lens_fitting.md b/docs/source/content/jacobian_lens_fitting.md index 9bec2f472e..eac7df52ce 100644 --- a/docs/source/content/jacobian_lens_fitting.md +++ b/docs/source/content/jacobian_lens_fitting.md @@ -404,6 +404,24 @@ vocabulary-scale solve on every forward pass unless `decomposition_cache` alread it. The conditioning and near-parallel warnings described above still fire from inside the hook, per pair, exactly as they would from an offline `coordinate_patch` call on that pair's activation. +### Causal-swap benchmark + +`transformer_lens.tools.analysis.jacobian_lens_causal_swap_benchmark` measures whether +`coordinate_patch_hooks` causes a directional change in model output, under baseline-capability +filtering, a norm-matched random-atom control, and bootstrap confidence intervals on every +reported rate. Each trial installs the hook at exactly one layer and the final prompt position; +a trial whose source concept is not active in that layer's support is recorded as skipped, not +silently dropped. + +A generation script (`python -m +transformer_lens.tools.analysis.jacobian_lens_causal_swap_benchmark`, no `HF_TOKEN` required) +produces a versioned, fingerprinted JSON artifact against the published GPT-2-small lens. The +[coordinate-patch benchmark demo](../generated/demos/Jacobian_Lens_Coordinate_Patch_Benchmark_Demo) +loads that frozen artifact and renders it; it never calls the model itself. A successful swap in +that artifact shows a directional causal effect under the stated controls on GPT-2-small, not +proof of unique causal mediation, exhaustive concept coverage, or a result that transfers to +closed-weight models. + ### Interpreting the numbers honestly The quantitative findings below are from Gurnee et al. (2026) and were measured on **closed diff --git a/docs/source/index.md b/docs/source/index.md index 565bb91cf8..d7551f0694 100644 --- a/docs/source/index.md +++ b/docs/source/index.md @@ -60,6 +60,7 @@ content/ssm_interpretability content/projection_kernel content/jacobian_lens_fitting generated/demos/Jacobian_Lens_Decomposition_Demo +generated/demos/Jacobian_Lens_Coordinate_Patch_Benchmark_Demo content/backward_lens content/debugging_numerical_divergence generated/demos/Main_Demo diff --git a/tests/integration/test_jacobian_lens_causal_swap_benchmark.py b/tests/integration/test_jacobian_lens_causal_swap_benchmark.py new file mode 100644 index 0000000000..0a7735cf17 --- /dev/null +++ b/tests/integration/test_jacobian_lens_causal_swap_benchmark.py @@ -0,0 +1,100 @@ +"""GPT-2 integration smoke test for the causal coordinate-swap benchmark. + +Structural assertions only -- no specific success-rate claim, matching the policy already +established for ``coordinate_patch_hooks`` itself. A deliberately tiny corpus (one function, +two concepts) keeps this fast enough for the regular cached-model integration suite; the full +country corpus runs only in the frozen-artifact generation script. +""" + +import pytest +import torch + +from transformer_lens.tools.analysis.jacobian_lens_causal_swap_benchmark import ( + SCHEMA_VERSION, + BenchmarkCorpus, + FunctionSpec, + bootstrap_success_rate_ci, + build_protocol_manifest, + run_causal_swap_benchmark, + serialize_artifact, +) + +LENS_REPO = "neuronpedia/jacobian-lens" +LENS_REVISION = "a4114d7752d11eb546e6cf372213d7e75526d3a1" +GPT2_LENS_FILE = "gpt2-small/jlens/Salesforce-wikitext/gpt2_jacobian_lens.pt" + + +@pytest.fixture(scope="module") +def gpt2_bridge(): + from transformer_lens.model_bridge import TransformerBridge + + device = "cuda" if torch.cuda.is_available() else "cpu" + return TransformerBridge.boot_transformers("gpt2", dtype=torch.float32, device=device) + + +@pytest.fixture(scope="module") +def published_gpt2_lens(gpt2_bridge): + from transformer_lens.tools.analysis import JacobianLens + + return JacobianLens.from_pretrained( + LENS_REPO, + filename=GPT2_LENS_FILE, + revision=LENS_REVISION, + model=gpt2_bridge, + ) + + +def test_causal_swap_benchmark_gpt2_smoke(published_gpt2_lens, gpt2_bridge) -> None: + corpus = BenchmarkCorpus( + name="smoke", + concepts=("France", "China"), + functions=( + FunctionSpec( + name="capital", + template="The capital of {arg} is the city of", + answers={"France": "Paris", "China": "Beijing"}, + ), + ), + ) + trials, excluded = run_causal_swap_benchmark( + published_gpt2_lens, + gpt2_bridge, + corpus, + layers=[6], + control_seed=0, + ) + assert len(trials) + len(excluded) >= 1 + + ok_trials = [t for t in trials if t.status == "ok"] + dictionary = published_gpt2_lens.lens_vector_dictionary(gpt2_bridge, 6) + for trial in ok_trials: + target_id = gpt2_bridge.to_single_token(f" {trial.target}") + control_norm = dictionary[trial.control_token_id].norm() + target_norm = dictionary[target_id].norm() + assert (control_norm - target_norm).abs() <= 0.1 * target_norm + 1e-6 + + manifest = build_protocol_manifest( + model_id="gpt2", + model_revision="n/a", + lens_repo=LENS_REPO, + lens_file=GPT2_LENS_FILE, + lens_revision=LENS_REVISION, + corpus_name=corpus.name, + layers=[6], + alpha=1.0, + k=8, + control_tolerance=0.1, + control_seed=0, + success_definition="target token id equals deterministic argmax token id", + baseline_definition="source answer token id equals deterministic argmax token id", + rank_definition="1 + count(logits strictly greater than target logit)", + ) + real_ci = bootstrap_success_rate_ci( + [t.real_target_metrics.target_is_top1 for t in ok_trials] or [False] + ) + control_ci = bootstrap_success_rate_ci( + [t.control_target_metrics.target_is_top1 for t in ok_trials] or [False] + ) + artifact = serialize_artifact(manifest, trials, excluded, real_ci, control_ci) + assert artifact["schema_version"] == SCHEMA_VERSION + assert artifact["protocol_fingerprint"] diff --git a/transformer_lens/tools/analysis/__init__.py b/transformer_lens/tools/analysis/__init__.py index 5d93a557ff..3959cd1584 100644 --- a/transformer_lens/tools/analysis/__init__.py +++ b/transformer_lens/tools/analysis/__init__.py @@ -20,6 +20,10 @@ the output vocabulary basis, with loading of published lens artifacts, native fitting, readouts, interventions, J-space sparse decomposition, and anchored coordinate patching (offline and dynamic/hooked). + - jacobian_lens_causal_swap_benchmark: A causal coordinate-swap benchmark for + ``coordinate_patch_hooks``, with baseline-capability filtering, norm-matched + random-atom controls, bootstrap confidence intervals, and a versioned, + fingerprinted JSON artifact schema. - projection_kernel: Basis-invariant subspace overlap and TransformerBridge attention-head OQ/OK/OV affinity. """ @@ -52,6 +56,13 @@ JacobianLens, JacobianLensReadout, ) +from transformer_lens.tools.analysis.jacobian_lens_causal_swap_benchmark import ( + BenchmarkCorpus, + FunctionSpec, + bootstrap_success_rate_ci, + load_artifact, + run_causal_swap_benchmark, +) from transformer_lens.tools.analysis.jacobian_lens_coordinate_patch import ( CoordinatePatch, solve_coordinate_patch, @@ -84,9 +95,11 @@ "BackwardLensLayerResult", "BackwardLensMatrixResult", "BackwardLensResult", + "BenchmarkCorpus", "CoordinatePatch", "DirectLogitAttribution", "EdgeAttributionConfig", + "FunctionSpec", "HeadAffinityPair", "HeadAffinityResult", "JSpaceDecomposition", @@ -104,14 +117,17 @@ "WeightLayout", "attention_head_subspace_affinity", "attribution_patch", + "bootstrap_success_rate_ci", "direct_logit_attribution", "estimate_occupancy", "get_act_patch_direct_path", "get_act_patch_direct_path_all_sources", "get_sparse_decomposition", + "load_artifact", "orthonormal_subspace", "projection_kernel", "random_projection_kernel_moments", + "run_causal_swap_benchmark", "solve_coordinate_patch", "solve_coordinate_patch_positions", ] diff --git a/transformer_lens/tools/analysis/jacobian_lens_causal_swap_benchmark.py b/transformer_lens/tools/analysis/jacobian_lens_causal_swap_benchmark.py index 43a5c88890..e9ccc4e970 100644 --- a/transformer_lens/tools/analysis/jacobian_lens_causal_swap_benchmark.py +++ b/transformer_lens/tools/analysis/jacobian_lens_causal_swap_benchmark.py @@ -7,10 +7,14 @@ from "any edit of similar magnitude would have mattered"), and bootstrap uncertainty on every reported rate. -This module is layered bottom-up and built out across several stages: the model-free prompt -corpus and rank/margin metric, baseline-capability filtering, norm-matched control-token -selection, and this stage's per-trial runner, which wires the first three together with real -``coordinate_patch_hooks`` calls against a live model. +This module is layered bottom-up: the model-free prompt corpus and rank/margin metric, +baseline-capability filtering, norm-matched control-token selection, a per-trial runner that +wires the first three together with real ``coordinate_patch_hooks`` calls against a live model, +and bootstrap confidence intervals plus a versioned, fingerprinted JSON artifact schema. Running +this module as a script (``python -m +transformer_lens.tools.analysis.jacobian_lens_causal_swap_benchmark``) generates the frozen +artifact consumed by ``demos/Jacobian_Lens_Coordinate_Patch_Benchmark_Demo.ipynb``; see +``main()`` below for the exact invocation. """ from __future__ import annotations @@ -562,3 +566,136 @@ def load_artifact(path: Path) -> Dict[str, Any]: "its protocol_manifest (the manifest may have been hand-edited or corrupted)" ) return artifact + + +_COUNTRY_CORPUS = BenchmarkCorpus( + name="countries", + concepts=("France", "Canada", "China", "Egypt"), + functions=( + FunctionSpec( + name="capital", + template="The capital of {arg} is the city of", + answers={"France": "Paris", "Canada": "Ottawa", "China": "Beijing", "Egypt": "Cairo"}, + ), + FunctionSpec( + name="language", + template="Most people in {arg} speak", + answers={ + "France": "French", + "Canada": "English", + "China": "Chinese", + "Egypt": "Arabic", + }, + ), + FunctionSpec( + name="continent", + template="{arg} is a country on the continent of", + answers={"France": "Europe", "Canada": "North", "China": "Asia", "Egypt": "Africa"}, + ), + FunctionSpec( + name="currency", + template="The single-word name for the currency now used in {arg} is the", + answers={"France": "Euro", "Canada": "Dollar", "China": "Yuan", "Egypt": "Pound"}, + ), + ), +) + +_GPT2_LENS_REPO = "neuronpedia/jacobian-lens" +_GPT2_LENS_FILE = "gpt2-small/jlens/Salesforce-wikitext/gpt2_jacobian_lens.pt" +_GPT2_LENS_REVISION = "a4114d7752d11eb546e6cf372213d7e75526d3a1" +_DEFAULT_ARTIFACT_PATH = ( + Path(__file__).resolve().parents[3] + / "demos" + / "data" + / "jacobian_lens_causal_swap_benchmark_gpt2.json" +) + + +def main(argv: Optional[Sequence[str]] = None) -> None: + """Generates the frozen GPT-2 causal-swap benchmark artifact. + + Reproduce with (no ``HF_TOKEN`` needed -- GPT-2 is not gated):: + + uv run python -m transformer_lens.tools.analysis.jacobian_lens_causal_swap_benchmark + + Loads the published GPT-2-small lens (the same artifact + ``tests/integration/test_jacobian_lens.py`` uses), runs the reused country corpus over + every one of the lens's fitted source layers, and writes the versioned, fingerprinted JSON + artifact consumed by ``demos/Jacobian_Lens_Coordinate_Patch_Benchmark_Demo.ipynb``. + """ + import argparse + + import torch + + from transformer_lens.model_bridge import TransformerBridge + + parser = argparse.ArgumentParser(description=main.__doc__) + parser.add_argument("--output", type=Path, default=_DEFAULT_ARTIFACT_PATH) + parser.add_argument("--control-tolerance", type=float, default=0.1) + parser.add_argument("--control-seed", type=int, default=0) + parser.add_argument("--alpha", type=float, default=1.0) + parser.add_argument("--k", type=int, default=DEFAULT_K) + args = parser.parse_args(argv) + + device = "cuda" if torch.cuda.is_available() else "cpu" + model = TransformerBridge.boot_transformers("gpt2", dtype=torch.float32, device=device) + lens = JacobianLens.from_pretrained( + _GPT2_LENS_REPO, + filename=_GPT2_LENS_FILE, + revision=_GPT2_LENS_REVISION, + model=model, + ) + layers = list(lens.source_layers) + + trials, excluded = run_causal_swap_benchmark( + lens, + model, + _COUNTRY_CORPUS, + layers, + control_tolerance=args.control_tolerance, + control_seed=args.control_seed, + alpha=args.alpha, + k=args.k, + ) + ok_trials = [trial for trial in trials if trial.status == "ok"] + if not ok_trials: + raise RuntimeError("no trial survived baseline filtering and the active-support check") + + real_successes: List[bool] = [] + control_successes: List[bool] = [] + for trial in ok_trials: + assert trial.real_target_metrics is not None + assert trial.control_target_metrics is not None + real_successes.append(trial.real_target_metrics.target_is_top1) + control_successes.append(trial.control_target_metrics.target_is_top1) + + manifest = build_protocol_manifest( + model_id="gpt2", + model_revision="n/a", + lens_repo=_GPT2_LENS_REPO, + lens_file=_GPT2_LENS_FILE, + lens_revision=_GPT2_LENS_REVISION, + corpus_name=_COUNTRY_CORPUS.name, + layers=layers, + alpha=args.alpha, + k=args.k, + control_tolerance=args.control_tolerance, + control_seed=args.control_seed, + success_definition="target token id equals deterministic argmax token id", + baseline_definition="source answer token id equals deterministic argmax token id", + rank_definition="1 + count(logits strictly greater than target logit)", + ) + real_ci = bootstrap_success_rate_ci(real_successes) + control_ci = bootstrap_success_rate_ci(control_successes) + artifact = serialize_artifact(manifest, trials, excluded, real_ci, control_ci) + + args.output.parent.mkdir(parents=True, exist_ok=True) + args.output.write_text(json.dumps(artifact, indent=2, sort_keys=True) + "\n") + print( + f"wrote {len(trials)} trials ({len(ok_trials)} ok, {len(excluded)} excluded prompts) " + f"to {args.output}" + ) + + +if __name__ == "__main__": + main() From 1c91036597a412f5996361cdd0e2fe0926d9b57e Mon Sep 17 00:00:00 2001 From: janmenjayap Date: Sun, 20 Sep 2026 08:30:41 +0530 Subject: [PATCH 7/7] test(make_docs): expect coordinate-patch benchmark demo in copied notebooks --- tests/unit/test_make_docs.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/unit/test_make_docs.py b/tests/unit/test_make_docs.py index fbfa6092b8..3066ce940c 100644 --- a/tests/unit/test_make_docs.py +++ b/tests/unit/test_make_docs.py @@ -39,6 +39,7 @@ def test_copy_demos_creates_generated_dir_when_absent(tmp_path, monkeypatch): copied = sorted(p.name for p in (generated / "demos").iterdir()) assert copied == [ "Exploratory_Analysis_Demo.ipynb", + "Jacobian_Lens_Coordinate_Patch_Benchmark_Demo.ipynb", "Jacobian_Lens_Decomposition_Demo.ipynb", "Main_Demo.ipynb", ]