Skip to content
Merged

v4.3.0 #1937

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
8350a11
docs(svd_circuits): add demo notebook, slow name-mover parity, and to…
janmenjayap Oct 12, 2026
0973df0
fix: preserve penalties in stateful generation fallback (#1888)
emerardd Oct 12, 2026
c4b1ddf
feat(relevance_lens): RelevanceLens.fit + provenance + integration + …
janmenjayap Oct 12, 2026
404de90
feat(attribution_patching): faithfulness (edge ablation) on Transform…
janmenjayap Oct 12, 2026
c5bf8e0
feat(sparse_probing): support group-aware probe splits (#1824)
lorenzozanee Oct 12, 2026
0b3ff8f
Adjusting post norm MLP to be properly differentiated (#1890)
jlarson4 Oct 12, 2026
884179c
Fix T5 bridge forward with transformers >= 5.15 (#1882)
YHC66 Oct 12, 2026
aa93326
fix: use last axis when removing BOS tokens (#1891)
AaravMehta-07 Oct 12, 2026
426ce24
fix: include Granite embedding scale in residual decomposition (#1878)
emerardd Oct 13, 2026
470e74f
fix: apply MLA complex RoPE to rope slices that are not aligned in st…
YHC66 Oct 13, 2026
ad42ad1
Add subspace interchange interventions (#1892)
dipo101 Oct 13, 2026
c80c38e
fix: keep RMSNorm offsets out of Gemma3 vision LayerNorm (#1897)
emerardd Oct 14, 2026
149ad58
Fixing a bug with Jais2 (#1900)
jlarson4 Oct 14, 2026
3ed294e
fix: preserve prompt attention masks in generation caches (#1899)
emerardd Oct 14, 2026
55d5284
Add distributed alignment search for interchange interventions (#1893)
dipo101 Oct 14, 2026
45e8331
Adding Guards to our `tools/analysis` modules (#1901)
jlarson4 Oct 14, 2026
edaf8a7
Add trained controls for distributed alignment search (#1894)
dipo101 Oct 15, 2026
413a38b
Demoted some analysis tools to demos or sub-methods of other features…
jlarson4 Oct 15, 2026
22ac563
fix: preserve final RMS predictions during weight processing (#1903)
emerardd Oct 16, 2026
177d2cc
Preserve float64 precision in bootstrap and sign-flip statistics (#1905)
AaravMehta-07 Oct 16, 2026
5ecec30
fix: preserve retained hooks during bridge helper cleanup (#1908)
emerardd Oct 19, 2026
487f8ae
Count only the cost warning in the coordinate_patch_hooks warn-once t…
YHC66 Oct 19, 2026
3c3879c
Fix level-scoped permanent hook cleanup (#1914)
koriyoshi2041 Oct 19, 2026
a4abca6
fix: keep created biases in the model dtype during weight processing …
tivris Oct 19, 2026
aac2197
fix: preserve autograd through equal-valued scaled hooks (#1915)
emerardd Oct 19, 2026
2ad4929
Restore num_experts when an HF config aliases it via attribute_map (#…
YHC66 Oct 19, 2026
c60d59f
Add neuron bases for interchange interventions (#1921)
dipo101 Oct 21, 2026
4a92ca5
fix: compute FactoredMatrix and SVDInterpreter SVDs in float32 for 16…
tivris Oct 21, 2026
91f2e7d
Apply the causal mask in MLAAttentionBridge when HF passes no 4D mask…
YHC66 Oct 21, 2026
873056f
fix(ActivationCache): build layer-0 stacks in the cache's dtype and d…
avgvi Oct 21, 2026
c5affed
fix(test_prompt): read each answer's first token regardless of the to…
avgvi Oct 21, 2026
e7feb73
fix: apply dtype and device changes to gated MLPs in compatibility mo…
tivris Oct 21, 2026
29eca2b
Fixing the flaky backwards lens test (#1930)
jlarson4 Oct 21, 2026
0c302cc
Fix/slow tier memory budget (#1928)
jlarson4 Oct 21, 2026
034ad4e
fix(statistics): compute the binomial CDF in log space so it does not…
bercedev Oct 21, 2026
a3dff50
feat(bridge): RoBERTa masked-LM adapter (#1895)
Canonik Oct 21, 2026
12cfe63
fix: validate reused coordinate decompositions by pursuit algorithm (…
emerardd Oct 22, 2026
81e2bb2
Pre-release preparation for v4.3.0 (#1934)
jlarson4 Oct 22, 2026
7d4f463
docs(demos): add SwiGLU gate-sign demo for double-negative echoes (#1…
emerardd Oct 22, 2026
883571a
fix: register unmapped leaf parameters so module conversions reach th…
tivris Oct 22, 2026
436f097
fix(bridge): discover non-standard block lists in _enumerate_blocks (…
LightWork666 Oct 23, 2026
a0db56e
fix(jacobian_lens): ablate token directions jointly (#1941)
flyingdoubleG Oct 23, 2026
34c5d77
fix: preserve selected J-space directions across atom scales (#1942)
emerardd Oct 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,8 @@ jobs:
- "Patchscopes_Generation_Demo"
- "Santa_Coder"
# - "stable_lm"
- "SVD_Circuits_Demo"
- "SwiGLU_Gate_Sign_Demo"
- "T5"
requires_hf_token: [false]
include:
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/slow-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ jobs:
df -h /
- name: Add swap for fp32 CPU model boots
run: |
# The runner image can ship /swapfile already active; fallocate on
# live swap fails with "Text file busy", so release it first.
sudo swapoff /swapfile 2>/dev/null || true
sudo rm -f /swapfile
sudo fallocate -l 8G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
Expand Down
1,192 changes: 387 additions & 805 deletions demos/Backward_Lens_Demo.ipynb

Large diffs are not rendered by default.

75 changes: 47 additions & 28 deletions demos/Jacobian_Lens_Coordinate_Patch_Benchmark_Demo.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@
"prompts behind it.\n",
"\n",
"**This notebook loads a frozen artifact and never calls the model.** The artifact was\n",
"generated once, out-of-band, by running the benchmark's CLI entry point; see the load cell\n",
"below for the exact command. Re-running the sweep is a separate, explicit step, not something\n",
"this notebook triggers.\n"
"generated once, out-of-band, by `scripts/jacobian_lens_causal_swap_benchmark.py`; the load\n",
"cell below names the exact command. Re-running the sweep is a separate, explicit step, not\n",
"something this notebook triggers.\n"
]
},
{
Expand All @@ -59,10 +59,10 @@
"id": "8a272a14",
"metadata": {
"execution": {
"iopub.execute_input": "2026-09-24T12:26:45.620923Z",
"iopub.status.busy": "2026-09-24T12:26:45.620839Z",
"iopub.status.idle": "2026-09-24T12:26:45.623972Z",
"shell.execute_reply": "2026-09-24T12:26:45.623559Z"
"iopub.execute_input": "2026-10-14T18:27:57.152894Z",
"iopub.status.busy": "2026-10-14T18:27:57.152687Z",
"iopub.status.idle": "2026-10-14T18:27:57.158584Z",
"shell.execute_reply": "2026-10-14T18:27:57.157853Z"
}
},
"outputs": [
Expand All @@ -88,10 +88,10 @@
"id": "bc924b1c",
"metadata": {
"execution": {
"iopub.execute_input": "2026-09-24T12:26:45.625566Z",
"iopub.status.busy": "2026-09-24T12:26:45.625485Z",
"iopub.status.idle": "2026-09-24T12:26:49.109284Z",
"shell.execute_reply": "2026-09-24T12:26:49.108728Z"
"iopub.execute_input": "2026-10-14T18:27:57.160521Z",
"iopub.status.busy": "2026-10-14T18:27:57.160357Z",
"iopub.status.idle": "2026-10-14T18:27:58.846420Z",
"shell.execute_reply": "2026-10-14T18:27:58.845982Z"
}
},
"outputs": [
Expand All @@ -111,14 +111,18 @@
}
],
"source": [
"import hashlib\n",
"import json\n",
"from pathlib import Path\n",
"\n",
"import numpy as np\n",
"import pandas as pd\n",
"\n",
"from transformer_lens.tools.analysis import load_artifact, success_rate_ci\n",
"from transformer_lens.utilities import success_rate_ci\n",
"\n",
"ARTIFACT_NAME = \"jacobian_lens_causal_swap_benchmark_gpt2.json\"\n",
"SCHEMA_VERSION = 2\n",
"RESULT_BLOCKS = (\"trials\", \"excluded_baselines\", \"real_success_ci\", \"control_success_ci\")\n",
"\n",
"\n",
"def _find_artifact() -> Path:\n",
Expand All @@ -137,15 +141,30 @@
" \"directory. This notebook requires a repository checkout: it loads a frozen \"\n",
" \"artifact that is not packaged in the transformer_lens wheel. Clone the repository \"\n",
" \"and run the notebook from within it, or regenerate the artifact with \"\n",
" \"`uv run python -m transformer_lens.tools.analysis.\"\n",
" \"jacobian_lens_causal_swap_benchmark_cli`.\"\n",
" \"`uv run python scripts/jacobian_lens_causal_swap_benchmark.py`.\"\n",
" )\n",
"\n",
"\n",
"def _fingerprint(payload) -> str:\n",
" \"\"\"SHA-256 over canonical JSON, the same recipe the generation script uses.\"\"\"\n",
" canonical = json.dumps(payload, sort_keys=True, separators=(\",\", \":\"))\n",
" return hashlib.sha256(canonical.encode()).hexdigest()\n",
"\n",
"\n",
"ARTIFACT_PATH = _find_artifact()\n",
"REPO_ROOT = ARTIFACT_PATH.parents[2]\n",
"artifact = load_artifact(ARTIFACT_PATH)\n",
"artifact = json.loads(ARTIFACT_PATH.read_text())\n",
"manifest = artifact[\"protocol_manifest\"]\n",
"# Recomputed rather than trusted, so a hand-edited artifact or one from another schema fails\n",
"# here instead of rendering as if the script had produced it.\n",
"expected = {\n",
" \"schema_version\": SCHEMA_VERSION,\n",
" \"protocol_fingerprint\": _fingerprint(manifest),\n",
" \"results_fingerprint\": _fingerprint({key: artifact[key] for key in RESULT_BLOCKS}),\n",
"}\n",
"for field, value in expected.items():\n",
" if artifact[field] != value:\n",
" raise ValueError(f\"artifact {field} is {artifact[field]!r}, expected {value!r}\")\n",
"print(f\"artifact={ARTIFACT_PATH.relative_to(REPO_ROOT)}\")\n",
"print(f\"schema_version={artifact['schema_version']}\")\n",
"print(f\"protocol_fingerprint={artifact['protocol_fingerprint']}\")\n",
Expand Down Expand Up @@ -188,10 +207,10 @@
"id": "1feb4158",
"metadata": {
"execution": {
"iopub.execute_input": "2026-09-24T12:26:49.110784Z",
"iopub.status.busy": "2026-09-24T12:26:49.110543Z",
"iopub.status.idle": "2026-09-24T12:26:49.123206Z",
"shell.execute_reply": "2026-09-24T12:26:49.122757Z"
"iopub.execute_input": "2026-10-14T18:27:58.847684Z",
"iopub.status.busy": "2026-10-14T18:27:58.847570Z",
"iopub.status.idle": "2026-10-14T18:27:58.860441Z",
"shell.execute_reply": "2026-10-14T18:27:58.860108Z"
}
},
"outputs": [
Expand Down Expand Up @@ -391,10 +410,10 @@
"id": "c74c1711",
"metadata": {
"execution": {
"iopub.execute_input": "2026-09-24T12:26:49.124146Z",
"iopub.status.busy": "2026-09-24T12:26:49.124073Z",
"iopub.status.idle": "2026-09-24T12:26:49.486825Z",
"shell.execute_reply": "2026-09-24T12:26:49.486520Z"
"iopub.execute_input": "2026-10-14T18:27:58.861362Z",
"iopub.status.busy": "2026-10-14T18:27:58.861303Z",
"iopub.status.idle": "2026-10-14T18:27:59.241197Z",
"shell.execute_reply": "2026-10-14T18:27:59.240779Z"
}
},
"outputs": [
Expand Down Expand Up @@ -516,10 +535,10 @@
"id": "dedef2ac",
"metadata": {
"execution": {
"iopub.execute_input": "2026-09-24T12:26:49.488012Z",
"iopub.status.busy": "2026-09-24T12:26:49.487879Z",
"iopub.status.idle": "2026-09-24T12:26:49.494153Z",
"shell.execute_reply": "2026-09-24T12:26:49.493735Z"
"iopub.execute_input": "2026-10-14T18:27:59.242250Z",
"iopub.status.busy": "2026-10-14T18:27:59.242130Z",
"iopub.status.idle": "2026-10-14T18:27:59.248415Z",
"shell.execute_reply": "2026-10-14T18:27:59.248094Z"
}
},
"outputs": [
Expand Down Expand Up @@ -764,7 +783,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.14"
"version": "3.12.12"
}
},
"nbformat": 4,
Expand Down
8 changes: 4 additions & 4 deletions demos/Jacobian_Lens_Demo.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -334,9 +334,9 @@
"(pseudoinverse), and write back $h \\leftarrow h + \\alpha\\, V(\\sigma(c) - c)$ where $\\sigma$\n",
"exchanges the two coordinates — leaving the orthogonal complement of the activation untouched.\n",
"The paper clamps the exchanged clean-run coordinates at every token position across an\n",
"intermediate-layer band (layers 10–24 ≈ the paper's 38–92% workspace band). Unlike\n",
"`swap_hooks`, which re-reads and swaps the live coordinates at each layer,\n",
"`swap_clamp_hooks` holds every layer at the same clean-run counterfactual target."
"intermediate-layer band (layers 10–24 ≈ the paper's 38–92% workspace band). By default\n",
"`swap_hooks` re-reads and swaps the live coordinates at each layer; passing the clean cache\n",
"as `clamp_to` instead holds every layer at the same clean-run counterfactual target."
]
},
{
Expand Down Expand Up @@ -393,7 +393,7 @@
" tokens = model.to_tokens(prompt)\n",
" with torch.no_grad():\n",
" _, clean_cache = model.run_with_cache(tokens)\n",
" hooks = lens.swap_clamp_hooks(model, source, target, layers, clean_cache)\n",
" hooks = lens.swap_hooks(model, source, target, layers, clamp_to=clean_cache)\n",
" with model.hooks(fwd_hooks=hooks):\n",
" return model(tokens)[0, -1].float()\n",
"\n",
Expand Down
Loading
Loading