diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml
index d40428a30..3cb338493 100644
--- a/.github/workflows/checks.yml
+++ b/.github/workflows/checks.yml
@@ -430,6 +430,7 @@ jobs:
- "Activation_Patching_in_TL_Demo"
- "ARENA_Content"
- "BERT"
+ - "Backward_Lens_Demo"
- "Bridge_Evals_Demo"
- "Exploratory_Analysis_Demo"
# - "Grokking_Demo"
diff --git a/demos/Backward_Lens_Demo.ipynb b/demos/Backward_Lens_Demo.ipynb
new file mode 100644
index 000000000..6e15b1238
--- /dev/null
+++ b/demos/Backward_Lens_Demo.ipynb
@@ -0,0 +1,1763 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "97d2c037",
+ "metadata": {},
+ "source": [
+ "# Backward Lens: GPT-2 gradient factors in vocabulary space\n",
+ "\n",
+ "This notebook demonstrates `BackwardLens` on a small, fixed set of GPT-2 next-token targets. It reproduces the *method* of projecting forward inputs and backward signals into vocabulary space; it is not a paper-scale replication and makes no causal claim from token rankings alone. All examples and layers are declared before analysis, and all outcomes are shown without filtering.\n",
+ "\n",
+ "The implementation follows [Katz et al. (2024)](https://aclanthology.org/2024.emnlp-main.142/). Gradient signs below are raw `d(loss) / d(tensor)` signs; gradient descent subtracts them."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "64c3d670",
+ "metadata": {},
+ "source": [
+ "## Geometry\n",
+ "\n",
+ "For GPT-2's `[in, out]` `Conv1D` weight layout, token-position factors reconstruct the gradient as\n",
+ "\n",
+ "$$\\nabla_W L = \\sum_i x_i \\delta_i^\\mathsf{T} = X^\\mathsf{T}\\Delta.$$\n",
+ "\n",
+ "For FF1 (`c_fc`), the residual-width factor is the forward input $x_i$. For FF2 (`c_proj`), it is the backward signal $\\delta_i$. `BackwardLens` applies a fresh `ln_final` and unembedding to those residual-width rows."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "4955da53",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-09-02T13:04:37.335213Z",
+ "iopub.status.busy": "2026-09-02T13:04:37.335044Z",
+ "iopub.status.idle": "2026-09-02T13:05:32.078419Z",
+ "shell.execute_reply": "2026-09-02T13:05:32.077709Z"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "
\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " prompt | \n",
+ " one-token target | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | 0 | \n",
+ " The capital of France is | \n",
+ " Paris | \n",
+ "
\n",
+ " \n",
+ " | 1 | \n",
+ " The capital of Italy is | \n",
+ " Rome | \n",
+ "
\n",
+ " \n",
+ " | 2 | \n",
+ " The largest planet in the Solar System is | \n",
+ " Jupiter | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " prompt one-token target\n",
+ "0 The capital of France is Paris\n",
+ "1 The capital of Italy is Rome\n",
+ "2 The largest planet in the Solar System is Jupiter"
+ ]
+ },
+ "execution_count": 1,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "# NBVAL_IGNORE_OUTPUT\n",
+ "import gc\n",
+ "import os\n",
+ "import warnings\n",
+ "\n",
+ "os.environ[\"HF_HUB_DISABLE_PROGRESS_BARS\"] = \"1\"\n",
+ "os.environ[\"TOKENIZERS_PARALLELISM\"] = \"false\"\n",
+ "\n",
+ "import matplotlib.pyplot as plt\n",
+ "import numpy as np\n",
+ "import pandas as pd\n",
+ "import torch\n",
+ "from huggingface_hub.utils import logging as hf_hub_logging\n",
+ "from IPython.display import display\n",
+ "from transformers.utils import logging as hf_logging\n",
+ "from typeguard import InstrumentationWarning\n",
+ "\n",
+ "with warnings.catch_warnings():\n",
+ " warnings.filterwarnings(\n",
+ " \"ignore\",\n",
+ " message=\"@typechecked only supports instrumenting functions wrapped.*\",\n",
+ " category=InstrumentationWarning,\n",
+ " )\n",
+ " from transformer_lens.model_bridge import TransformerBridge\n",
+ " from transformer_lens.tools.analysis import BackwardLens\n",
+ "\n",
+ "hf_hub_logging.set_verbosity_error()\n",
+ "hf_logging.set_verbosity_error()\n",
+ "hf_logging.disable_progress_bar()\n",
+ "torch.manual_seed(0)\n",
+ "\n",
+ "DEVICE = \"cpu\" # Stable saved outputs and portable notebook validation.\n",
+ "DETAILED_LAYERS = (0, 2, 4, 6, 8, 10, 11)\n",
+ "EXAMPLES = (\n",
+ " (\"The capital of France is\", \" Paris\"),\n",
+ " (\"The capital of Italy is\", \" Rome\"),\n",
+ " (\"The largest planet in the Solar System is\", \" Jupiter\"),\n",
+ ")\n",
+ "\n",
+ "pd.DataFrame(EXAMPLES, columns=[\"prompt\", \"one-token target\"])"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "8b1857ae",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-09-02T13:05:32.080857Z",
+ "iopub.status.busy": "2026-09-02T13:05:32.080627Z",
+ "iopub.status.idle": "2026-09-02T13:05:32.517362Z",
+ "shell.execute_reply": "2026-09-02T13:05:32.516603Z"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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OxyiZ9LWyx1eHk0xd/VWXLmdqO1wSIuORl7B8u0H0aubL+wb1NN2OPQfJZFI8NbQl3E+6hJW/b2J90q1xMUr0Vi+7k907tAKTRu5aDscegqJKNMPY//hU1i0fD2aNGkCn44d0aZNG5ibm2szPnoKmUyG69euITIyEufOnUP7Nh74bNo4GBkaajs0omdWUFCIz7/5GTdvxWNod18EtHGHk62NtsOiF0AIgZt3U3E08gq2HTuLbgEdMe39t6Cvx9ePkXbJ75W8W7VCjy7+8GrRAgYGfJ93TSKEQGJyMsIiIrDrYAi823jg84/egSHPo85TSlwA4OTZC/h331Fcio6BRCKBg4M9TE3NYMgbYZ1SUlKC/Lw83H9wH3l5+XCwt0W3Lh3w+mt9mLRQrVJQUIglv2/EibBIFBYVobFjAzRybADzOiYw5CDtWqdIKkV2XgGu3rmLlLQMWJqboVd3X4wZ/iqTFtIZh0PPYt0/e5CUcg9mpqZo2bw5LMzNYWJszDESOqxYKkVuXh5ux8fjbkoKTOuYoJu/DyaMGcKkpYZQSVzkMjKzcfJMJG7HJyEnNw9FxXyfgi7R09ODuakp6terC1+f1mjc0JkXS6rVCgqLEB4ZjRNnInHvwUPk5ORBxq4atY6hgT7MzUzh4mQP/87t0KZlCxgYMEEl3SOEwO07d3E8LAJXb9xCTk6+4l0gpJsM9EuvLw729RHQ2RvtWrvzy94aptzEhYiIiIiISFfwuTsREREREek8Ji5ERERERKTzmLgQEREREZHOY+JCREREREQ6j4kLERERERHpPCYuRERERESk85i4EBERERGRzmPiQkREREREOo+JCxERERER6TwmLkREREREpPOYuBARERERkc5j4kJERERERDqPiQsREREREek8Ji5ERERERKTzmLgQEREREZHOY+JCREREREQ6j4kLERERERHpPCYuRERERESk85i4EBERERGRzmPiQkREREREOo+JCxERERER6TwmLkREREREpPOYuBARERERkc5j4kJERERERDqPiQsREREREek8Ji5ERERERKTzmLgQEREREZHOY+JCREREREQ6j4kLERERERHpPCYuRERERESk85i4EBERERGRzmPiQkREREREOo+JCxERERER6TwmLkREREREpPOYuBARERERkc5j4kJERERERDqPiQsRERHRf0RG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",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "# Original schematic: each position contributes one outer product.\n",
+ "fig, ax = plt.subplots(figsize=(10, 3.2))\n",
+ "ax.axis(\"off\")\n",
+ "boxes = [\n",
+ " (0.04, 0.55, \"forward row\\n$x_i$\", \"#dbeafe\"),\n",
+ " (0.28, 0.55, r\"$\\otimes$\", \"white\"),\n",
+ " (0.43, 0.55, \"backward row\\n\" r\"$\\delta_i$\", \"#fee2e2\"),\n",
+ " (0.67, 0.55, \"$=$\", \"white\"),\n",
+ " (0.80, 0.55, \"rank-one\\ncontribution\", \"#ede9fe\"),\n",
+ "]\n",
+ "for x, y, label, color in boxes:\n",
+ " ax.text(\n",
+ " x,\n",
+ " y,\n",
+ " label,\n",
+ " ha=\"center\",\n",
+ " va=\"center\",\n",
+ " fontsize=12,\n",
+ " bbox=dict(boxstyle=\"round,pad=0.5\", facecolor=color, edgecolor=\"#475569\"),\n",
+ " )\n",
+ "ax.annotate(\n",
+ " \"sum over prompt positions\",\n",
+ " xy=(0.80, 0.27),\n",
+ " xytext=(0.43, 0.12),\n",
+ " arrowprops=dict(arrowstyle=\"->\", color=\"#475569\"),\n",
+ " color=\"#334155\",\n",
+ ")\n",
+ "ax.set_title(\"Outer-product decomposition of one MLP weight gradient\", fontsize=14)\n",
+ "plt.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ea451106",
+ "metadata": {},
+ "source": [
+ "## Load a raw GPT-2 Bridge\n",
+ "\n",
+ "Backward Lens requires original GPT-2 weights. Do not enable compatibility mode or process the weights. CPU float32 is used deliberately so the saved notebook is portable; change `DEVICE` for interactive exploration."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "a5007e02",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-09-02T13:05:32.519185Z",
+ "iopub.status.busy": "2026-09-02T13:05:32.518979Z",
+ "iopub.status.idle": "2026-09-02T13:05:34.263223Z",
+ "shell.execute_reply": "2026-09-02T13:05:34.262420Z"
+ }
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Loaded a raw GPT-2 TransformerBridge.\n"
+ ]
+ }
+ ],
+ "source": [
+ "with warnings.catch_warnings():\n",
+ " warnings.simplefilter(\"ignore\")\n",
+ " model = TransformerBridge.boot_transformers(\n",
+ " \"gpt2\", device=DEVICE, dtype=torch.float32\n",
+ " )\n",
+ "model.eval()\n",
+ "lens = BackwardLens(model)\n",
+ "print(\"Loaded a raw GPT-2 TransformerBridge.\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "60ea683d",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-09-02T13:05:34.265510Z",
+ "iopub.status.busy": "2026-09-02T13:05:34.265279Z",
+ "iopub.status.idle": "2026-09-02T13:05:34.682954Z",
+ "shell.execute_reply": "2026-09-02T13:05:34.682165Z"
+ }
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Analyzed 6 positions across 7 layers.\n"
+ ]
+ }
+ ],
+ "source": [
+ "def final_position_summary(result):\n",
+ " rows = []\n",
+ " for layer_result in result.layers:\n",
+ " ff2 = layer_result.output_projection\n",
+ " rows.append(\n",
+ " {\n",
+ " \"layer\": layer_result.layer,\n",
+ " \"raw target rank\": int(\n",
+ " ff2.gradient_descent_target_ranks(result.target_token_id)[-1]\n",
+ " ),\n",
+ " \"normalized target rank\": int(\n",
+ " ff2.gradient_descent_target_ranks(\n",
+ " result.target_token_id, normalized=True\n",
+ " )[-1]\n",
+ " ),\n",
+ " \"final-position VJP norm\": float(ff2.factor_norms[-1]),\n",
+ " }\n",
+ " )\n",
+ " return pd.DataFrame(rows)\n",
+ "\n",
+ "\n",
+ "prompt, target = EXAMPLES[0]\n",
+ "primary_result = lens.analyze(prompt, target, DETAILED_LAYERS, normalized=True)\n",
+ "primary_layer_summary = final_position_summary(primary_result)\n",
+ "print(\n",
+ " f\"Analyzed {len(primary_result.prompt_token_ids)} positions across \"\n",
+ " f\"{len(primary_result.layers)} layers.\"\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8c36830d",
+ "metadata": {},
+ "source": [
+ "## Vocabulary-facing factor tables\n",
+ "\n",
+ "FF1 top tokens describe forward residual directions. FF2 bottom tokens use the ascending raw-gradient ordering relevant to a subtracted gradient-descent update. The layer-by-position table keeps those two factors separate. The final-position comparison shows how unit normalization changes FF2 token ordering while retaining and coloring by the original VJP norm.\n",
+ "\n",
+ "The sign panel compares the largest raw-gradient logits with the ordering obtained by subtracting those same projected logits. It is deliberately labeled as an ordering diagnostic, not as $P(-v)$: final LayerNorm makes direct factor negation a different operation. None of these tables are direct model predictions."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "id": "663bd83f",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-09-02T13:05:34.685339Z",
+ "iopub.status.busy": "2026-09-02T13:05:34.685077Z",
+ "iopub.status.idle": "2026-09-02T13:05:35.033441Z",
+ "shell.execute_reply": "2026-09-02T13:05:35.032697Z"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " layer | \n",
+ " position | \n",
+ " prompt token | \n",
+ " FF1 top raw directions | \n",
+ " FF2 bottom raw (update ordering) | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | 0 | \n",
+ " 0 | \n",
+ " 0 | \n",
+ " <|endoftext|> | \n",
+ " <|endoftext|>, Advertisements, \\n | \n",
+ " %], Thumbnail, 女 | \n",
+ "
\n",
+ " \n",
+ " | 1 | \n",
+ " 0 | \n",
+ " 1 | \n",
+ " The | \n",
+ " The, the, The | \n",
+ " ixel, Medium, iop | \n",
+ "
\n",
+ " \n",
+ " | 2 | \n",
+ " 0 | \n",
+ " 2 | \n",
+ " capital | \n",
+ " capital, capital, Capital | \n",
+ " inventoryQuantity, catentry, }}} | \n",
+ "
\n",
+ " \n",
+ " | 3 | \n",
+ " 0 | \n",
+ " 3 | \n",
+ " of | \n",
+ " of, of, Of | \n",
+ " Archdemon, ortium, Difference | \n",
+ "
\n",
+ " \n",
+ " | 4 | \n",
+ " 0 | \n",
+ " 4 | \n",
+ " France | \n",
+ " France, France, French | \n",
+ " anton, Seasons, figure | \n",
+ "
\n",
+ " \n",
+ " | 5 | \n",
+ " 0 | \n",
+ " 5 | \n",
+ " is | \n",
+ " is, also, was | \n",
+ " adr, adian, umn | \n",
+ "
\n",
+ " \n",
+ " | 6 | \n",
+ " 2 | \n",
+ " 0 | \n",
+ " <|endoftext|> | \n",
+ " ,, the, \\n | \n",
+ " ometric, Associates, 76561 | \n",
+ "
\n",
+ " \n",
+ " | 7 | \n",
+ " 2 | \n",
+ " 1 | \n",
+ " The | \n",
+ " latest, following, Official | \n",
+ " orescent, oro, ulhu | \n",
+ "
\n",
+ " \n",
+ " | 8 | \n",
+ " 2 | \n",
+ " 2 | \n",
+ " capital | \n",
+ " capital, punishment, penalty | \n",
+ " illary, fig, Variant | \n",
+ "
\n",
+ " \n",
+ " | 9 | \n",
+ " 2 | \n",
+ " 3 | \n",
+ " of | \n",
+ " the, course, interest | \n",
+ " uably, iqueness, uments | \n",
+ "
\n",
+ " \n",
+ " | 10 | \n",
+ " 2 | \n",
+ " 4 | \n",
+ " France | \n",
+ " Connection, France, 's | \n",
+ " Emerald, baugh, DIT | \n",
+ "
\n",
+ " \n",
+ " | 11 | \n",
+ " 2 | \n",
+ " 5 | \n",
+ " is | \n",
+ " now, not, also | \n",
+ " EStreamFrame, ORPG, Dise | \n",
+ "
\n",
+ " \n",
+ " | 12 | \n",
+ " 4 | \n",
+ " 0 | \n",
+ " <|endoftext|> | \n",
+ " ,, the, and | \n",
+ " OTOS, ë, istg | \n",
+ "
\n",
+ " \n",
+ " | 13 | \n",
+ " 4 | \n",
+ " 1 | \n",
+ " The | \n",
+ " resa, latest, Bottom | \n",
+ " ��, Eth, � | \n",
+ "
\n",
+ " \n",
+ " | 14 | \n",
+ " 4 | \n",
+ " 2 | \n",
+ " capital | \n",
+ " capital, punishment, city | \n",
+ " nings, BILITIES, cles | \n",
+ "
\n",
+ " \n",
+ " | 15 | \n",
+ " 4 | \n",
+ " 3 | \n",
+ " of | \n",
+ " the, Reach, course | \n",
+ " motivating, Appearance, Cups | \n",
+ "
\n",
+ " \n",
+ " | 16 | \n",
+ " 4 | \n",
+ " 4 | \n",
+ " France | \n",
+ " 's, ,, Telecom | \n",
+ " ��, Antar, Explosive | \n",
+ "
\n",
+ " \n",
+ " | 17 | \n",
+ " 4 | \n",
+ " 5 | \n",
+ " is | \n",
+ " now, not, also | \n",
+ " Diseases, Firstly, Feet | \n",
+ "
\n",
+ " \n",
+ " | 18 | \n",
+ " 6 | \n",
+ " 0 | \n",
+ " <|endoftext|> | \n",
+ " ,, ., and | \n",
+ " SON, leys, VAL | \n",
+ "
\n",
+ " \n",
+ " | 19 | \n",
+ " 6 | \n",
+ " 1 | \n",
+ " The | \n",
+ " resa, oret, Latest | \n",
+ " �, ��, esters | \n",
+ "
\n",
+ " \n",
+ " | 20 | \n",
+ " 6 | \n",
+ " 2 | \n",
+ " capital | \n",
+ " city, capital, cities | \n",
+ " appings, UES, =-=- | \n",
+ "
\n",
+ " \n",
+ " | 21 | \n",
+ " 6 | \n",
+ " 3 | \n",
+ " of | \n",
+ " the, State, British | \n",
+ " ヘラ, TABLE, � | \n",
+ "
\n",
+ " \n",
+ " | 22 | \n",
+ " 6 | \n",
+ " 4 | \n",
+ " France | \n",
+ " 's, ,, and | \n",
+ " , /_, ciation | \n",
+ "
\n",
+ " \n",
+ " | 23 | \n",
+ " 6 | \n",
+ " 5 | \n",
+ " is | \n",
+ " now, officially, not | \n",
+ " Tycoon, 76561, Osiris | \n",
+ "
\n",
+ " \n",
+ " | 24 | \n",
+ " 8 | \n",
+ " 0 | \n",
+ " <|endoftext|> | \n",
+ " ,, \\n, . | \n",
+ " Paris, xes, SON | \n",
+ "
\n",
+ " \n",
+ " | 25 | \n",
+ " 8 | \n",
+ " 1 | \n",
+ " The | \n",
+ " resa, oret, following | \n",
+ " Notting, ournals, EngineDebug | \n",
+ "
\n",
+ " \n",
+ " | 26 | \n",
+ " 8 | \n",
+ " 2 | \n",
+ " capital | \n",
+ " city, capital, cities | \n",
+ " Paris, Denver, Philadelphia | \n",
+ "
\n",
+ " \n",
+ " | 27 | \n",
+ " 8 | \n",
+ " 3 | \n",
+ " of | \n",
+ " South, British, China | \n",
+ " Frames, Reviewer, selage | \n",
+ "
\n",
+ " \n",
+ " | 28 | \n",
+ " 8 | \n",
+ " 4 | \n",
+ " France | \n",
+ " 's, ,, has | \n",
+ " ciation, ㅋㅋ, Spac | \n",
+ "
\n",
+ " \n",
+ " | 29 | \n",
+ " 8 | \n",
+ " 5 | \n",
+ " is | \n",
+ " now, officially, still | \n",
+ " Paris, Paris, Cologne | \n",
+ "
\n",
+ " \n",
+ " | 30 | \n",
+ " 10 | \n",
+ " 0 | \n",
+ " <|endoftext|> | \n",
+ " \\n, the, , | \n",
+ " Paris, ゼウス, Hollande | \n",
+ "
\n",
+ " \n",
+ " | 31 | \n",
+ " 10 | \n",
+ " 1 | \n",
+ " The | \n",
+ " resa, oret, latest | \n",
+ " �醒, ��, ��� | \n",
+ "
\n",
+ " \n",
+ " | 32 | \n",
+ " 10 | \n",
+ " 2 | \n",
+ " capital | \n",
+ " city, cities, capital | \n",
+ " Paris, ��, � | \n",
+ "
\n",
+ " \n",
+ " | 33 | \n",
+ " 10 | \n",
+ " 3 | \n",
+ " of | \n",
+ " China, Kazakhstan, Ukraine | \n",
+ " �醒, ���, Paris | \n",
+ "
\n",
+ " \n",
+ " | 34 | \n",
+ " 10 | \n",
+ " 4 | \n",
+ " France | \n",
+ " has, is, 's | \n",
+ " cffff, eteenth, mathemat | \n",
+ "
\n",
+ " \n",
+ " | 35 | \n",
+ " 10 | \n",
+ " 5 | \n",
+ " is | \n",
+ " now, officially, rapidly | \n",
+ " Paris, Paris, Copenhagen | \n",
+ "
\n",
+ " \n",
+ " | 36 | \n",
+ " 11 | \n",
+ " 0 | \n",
+ " <|endoftext|> | \n",
+ " The, Still, \\n | \n",
+ " �, �, \u0010 | \n",
+ "
\n",
+ " \n",
+ " | 37 | \n",
+ " 11 | \n",
+ " 1 | \n",
+ " The | \n",
+ " resa, odore, latest | \n",
+ " �, �, \u0010 | \n",
+ "
\n",
+ " \n",
+ " | 38 | \n",
+ " 11 | \n",
+ " 2 | \n",
+ " capital | \n",
+ " city, cities, Manila | \n",
+ " �, �, \u0010 | \n",
+ "
\n",
+ " \n",
+ " | 39 | \n",
+ " 11 | \n",
+ " 3 | \n",
+ " of | \n",
+ " Romania, Kazakhstan, Armenia | \n",
+ " �, �, \u0010 | \n",
+ "
\n",
+ " \n",
+ " | 40 | \n",
+ " 11 | \n",
+ " 4 | \n",
+ " France | \n",
+ " has, is, 's | \n",
+ " �, �, \u0010 | \n",
+ "
\n",
+ " \n",
+ " | 41 | \n",
+ " 11 | \n",
+ " 5 | \n",
+ " is | \n",
+ " undergoing, reeling, hosting | \n",
+ " Paris, Paris, Copenhagen | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " layer position prompt token FF1 top raw directions \\\n",
+ "0 0 0 <|endoftext|> <|endoftext|>, Advertisements, \\n \n",
+ "1 0 1 The The, the, The \n",
+ "2 0 2 capital capital, capital, Capital \n",
+ "3 0 3 of of, of, Of \n",
+ "4 0 4 France France, France, French \n",
+ "5 0 5 is is, also, was \n",
+ "6 2 0 <|endoftext|> ,, the, \\n \n",
+ "7 2 1 The latest, following, Official \n",
+ "8 2 2 capital capital, punishment, penalty \n",
+ "9 2 3 of the, course, interest \n",
+ "10 2 4 France Connection, France, 's \n",
+ "11 2 5 is now, not, also \n",
+ "12 4 0 <|endoftext|> ,, the, and \n",
+ "13 4 1 The resa, latest, Bottom \n",
+ "14 4 2 capital capital, punishment, city \n",
+ "15 4 3 of the, Reach, course \n",
+ "16 4 4 France 's, ,, Telecom \n",
+ "17 4 5 is now, not, also \n",
+ "18 6 0 <|endoftext|> ,, ., and \n",
+ "19 6 1 The resa, oret, Latest \n",
+ "20 6 2 capital city, capital, cities \n",
+ "21 6 3 of the, State, British \n",
+ "22 6 4 France 's, ,, and \n",
+ "23 6 5 is now, officially, not \n",
+ "24 8 0 <|endoftext|> ,, \\n, . \n",
+ "25 8 1 The resa, oret, following \n",
+ "26 8 2 capital city, capital, cities \n",
+ "27 8 3 of South, British, China \n",
+ "28 8 4 France 's, ,, has \n",
+ "29 8 5 is now, officially, still \n",
+ "30 10 0 <|endoftext|> \\n, the, , \n",
+ "31 10 1 The resa, oret, latest \n",
+ "32 10 2 capital city, cities, capital \n",
+ "33 10 3 of China, Kazakhstan, Ukraine \n",
+ "34 10 4 France has, is, 's \n",
+ "35 10 5 is now, officially, rapidly \n",
+ "36 11 0 <|endoftext|> The, Still, \\n \n",
+ "37 11 1 The resa, odore, latest \n",
+ "38 11 2 capital city, cities, Manila \n",
+ "39 11 3 of Romania, Kazakhstan, Armenia \n",
+ "40 11 4 France has, is, 's \n",
+ "41 11 5 is undergoing, reeling, hosting \n",
+ "\n",
+ " FF2 bottom raw (update ordering) \n",
+ "0 %], Thumbnail, 女 \n",
+ "1 ixel, Medium, iop \n",
+ "2 inventoryQuantity, catentry, }}} \n",
+ "3 Archdemon, ortium, Difference \n",
+ "4 anton, Seasons, figure \n",
+ "5 adr, adian, umn \n",
+ "6 ometric, Associates, 76561 \n",
+ "7 orescent, oro, ulhu \n",
+ "8 illary, fig, Variant \n",
+ "9 uably, iqueness, uments \n",
+ "10 Emerald, baugh, DIT \n",
+ "11 EStreamFrame, ORPG, Dise \n",
+ "12 OTOS, ë, istg \n",
+ "13 ��, Eth, � \n",
+ "14 nings, BILITIES, cles \n",
+ "15 motivating, Appearance, Cups \n",
+ "16 ��, Antar, Explosive \n",
+ "17 Diseases, Firstly, Feet \n",
+ "18 SON, leys, VAL \n",
+ "19 �, ��, esters \n",
+ "20 appings, UES, =-=- \n",
+ "21 ヘラ, TABLE, � \n",
+ "22 , /_, ciation \n",
+ "23 Tycoon, 76561, Osiris \n",
+ "24 Paris, xes, SON \n",
+ "25 Notting, ournals, EngineDebug \n",
+ "26 Paris, Denver, Philadelphia \n",
+ "27 Frames, Reviewer, selage \n",
+ "28 ciation, ㅋㅋ, Spac \n",
+ "29 Paris, Paris, Cologne \n",
+ "30 Paris, ゼウス, Hollande \n",
+ "31 �醒, ��, ��� \n",
+ "32 Paris, ��, � \n",
+ "33 �醒, ���, Paris \n",
+ "34 cffff, eteenth, mathemat \n",
+ "35 Paris, Paris, Copenhagen \n",
+ "36 �, �, \u0010 \n",
+ "37 �, �, \u0010 \n",
+ "38 �, �, \u0010 \n",
+ "39 �, �, \u0010 \n",
+ "40 �, �, \u0010 \n",
+ "41 Paris, Paris, Copenhagen "
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ " \n",
+ " \n",
+ " | | \n",
+ " layer | \n",
+ " VJP norm | \n",
+ " raw FF2 bottom tokens | \n",
+ " normalized FF2 bottom tokens | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | 0 | \n",
+ " 0 | \n",
+ " 6.557e-01 | \n",
+ " adr, adian, umn, itia, igmatic | \n",
+ " adr, adian, umn, itia, igmatic | \n",
+ "
\n",
+ " \n",
+ " | 1 | \n",
+ " 2 | \n",
+ " 1.442e+00 | \n",
+ " EStreamFrame, ORPG, Dise, misconception, senal | \n",
+ " EStreamFrame, ORPG, Dise, misconception, senal | \n",
+ "
\n",
+ " \n",
+ " | 2 | \n",
+ " 4 | \n",
+ " 1.329e+00 | \n",
+ " Diseases, Firstly, Feet, heses, Differences | \n",
+ " Diseases, Firstly, Feet, heses, Differences | \n",
+ "
\n",
+ " \n",
+ " | 3 | \n",
+ " 6 | \n",
+ " 1.042e+00 | \n",
+ " Tycoon, 76561, Osiris, Modes, Memories | \n",
+ " Tycoon, 76561, Osiris, Modes, Memories | \n",
+ "
\n",
+ " \n",
+ " | 4 | \n",
+ " 8 | \n",
+ " 4.872e-01 | \n",
+ " Paris, Paris, Cologne, Copenhagen, Rome | \n",
+ " Paris, Paris, Cologne, Copenhagen, Rome | \n",
+ "
\n",
+ " \n",
+ " | 5 | \n",
+ " 10 | \n",
+ " 2.749e-01 | \n",
+ " Paris, Paris, Copenhagen, Cologne, Kyoto | \n",
+ " Paris, Paris, Copenhagen, Cologne, Kyoto | \n",
+ "
\n",
+ " \n",
+ " | 6 | \n",
+ " 11 | \n",
+ " 2.609e-01 | \n",
+ " Paris, Paris, Copenhagen, Marse, France | \n",
+ " Paris, Paris, Copenhagen, Marse, France | \n",
+ "
\n",
+ " \n",
+ "
\n"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/png": "iVBORw0KGgoAAAANSUhEUgAABKYAAAGNCAYAAAArTXm0AAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjExLjEsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvctoD+AAAAAlwSFlzAAAPYQAAD2EBqD+naQAAmDlJREFUeJzs3Xd4FNX79/HPpoeQhE4oIfQmTelILwLSMTRFUTqiX1FRQFEsIKigIiqKqKCooCJdFKWGDhKaNCEQeoAESAIkkOQ8f/hkfyxJYAMJk4T367q4LvbMmTP3nJnsnr135ozNGGMEAAAAAAAA3GUuVgcAAAAAAACAexOJKQAAAAAAAFiCxBQAAAAAAAAsQWIKAAAAAAAAliAxBQAAAAAAAEuQmAIAAAAAAIAlSEwBAAAAAADAEiSmAAAAAAAAYAkSUwAAAAAAALAEiSkAuIddvHhRTzzxhAoWLCibzabhw4dr+/btstlsmj17dqZue9++fbLZbJo1a1ambudOpDfGrL5PWT2+OzF79mzZbDZt3749Q9udOHGibDabLly4kKHtptfUqVNVpEgRXb582dI47obUjmVWOQ6ZoWHDhho6dGiGtbd8+XJ5e3vryJEjGdZmZhs9erRsNpsSEhIsi+Gpp55Sq1atLNs+ANzLSEwBwF1y+vRp2Wy2NP/FxcWlq96VK1f07bffqlWrVipcuLDy5s2rOnXq6JtvvlFSUpJTMY0ZM0bLly/X5s2bZYzRxIkTM23/c4q7lbgDkl28eFFjxozRqFGjlCtXrkzd1tixY2Wz2RQbG5up28lOKlasqM6dOztdv2nTpg7v2V5eXqpUqZLeeOMN+/t3sp9++kl///23Xn311QyLt0WLFqpXr55GjBiRYW3mFD179lTJkiVTXfb6669r9erVWrRo0d0NCgBAYgoA7rahQ4fKGJPin5eXV7rqffHFFxo4cKAaNmyo0NBQhYWF6amnntLAgQM1cOBAp2L566+/1LBhQ5UqVcpeVqNGDRlj1LNnz4zb6WyqYsWKMsaod+/emVL/bsvq8WVFw4cPlzFGefLksSyGL7/8UpcvX1bfvn0ti8FqWeE4pEf+/Pnt79knTpxQ//799eabb6b42xs/fry6du2qokWLZuj2hw4dqp9//lkHDx7M0HZzslKlSunhhx/WO++8Y3UoAHDPITEFANlU4cKFtXbtWo0ZM0ZFixZV3rx5NWTIEPXv319fffWVU7dxnDlzRt7e3pkfLIDb9sUXX6hz587KnTu31aHgNuTPn18vvvii2rZtq7lz5+rYsWOSpI0bN2r79u16/PHHM3ybHTp0kJ+fn7744osMbzsn6927t/24AADuHhJTAJBN9erVS7Vq1UpRXrZsWUnS4cOH01x3xowZstlsOnv2rGbOnJnqLYPX36q2ceNG2Ww2zZ8/X998843Kli0rLy8v1apVS+vWrXNo+8KFCw7teHp6qnz58hozZoyuXr16W/t6/fY//fRTlSxZUl5eXqpXr55Wr16dov6ZM2c0cOBAFS1aVB4eHipVqpRefvllh/l5kpKS9M4776hSpUry8fFRYGCgevbsqX379tnr3Dgn0/z583X//fdL+q//k/fxjTfeSLV+euJJTx+n5nb2J9nhw4fVpUsX+fr6Kn/+/BoyZIjOnj0rm82msWPHZliMt9MX06ZNU7ly5eTm5qaNGzdKkpYtW6ZatWrJy8tLpUuX1pdffpnm9g4dOqTHH39cAQEB8vDwUNmyZfXOO+8oMTHRXid5fpvo6Gg9/fTTKlSokAoWLCgp9bmNkutfunRJ//vf/5Q/f375+vrqkUce0dmzZ1PE8Pvvv6tmzZoO8To7J9bevXt18OBBNW/ePMWy9MaxceNGtWnTRv7+/vL29tYDDzygmTNn2pf3799fr732miTJ19fXfn5v3bo1zfhmzZrl8PeeO3du1a9fXz///PNN9yuZs8fyZschteMmSfPmzVPDhg2VO3du5cqVS40aNdLKlStTtD1v3jw1adJE/v7+ypMnj1q3bq1NmzZJkry8vLR//34tWLDAvo8VK1Z0at9ulLxecmJq0aJFcnV1VePGjW+57s6dO2Wz2fTRRx+lWBYWFiYXFxeNHz/eXubp6akGDRpo4cKFt2z7l19+kc1m05YtWzR+/HgFBQXJxcVFx48flyRt2rRJ7du3V758+eTl5aVq1ao5nDeSNHLkSHv/uLi4KG/evHrooYdSfV/46quvVLFiRXl5eal69er6/fff04xt/vz5ql+/vnLlyqXcuXOrSZMm+uuvvxzq1KpVSy1btkyxbnJMyerVq6c5c+YoPDw81dvjJdn/zridDwDuLhJTAJDDLF68WDabTeXKlUuzzpNPPiljjPLnz68+ffo43CoYGhqa5nqzZ89WWFiY1q5dqwMHDih37tzq1KmTw3w0efLkcWgvIiJC48eP15QpU/TKK6/c0b7NnDlTJ06c0KZNm7Rv3z6VKFFCDz30kP1LpCRFR0frwQcf1PLlyzVnzhydO3dOH3/8sb7++mu1adPGnpAYP3683nnnHU2cOFFnzpzR1q1bFRwcrA8++CDN7Xfu3NnePz/++KN9H5MTU6lxNp5kzvRxam5nfyTp/PnzatKkiQ4dOqRVq1YpLCxMTZs21YsvvpjmOrcbY3r74ttvv9Xhw4e1Zs0arV69Wj4+Plq5cqXatWun++67T/v379e6deu0d+9ezZkzJ8X29u3bp9q1a+vkyZP6448/FBUVpY8//lgfffSRBg0alKL+//73PzVp0kT79+93+JKfluHDh6tx48Y6fPiwli5dqpCQEA0ZMsShzvLly9W+fXtVr15dBw4c0Pr163Xw4EGn5yhbu3atJKWahE5PHGvXrlWTJk3k7e2tbdu26ejRo3rkkUf01FNP2W9dmj59ut5++21JUkxMjP38vtm2e/fuba+XlJSk/fv3q1WrVurZs6dWrFhx031Lz7G8mdSO26RJkxQcHKzWrVtr//79Cg8PV7NmzdSqVSuHxMa7776r4OBg1a9fX6GhoQoPD9fw4cPtCaC4uDhVqFBBnTp1su/n9cne9Ni/f78kqXjx4pL+OyaVK1d2at6watWqqVatWvrqq69SLPv666/l4uKiPn36OJTXqVNHBw4cUEREhFPxvffee3J3d9fWrVs1f/58ubq66vfff1ejRo1UoEABbdmyRRERERo2bJgGDRrkkCSbMGGCvX+uXr2qLVu2qEiRImrTpo3CwsLs9aZOnar+/furZ8+eOnbsmObNm6evvvoq1QTt119/rS5duqhBgwY6ePCg9uzZo3Llyql169aaN2+eU/t0vY0bN6pHjx4KCgpK8zb6fPnyqUyZMlqzZk262wcA3AEDALgrTp06ZSSl+m/MmDHprpeaGTNmGEmmd+/eTsWUP39+06dPH4ey0NBQI8n8+OOP9rINGzYYSebhhx92qPv3338bSWbmzJm33NYbb7xhfH197a/37t1rJJnvvvvulusmb79FixYO5fHx8aZYsWKmefPm9rJ33nnHSDLr1q1zqPvdd9857FfLli1No0aNbrrd1GJMrX9uVt/ZeO60j293f95++21js9nM7t27HepO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8OHDio6O1l9//aVevXrZ26tSpYq2b9/ucOVSRujQoYMSExPT/QS4vn37as2aNfrggw/04IMPqmLFiinqxMfHa/369emeN+16rq6umjZtmtauXavHH39c//zzj65cuaIjR45o9uzZatKkiaT/EuGVK1fWxIkTtWvXLl28eFE//PCDFixY4HCbqYeHh9566y0tWbJEb7/9ts6dO6fDhw+rT58+ql27tsO2PTw8NH78eK1atUovv/yyTp06pePHj2vw4MHauXOn/dZwSRowYIDOnz+vkSNH6vz58zp48KD69u2rOnXqpNinKlWq6MyZM9q4cWOKhKgk+99Zhw4dbrvfAADpR2IKALKpb775RqdOnVJ4eLhKlizpMFmuzWZz+nH0Ge3JJ5/U+++/r08++USFChVSz549NWjQIDVr1ixD2i5QoIBq166tChUq6NChQ/rjjz9Uv359ex1/f3+tW7dOTZo0UXBwsPLly6enn35aTzzxhP744w/7LS/vvPOOtm3bpocfflj+/v5q1qyZAgICtHbtWvttganx9PTU9OnTtXXrVvvtSDeblN7ZeO7U7e5P3rx5tXr1apUsWVKNGzdWyZIltXz5co0bN86+vxklI/qiRYsWWrx4sXbu3KmyZcuqfv36Kl26tHr06JGibqVKlRQaGqqyZcuqR48eyps3r+rWraupU6dq6NChKlWqVIbt283iXbRokbZt26YyZcqofv36KlmypH2Cb2f6d/DgwZo/f75TidC0NG7cWKtWrVJ0dLT9Spg5c+boyy+/1GuvvWav16pVKz3//PMaMWKEfRLrm12tNW3aNHXs2FHdunVTQECAJk2apO+++07+/v63jCk9xzK9XnzxRS1evFibNm3SAw88oHz58qlLly7av3+/3nrrLXu9kSNH6qefflJISIiqVq2qkiVLauLEiRo2bJi9zltvvaXKlSurSpUqstlsqSaCbkfdunV1//3367vvvkvXen369JGbm1uak55L/11dGh0drYEDB95RjG3bttXGjRsVHx+v5s2bK0+ePPbjlpwccnFx0cKFC1WmTBk1atRIpUqV0tKlS/Xjjz+mmPR/6NCh+uKLL/Tdd9+pWLFi6tixo5544gnVqFEjxbYHDBigX375RWvWrFGZMmVUoUIF7d27V0uXLrU/MEGSateurenTp2v+/PkKCAhQjx499PTTT6d6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+61T693s+HTo0EFXrlzRwoULnY4jvUqUKKE+ffpo8uTJiouLsx+joKAgubq6avfu3Q71U3sKXbIlS5akuJpq4cKFKl++vP1qvzsZWyVfkZPMGJPiKc/t27eXMUY//vhjmu1k5li6WbNmio+P1/Llyx3KnR3P3en613Omv5o3b674+HgtW7bModzZxHZmnKN347tOTkNiCsimOnbsqNOnT+vtt99WTEyMDhw4oG7duqlWrVpOt/H2228rIiJCTz75pMLDw3X27Fm9/fbbqV72OnHiRCUlJaldu3Zau3atYmJidPr0aS1btkxdunTRrl27FBERoVatWmnhwoU6efKk4uPjtXHjRq1YsUJNmza1t5U8F9KSJUvu6PLwjNy/m+nYsaNmz56tP//8U5cuXdLq1as1ZMgQNW7c2KHeW2+9pTNnzuiJJ57QkSNHdObMGb3++uv2D6dbcaaP0ysj+nrcuHGKjY1V9+7d9e+//yoqKkofffSRvv76a7344ov2gdqd9ndasTp7XgEA0taxY0cdPHhQH3zwgWJiYrR371517dr1lkma640bN05hYWEaOHCgjh8/roiICL3yyivKly9firqTJ09WdHS02rdvr40bN+rSpUs6efKkli5dqvbt2yssLExhYWFq166dfvvtN506dUpxcXEKCQnR2rVr1axZM3tbyZ8PixcvduqzbMKECTpz5oweffRRhYWF6dy5c5owYYLmzJmjV199NcUVUzcKCAjQsGHDNG3aNH3++ec6f/689uzZo/79+6tBgwYOdfPly6ePPvpIM2fO1IsvvqiDBw8qLi5O//77r6ZPn66uXbs607V3JCAgQM8995ymTp2qL7/8UhcuXNDevXs1YMAA1a9f/5br161bV4UKFdIbb7yhsLAwRUZGasqUKTp+/LhT2/f29lbp0qW1atWqFLczdenSRV27dtWAAQP09ddf69SpU4qNjdX27ds1evRovfPOO7ezy+rfv78++ugj7du3T3FxcTp27Ji+/vpreXt7q27dupL+S5A+9thj+vLLL7Vy5UrFxMRo4cKFWrFiRZpjs7Jly2rIkCE6fvy4Tp06peeee06hoaGaMGGCU/t7Mx07dtTly5c1cuRIXbhwQWFhYerdu7cqVarkUK9Lly7q0KGDhg0bpq+++kpnzpxRRESEZs2apVdfffWOYnBGr169VK1aNQ0cOFAhISGKiYnRsmXLtGjRIvtVaJm5fjJn+6tnz56qXr26Bg0apNWrVysmJkZLly7VkiVLnNpeZpyjmXl8cqy7OdM6AOckPzEirX/JT36ZMmWKKVOmjPHy8jL33Xef+fHHH+1Pwkh+4kvyU/lufNJEsuXLl5vatWsbT09PU6JECTN58mT700A2b97sUPfkyZPm6aefNiVLljTu7u6maNGipm3btmb+/Pn2J/T89ddfpkuXLqZo0aLG29vblCtXzowcOdL+5Ixkr7zyiilSpIhxcXExkszKlSvT1UeDBg0yNWvWvGU9Z/cv+Ul358+fT9HGxYsXzYABA0zhwoWNj4+PadGihdm9e7d55JFHHJ62Y4wxK1asMHXq1DGenp4mMDDQfPDBB2bRokVOPZXOGOf6OK1Y03r6THr6Oq24tmzZYh5++GHj5+dnPDw8TJUqVcxnn32WYn1n+zut7aQVq7PnFQDci5KfypfWv379+hljjHn//fdNqVKljJeXl6lWrZqZN2+emTJlisP78c2eZGaMMb/99pu5//77jYeHhylVqpT54osvHJ60d73w8HAzYMAAU6JECePu7m6KFy9uOnToYH777TeTlJRkkpKSzNKlS02HDh1MkSJFTK5cuUyFChXMa6+9ZmJjYx3aev75503hwoWNzWZzeFJtWtatW2datWplfH19jaenp6lRo4b56quvHOokP2Eu+UnG10tMTDTjxo0zJUqUMJ6enqZOnTpmw4YN5rHHHkv1KXcrVqwwDz/8sMmXL5/x9PQ0FSpUMIMGDXJ4Al/16tVN69atU403rafypVb/ueeeM56eniniHTt2rAkMDDSenp6mXr16ZvPmzSY4ONiULl067Y76/7Zu3WoaN25sfHx8TKFChcyzzz5rH4+++uqr9nqpPZXPmP8+/6tVq2Y8PDwczrnk2D755BNTq1YtkytXLuPn52dq1qxpxo8fb6Kioowx//fEs+ufrnwz4eHhZvjw4aZSpUrGy8vLFClSxHTt2tVs3brVoV5UVJTp2bOn8fX1Nf7+/qZv374mNjY2zafyTZkyxcyaNcuUK1fOPt755ZdfUmw/rf291X58/fXXpkKFCsbLy8tUqFDBfPXVV2bevHlGktmwYYO93rVr18y7775rKleubH8SZJ8+fczRo0dvGcPNnsqXWlxlypQxjzzyiENZRESEeeyxx4y/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27bp3Xff1YsvvqgPPvhAGzZssDqkm/rmm2+0d+9eq8MAAAD3uGydmEqvKVOmqGLFilaHAQAAcpC4uDj16tVLzZo105EjR1S0aFGdOnVKI0aM0COPPGJ1eAAAAFmam9UBfPLJJypRooTy5Mmj33//XQEBAfrf//4nSfr777+1aNEiXb16VQ888IAeeeQR2Wy2VNuZNGmSypQpo86dOzuUv/baa2rWrJmaN2+uffv26dKlS5Kkq1ev6oUXXtDzzz+vLVu2aOfOnSpUqJCeeuop+fv729dPSkrSnDlztG3bNgUFBal79+5699131bdvX913332Z0ykAACDbGDZsmJYtW6YdO3aoZMmSDst27drl8Hrz5s1atGiR4uLi9OCDD6pTp04OY5vXXntN7du3V0REhDZv3iwfHx899dRTCggIcGjn4MGD+vnnn3XhwgVVqlRJvXr1kqenZ4p2oqKitGHDBuXKlUu9e/dW8eLFU8S/dOnSNOtMnjxZ//77r2w2mwICAtSiRQvVq1cvRRt//PGHli9froCAAHXs2FHz5s3TAw88oBYtWmRKzAAAIOew/Iqp+fPn69lnn9WLL74oPz8/BQYGSpImTpyotm3b6sqVK/L19dXbb7+t9u3byxiTajvXrl3TyJEjHcq2bdumsWPH2gc019/Kd/XqVX366adq1aqVlixZIn9/f/3www9q2LChEhIS7G0MGDBA//vf/+Tl5aV///1XdevW1ccff6zDhw9nRncAAIBs5MyZM5o+fbpGjhyZIiklSVWrVrX/f9q0aWrUqJEuXLggb29vDR48WL1793ao/80336h79+6aOHGicuXKpWXLlqlGjRo6efKkvc68efNUu3ZtHT9+XPnz59e3336rWrVq2X98S26nZ8+e+uSTT+Tj46PVq1erRo0aioyMdNjem2++edM6JUqUUMWKFVW+fHlFRUWpbdu2+uyzzxzaeP/999W5c2clJCQoMjJSLVq00IQJExQaGpopMQMAgJzFZtLK9NwlLVu21KFDh7R//355eHhIkg4cOKAqVapo586d9lvvYmJiVLZsWX3xxRf2q6JsNpv+/PNPtWzZUqdPn1ZgYKBWrVqlBx98UNJ/k53v2LFDISEhKerHxsbK19dXL7/8st59911J0rlz5xQQEKDly5erSZMm2rlzp2rUqKH169fbfx38/PPPNWTIEC1atEjt27dPsT/x8fGKj4+3v46OjlZgYKAW5a0nH5vlF6gBAJDhmkWGWB2C06Kjo+Xv76+LFy/Kz8/vjttbvHixOnTooI0bN6pu3bpp1rtw4YJKliyp8ePHa8iQIZJkH2esWLFCTZs2lSQVL15cBQoU0NatW+Xm5qbExETVrVtXderU0WeffabY2FgFBgbq22+/VYcOHST9d3V3nTp1FBwcbP+Rrnjx4qpZs6YWLFggSUpISFBQUJBef/11DRo0yOk6N5o/f76eeuopRUVFyWazKSoqSkFBQfrkk0/Up08fSdKqVavUrFkzvf/++xo+fHiGxnyjtMZdpR8Pk6uH780OHQBY6sD0AlaHAGSq9Iy5skSm5KGHHrInpaT/Bnne3t76/PPP7VdIGWPk7u6ubdu2pbhdT5ICAgLUvn17ff3113rwwQcVHx+vH374QZMmTbrptlu3bm3/f4ECBVSwYEH7VVWrV69WUFCQwyXrvXr1sg8oUzN+/Hi9+eabTu03AADI3i5evChJKly48E3r/f3337p48aLDFVLVqlVLkZiSpG7dusnN7b8hmqurq3r27KmvvvpKkrRmzRpduHBBy5Yt0/Lly2WMkTFG8fHx2rZtm8M2rx/juLm5qXz58ikeAnOrOgkJCZo3b5527dql8+fPKzo6WhcuXNCpU6dUtGhR/f3337p06ZJ69OhhX6dp06YOtx5mdMzXY9wFAED2lyUSU3nz5nV4ffbsWfn6+qps2bIO5SNHjlSNGjXSbKd///7q2bOnPv74Yy1atEjXrl1T9+7db7rtXLlyObx2dXW138p35swZFSjgmMn29/eXu7t7mu2NGjVKL7zwgv118i93AAAg5ylYsKAk6fjx46neypfs9OnT8vLykq+v41U8hQsX1unTpx3Kbhx7FCxY0F7n7NmzcnNzU4UKFRzqlC9fXkFBQQ5lNxvjOFMnISFBzZo1U1RUlLp06aKyZcsqOjpa0n/jm6JFi+rMmTPy8fGRl5dXmvuQ0TFfj3EXAADZX5ZITN2oSJEiunjxogYNGnTTJNCN2rRpozx58uinn37Sjz/+qO7du8vHx+e24yhWrJhOnDjhUBYREaFr166luY6np6fDRJ4AACDnqlevnnLlyqUlS5aoYcOGadYLDAxUXFyczp0755C0OXr0qBo0aOBQ9/jx4w6vjx07Zk+2FClSRAkJCWrXrp1KlSqVgXuS0t9//63169crMjJSefLkkSStX79er7/+ur1OsWLFFBsbq+joaPtl+sYYhzmxMjNmxl0AAGR/lk9+npquXbsqISFBY8eOdSj/559/FBYWluZ6rq6ueuqpp/T+++9r+fLl6tev3x3F0aZNG507d84+14EkTZ069Y7aBAAAOYefn59eeuklTZ48WevWrXNYdu3aNfsYonbt2ipWrJg+/vhj+/I///xT+/bts8+7lGzWrFn2K5NiYmI0c+ZMdezYUZLUuHFjFStWTK+++qoSExPt65w4ccJhsvGMkNx+8hxOSUlJ+uCDDxzq1KlTR4ULF3YYH82ZM0dRUVH213czZgAAkP1kySumihcvrh9++EF9+vTR77//rsqVKyssLEzR0dH69ddfb7puv379NG7cOJUrVy7FL5DpVbJkSb3++uvq0aOHOnbsqJiYGJ05c0bu7u5yccmSOT0AAHCXvf7660pMTFSrVq1Ut25dlStXTqdPn9bu3bv1yCOPqFOnTvL29tYXX3yh7t27a+PGjcqbN68WL16s0aNHp5imoFChQnrggQfUoEEDrV+/Xt7e3ho+fLgkycvLS7/++qu6dOmiqlWrqm7dujpx4oTCw8P1zTffZOh+1a1bVw0aNFC9evXUrFkzbdu2TTabzaFOrly59NFHH+mJJ57QmjVr5O3trR07diggIMA+VrqbMQMAgOzH8sTUs88+q0KFCqUo79Kli5o1a6YVK1bo/Pnz6tevnxo0aOCQEJoyZYr9qX3JSpQooUKFCqlv374p2ry+vqenp6ZMmZLikvKxY8c6THY+evRotW3bVqGhoQoKClKNGjVUqFAh5c+f/472GwAA5AwuLi56++23NWzYMIWEhOjs2bMqWrSoatas6TAJeLt27RQWFqa//vpLcXFxGjNmjCpXrpyivSFDhqhu3br6+++/1blzZz388MMOczjVqVNHhw4d0ooVK3TixAmVKlVKDRs2dKhz43hGSjnmulUdV1dXrVy5Ur///rtOnjyp3r17q3bt2po5c6bDfvXs2VM1a9bUmjVrFBAQoEaNGqlixYoOY6WMihkAAOQ8NpP82LscYunSperatavCw8MzZCCzbds23X///fZfCCdMmKB3331Xp06dSjHRZ2qSH5G4KG89+dgszwMCAJDhmkWGWB2C09Lz6GIrFC9eXGPHjtWTTz5pdShO27Vrl8qXL2+f62n+/Pnq2rWrDh06lOnzYN0o+fiWfjxMrh6+t14BACxyYHqBW1cCsrH0jLlyTKbk6NGjeueddzR//nw9//zzGfbr2ubNm/XEE0+oVq1aCg8P19atW/X11187lZQCAADI6U6dOqVHHnlEdevW1fnz5/XXX3/p3XffvetJKQAAkD3lmMSUt7e3qlatqo4dO6pt27YZ1u7gwYPVsmVLbdy4Ublz51a9evUcLl8HAADIKKndzpbVPfTQQ1q1apVCQkJks9n08ccfq3Tp0laHBQAAsokcdytfVsOtfACAnI5b+ZBVcCsfgOyCW/mQ06VnzMWj5QAAAAAAAGAJElMAAAAAAACwBIkpAAAAAAAAWILEFAAAAAAAACxBYgoAAAAAAACWIDEFAAAAAAAAS5CYAgAAAAAAgCVITAEAAAAAAMASJKYAAAAAAABgCRJTAAAAAAAAsASJKQAAAAAAAFjCzeoA7hWNj/whPz8/q8MAAADI8UI/yc+4CwCAbIIrpgAAAAAAAGAJElMAAAAAAACwBIkpAAAAAAAAWILEFAAAAAAAACxBYgoAAAAAAACWIDEFAAAAAAAAS5CYAgAAAAAAgCVITAEAAAAAAMASJKYAAAAAAABgCTerA7hXrCnZWj42uhsAkD00iwyxOgTgtt3/TKRcPa5aHQaAbO7A9AJWhwDcE7hiCgAAAAAAAJYgMQUAAAAAAABLkJgCAAAAAACAJUhMAQAAAAAAwBIkpgAAAAAAAGAJElMAAAAAAACwBIkpAAAAAAAAWILEFAAAAAAAACxBYgoAAAAAAACWIDEFAAAAAAAAS5CYAgAAAAAAgCVITAEAAAAAAMASJKYAAAAAAABgCRJTAAAAAAAAsMRdT0xFRUVpwIABqlGjhpo2baoLFy6oYsWK2rdvX7raqVixojZs2HDTOjVr1tSqVavStQ4AAMC95OLFizp37pyuXbuWYtnly5d17tw5Xbp0yYLIAADAveCuJ6befPNN7d27VzNmzNBXX32lhIQE7d+/X3FxcelqZ//+/bccJO3fv1+xsbHpWgcAAOBe0rp1axUsWFDjxo1Lsaxz584qWLCgXn31VQsiAwAA94K7npjavn27HnroIdWoUUNlypRR3rx5tXfvXlWqVCnTt7137141aNAg07cDAACQnZQrV07ffPONkpKS7GXh4eEKCQlRUFCQQ93kK6wiIyMd6l/v/Pnzio+PlyRdunQpxQ+Dly9fTjOWpKSkmy4HAAA5y11NTFWpUkWbN2/WlClTVLFiRVWsWFH33XefOnfurMOHD9vrXbt2Te+9954aNmyoOnXqaPDgwTp16tRN2z537pwGDBig+++/X507d9by5ctT1OncubN27Ngh6b8BUcWKFbVkyRL1799fderUUfv27bVp0yaHdSIiItSvXz+Hdm+8RRAAACA7a926tRISEhzGT1999ZXat2+vAgUKONR94oknVLFiRZUvX14+Pj5q27atjh496lCnatWqGjFihGrUqKGAgACNGTNGkjRx4kQVKFBAhQoVUtGiRTV58mQZYyRJsbGx6tu3r3x9fVWwYEGVLFlSs2bNyuQ9BwAAVruriam5c+eqQoUKeuyxxzR//nzNnz9fM2bMSHErX7du3bRkyRKNGTNGn376qSSpXr16Drfl3ahjx47as2ePPvroI/Xr108DBgxI8Wvb9bfyJSUlaf/+/erbt68aNWqkqVOnKigoSG3atNH58+clScYYtW/fXvv377e3O3DgQIWGht40FgAAgOzE1dVVTz75pL766itJ/42TZsyYoX79+qWou2DBAvsVU6dPn1aePHnUt2/fFPVmzpypTz/9VDExMZo4caK2bdumUaNG6bffflNsbKx27Niho0eP6sqVK5Kknj176vz58zpy5IguXbqkGTNmaPDgwQoJCcncnQcAAJZyu5sbq1Chgry8vFSgQAFVrFhR0n9XOl1v9erVWrZsmSIiIuTr6ytJqlWrlipWrKg5c+akOkD6888/tWXLFh05ckTFihWTJLm7u6tt27a3jOn1119Xnz59JEnVqlXTV199pY0bN6pt27ZatmyZduzYoSNHjqho0aKSJC8vLz300ENpthcfH2+/dF2SoqOjbxkDAACA1fr27asqVaooKipKmzZtkjFGDz30kEaPHp1q/YSEBCUkJOiZZ55Ro0aNdOXKFXl7e9uXDxgwQA8++KD9dUREhHLlyqXKlStLkgoWLKhJkyZJkv755x8tWbJE+/btk7u7u86fP69q1aqpXbt2+vHHH9WoUaNUY2DcBQBA9ndXE1POCAkJUVJSkurXr2+/tNsYoxMnTujAgQOprhMaGqpy5crZk1KS1LRpU6e2V716dfv/3d3dVaBAAZ05c0aStGPHDpUtW9ae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LFhQknT69Gnlzp1buXPndqhz5swZeXp6yt/f36G+MUYnTpxQoUKF5OHhoYsXL8rX11cuLinvbjTGKCoqSvny5ZPNZtPJkyeVL18+BnAAACDbadasmaZPn56ifOHChapatao8PDy0detWFStWTLVq1dKKFSt05swZ2Ww2BQQEqEaNGvL39091XR8fH23fvl25cuVSvXr15ObmONRMSEjQ5s2bFRkZqVq1aqlIkSIOy69du6aNGzfqwoULqlixosqVK5fxHQAAALKUO5pjqmfPnhowYIAaNmyooKAgDRkyRJIUHh6uhx56SPnz51dgYKDKli2r33//3WHdI0eOqE2bNvLz81NgYKAaNmyof//9177cmTYCAwMVEhIiSXrmmWc0YMAAh+WXLl1S6dKl7etdX//SpUsKDAzUW2+9pVKlSqlkyZLy9fXVxx9/7NDGmjVrVKpUKQUGBip//vwaPXq0ypUrp7/++utOug4AACBLefrppzVw4EA9+OCD+uabb7Rjxw5J0tq1azV//nz9+uuvevnll1WmTBmtWLEixbqDBg1S/fr1NWXKFPXs2VMNGzbU1atX7XV27dqlihUr6rHHHtPnn3+uBg0a6KuvvrIv/+eff1SxYkU9++yz+vLLL/Xggw/qqaeekjHm7nQAAACwxB3fyjd37lwtWLBA7dq1kyTFx8erVatW6ty5sxYtWiRPT0/99NNPCg4O1s6dO1W6dGnFxcWpRYsWqlKlik6fPq38+fNr/fr12rBhg8qVK+dUGzd67LHH1Lt3b8XGxtqvmpo/f75cXFzUsWPHNONftGiRQkJCVLx4cf3000969NFH1aFDB5UqVUqXL19W9+7d1aNHD02aNElXrlxRcHCwLl++nGZ78fHxDhOsR0dH327XAgAAZLiwsDDNnj3b/jooKEj169eXJB07dkw7duxwuCLq9ddfd1j/gw8+0KBBgxx+UJSks2fPaufOnfLx8VFUVJRKlSqluXPnqlevXkpISFDnzp1Vt25dzZw5U+7u7rp69ao9wZWYmKiuXbtqwIABGjlypCQpKipK999/v2bOnKknn3wy1X1h3AUAQPZ3x0/la9++vT0pJUkLFizQ2bNnNWzYMEVFRenUqVNq2LChypUrp0WLFkmSfv31V504cUJff/218ufPL0lq0KCBnnjiCafbuFG7du3k6empefPm2cu+//57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kqlUqZLx8/NL8bfOuZm6L774wlStWtXkyZPHFCtWLNU627ZtM0FBQaZYsWImICDAlClTxuzatSvdde5lJKYyyejRo03RokXN8ePHjTHGLFq0yEgy69atsziyjPHWW2+ZY8eO2V9/8803xsXFxWzbts3CqDLemjVrTOnSpU3Pnj1zVGIqNjbWlClTxnTt2tVcvnzZGGPMqVOnzC+//GJxZBnjhx9+MK6urvY3+8TERPPEE0+YoKAgawO7TbNmzTI//vijOXHiRJqJqTfeeMMEBASYo0ePGmOM+e2334zNZjOrV6++2+Gm2+LFi8306dPNpUuXjKenZ6qJqbFjx5rw8HD76++++87YbDazZcuWuxnqbVmzZo35+OOPzYULF0xQUNBNE1Pr1683JUuWNI8++mi2SUzt3r3bjB8/3kRERJgHH3ww1cTU5cuXTbly5UynTp3s7zkRERHm559/vtvhIgeaNWuW8fb2Nn///bcxxpgdO3aYXLly5dgfzDLSO++8Yw4fPmx//dNPPxmbzWbWrl1rL6N/0+fatWumQYMGZsSIESkSU9euXTPlypUzjz32mElKSjJJSUmmZ8+eply5ciYhIcHCqLOew4cPG19fXzNixAiTmJhojDHmn3/+cfhBY8aMGSZXrlz25Mm2bduMt7e3mTlzpiUxZ1Xh4eEpfvj7/PPPjc1ms4+tODfT9tJLL5kdO3aY8ePHp5qYunr1qildurTp06ePMcaYpKQk061bN1OxYkX7uetMnXsdialMUrRoUTN69GiHsho1aph+/fpZFFHm8/b2Np9++qnVYWSYyMhIExQUZFavXm0GDRqUoxJTn376qfHw8DBnz561OpRMMXnyZJM3b16HsqlTpxofH59s/Qvv2bNn00xMlShRwowcOdKhrFatWvYPwOwircRUanLnzm0mT56cyRFlrJslps6fP29KlSplVqxYYYYOHZptElPXSysx9cUXXxh3d3cTERFhQVTI6Zo3b26Cg4Mdynr27GkefPBBiyLK3goUKGDeffdd+2v6N31GjRplgoODzd69e1MkplasWGEkmX379tnLdu/ebSRl26u6M8uQIUNMqVKlbpoUady4senZs6dDWXBwsGnSpEkmR5e9/P3330aS2b17t71s165dRpL9ogLOzVtLKzG1bNkyI8kcPHjQXrZ9+3YjyYSEhDhd517HHFOZ4MyZMzp58qRq1qzpUF6nTh2FhoZaFFXm2r17t65cuaKyZctaHUqG6du3rx599FE1btzY6lAy3PLly1W/fn3ly5dPO3fu1IEDB3LEHEzJHnvsMRUvXlwDBgzQn3/+qVmzZum9997T+PHjZbPZrA4vw0VFReno0aP31HvO3r17FRsbm6Pec/r376/g4GA1a9bM6lAy3PLly1WnTh0VLFhQu3btynHvObBWaGjoPfX+l5nCwsIUFRXl8N5K/zpv+fLl+v777/XFF1+kujw0NFQ+Pj6qUKGCvey+++5Trly56M8bLF++XA8//LASEhK0bds2hYeHp5hjinPTOQ888IB69OihoUOHavHixVq0aJGefvppPfroo7r//vslcW7eidDQUPn7+6tMmTL2surVq8vDw8Ped87Uude5WR1AThQVFSVJyp8/v0N5/vz57ctykitXruipp55S/fr11bJlS6vDyRBTpkzRiRMn9PPPP1sdSqY4efKkfHx8VLNmTSUkJOjChQtycXHRzJkz1bRpU6vDu2P58+fXM888o1GjRmnLli06e/asKlasqPbt21sdWqa4195z4uLi9NRTT6lOnTpq3bq11eFkiKlTpyosLEw//PCD1aFkipMnT8rDw0O1atXS1atX7Q8EmTFjhpo3b25xdMjOjDG6cOFCqu9/ly9fVnx8vDw9PS2KLnu5du2annzySVWrVk0dOnSQRP+mx9mzZ/XEE0/ou+++U758+VKdiDsqKipFX0o59/P6Tpw8eVKRkZGqVKmS/P39dfz4cQUGBmr27NkqX768EhISFBMTk+q5GR0drcTERLm6uloUfdYzePBgDRgwQMOHD5f03yTcb7/9tn055+btc6bv6N9b44qpTODu7i5JKZ5scuXKFXl4eFgRUqa5evWqgoODdeHCBc2dO1cuLtn/lDp27JhefvllDRkyRJs2bdLatWt1+vRpxcTEaO3atYqOjrY6xDvm7u6u5cuXa9y4cdq1a5fCw8P18MMPq3v37jd9Ik928dVXX+mFF17Q6tWrtX37dh07dkwVKlRQs2bNcsT+3ehees+5du2aunfvrrNnz+rXX3/NEYPOEydO6MUXX9SQIUO0efNmrV27VqdOnVJsbKzWrl2bI57q6u7urpUrV2rMmDH295xOnTqpe/fuaT4ZCHCGzWaTm5tbqu9/0v+9P+LmEhMT9eijjyo8PFzz58+39xv967znnntO1apVk4eHh9auXatt27ZJ+u9JXvv27ZP0X3+lNg7JiZ/Xd8rd3V2LFy/WkiVLFBoaqqNHjypfvnzq06ePJMnV1VUuLi6pnpsuLi45YnyQUf755x+1atVKY8aM0b59+7Rv3z69/vrratWqlfbs2SOJc/NOONN39O+tZf8sQhZUrFgxubq66sSJEw7lJ06cUIkSJSyKKuMlJ6X279+vlStXqkiRIlaHlCEuX76smjVr6uuvv9bIkSM1cuRIbdq0SceOHdPIkSMVHh5udYh3rGTJkipRooQefvhhSZKLi4sGDhyos2fP2gdP2dnixYvVpEkTValSRdJ/+zdkyBCFh4dr586dFkeX8YoWLSp3d/cc/55z7do19ejRQ7t379bKlStVrFgxq0PKEFeuXNEDDzygmTNn2t9zNmzYoBMnTmjkyJEKCwuzOsQ7VrJkSRUtWlQdO3aU9N+X3YEDByoyMtI+KAZuV4kSJVJ9/ytevHiO+MEssyUmJuqxxx7Tpk2btHLlSgUFBTksp3+dkydPHsXExNjfxydNmiRJ+vTTT/X9999LkoKCghQZGenwBfXKlSs6f/58jvq8zgglS5ZU48aNValSJUmSt7e3+vTpo82bNys+Pl42m02BgYE5fuyTEX7//XflypVLvXv3tpc9/vjj8vb21u+//y6Jc/NOBAUF6dy5c7p69aq97NKlS7p48aK975ypc6/j0yQTeHl5qVGjRlq4cKG97MqVK/rzzz/VqlUrCyPLONeuXVO3bt20Z88erVq1SsWLF7c6pAxToUIFrV271uFfp06dVLlyZa1du1ZVq1a1OsQ71rp1a50/f97+i6ckHT9+XJJUsGBBq8LKMAULFkwxUDl27Jh9WU7j7u6uJk2aOLznxMXF6Y8//sgx7zkJCQnq2bOntm/frlWrVuWoD/GyZcumeM/p2rWr/b0oef6H7Kx169a6cOGCLl26ZC/LSe85sFarVq20ePFi+/wzxhgtXLgwx7z/ZabExET17t1b69ev16pVq1S6dOkUdehf53z22WcO7+PJyagvvvjCfstUixYtZIzRb7/9Zl8vuW+5rdlR69atU4zljh8/Lj8/P/vto6mdm4sWLeLcvEHBggV16dIlnT9/3l4WFRWlS5cu2T+DOTdvX4sWLXTt2jV7kk+SFi5cKBcXF3vfOVPnXsccU5lk7NixatasmV5++WU1bNhQn376qfLkyaPBgwdbHVqGeOyxx7R8+XJNnz5dR44c0ZEjRyT996taTvrCmFP16NFDH3/8sR555BENHTpUUVFReu211/TYY4/liKtQBg8erBkzZqhv377q3r27IiIi9Prrr6tdu3YqVaqU1eGl27lz57Rv3z77LV3//POPcufOrcDAQPsv22+//baaNGmi4cOHq3Hjxvr888+VO3duPf3001aG7pTo6Gj7lWzGGB08eFBr165VoUKFVL58eUnSE088oaVLl2r69Ok6evSojh49KkkOfZBVxcXFaevWrZKk+Ph4HT16VGvXrlWePHnsV/VlZ8YYrVu3TtJ/x/L06dNau3atcuXKpQceeECSFBwcrMmTJ6tr16763//+pwsXLmj06NHq0aNHlj9+yPpGjBihOXPm6PHHH1ePHj00d+5cHT58WL/88ovVoWV5AwYM0Lx58zRt2jSdPHlSJ0+elPTf1f/Jn5f0b8YJDAzU0KFDNWTIEMXGxkqShg8frmeeeUaBgYEWR5e1vPDCC/ruu+80cOBAPfLII/r33381YcIEjRo1yl5n1KhRqlmzpp588kkFBwfr559/1vHjxzVy5EgLI896OnXqpOLFi6tjx44aPny4jDGaNGmSvUzi3LyZ3bt368KFCwoPD9fVq1e1du1aSVKtWrXk5eWlUqVKafDgwRo0aJAuXryoxMREDR8+XM8995z9jiJn6tzrbObGxxsgw2zYsEGffPKJTp8+rSpVqmjkyJE55sR76KGHUp0XpE+fPhowYIAFEWWuiRMn6t9//03zKSvZUUxMjCZOnKj169fL399fDz30kPr165dj7sn/559/9Omnn+rQoUPy9fVVkyZNNHDgwGw5Sevy5cs1ZsyYFOW9e/d2SHZv2rRJU6ZM0alTp3TfffdpxIgR2SLRuGvXLg0ZMiRFeevWrfXaa69Jktq2bauYmJgUdW7sg6zoxIkT6tGjR4ry2rVr68MPP0x1nQ8//FD//POPpk+fntnh3bGrV6+m+mtfUFCQ/YoBSYqNjdWkSZO0bt06+fn5qWXLlurfv7/c3PiNDHfuwIEDev/993Xo0CGVKlVKw4cPt98ChLR16tRJkZGRKcq7d++u//3vf/bX9G/6HT16VI8++qimTZumypUr28uTkpL0+eefa/HixZKk9u3ba/DgwdwWmYoTJ07ovffe0z///KPChQurW7du6ty5s0Odffv2aeLEiQoLC1Pp0qU1fPhwVaxY0ZqAs7CzZ89q8uTJ2r59u2w2m6pXr67nnnvO4aplzs3UPf/889qyZUuK8jlz5tjH2YmJiZo6daqWLFkim82mjh07auDAgQ5950ydexmJKQAAAAAAAFiC9BwAAAAAAAAsQWIKAAAAAAAAliAxBQAAAAAAAEuQmAIAAAAAAIAlSEwBAAAAAADAEiSmAAAAAAAAYAkSUwAAAAAAALAEiSkAWr16tbZv3251GGlat26dtm3bZnUYWcaN/WHl8cusbWf1cxIAcG86c+aMZs+eLWOM1aHcttDQUIWEhFgdRpp27dqlVatWWR1GlnFjf1h5/DJr21n9nETmIzEFQOPHj9esWbMytM1Vq1Zp586dGdLWhx9+qK+//jpD2soJbuyPzDh+knPHMLO2fWO7GXk+AQDgjIiICM2ePduhbM+ePerVq5cSExMtiurOzZw5U++++26Gtrlt2zatXbs2Q9qaM2eOxo4dmyFt5QQ39kdmHD/JuWOYWdu+sd2MPJ+QPbhZHQAA6zVt2lSBgYEZ2ubYsWNVq1YtVatWLUPbRUqZcfwka4/hjfvE+QQAuNt27dqlXr16qWfPnvayQoUKqUePHnJxyb6/7z/wwAMqWrRohrb59ddf6/jx42rYsGGGtouUMuP4SdYewxv3ifPp3kNiCsgG9u/fryNHjqhZs2bavn27Tp8+rfr166tgwYKp1tmwYYMiIiIUHBwsFxcXxcfHa/369bp48aKqVaum0qVLO7Rfv359+fv7O5QlJSVp69atOnnypMqUKaOqVaumiMsYo23btun48eOqVq2aSpUqJUn27e/du9f+S2OHDh3k4+PjVLvR0dEKCQmRv7+/7r///lv2z/Lly1W4cGEFBARo06ZNyp07t5o0aaJNmzbp8OHDstlsyp8/v2rUqKECBQrY1wsLC9PevXvVrl07SVLc/2vv3oOiOs8/gH8XWS4KgoARuQiCWhBwAyWwgAwraKQVb4GCeEu9dbwkRgc7tpGqmUTqRO1oI1UTLUoUQ0GKEKFeURFQQMSEAF5SFFgQKQuU63J7f38we37usgvHtQ4hPp8ZZ9iz73nPs885+L685z3vdnYiNTUVM2bMwPTp0wEAZWVlkEqlmD17tsbjNzc3Izs7G6ampnB3d0dxcTEMDQ3h4eHxSvHxzYc2508Rk42NDe7duwcAEIvFMDQ0BDD4ORzKUNcbn5y9+JleJRZCCCEjR01NDXJycvCb3/wGJSUlePLkCZydneHo6DigbF1dHfLz82FkZAQPD48B7SAA3L17F7W1tZg+fTrGjRuHixcvIiwsDLq6umhpacGFCxcAAHp6enB0dIRIJOL2bWpq4h6fUrQ9U6ZMwaRJk7Bo0SIIBALI5XL885//RFBQkFKfTNGfCAwMxFtvvcU7XtU8hIaG4vvvv8eTJ08gEolgb28/oExYWBjy8/NRVVWF2bNnw9TUFH19fbhz5w5qa2sxderUAX0ANzc3rs/2opKSEjx+/Bg2NjZwd3fHqFGjBpQpLS3Fw4cPMWXKFLi6unL7PXr0CDKZjMuVRCKBpaUlr3rlcjlu3rwJHR0dXv2+goIC9PT0wM3NDbm5uejq6kJISAjKyspw//59AICJiQlcXV2VbnLV19fj2rVrCA8Ph0AgAACkpKTAysoKYrEYACCVSnHnzh289957Go/f2dmJ7OxsLl6pVIqGhgZIJJJXio9vPrQ5f4qYRCIRiouL0dLSAi8vL4wbN47bd7BzOJihrjc+OXvxM71KLGTkooEpQkaA9PR0HDp0CGZmZjAxMYFcLscPP/yA5ORkBAcHK5UZP348xo4dC0tLSyxevBgPHjxAcHAwDAwMYGdnh5ycHGzcuBH79u3j6v/zn/8MV1dXvP322wD6G+UFCxagtbUVTk5OuHfvHlxcXJCSksINXFRXV2PRokWQSqXw8PDAgwcPsHLlSuzcuRMFBQWor69Hb28vUlNTAQBBQUFoamoast779+9jzpw5eOutt2BpaYknT57A0NBw0MZo165dEAgEqKqqgpubG/z8/BAQEICioiLcuHEDAFBbW4uioiJ8+eWXiIyM5LYtXrwYjY2NGDNmDHJychAZGYnIyEgkJCQAAGJiYqCnp6dxYOru3buYO3cuLC0tMXHiRFRUVMDQ0BABAQHcIIu28fHNhzbnb9euXdDR0UFNTQ2cnJzw4MEDAMCdO3dgZmam8RwONRhUVlY25PXGJ2cvfiZtYyGEEDKyFBUVYdmyZfj73/+OxsZGmJqaIisrCwcPHsSGDRu4cp9//jliYmIgFovR2dmJkpISxMfH49e//jWA/htnS5cuxYULF+Dn54fy8nI4OzsjMzMTISEhMDIyQktLC9emdHZ2Ij8/H05OTsjIyICBgQGam5uRk5MDAFy5OXPmoLW1FZGRkQgLC4O+vj4++eQTPH78GNHR0Vx86enpWLNmDerq6njFqykPX375JRoaGmBiYoK8vDwcPHgQ69evVypz/PhxyGQyODo64p133kF3dzeCg4Px/PlzuLq64vbt2wgMDERiYiJ0dfv/9Dt16hQeP34Mf39/AEBbWxsiIiJQXFwMDw8PPHr0CKNHj0Z6ejo3i6W1tRVLlixBTk4OvL29IZVKIRKJcPr0aZSXl6OiogLt7e1crpydnWFsbDxkvc+ePYNEIoFcLoeTkxNKSkpgZ2cHAwMDjdfJsWPHUFBQgM7OTtjb22PatGkICQnBo0ePuOM3Njbi1q1b2LFjBz7++GMAgEAgQGRkJJydnTFjxgzU1NQgNDQU7u7u3NqdJ0+eREZGhsaBqerqakgkEvT29g6IVzHIom18fPOhzfk7duwYCgsLIZfLYWdnh7q6OlRXV+P69etwcXHReA6HGgyqr68f8nrjk7MXP5O2sZARjhFCfvL27dvHALAvvviC27Z9+3Y2adIkJpfLlcqcPXtWad+ZM2eyhQsXsp6eHsYYY7m5uUxHR4ddvXqVKzN37lwWFRXFvQ4MDGQbNmxgfX19jDHGOjo6mKenJ9u1axdXxt/fn0kkEtba2soYY6y3t5elpaVx7wcFBbHt27crxcKnXl9fX7ZkyRKuTHp6OgPANm3apDE/fn5+zMzMjEmlUo1lGGPs3LlzzNTUlIu5q6uLjR49ml28eJExxlh0dDTz9PRkEydO5PaxtbVl8fHxGuv09vZmkZGRXLyZmZkD4tU2Psb45UOb8+fn58esrKxYXV0dY4wxuVzOHB0dWUxMDFdG3TlUpXpsPtcbn5yp1ssnFkIIISOboo3bv38/t+3w4cPMxMSEazMuXbrEzMzM2I8//siVOX36NLOwsGAtLS2MMcZSUlKYvr4+KysrY4z1t4Pe3t4MAFdGVXt7O5sxY4bSsS9fvsxU/1zKyspiAFh3dzdjjLFPP/2UOTk5KZVZuHAhi4yM5B2vpjy82C7GxcUxQ0NDri+hKPNi284YY2vXrmVvv/02V3dFRQUzNTVlsbGxXJmPPvqIzZs3j3u9ceNG9u6773J9yt7eXhYeHs4iIiK4MuvWrWNTpkxhtbW13LbU1FTu502bNrGFCxcqxcKn3lWrVjGxWMza29sZY4yVlJQwPT09FhQUpDY3jDG2Zs0aNmrUKFZYWKixDGOMFRcXM319ffbgwQNum6urKzt06BBjrP88uLu7M6FQyGQyGWOMsdmzZ7OPP/5YY50rV65kYrGYdXR0MMYYKysrY/r6+krxvkp8fPKhzflbs2YNMzAwYCUlJYwxxvr6+ticOXPYypUruTLqzqEq1WPzud745Ey1Xj6xkJ+XkftwNCFvGGNjY+4uGQBs374dlZWVyMvL47aNHz9eaR0EqVSKW7duYfv27dx0Xh8fHwQGBg5YzFOhsrIS165dg6OjI86dO4ekpCSkpaXBwcEBWVlZAICKigpkZ2dj9+7d3KwVHR0dzJ8/X2P8fOqtrq5Gbm4utm3bxk2xDgkJ4R6rG0xoaKja5+3r6+tx9epVJCYmoqOjA01NTXj48CEAQCgUwtfXlzv+9evXsWXLFnR0dODBgwf48ccfUVVVxd3NUVVVVYU7d+4gKiqKizc4OJib2v6q8WmTDz55fjEmxSMGenp68PHx4WZOaYPP9fYyOSOEEPLmEQgESv0diUSC5uZmbvZRXFwcpk+fjqKiIiQlJeEf//gHAKChoQHff/89ACA5ORnz58+Hk5MTAMDAwAAffvjhgGMxxnD37l2kpqbi/PnzsLW1RX5+/kvFu2zZMpSXl3MzbhobG5GZmYnly5fzjleT3//+99zP77//PkxMTJCenq5UZvPmzUqvExMTsXnzZhgZGQEA7O3tsXz5co39vt7eXnz99ddwcXFBWloakpKSkJycDGtra67f0NPTgzNnzmDbtm1Ks1YWLlyoMXY+9QJAUlISPvjgA25Gt4uLC0JCQgbNCwD4+vril7/85YDtLS0tuHnzJpKSklBWVgZTU1PcvXuXe18ikSj1+xYsWACRSISbN2+iu7sbeXl5Gvt9AHDu3Dl88MEH3AwmJycntf1fbeN72XzwzTMA+Pv7w8XFBUD/71lAQMAr9fsAftcb35yRNxs9ykfICGFtbc1NiQWAcePGwcTEBE+fPuW2TZw4UWkfxXuqa/w4OjqioqJC7XGePHkCAMjJyUFBQQG3XSAQwNPTE0D/4AcATJs2jXf8L1Pvi2soAFD7HL0q1c8OAAcPHkR0dDREIhEsLS0hFAohEAjw/PlzroxEIkF6ejo6OjpQUFCApKQkzJw5E1lZWRAKhXBwcICtrS0qKyuRm5vL7efr64vq6mq18aq+1jY+bfLBJ88KZmZmSq/19fXR2tqqse6h8LneqqqqAPDLGSGEkDePnp6e0qPa+vr6APoftwP627nGxkYkJycr7RceHg6hUAigv63x9vZWel+1nampqcHs2bPR2toKNzc3GBsbo6Kigrthw9fkyZPh6+uLM2fOwMPDA0lJSTA1NcW7777LO151dHR0MGnSJO61QCCAnZ2dUr9PT09PqS2XyWRoaWlR2w6npaWpPU5DQwNaWlrw3XffoaamRum9wMBArkx7e/tL9fv41CuTydDa2qq2n1NcXDxo/er6VampqVi1ahUmT54MOzs76Ovro7Ozc0C/b926dejr68P169fx1Vdfoa2tDVlZWbCwsEBXVxd8fX3R1NSEf/3rX9x+rq6usLKyQltbm9o+TGNj4yvHp00++ORZQV2/T/F7pQ0+15tMJuOdM/Jmo4EpQkYI1f+8e3p60NraqrRYtmIGioLiPZlMhgkTJnDbZTKZ2kW2AWDs2LEAgOjoaG69H1WmpqYA+htDdQ2vtvWam5sD6P+sip8Vr4cauFD97C0tLYiKisK3336LX/3qVwD6FzJNTEwEY4wrJ5FIsHv3bly8eBGTJ0+GpaUlJBIJrl+/DqFQyN01k0ql3HPuAGBnZ8c18E1NTQPitbOze+X4tMkHnzy/Lnyut5fJGSGEEKJq7NixsLGx0TgDCOhva5qampS2qfaj9u7diwkTJqCkpIT7hr3169ejvLz8pWNavnw5PvvsM+zbtw9nzpxBREQEdzORT7zq9PX1obm5metzKT7DYP0+ExMTCIVCyGQype2D9fuMjIygo6OD1atXY+nSpWrLGBsbQ0dHBw0NDbzj51Pv2LFjoaurO+Dc8BmwUP3sQP/ssZ07d2Lr1q3cNktLS6V+X0BAAJqampCZmYnq6mqIxWK0tbVhx44dGD9+PN555x2MGTMGT58+Ver36erqwsnJCbq6ukNeW9rGp00++OT5deFzvSk+E5+ckTcbPcpHyAhRV1eH27dvc6/Pnz8PoVCodpqwgoODA6ysrJCSksJta25uxuXLlzV+/aqbmxusra1x9OjRAe8p7sS4uLjAysoK8fHxSu/X19dzPxsZGSndheFTr4ODAyZOnKjUEaiqqlKa+cNXfX09+vr68Itf/ILbpnq3EgC8vLygp6eHPXv2cINQioGpGzducNt8fHzwzTffcP98fHzg6OgIS0tLnD9/nquvtraWV7x84tMmH3zyzJfqORwKn+tN25y9bCyEEEJ+noKDg3HhwgVuBq5CbW0t9we+n58fMjMz0dXVxb3/YrsD9C8yPXXqVG5QqqOjAxkZGUplFI8nDdX+hIeHo76+HqdOnUJ2djb3GB/feDV5sf1XfFOZn5+fxvKjRo2CWCxWaof7+vqQkpKisd83evRo+Pv749ixYwPikUqlXJmZM2e+VL+PT726uroQi8VKn7Ozs3PAeeCDMYbnz58r9atu3brFPQKqYGFhARcXF+zevRtisRgGBgbw9/dHaWkpUlJSuH6fnZ2dUr9P8W2OXl5eStdSV1eX0syqV4lPm3zwyTNfL9vX4nO9aZsz6ve9eWjGFCEjhLGxMZYsWYLNmzdDLpdj7969iIqKUpqZokpXVxd/+ctfsGLFCjQ1NcHBwQFfffUV7O3tsXbtWrX7jBo1CidOnMDixYvR0NCAuXPnQiaT4dtvv0VYWBi2bNkCXV1dHDt2DGFhYairq8PMmTNRWlqKyspKnDt3DgDg6emJ48ePw83NDWPGjMH8+fOHrFcoFGLPnj1Yv349ZDIZrK2tcfjwYRgbG790vuzt7SESibBixQqsXr0ajx49Qlxc3IA7WIp1pq5cucKt5eDu7g65XI66urpB1xkQCoX49NNPsWnTJshkMkycOBFHjhyBkZGR2jtlLxufNvngc/74UncOB/smPD7Xm7Y5e9lYCCGE/Dxt2LABaWlpEIvF2LRpEywsLFBcXIwrV66gvLwcAoEAGzZsQGxsLObMmYOlS5fi/v373B/GirZm0aJFWLNmDWxtbWFhYYETJ06gpaVF6VhOTk4wMjLCH/7wB3h7e2Pq1KlqYzI3N0dwcDA2b96MqVOnwsvL66XiVUdHRwfR0dGorKyEqakp9u/fj/fee2/AI4qq9u/fj4CAAAiFQojFYiQnJ0Mmk2HHjh0a94mNjcWsWbMgkUgQHh6Orq4uXLt2DTY2Njhy5AgA4K9//StmzZqFefPmYcGCBZBKpcjMzORuLHl6euJvf/sbYmNjYW5uDolEwqvemJgYBAUFQVdXF+7u7oiPj0dPT8+gn1EdgUCABQsWYOvWraiqqkJDQwMOHTqktq8gkUhw+PBhfPLJJwD6Z/WIRCIUFhZi7969gx5nz549mDNnDnR1dSESiZCQkAC5XD5kv49vfNrkg0+e+VB3Dof6Jjw+15s2OdMmFjKy0cAUISOEg4MDTp48icTERDx79gyxsbFYtmwZ976TkxOCg4MH7BcREQFbW1skJibi9u3bWLFiBdatWzdgXYMXG4e5c+fihx9+QHx8PHJycmBjY4MDBw4odYZCQkJw7949xMfHIzc3Fx4eHkqN+bZt22BsbIycnBy0t7cjKCiIV72rVq3ChAkTkJKSArlcjiNHjqC4uBgmJiYaczN79uwBi2fr6Ojg6tWrOHz4MG7evAlra2vk5uZi586dAx4/XLt2LczNzTFr1ixu36ioKFRXV8PW1lbjcRX7WlpaIjU1FR0dHVxH58XBo1eJj08+JBKJUpx88qwuJi8vL6W7U+rOoWoHSvXYfK43PjlTrZdPLIQQQkY2a2trhIeHK20zNjZGREQE93++vr4+Ll26hKSkJNy4cQNPnz6Fh4cHDhw4wM1+MjIywp07d/DFF18gPz8fLi4uOHr0KMLDw7lFpZcuXYoxY8YgIyMDVVVV3JdyKL6ABOhfuuDKlStISEhAeno6goKC4OPjg4iICO5YCh999BFGjx6NefPmKW3nE686QqEQOTk5iIuLQ1FREbZt26a0KLy6XAH9bXlRURHi4uJw69Yt+Pv74+uvvx6wdtaL/T4XFxeUlpYiLi4OBQUFsLCwwMaNG7mlBgBAJBKhpKQEJ06cQF5eHqZNm4ZLly5x74eGhqK1tRW5ubn473//C2dnZ4hEoiHr9ff3x61bt3Dy5EmUlJRg69at6Ovrw6NHjzTmRrW/onDq1CkcOXIEeXl5MDMzQ0ZGBr755hulWUrA/89we3Hx9g0bNuDy5cvw9fXVeFygv3+SnZ2N+Ph4lJSU4MMPP8TVq1eVZj69Snx88uHh4aH0hTp8zp+6mFT/dlB3DlUHg1SPzed645Mz1Xr5xEJ+XgRsqDmkhJBht3//fpw+fXrIhSC15evri/nz5+OPf/zja6n/56yxsRHjxo3jXtfX18PR0RFxcXEIDQ0dxsh+uihnhBBCXjeZTKa02POWLVsGfDHIT5VilvPrepRp9erV6O3txalTp15L/T9nbW1tEAqF0NPTAwB0d3fDxcUF77///qCz0t5klDPCB82YIuQN9uzZM5w9exaFhYU4cODAcIczIt27dw8xMTFYtGgRuru7cfToUUyfPp2+BncQlDNCCCGv27Jly+Du7g5HR0fk5uYiISEBSUlJwx3WsGpra8OZM2eQnp6Ozz//fLjDGZH+85//IDw8HOHh4TAwMEBCQgK6urrwu9/9brhD+8minBE+aPFzQkYATY/pvaq6ujqUlpYiKSkJPj4+//P63wSBgYH405/+hH//+994+PAhoqKikJ2dzd0VIgNRzgghhLxuZ8+ehbm5OXJzc2FtbY3CwkKEhIQMd1i8aHpM71W1t7cjLy8Pe/fuxW9/+9v/ef1vAjs7Oxw/fhwNDQ0oLi5GaGgovvvuO4wfP364Q/vJopwRPuhRPkIIIYQQQgghhBAyLGjGFCGEEEIIIYQQQggZFjQwRQghhBBCCCGEEEKGBQ1MEUIIIYQQQgghhJBhQQNThBBCCCGEEEIIIWRY0MAUIYQQQgghhBBCCBkWNDBFCCGEEEIIIYQQQoYFDUwRQgghhBBCCCGEkGFBA1OEEEIIIYQQQgghZFjQwBQhhBBCCCGEEEIIGRb/Bw2Wa4mj0mBXAAAAAElFTkSuQmCC",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "def clean_token(token):\n",
+ " return token.replace(\"\\n\", \"\\\\n\")\n",
+ "\n",
+ "\n",
+ "token_ids = primary_result.prompt_token_ids.tolist()\n",
+ "position_tokens = [\n",
+ " clean_token(model.tokenizer.decode([token_id])) for token_id in token_ids\n",
+ "]\n",
+ "\n",
+ "layer_position_rows = []\n",
+ "for layer_result in primary_result.layers:\n",
+ " ff1_top = layer_result.input_projection.top_tokens(model.tokenizer, k=3)\n",
+ " ff2_bottom = layer_result.output_projection.bottom_tokens(model.tokenizer, k=3)\n",
+ " for position, prompt_token in enumerate(position_tokens):\n",
+ " layer_position_rows.append(\n",
+ " {\n",
+ " \"layer\": layer_result.layer,\n",
+ " \"position\": position,\n",
+ " \"prompt token\": prompt_token,\n",
+ " \"FF1 top raw directions\": \", \".join(\n",
+ " map(clean_token, ff1_top[position])\n",
+ " ),\n",
+ " \"FF2 bottom raw (update ordering)\": \", \".join(\n",
+ " map(clean_token, ff2_bottom[position])\n",
+ " ),\n",
+ " }\n",
+ " )\n",
+ "display(pd.DataFrame(layer_position_rows))\n",
+ "\n",
+ "final_position = -1\n",
+ "norm_comparison_rows = []\n",
+ "for layer_result in primary_result.layers:\n",
+ " ff2 = layer_result.output_projection\n",
+ " raw_bottom = ff2.bottom_tokens(model.tokenizer, k=5)[final_position]\n",
+ " normalized_bottom = ff2.bottom_tokens(\n",
+ " model.tokenizer, k=5, normalized=True\n",
+ " )[final_position]\n",
+ " norm_comparison_rows.append(\n",
+ " {\n",
+ " \"layer\": layer_result.layer,\n",
+ " \"VJP norm\": float(ff2.factor_norms[final_position]),\n",
+ " \"raw FF2 bottom tokens\": \", \".join(map(clean_token, raw_bottom)),\n",
+ " \"normalized FF2 bottom tokens\": \", \".join(\n",
+ " map(clean_token, normalized_bottom)\n",
+ " ),\n",
+ " }\n",
+ " )\n",
+ "norm_comparison = pd.DataFrame(norm_comparison_rows)\n",
+ "display(\n",
+ " norm_comparison.style.set_uuid(\"ff2-norm-comparison\")\n",
+ " .background_gradient(cmap=\"viridis\", subset=[\"VJP norm\"])\n",
+ " .format({\"VJP norm\": \"{:.3e}\"})\n",
+ ")\n",
+ "\n",
+ "last = primary_result.layer(DETAILED_LAYERS[-1]).output_projection\n",
+ "raw_top = last.top(k=5)\n",
+ "raw_bottom = last.bottom(k=5)\n",
+ "top_ids = raw_top.indices[final_position].tolist()\n",
+ "bottom_ids = raw_bottom.indices[final_position].tolist()\n",
+ "top_tokens = [clean_token(model.tokenizer.decode([token_id])) for token_id in top_ids]\n",
+ "bottom_tokens = [\n",
+ " clean_token(model.tokenizer.decode([token_id])) for token_id in bottom_ids\n",
+ "]\n",
+ "\n",
+ "fig, axes = plt.subplots(1, 2, figsize=(12, 4))\n",
+ "axes[0].barh(top_tokens, raw_top.values[final_position].numpy(), color=\"#be123c\")\n",
+ "axes[0].invert_yaxis()\n",
+ "axes[0].set(\n",
+ " xlabel=\"projected raw-gradient logit\",\n",
+ " title=\"Largest +gradient logits\",\n",
+ ")\n",
+ "axes[1].barh(\n",
+ " bottom_tokens, -raw_bottom.values[final_position].numpy(), color=\"#2563eb\"\n",
+ ")\n",
+ "axes[1].invert_yaxis()\n",
+ "axes[1].set(\n",
+ " xlabel=\"negative projected raw-gradient logit\",\n",
+ " title=\"Largest ordering after subtracting gradient\",\n",
+ ")\n",
+ "fig.suptitle(\"FF2 final-position sign ordering (not a direct P(-v) readout)\")\n",
+ "fig.tight_layout()\n",
+ "plt.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2bc454cb",
+ "metadata": {},
+ "source": [
+ "## Reconstruction error and compact gradient rank\n",
+ "\n",
+ "The gradient rank is estimated from the small factor core rather than by taking an expensive SVD of the full MLP matrix. The estimate uses a relative singular-value threshold of $10^{-5}$ and is bounded by the number of prompt positions."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "id": "323e645c",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-09-02T13:05:35.035652Z",
+ "iopub.status.busy": "2026-09-02T13:05:35.035444Z",
+ "iopub.status.idle": "2026-09-02T13:05:35.408876Z",
+ "shell.execute_reply": "2026-09-02T13:05:35.408222Z"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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zhg9erRzndzcXEOS8eSTT5Z73WX7GjVqlHHjjTcae/bsMbZu3WosWbLE2LBhgyHJ+PDDD8s9LzQ01Jg8ebLL2Ole/6lyFBcXG5KMmTNnOsfMqBcAoP7r2rWrERISUun1d+zYYQQGBhoDBgwwNm3aZGRkZBivv/664ePjY9x8883O9d544w1DknHdddcZc+fONbKysowlS5YYAQEBxgMPPGDcc889xptvvmlkZmYay5YtMwIDA43bbrvNZV9l27jmmmuMV1991cjIyDA2bdpknHvuuUazZs2MQ4cOnTRnamqqMWfOHMPT09OYO3euczwpKcmIjIw0unTpYvz0009GTk6OsWPHDuOxxx4zFi5caBiGYbz33nuGJGPTpk2VqsmWLVsMPz8/Y9iwYcaOHTuM9PR044UXXjBGjx5tSDI+++yzcq/p2muvNf79738b6enpxvz58428vLxKv4atW7cajRs3Ni655BJj+/btRnp6uvHss89WuL+PP/7YkGRs2LDBOXb48GGjTZs2Ro8ePYyVK1caubm5xooVK4z27dsbF198seFwOFyyTpgwwXjttdeMjIwM448//jDat29vnHPOOS5Zq1ozd9ShKvnK1t25c6dhGIbx559/Gq1btzZ69eplJCUlVSozUBvRmALqsO+++86QZDz11FNVet7QoUMNScayZcsqtX5hYaHh4+NjPP/884ZhGEZ+fr4RGBhoXHXVVS7r5eTkGMHBwadtTBUVFRkRERHGeeedV25fU6dONUJCQozCwkKXrGvWrHFZb8SIEUZ0dLTLWHUaUxXVoayub7zxhsv4sWPHjPDwcGcj8MsvvzQkGf/+979Puo+PPvrIkGS8++67LuOrVq1yadiUNVo6d+5slJaWOtdLT083PD09jUcffdQ5dttttxnh4eGnfG2VaUxFRUUZJSUlLsuq0piqzOuvamPKjHoBAOq/Jk2aGD169Kj0+tddd53RqFEjIyUlxWX8gQcecGlMlDUCZsyY4bLeHXfcYfj5+Rn333+/y/idd95p+Pr6ury/lm3jrrvucll3//79hpeXlzFt2rTT5h0zZozRt29f5+MpU6YYPj4+p/wgpqpNlmuvvdYIDAw0srOzXcbHjx9/0sbUnXfeWaltV/Qaxo0bZwQEBDg/dCozduzYSjWmbr/9dqNRo0YuH5wahmH8/PPPhiTjm2++ccn613+refPmGZKM33//3TlW3cbUmdShKvlObEx99dVXhr+/vzF69Gjj6NGjld4/UBtxKR9QhxmnuNNeq1atXE4ffuSRR1yWBwYGavDgweWel56erjvvvFNt27aVj4+PbDabfHx8VFhY6DydeN26dcrOztbIkSNdnuvv76+LLrrotLnXr1+vpKQkXX311eWWXXzxxcrIyNCmTZucY82aNVPv3r1d1ouNjdX+/fvPeBLTiurwxRdfyGaz6aqrrnIZ9/X11YABA7Rs2TJJ0tdffy1Juu666066/bLLG6+88kqX8b59+6ply5blLn8cNmyY7Pb//WoODQ1VeHi49uzZ4xzr3r27kpOTdcstt+i3336rdg0uv/xyl0saqqoyr7+qzKgXAAB/9dNPP2nAgAFq0aKFy/iYMWOcy080bNgwl8edO3dWfn6+hg4d6jLepUsXFRQUKDk5udw+/3rcFBkZqXPOOUdLlixxjhmGofj4ePXq1UtNmjRxuZzsxMu6vv76a/Xr10/R0dFVeNWntnTpUp133nkKCAg4Ze7TLavsa/jpp5903nnnKTAw0OX5V1xxRaXyfvHFFzr33HMVGRnpMj5o0CD5+Pg4j9fKXH755S6PY2NjJcktxwxnUofq5IuPj9fIkSN122236ZNPPpGfn98ZvwbASjSmgDqsTZs2kqQDBw6UW3bw4EEZhqGdO3dW+NyWLVuWGzMMQ5dccom+/PJLvfHGG0pNTZXD4ZBhGGrSpIlzTqcjR45IUrmDuZON/VVKSookadq0afL09JSHh4c8PDxkt9udByNl+5Ck8PDwctsICAhQaWmp8vLyTru/U6moDikpKTIMQ82aNXPms9vtstvt+uSTT5zZUlNT1bhx43IHVCc6cuSImjRpoiZNmpRbFhYWpvT0dJexk73WrKws5+NbbrlFzz77rJYuXaq+ffsqODhYo0aNcs4xVVkVvfZT+WsjtDKvv6rMqBcAoP5r06aN9u/fX+n1jxw5orCwsHLjZWOne78pm0PxZOMVvQ+d7LjpxH09/fTTmjZtmiZOnKgdO3aopKREhmFo4sSJLnNrpqamVvl9/HSOHDmi5s2blxuvaKxMRRkq+xqOHDlS7WNJ6fjx2rJly+Tp6elyvObh4aHCwkKXY0mp/L9VWQPOHccMZ1KH6uSbP3++AgICNGXKFCb0R71AYwqowzp37qw2bdrohx9+OOXZUxWp6C59mzZt0oYNG/Too4/qoosuUmBgoGw2m9LT010aQKGhoZKOT7r5VxWN/VXTpk0lSW+//bZKSkpUWlqq0tJSZxOsrEFWxsw33Irq0LRpU3l5eSkvL8+Zz+FwOPOVTcLdrFkzHT16VNnZ2SfdfkhIiPLy8nT06NFyyw4fPuysRZnKvFa73a77779fO3fu1IEDB/Tqq68qMTFR559/frnJ2U+lotde1mTKzc11GS8oKFBmZqbLWGVef1WZUS8AQP136aWXKiMjQ2vWrKnU+iEhIac8jqns+01V3odOtr+y4ypJevfddzV06FBNnTpVERERzjOb9+7d6/K8Zs2a6dChQ5Xed2WEhoa63GikTEVjZSo6lqjsawgNDa32saR0/N/o8ssvV0lJicvxWtmx5Ouvv+6yfk0fT1a2DtXJ9/nnn6t169YaNGiQNmzYUL3QQC1CYwqo4x577DHt2bNHc+bMcds2fXx8XB6/++67Lo/POeccBQQE6IsvvnAZz8vLczkd/WR69+6tFi1a6KOPPjrzsCdo3LixCgsLz3g7I0aMUHFx8Wnv7jZ8+HBJKncnwROVXdp44p1spON3vTl48GClLn08lVatWmn8+PGKj49XUVGR8+6Jvr6+zk8Mq7o9b29vbd682WX8yy+/LNf8rMzrr2oOs+sFAKif7r77bgUGBur++++v8GwU6fhd10pLSyUdf79ZuXKl0tLSXNZZuHChJOnCCy90e8a/HjcdPHhQ69evL/fe9tfjsL1792rlypUuY8OHD9eqVatc7gL8V40bN5akSr8HX3DBBfrll1/KfTj15ZdfVur5J6rMa7jwwgv1yy+/lLuL4aJFiyq1jxEjRuiXX35xnonvDlWt2elUpg7V0aJFCy1btkwdOnTQBRdcoOXLl5/xNgEr0ZgC6rhJkybpgQce0D333KOpU6dq48aNOnbsmI4ePaotW7botddek1S5T2G6dOmi9u3b69lnn1VCQoKysrI0b948LVmyRCEhIc71/Pz89Nhjj+nTTz/Vs88+q/T0dO3evVsTJkzQueeee9r9eHt76z//+Y++//57TZ48WVu3btWxY8e0d+9evf/++7r44ourVYvY2FjnQd6Jt3quqssuu0zjxo1TXFycXn/9dSUlJeno0aP6448/NHPmTD3++OPO9caMGaP7779fr732mlJSUpSWlqYPP/xQ999/vyRp9OjR6t+/v+655x599dVXys3N1a+//qrx48erbdu2mjp1apXz3X777Xr++eeVkJCggoICHTp0SG+++aZ8fHzUr18/SZKnp6c6deqkX375RRkZGZXetpeXlyZOnKh33nlHP/zwg3Jzc/X1119r0aJFLj8DlX39Vc1hRr0AAPVfq1attHDhQm3cuFEXXHCB8z0sPz9fK1as0PDhw/Xoo486P2SZOXOmPDw8dNVVV2nLli3KysrSW2+9pRdffFGTJk1St27d3J4xKSlJb7zxhrKysrRlyxZdc8018vf3d75nSsfnKvrqq6/02Wef6ejRo/rtt9903XXXlWtezZo1S82bN9fll1+uJUuWKDc3V7t27dLjjz/u/GCta9eustls+vrrryvVaHn00UdVVFSkcePGadeuXcrIyNDLL79c4VnMp1LZ1/Doo4+quLhY1157rXbu3KmMjAw9//zzlW4KPfHEEwoNDdWwYcP0008/KTs7W2lpafr55591/fXXl5tjqjKqWrNTqWwdqiswMFDff/+9+vXrp6FDh+qbb75xy3YBK9CYAuqBZ555RsuWLVNGRoZGjRqloKAgtWzZUmPGjNGuXbv0wQcf6MEHHzztdry8vPTll1+qZcuW6tevn9q3b6+ff/5Z77//frnG1t/+9jfNmTNHb7zxhlq1aqXRo0fr1ltvVUxMTKUyl82JlJWVpfPOO09BQUEaMmSIvv/+ez333HPVqsPUqVM1atQoXXjhhfLw8DijU7bff/99Pfvss3rrrbfUsWNHhYeH66abbpK3t7emTZvmXG/BggWaNWuW/v3vfysqKkrdu3fX119/rTvuuEPS8cbMd999pxtvvFF33HGHQkJCdNVVV2nw4MFauXKlgoKCqpzt4YcfVnp6uq655hoFBwerV69eysrKcn5yVua1115Tbm6uwsPDZbPZNH78+Ept/7nnntPIkSM1ZswYtWrVSgsWLFB8fHyF9Tzd669qDjPqBQBoGC666CJt3rxZ5557ru6++26FhYWpRYsWuu222xQeHq41a9bI09NTktSpUyetXr1aTZs21aBBg9S8eXM9//zzevLJJ/XGG2+Ykm/WrFnavn27OnTooN69e8vf31+//PKLy/xETz75pOLi4jR16lQ1a9ZM9957r1555RVFRUW5bKvs9QwaNEgTJkxQ06ZNNXz4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SDr+CV5BQYH8/f318ssv67///a9bAwIAADR0+/bt04QJEzRhwgT16tVLPXr0cPmqbGOqsLBQr7zyijp27KjAwEAFBARo/PjxzF8FAEAd4OXto2SPCElS2t5NFqdxn2o1po4ePSp/f39JUosWLZSYmCjp+PwG2dnZbgsHAAAAqX379kpOTj7j7WzatElpaWn67rvvdOzYMf3xxx/avHmzJk2a5IaUAADAbBmN2kiSjh7aanES96n25OdlhgwZojvvvFOTJ0/Whx9+qN69e7sjFwAAAP7foEGD9MADD+jZZ5/VqFGjyk1+HhAQoICAgNNup1evXurVq5fzcXR0tEaPHq0333zT7ZkBAID7FQS2k46ukO3ITqujuE21zph64403nN//4x//UJMmTXT33XcrOztbr7/+utvCAQAA4PjNV3bt2qUZM2aoS5cuioyMdPl68cUXq7S9vLw8HTlyRCtWrNB7772nm266yaTkAADAnTybd5IkNc7dY3ES96nWGVNTpkxxft+8eXN99tlnbgsEAAAAV1OnTtXYsWNPurxp06ZV2t6VV16pX3/9Vfn5+Ro1apRmzJhx0nULCwtVWFjofJyTkyNJcjgccjgcVdpvZTgcDhmGYcq2Gzpqaw7qah5qaw7qap6aqG1Aqy7SRql54f5a/W9YlWxnfCkfAAAAzNW0adMqN59O5YcffpAk7dy5U9ddd51GjhzpHPur2bNna9asWeXGMzMzVVJS4rZMZRwOh3Jzc2UYhuz2ap3cj5Ogtuagruahtuagruapidr6hkZKkporQ/v27VFj/yBT9nOmcnNzK71upRtTffv2rfRGV69eXel1AQAAUF56errS09OdDalT3Tmvuo2rDh066Mknn9SwYcN08OBBtWrVqtw6Dz74oKZPn+58nJOTo8jISAUHB1dqXquqcjgcstlsCg4O5g8mN6O25qCu5qG25qCu5qmJ2oaEhChNwWqmTBVkHFBkm7am7OdMeXpW/jyoSq85fPjwaoUBAABA1f3rX//SrFmzNHPmTEmq8KylMjNnztTjjz9erf2UXZrn5eVV4XIfHx/5+PiUG7fb7aYddNtsNlO335BRW3NQV/NQW3NQV/PURG1TvVurWVGmcg5ulf2cC0zbz5moyuuvdGPqkUceqVaY+iY+Pl7x8fEqLS21OgoAAKjHpk+frilTpjjPSjpxjs+/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AAAAWIJL+arJMAxJUk5Ojtu37XA4lJubK09PT05hdzNqax5qaw7qah5qaw7q6qrsOKHsuKE+MPMYSOJnyEzU1hzU1TzU1hzU1TzU9n+qcgxEY6qK4uPjFR8fr6KiIklSZGSkxYkAAEBtl5ubW2/u5pubmyuJYyAAAHB6lTkGshn16SO8GuRwOJSUlCR/f3+338o4JydHkZGROnDggAICAty67YaO2pqH2pqDupqH2pqDuroyDEO5ubmKiIioN5+cmnkMJPEzZCZqaw7qah5qaw7qah5q+z9VOQbijKlqstvtatWqlan7CAgIaPA/zGahtuahtuagruahtuagrv9TX86UKlMTx0ASP0NmorbmoK7mobbmoK7mobbHVfYYqH58dAcAAAAAAIA6h8YUAAAAAAAALEFjqhby8fHRzJkz5ePjY3WUeofamofamoO6mofamoO64kzxM2QeamsO6moeamsO6moeals9TH4OAAAAAAAAS3DGFAAAAAAAACxBYwoAAAAAAACWoDEFAAAAAAAAS9CYqoUOHjyodevWKSsry+oo9Upubq42bNiglJQUq6PUSw6HQytXrtSff/5pdZR65dixY9qwYYMOHz5sdZR6JSMjQ+vXr9fOnTtVWlpqdZw6y+FwaO3atdq0adNJ1yksLNT69eu1ffv2GkyGuqqoqEgbNmzQtm3brI5SrxiGod27dyshIUGFhYVWx6mXEhMTtWLFCo7f3Wzfvn36888/VVJSYnWUeqO0tFQ7d+7U+vXrlZGRYXWcOi05OVkrVqxQdnb2Sdc5cOCA1q1bp5ycnBpMVvfQmKpFioqKNHbsWHXs2FE33nijwsPD9fzzz1sdq85LTEzUNddco8jISE2aNEmdOnXSJZdcotTUVKuj1StPPfWUBg8erFtuucXqKPXGc889p+bNm+vGG29U//79NWXKFA7MzlBpaakmT56sVq1aacqUKbrgggvUvn17LV++3OpodUpxcbGeeeYZdejQQUOGDNGdd95Z4XrffPONWrZsqauvvlr9+vVTr169lJycXMNpUVf89NNPatWqla666ioNHDhQPXr00IEDB6yOVee9/vrrio6O1tChQzV69GiFh4fr7bfftjpWvZKamqoBAwZo0KBBWr16tdVx6oXdu3erf//+OvvsszV58mTFxMTwXu0Gy5cvV/v27XXhhRdqypQpatWqlSZPnsyHdFW0bt06jRkzRt27d9egQYO0YcOGcusUFBToqquuUqdOnXTDDTcoLCxMc+bMsSBt3UBjqhaZPXu2li1bpu3btyshIUGffvqp7r//fv3yyy9WR6vTdu/erauvvlqZmZnasGGDEhMTlZaWpttuu83qaPXG8uXLNW/ePF1zzTVWR6k34uPj9fjjj+ubb77Rpk2btHv3bg0aNIhPus/QBx98oPfee0/r1q3T+vXrtX//fg0YMEA33XST1dHqlPz8fGVlZemHH37QmDFjKlwnPT1d1157re666y7t3r1bSUlJ8vLy0uTJk2s4LeqCrKwsXX311br55pu1Z88eJSUlKSAgQBMmTLA6Wp13+PBhrVixQrt27dK2bdv04osv6uabb67wDylUnWEYmjBhgm644Qaro9QbeXl5GjJkiFq1aqVDhw5p7dq1WrZsmdLT062OVudNnDhRgwYN0r59+7R+/XqtWbNG7777rj788EOro9Upmzdv1rXXXqvffvvtpOvMmjVLa9as0e7du7V161Z98MEHmjZt2imf05DRmKpF3n77bU2cOFGRkZGSpGHDhumcc87hU60zdNFFF+nqq6+WzWaTJAUHB2vs2LFasWKFxcnqh4yMDN1www2aO3euAgMDrY5TL5SUlOiJJ57Q1KlTNXDgQOf4hAkT1LhxYwuT1X1paWkKDAxUTEyMJMlut6tv375KS0uzOFndEhgYqGeeeUZt27Y96Toff/yxSktL9be//U2S5Ovrq3vvvVfffvstZ02hnM8++0xHjx7VAw88IEny9vbWAw88oKVLlyoxMdHacHXco48+qlatWjkfT5w4UT4+Plq1apWFqeqP5557TqWlpbrrrrusjlJvvP3220pOTtZ//vMf+fr6SpLCw8N15ZVXWpys7ktLS9O5554ru/14GyA2NlZBQUEcB1XRxIkTdfXVV8vLy+uk68ydO1dTpkxReHi4JOmKK65QbGys5s6dW1Mx6xQaU7VERkaG9u/fr3POOcdlvE+fPnyiZYK1a9eqffv2VseoFyZNmqTrrrtOgwcPtjpKvbFp0yalpqZqxIgRSk1N1fr165WZmWl1rHrhxhtvVIsWLXTbbbfphx9+0HvvvacXXnhBzzzzjNXR6p0NGzaoS5cu8vPzc4716dNHhmFo48aN1gVDrbRhwwZ16NBBAQEBzrE+ffo4l8F9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YwoAAAAAAACWYI4pAAAAAAAAWILGFAAAAAAAACxBYwoAAAAAAACWoDEFAAAAAAAAS9CYAgAAAAAAgCVoTAEAAAAAAMASNKYAAAAAAABgCRpTACDp6NGjWrBggfLy8qyOAgAAUKN+++03rV692uoYABoom2EYhtUhAMBqiYmJio6O1s6dO9W+fXur4wAAANSYiRMnqqSkRPPnz7c6CoAGiDOmAAAAAAAAYAlPqwMAQG3kcDj00UcfSZI8PT0VFRWlHj16yNPzf782Fy5cqLPPPlvR0dEuz/3444/Vu3dvRUVFSZKysrK0evVq2e129ezZU82aNXOum52drW+++UZXXHGFtm/frl27dqlv375q2bKl+S8SAACgAn/++acSEhIkScHBwTrrrLMUHh7uXL59+3bt2LFDI0aMcHne1q1btXv3bg0fPtw5tmHDBu3bt09t2rRR9+7dZbf/79yIlStXysfHRx06dNCqVatks9k0dOhQk18dgNqGxhQAVKC0tFSff/65JKm4uFgbNmxQYGCgvv32W7Vo0UKS9N5772nRokV69913nc9buXKlxo4dqz179kiS5s+frzvvvFM9e/aUl5eXfvvtN7344ouaNGmSJOnAgQMaN26cLr/8ciUmJiomJkZt2rShMQUAACyzZcsWLVq0SJKUnp6uVatW6ZlnntGdd94pSSooKNCoUaO0c+dOtWvXzvm8adOmqXXr1ho+fLgyMzM1evRo7d27V927d9eWLVvUokULLV68WKGhoZKkl156Sfv379eRI0fUsWNHde/encYU0AAxxxQA6PRzTJWWlmr48OFq37695syZI0n66quvdM011yg5OVkBAQGSpMmTJ+vAgQP6/vvvlZCQoD59+mjJkiXq06ePJGn58uW65JJLtG3bNrVp00abN29Wt27dNHHiRL399tuy2Ww196IBAAB0+jmmVq5cqYsuukh79uxRRESEJKl3794aOnSonnrqKUnS/v37FR0dreXLl6t///66/vrrVVRUpA8//FCenp4qKSnRiBEj1KZNG7322muSpDFjxujLL7/Uxo0b1blz55p5sQBqHc6YAoBT2LRpkxITE3X06FGFhYVpzZo1zmWXXnqpQkJCtGDBAt1yyy06evSoPvroI73xxhuSjp8t1bJlS+3fv1/79u1T2ecAfn5++vXXX9WmTRvntu68806aUgAAoNbIysrSxo0blZqaKofDIS8vL/3xxx/OxtSUKVP01FNP6YknnpDdbtfcuXPVoUMH9e/f33lMNGPGDH3++ecyDEOGYah169ZaunSpy34uueQSmlJAA0djCgAqkJeXp0svvVQ7duzQOeeco4CAAO3du1dpaWnOdTw8PJxnOt1yyy366KOP5OXlpSuvvFLS8bOwjh07pk8++cRl20OGDFFQUJDL2InzNgAAAFhp/vz5uuOOO9S5c2e1atVK3t7eKi0tVWpqqnOd6667Tn/729/0/fffa+jQoXrnnXd0++23S5IOHTqkkpIS/f7779q5c6fLtgcOHOjymGMgADSmAKACr7/+utLS0rR//375+vpKkp555hnnqedlJk+erL///e9KSEjQ22+/reuuu04+Pj6SpICAAIWFhWnBggWn3R9nSwEAgNrAMAzFxcXplVde0U033eQca9y4sU6cBcbf31/XXHON3n77bXl5eengwYO68cYbJck5xcHUqVN12WWXnXJ/HAMBsJ9+FQBoeFJSUtSmTRtnU8owDH366afl1ouKitJFF12khx56SCtWrNDkyZOdyy699FL9/vvvWrt2rctzsrKylJ+fb+4LAAAAqIZjx44pJydHnTp1co599dVXOnbsWLl1p0yZosWLF+uFF17QZZddprCwMElSWFiYunfvXu4DPen42VQAcCLOmAKACowcOVIvvvii7r//fnXo0EEfffSRdu7cqcDAwHLr3nzzzbrmmmvUo0cP9ezZ0zk+atQojRs3TkOGDNG0adPUpk0bJSQkaPHixfrll1/k5+dXky8JAADgtPz8/DRkyBDdfvvtmjp1qpKSkhQfH+/8sO5E/fv3V/v27fXNN98472Zc5vXXX9fQoUM1dOhQXXnllcrLy9P333+vc845R7Nnz66hVwOgLuCMKQCQ1LhxY1177bXy9/eXdHz+gyVLlujo0aNatWqVrr76ai1YsEAjRowo99zhw4fLw8NDkyZNchm32WyaP3++5s+fr8zMTK1atUqRkZFas2aNcz6FoKAgXXvttWrUqJH5LxIAAKAC5557rvr16+d8/Omnn+q6667TihUrlJeXpyVLlmjSpEmKjo4u99xRo0apRYsWuvzyy13G+/Tpo4SEBJ1//vlatWqVUlNTNWPGDJem1MCBA9W7d2/zXhiAOsFmnHihMACgyhYvXqxx48bpwIEDCgkJsToOAABAjTnnnHM0ZMgQPfPMM1ZHAVBHcSkfAFTTwYMH9dNPP+mpp57S7bffTlMKAAA0GN98841++OEH7dy5U1988YXVcQDUYTSmAKCaDh06pO+++04TJ07Uvffea3UcAACAGrNkyRLl5OTou+++U0REhNVxANRhXMoHAAAAAAAASzD5OQAAAAAAACxBYwoAAAAAAACWoDEFAAAAAAAAS9CYAgAAAAAAgCVoTAEAAAAAAMASNKYAAAAAAABgCRpTAAAAAAAAsASNKQAAAAAAAFiCxhQAAAAAAAAs8X8Qr1RS5/heoQAAAABJRU5ErkJggg==",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " layer | \n",
+ " matrix | \n",
+ " relative reconstruction error | \n",
+ " compact numerical rank | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | 0 | \n",
+ " 0 | \n",
+ " FF1 | \n",
+ " 0.000e+00 | \n",
+ " 6 | \n",
+ "
\n",
+ " \n",
+ " | 1 | \n",
+ " 0 | \n",
+ " FF2 | \n",
+ " 0.000e+00 | \n",
+ " 6 | \n",
+ "
\n",
+ " \n",
+ " | 2 | \n",
+ " 2 | \n",
+ " FF1 | \n",
+ " 0.000e+00 | \n",
+ " 6 | \n",
+ "
\n",
+ " \n",
+ " | 3 | \n",
+ " 2 | \n",
+ " FF2 | \n",
+ " 0.000e+00 | \n",
+ " 6 | \n",
+ "
\n",
+ " \n",
+ " | 4 | \n",
+ " 4 | \n",
+ " FF1 | \n",
+ " 0.000e+00 | \n",
+ " 6 | \n",
+ "
\n",
+ " \n",
+ " | 5 | \n",
+ " 4 | \n",
+ " FF2 | \n",
+ " 0.000e+00 | \n",
+ " 6 | \n",
+ "
\n",
+ " \n",
+ " | 6 | \n",
+ " 6 | \n",
+ " FF1 | \n",
+ " 0.000e+00 | \n",
+ " 6 | \n",
+ "
\n",
+ " \n",
+ " | 7 | \n",
+ " 6 | \n",
+ " FF2 | \n",
+ " 0.000e+00 | \n",
+ " 6 | \n",
+ "
\n",
+ " \n",
+ " | 8 | \n",
+ " 8 | \n",
+ " FF1 | \n",
+ " 0.000e+00 | \n",
+ " 6 | \n",
+ "
\n",
+ " \n",
+ " | 9 | \n",
+ " 8 | \n",
+ " FF2 | \n",
+ " 0.000e+00 | \n",
+ " 6 | \n",
+ "
\n",
+ " \n",
+ " | 10 | \n",
+ " 10 | \n",
+ " FF1 | \n",
+ " 0.000e+00 | \n",
+ " 6 | \n",
+ "
\n",
+ " \n",
+ " | 11 | \n",
+ " 10 | \n",
+ " FF2 | \n",
+ " 0.000e+00 | \n",
+ " 6 | \n",
+ "
\n",
+ " \n",
+ " | 12 | \n",
+ " 11 | \n",
+ " FF1 | \n",
+ " 0.000e+00 | \n",
+ " 1 | \n",
+ "
\n",
+ " \n",
+ " | 13 | \n",
+ " 11 | \n",
+ " FF2 | \n",
+ " 0.000e+00 | \n",
+ " 1 | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " layer matrix relative reconstruction error compact numerical rank\n",
+ "0 0 FF1 0.000e+00 6\n",
+ "1 0 FF2 0.000e+00 6\n",
+ "2 2 FF1 0.000e+00 6\n",
+ "3 2 FF2 0.000e+00 6\n",
+ "4 4 FF1 0.000e+00 6\n",
+ "5 4 FF2 0.000e+00 6\n",
+ "6 6 FF1 0.000e+00 6\n",
+ "7 6 FF2 0.000e+00 6\n",
+ "8 8 FF1 0.000e+00 6\n",
+ "9 8 FF2 0.000e+00 6\n",
+ "10 10 FF1 0.000e+00 6\n",
+ "11 10 FF2 0.000e+00 6\n",
+ "12 11 FF1 0.000e+00 1\n",
+ "13 11 FF2 0.000e+00 1"
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "def compact_gradient_rank(factors, relative_threshold=1e-5):\n",
+ " x = factors.forward_inputs\n",
+ " delta = factors.output_gradients\n",
+ " _, rx = torch.linalg.qr(x.T, mode=\"reduced\")\n",
+ " _, rd = torch.linalg.qr(delta.T, mode=\"reduced\")\n",
+ " singular_values = torch.linalg.svdvals(rx @ rd.T)\n",
+ " threshold = singular_values.max() * relative_threshold\n",
+ " return int((singular_values > threshold).sum())\n",
+ "\n",
+ "\n",
+ "diagnostic_rows = []\n",
+ "for layer_result in primary_result.layers:\n",
+ " for name, matrix in (\n",
+ " (\"FF1\", layer_result.input_projection),\n",
+ " (\"FF2\", layer_result.output_projection),\n",
+ " ):\n",
+ " diagnostic_rows.append(\n",
+ " {\n",
+ " \"layer\": layer_result.layer,\n",
+ " \"matrix\": name,\n",
+ " \"relative reconstruction error\": (\n",
+ " matrix.factors.relative_reconstruction_error\n",
+ " ),\n",
+ " \"compact numerical rank\": compact_gradient_rank(matrix.factors),\n",
+ " }\n",
+ " )\n",
+ "diagnostics = pd.DataFrame(diagnostic_rows)\n",
+ "\n",
+ "fig, axes = plt.subplots(1, 2, figsize=(12, 4))\n",
+ "for matrix_name, group in diagnostics.groupby(\"matrix\"):\n",
+ " axes[0].plot(\n",
+ " group[\"layer\"],\n",
+ " np.maximum(group[\"relative reconstruction error\"], 1e-12),\n",
+ " marker=\"o\",\n",
+ " label=matrix_name,\n",
+ " )\n",
+ " axes[1].plot(\n",
+ " group[\"layer\"],\n",
+ " group[\"compact numerical rank\"],\n",
+ " marker=\"o\",\n",
+ " label=matrix_name,\n",
+ " )\n",
+ "axes[0].set(\n",
+ " yscale=\"log\",\n",
+ " xlabel=\"layer\",\n",
+ " ylabel=\"relative error\",\n",
+ " title=\"Gradient reconstruction\",\n",
+ ")\n",
+ "axes[1].set(xlabel=\"layer\", ylabel=\"estimated rank\", title=\"Compact gradient rank\")\n",
+ "for ax in axes:\n",
+ " ax.grid(alpha=0.25)\n",
+ " ax.legend()\n",
+ "fig.tight_layout()\n",
+ "plt.show()\n",
+ "diagnostics_for_display = diagnostics.copy()\n",
+ "diagnostics_for_display[\"relative reconstruction error\"] = diagnostics_for_display[\n",
+ " \"relative reconstruction error\"\n",
+ "].map(lambda value: f\"{value:.3e}\")\n",
+ "display(diagnostics_for_display)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "79b42321",
+ "metadata": {},
+ "source": [
+ "## Target-token ranks: raw versus Normalized Logit Lens\n",
+ "\n",
+ "Ranks are zero-based and ascending in raw-gradient space: rank 0 is the smallest projected FF2 gradient logit. Lower is therefore the update-relevant ordering, but this remains a directional diagnostic rather than a prediction of an optimizer step."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "id": "e87a4974",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-09-02T13:05:35.410940Z",
+ "iopub.status.busy": "2026-09-02T13:05:35.410743Z",
+ "iopub.status.idle": "2026-09-02T13:05:35.592085Z",
+ "shell.execute_reply": "2026-09-02T13:05:35.591305Z"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " layer | \n",
+ " final-position VJP norm | \n",
+ " raw target rank percentile | \n",
+ " normalized target rank percentile | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | 0 | \n",
+ " 0 | \n",
+ " 0.655670 | \n",
+ " 80.9 | \n",
+ " 80.9 | \n",
+ "
\n",
+ " \n",
+ " | 1 | \n",
+ " 2 | \n",
+ " 1.442085 | \n",
+ " 41.3 | \n",
+ " 41.4 | \n",
+ "
\n",
+ " \n",
+ " | 2 | \n",
+ " 4 | \n",
+ " 1.329280 | \n",
+ " 11.2 | \n",
+ " 11.2 | \n",
+ "
\n",
+ " \n",
+ " | 3 | \n",
+ " 6 | \n",
+ " 1.042345 | \n",
+ " 4.4 | \n",
+ " 4.4 | \n",
+ "
\n",
+ " \n",
+ " | 4 | \n",
+ " 8 | \n",
+ " 0.487238 | \n",
+ " 0.0 | \n",
+ " 0.0 | \n",
+ "
\n",
+ " \n",
+ " | 5 | \n",
+ " 10 | \n",
+ " 0.274904 | \n",
+ " 0.0 | \n",
+ " 0.0 | \n",
+ "
\n",
+ " \n",
+ " | 6 | \n",
+ " 11 | \n",
+ " 0.260877 | \n",
+ " 0.0 | \n",
+ " 0.0 | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " layer final-position VJP norm raw target rank percentile \\\n",
+ "0 0 0.655670 80.9 \n",
+ "1 2 1.442085 41.3 \n",
+ "2 4 1.329280 11.2 \n",
+ "3 6 1.042345 4.4 \n",
+ "4 8 0.487238 0.0 \n",
+ "5 10 0.274904 0.0 \n",
+ "6 11 0.260877 0.0 \n",
+ "\n",
+ " normalized target rank percentile \n",
+ "0 80.9 \n",
+ "1 41.4 \n",
+ "2 11.2 \n",
+ "3 4.4 \n",
+ "4 0.0 \n",
+ "5 0.0 \n",
+ "6 0.0 "
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "# Exact ranks can move by one across numeric backends when vocabulary logits are nearly tied.\n",
+ "# Keep them in primary_layer_summary, but display stable vocabulary percentiles.\n",
+ "vocab_size = primary_result.layers[0].output_projection.vocabulary_size\n",
+ "rank_percentiles = primary_layer_summary[[\"layer\", \"final-position VJP norm\"]].copy()\n",
+ "rank_percentiles[\"raw target rank percentile\"] = (\n",
+ " 100 * primary_layer_summary[\"raw target rank\"] / vocab_size\n",
+ ")\n",
+ "rank_percentiles[\"normalized target rank percentile\"] = (\n",
+ " 100 * primary_layer_summary[\"normalized target rank\"] / vocab_size\n",
+ ")\n",
+ "display(\n",
+ " rank_percentiles.round(\n",
+ " {\n",
+ " \"final-position VJP norm\": 8,\n",
+ " \"raw target rank percentile\": 1,\n",
+ " \"normalized target rank percentile\": 1,\n",
+ " }\n",
+ " )\n",
+ ")\n",
+ "\n",
+ "fig, ax = plt.subplots(figsize=(7, 4))\n",
+ "ax.plot(\n",
+ " rank_percentiles[\"layer\"],\n",
+ " rank_percentiles[\"raw target rank percentile\"],\n",
+ " marker=\"o\",\n",
+ " label=\"raw factor\",\n",
+ ")\n",
+ "ax.plot(\n",
+ " rank_percentiles[\"layer\"],\n",
+ " rank_percentiles[\"normalized target rank percentile\"],\n",
+ " marker=\"s\",\n",
+ " label=\"unit-normalized factor\",\n",
+ ")\n",
+ "ax.set(\n",
+ " xlabel=\"layer\",\n",
+ " ylabel=\"ascending target-rank percentile (lower is smaller)\",\n",
+ " title=f\"FF2 target-rank percentiles for {target!r}\",\n",
+ ")\n",
+ "ax.grid(alpha=0.25)\n",
+ "ax.legend()\n",
+ "plt.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "1d7baa6d",
+ "metadata": {},
+ "source": [
+ "## VJP norm heatmap\n",
+ "\n",
+ "FF2 factor norms are norms of the residual-width vector-Jacobian products (VJPs). The logarithmic heatmap exposes both token-position and layer variation without discarding low-norm rows."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "id": "942c9dce",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-09-02T13:05:35.593912Z",
+ "iopub.status.busy": "2026-09-02T13:05:35.593713Z",
+ "iopub.status.idle": "2026-09-02T13:05:35.846776Z",
+ "shell.execute_reply": "2026-09-02T13:05:35.846027Z"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/png": "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MD8vFXwlSpRQuZZ29uzZqFChAlq2bAlDQ0McPHgQM2bMQLdu3fJk+j4/w8pCQ0OlDqHQMTAwwN27d6UOg4j0GJNVonzUpk0bpKenSx1GkREQEIA+ffrA0dERs2fPzrdREamelwq3AQMGYMaMGZgyZQoiIiLg5uaG0aNHK251okv8DBMRkT7gmlUiIiIiIiLSO1yzSkRERERERHqHySoRERERERHpnSKxZlUul+P58+ewsrKCTCaTOhwiIiIioiJBCIG4uDiULFkSBgYFa5wsOTkZqampWrU1MTGBmZmZjiMqeopEsvr8+XO4u7tLHQYRERERUZEUGhpaoG5RlJycDE9PV0REvNGqvbOzM548ecKENZeKRLJqZWUFAAj5oR+szUwkjobymqy8i9QhUD6R1yna930sSgyO/St1CJRPUm+8lDoEyicmjTykDoHyQWxiCjx8flH8PF5QpKamIiLiDZ6G/A5rawuN2sbGJqJ0qS+QmprKZDWXikSymjn119rMBNbmTFYLO5kl/1EoKuQa/udBBZeBhanUIVA+STXl/9NFhQm/10VKQV2KZ13MDNbFzDVrJJfnTTBFUJFIVomIiIiIiDQml2uefDJZ1Rkmq0RERERERKowWZUUk1UiIiIiIiJVhHh3aNqGdILJKhERERERkSpyocXIKpNVXWGySkREREREpAqnAUuqYN2Zl4iIiIiIiIoEjqwSERERERGpwpFVSTFZJSIiIiIiUoXJqqSYrBIREREREakitEhWBZNVXWGySkREREREpIJMyCHTMPnUtD5lj8kqERERERGRKpwGLCkmq0RERERERKrIheb3TeV9VnWGt64hIiIiIiIivVOgRlblcjkMDJhfExERERFRPuA0YEkViGTV398fy5YtQ1RUFKpUqYKffvoJrVq1kjosIiIiIiIqzPIhWZXL5di+fTsuXLgAW1tb9OvXD5UqVcp1G2361Td6P0y5atUqzJ07F9u2bUNMTAx69OiBzp0748mTJ1KHRkREREREhZkQ725Fo9Gh2ZrVnj17Yvr06XBxccGzZ89Qq1Yt/Pvvv7luo02/+kbvR1aXLFmCoUOHok2bNgAAPz8/bNy4EatWrcL8+fMljo6IiIiIiAqtPB5ZPXLkCPbs2YNbt26hatWqAID09HSMHz8eV69e1bqNNv3qI70eWX39+jUePHiAFi1aKMpk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kQKTVSIiIiIiIhWEln8AIDY2VulISUnReXwhISE4cuQIWrVqlW2dhw8fonTp0kplnp6einPq1pECpwETERERERGppPkGS5m7Abu7uyuVzpo1C35+fkplISEhmDNnTo69ffrpp+jVq1eW8ri4OPTo0QM1atTA6NGjs22flJQER0dHpTIrKyvFOXXrSIHJKhERERERkUpCizvRvGsQGhoKa2trRampqWmWmpaWlmjYsGGOvZUqVSpLWUJCAjp16oSMjAz89ddfMDExyba9tbU1oqOjlcrevHmjOKduHSkUiWQ1c/vohPh4iSMhIiIiIgCITU2VOgTKB3FpaQDy/nYueed/03o1ZW1t/dFEz9HREb6+vhr1m5iYiE6dOiEmJgYnT56Evb19jvWrVauGgIAApbLbt2/DwMAAlStXVruOJEQREBoaKvDuVxw8ePDgwYMHDx48ePDI5yM0NFTqlEAjSUlJwtnZWevrdXZ2FklJSTqPKzExUXh5eYkaNWqIV69eqazz7NkzMXToUHHv3j0hhBBBQUFCJpOJwMBAIYQQaWlpomnTpqJjx46KNurUkYJMiAL7aw61yeVyPH/+HFZWVpDJNJ1zXjDFxsbC3d09y/QDKnz4XhcdfK+LDr7XRQff66KjqL7XQgjExcWhZMmSSrvYFgTJyclI1XIGgImJCczMzHQcETB69GisWLEC3t7ecHBwUJR7eHhg5syZAIBr166hdu3aOHXqFLy8vAAAP/74I/z9/dG6dWs8evQICQkJOHnypGITJXXr5LcikawWRbGxsbCxsUFMTEyR+gexKOJ7XXTwvS46+F4XHXyviw6+16QLp06dwqNHj7KUOzg4oHv37gDerTX9888/0alTJ7i4uCjqBAcH49KlS7C1tUXr1q1hbm6epR916uQnJquFFP9BLDr4XhcdfK+LDr7XRQff66KD7zWR5grWWDwREREREREVCUxWCylTU1PMmjVL5RbZVLjwvS46+F4XHXyviw6+10UH32sizXEaMBEREREREekdjqwSERERERGR3mGySkRERERERHqHySoRERERERHpHSarRERE+SgpKQlDhgzB/v37pQ6FiIhIrzFZJSKSWGhoKOrUqYOQkBCpQ6F80LFjR6SkpKBVq1ZSh0JERKTXuBswEZHE5HI5WrRoAZlMhr///hsGBvw9YmF1//59VKxYETExMbC2tkZERAScnZ2lDouIiEgvMVklItIDT548Qc2aNTFt2jR8++23UodDeSQpKQmenp7o378/Xrx4gfDwcPz9999Sh0VEOvL06VPY2trC1tZW6lCICgX++p5Ij927dw/+/v5YsmQJwsPDpQ6H8pCnpyd+/vlnzJw5E0FBQVKHQ3nE3NwcgwcPxuLFi5GamopDhw5JHRLlkYSEBEybNg2VK1fGJ598gs2bN0sdEuWhM2fOoGbNmujWrRt+/PFHqcMhKjSYrBLpqcWLF6NZs2Z49OgR9u/fj6pVq+LixYtSh0V5aPDgwejSpQv69++P5ORkqcOhPPDq1Svs3r0bXl5euH79OuRyudQhUR6Ij49Hs2bN8OTJE6xevRo+Pj4YMWIEfvnlF6lDo1xIT09Hu3btcPjwYaXyq1evwtvbG3PnzsX169excOFCiSIkKnyYrBZQGRkZuHTpEhYuXMhRmELoyJEj+OWXX3D16lWsW7cOu3fvRrFixTB79mypQ6M8tmbNGkRHR2PKlClSh0J5oHjx4rh37x52796NhIQETJo0SeqQKA8sXrwY5cqVw44dO9C8eXPY2NjAysqKv5wo4IyMjFCpUiVMmTIF76+iW7VqFXr37o1OnToBAIQQuHHjBu7evStVqESFBpPVAiI9PR0XLlzAggUL0LFjR9jZ2aFJkyaYPHkyli5dKnV4pGNbt27FuHHj4O7ujmPHjqFWrVro3bs3/vzzT6lDIx0QQmDNmjUoX748ihUrhiFDhiAhIQEA4ODggI0bN2L58uU4evSoxJGSLhw5cgT+/v74/fffkZaWBkNDQ9jb22PTpk1Ys2YNDhw4IHWIpGNnzpxBt27d8PbtW/Tp0wcLFizAiRMnMH78eKlDo1yaP38+Dh06hD179ijKypQpg4MHD+KPP/7AtGnT4O7ujmbNmqFKlSpYtWqVhNESFXzcYElPBAUF4dixY5g8ebJS+c8//4yDBw/i7NmzSE5OxieffIKWLVuiZcuWuH//PqZOnYqbN2+iVKlSEkVOeaFnz54oV64cUlNT8eeff2LTpk3w8vICAFy/fh2urq5wdHSUNkjSSnh4OIYMGYK4uDh8//33sLKywvDhw+Hi4oJDhw4pdgIeO3Ys/vzzT9y8eRP29vYSR03aSEhIwGeffYZHjx6hUqVKOHHiBCpUqIDDhw8rdgD+6quvsGPHDty8eRMlSpSQOGLSVkxMDFJTU1G8eHEAwBdffIG3b9/i/v376NGjB/z9/WFqagoA+PXXX9GsWTPUqFFDypApF+7cuYNatWph3bp1GDhwIJKTk/Hll1/iypUraNKkCQYOHIiGDRvCz88Pe/fuxbVr16QOmajgEqQXrl27JszMzMTRo0eVyjdv3iy+/vpr8ddff4nY2FhF+bNnz4SNjY1Ys2ZNfodKubB06VIxdepUpbLLly+LJUuWiPPnzyvKfvrpJwFA9OjRQ0RHRyvK5XK5aNeunfj777/zK2TKhaSkpCxlvXv3Fj/++KPIyMgQQghx6dIlUaFCBWFsbCzmz5+vqJeYmCgqV64sevbsmW/xkm59+eWXol27diI9PV0IIcTTp09FmTJlROPGjRXvf1JSkqhataro0qWLlKGSlqKjo8Xnn38unJ2dRefOnUVERIQQQog///xTABD+/v5K9Z8+fSrKli0rXr16JUW4pEM//vijsLa2Fk+ePMm2zqRJk0S/fv3yLyiiQojJqh5ZsGCBKFmypHj9+nWO9eRyuWjTpo1o27ZtPkVGurJ7925hYGCgSDa/+eYb4ezsLJo3by5kMplYvny5EEKIhIQE4enpKWrXri3Cw8OFEO+Sl+HDh4uOHTtKFj+p782bN8LNzU2cPHlSxMTEiIEDB4rNmzcLuVyuqLNixQrh4OAgdu3aJRYuXChMTEzEtWvXFOevXLki/vjjDynCJx1wdXUVmzdvViq7du2aMDAwEAEBAYqyoKAgUbJkSfH06dP8DpFyqVWrVqJv374iJSUly7muXbuKYsWKiZUrV4rHjx+LXbt2idKlS4uNGzfmf6CkcxkZGaJp06aiadOmil8+CfHuZ7T79++LUaNGiYoVKyr+Dyci7TBZ1SMZGRnCy8tLfP755znWW758ubC2thbPnj3Lp8got5KTk8WlS5eEEEL4+PgIDw8P8ccff4i6deuKmJgYIYQQW7ZsEYaGhuLMmTNCCCFu374tSpcuLUxNTUWjRo1E8eLFRdeuXUVCQoJk10E5W7VqlXj48KHi8ciRI4Wbm5soXbq0+PLLL0ViYqLi3F9//SXs7e3F3bt3hRBChIaGCgCiWrVqIjk5Od9jJ90rU6aMmDFjRpby9u3bi4EDByqVqUp2SL9duHBBmJiYKM1+eV9SUpIYPXq0sLCwEABE9erVxb59+/I3SMpTT548EdbW1mLu3LlCCCHS0tJEy5YtRd26dcWMGTPEmzdvJI6QqOBjsiqRu3fvCh8fH5Geni7S0tLEvHnzRHR0tAgJCRE2Njbit99+U9nu4cOHwtLSUqxbty6fIyZtXb9+XVSrVk0MHz5cCCFEbGys8PT0FBYWFmLDhg1KdX19fYWnp6diyndiYqL4448/xMqVK8Xly5fzPXZSn1wuF15eXqJhw4aK37LPnDlTABCtW7fOUr9Pnz5i9OjRisfXr18X7u7uwtPTU/z777/5Fjflna+//lo4ODiIqKgopfKhQ4dmSVap4Nm9e7cwMTFRGlVTJS0tTcTHx+dTVJTfNm3aJIyNjcWVK1ekDoWoUGKyKpHQ0FBha2srRo8eLT755BPRqVMnxRqWrVu3Cmtr6yxTwjKnnLRv316KkElDGRkZYuHChaJEiRJi69atSufOnDkjDA0NxaxZs5TK4+LiRNmyZcWgQYPyL1DSmWfPnomdO3cqRlrOnTsnDh06JIyNjcX27duV6s6cOVO4u7uLkJAQERISIj755BOxdOlSkZqaKkHklBcyp4I3adJEvHz5UgjxbiTGyclJ/PXXXxJHR5q6du2aCA4OVjx+9OiRACB27dqVpe6iRYs4qlaE9OzZU1SqVElp9gwR6QaTVQkNGjRIABCTJk3Kcq53796iWbNmSr+xTUhIEHXq1BGhoaH5GSZpISQkRHh5eQkA4sKFCyrrTJs2Tdja2mZ5P8+dOycMDQ25VrGACg4OFlZWVkoj4T/88IOwtbVVmrofFxcnmjVrJmQymTA3Nxdz5syRIlzKYzdu3BAeHh7C2tpaNG7cWFhbW4vFixdLHRZpIDw8XDRu3FhYWloKAwMDMWbMGMW5L774Ist640ePHony5ctzOn8R8vr1a7FgwQLFZmpEpDu8dY0EIiIiEB0djRUrVuDZs2e4d+8egoKCYGFhoagTHR2NGjVqYMyYMZgyZYqiPCUlRbH9Pemnbdu2YeLEiRg7dixWrVqF6tWr49ChQ1nqpaWloVGjRrC1tcWxY8cgk8kU53755RfUrFkTzZs3z8/QSUd69eqFGzdu4OrVqzA3N0dGRgaaN28OU1NTnDhxAjKZDImJiRBC4Pnz5yhevDhsbW2lDpvySGJiIg4dOoSYmBi0adMGHh4eUodEahBC4NWrV+jRowe6du2KSZMm4b///kPHjh0xa9YsfP3114iOjoaXlxfCwsIwZMgQyOVybNmyBT/99BP69Okj9SUQERV80ubKRVPFihXF7t27hRBCvH37Vnh4eIiRI0dmqXfixAlhamoqrl69mt8hkpaWLFkiqlatqtjR9dixY0q7/H7o7t27wtzcXCxZsiQ/w6Q89ubNG+Hq6iq+/PJLRdmjR4+EtbW1GDt2rNi3b58oX758ljXLRKQ/5syZI0qVKiVq1qypVL5582alnbsTEhLEokWLRI8ePcSoUaO4vwARkQ5xZFUCJUuWxIoVK+Dt7Q0AOH36NFq1aoX9+/ejU6dOSnUnTpyII0eO4MqVKzAzM5MgWtLE27dvYWZmpvReffXVV1izZg2uXr2KSpUqZWnz66+/YtKkSbh8+TKqVauWn+FSLiUmJmLSpEnYsWMHLC0t4evri+nTp8PY2BjHjx9Hu3btcODAAXTo0AEAcPz4cfj4+KB48eKYPXs2OnfuLPEVEFF2Xr16herVq6NEiRK4ceOG0rnPP/8cd+/exeXLl/l/MxFRHmKymg8uXboES0tLVKlSBQDg4uKC1atXo2vXroo6kydPxubNm3HhwgVkZGRg5MiRWL58OUqXLo1PPvkErVq1wk8//STVJVAuJCcn45NPPoGZmRnOnTsHY2PjLHVmzpyJ4cOHw83NTYIISRtCCHTt2hUWFhYYO3Ysbty4genTp6NZs2bYs2cPDAwMMGHCBOzYsQM3b95E8eLFpQ6ZiDR08OBBdOrUCYGBgUq/XHrz5g2qV6+Ozz//HMuWLZMuQCKiQs5A6gAKuxcvXuDrr79GtWrVUKtWLSxcuBApKSkwMFB+6X/88UdUq1YNVatWRcOGDdGpUydUqFABpqam2LZtG9asWYO7d+9KdBWUG2ZmZti6dStu3ryJ77//XmWd2bNnM1EtQJYsWYJPP/0UQUFB2L59O5o2bYovv/wShw4dwpEjR7By5UoAwLx581C8eHEMGzZM4oiJKCdBQUEYMmQIunTpgp07dyrKO3bsiFGjRmHYsGGIiopSlNvb22Pjxo0IDg5Genq6FCETERUJHFnNJyEhIQgICMCOHTtw/fp11KtXD8OGDcPnn3+u2FglPT0dly9fRqVKlbJsthISEoJSpUrlf+CkM/Pnz8d3332Hf/75B40bN5Y6HMqFs2fPokWLFqhUqRJu3bqldO7rr7/Gnj178OjRIwDAjRs3MGLECBw6dIibKBHpmbS0NMyePRtr167FiBEjYGxsjHnz5uG7777D1KlTAbyb7l+nTh1UqVIFf/75p8QRExEVLUxW88C///6LK1euoEKFCujQoYPSLq9paWkwMTFB37598e+//+Lly5fo3LkzBg4cqDQtmAofuVyOli1b4vnz57h79y6MjIykDolyYfr06fD398f169eV1hqfPXsWTZs2RXx8PCwtLSWMkIg+pmvXrpDJZFi3bh2KFy+ON2/eoFu3bvjvv/9w8uRJtGjRAgBw+fJlNG7cGKtXr4aPj4/EURMRFR2cBqxDiYmJ6NGjB3x8fHD+/HkMHDgQnTt3RlpamqKOXC4HAEyZMgUhISE4cuQISpQoASsrK6nCpnxiYGCA3377DevWrWOiWoBER0dj1apVWLRoEUJDQxXlfn5+qFOnDoYNG4akpCRFeWRkJOzs7JRuRUVE+uXAgQMAgFWrVmHfvn0oXrw4zpw5gxo1aqBhw4b44osvMGjQIMTGxgIAPvnkE8yePVvp3wAiIsp7HFnVoREjRuDNmzfYvn07jI2NsX//fnTr1g1btmxB//79AbzbbMfc3Bw3btxA9erVJY6YiHKya9cujBkzBrVr10ZqaiouX76Mw4cPK6ZxBwcHo06dOqhevTqmTZuGxMRETJw4EdOmTcOYMWMkjp6IVBk5ciSuXbuGo0ePwtraGgBw9epVtGrVCps2bYK3tzcuXbqE+vXrY8CAAfjtt98kjpiIqOhisqqFmzdvKhLN+Ph4mJmZQQgBa2trPHr0CC4uLli8eDEWLlyIJUuWoF+/foq2iYmJsLS0xM2bN3mbEiI95uPjgwsXLmDLli2oW7cuMjIy0KhRIzx79gw3btxAiRIlAAArV67El19+iUqVKqFixYoYNWoU2rVrJ3H0RPTmzRuMGDECPXv2RK9evbB3716Eh4dj3bp1+O+//2Bubq6o27t3bxQvXhy//PILAODWrVto3rw5YmNjcfbsWTRo0ECqyyAiKtI4DVhNv/32G7p27Yrnz5/jk08+wY4dO3Du3DnUqlULBw4cQFpaGpKTk/H48WO0bt0aBw4cwKVLlxSJ6oULFwC8u91Fq1at4O7uLuXlENFHfPHFF7hy5Qrq1q2LkJAQNG3aFPb29nBwcFDa3XfUqFHo2LEjTExMsHPnTiaqRHrg+PHjqFWrFjw8PBT3NN+wYQPGjh2LTp06KSWqAGBiYoLbt29DLpcjIyMDc+bMga+vL27evMlElYhISoI+auPGjaJs2bLi5s2bQgghZs+eLSwtLYWLi4vYt2+fol7NmjWFsbGxWLBggcjIyFCUR0REiAoVKoiMjAwhl8uFXC7P92sgIu08fPhQODs7ix9//FEIIcTWrVsFALF27VpFnYiICFG8eHExceJEqcIkIiFEcnKymDBhgvDw8BAnTpxQOhcZGSlKlCgh2rZtm6XdnTt3hJ2dnahSpYooXbq06Ny5s0hKSsqvsImIKBscWVXDtm3bMHjwYFSrVg1PnjzBzZs3YWhoiIoVK6JLly6Ket9//z3S0tKQkZGh2AH4xYsXaNeuHb755hsYGBhAJpMp7Q5MRNJ78OABOnfuDA8PD4wePVrp3NSpU+Ht7Y1p06YBAMqWLQsjIyNMmDABT548AQA4OTlh7dq1WLZsGU6dOpXv8RPRO9999x2WLVuGw4cPo1WrVoryixcvwtjYGOvXr8fRo0dx+PBhpXaVK1fG9evXMW7cOKxfvx6BgYEwMzPL7/CJiOgDTFbV0KxZM6xcuRJLlixBgwYNMHz4cAQFBeHKlStYsmSJol63bt3w448/Ytq0aahSpQrat2+PihUronfv3vD19ZXwCogoOxEREWjevDmaNGmChw8f4tdff1U6/+LFC6Wdfbdv346RI0di6dKlcHNzU5R369YNK1as4MZpRBKaOnUqnJ2dMXHiRABARkYGZs+eja5duyI4OBidO3fGiBEjMGTIELx+/Vqprbu7O0aMGKGU5BIRkbS4wZIaHj58iMqVK6NYsWK4ePEiypcvDwDYuHEjRo0ahYsXL6JGjRqK+rdu3cKRI0dgbGyMLl26wNPTU6rQiegjpk6diqtXr+LIkSMqz2/fvh2DBg3CiBEjEB4ejocPH+L06dOwt7fP50iJSB1HjhxBhw4dMHXqVJw6dQpWVlbYtGkTXFxcALzb6LB27dqoXr06/vjjD4mjJSKinDBZVcPIkSMBAOvXr8fGjRsVt6EBgB49euDhw4e4cOECzM3Nce3aNbi4uMDJyUmqcIlIA927d4ejoyPWrl2bbZ1du3Zh3759qF69OkaPHo1ixYrlY4REpKlx48bhl19+weTJkzFv3rwsy28uXbqExo0bY/Pmzejbt69EURIR0ccwWdWAn58fli1bhhs3bsDDwwMAEBUVhdq1a6Nq1aqoVKkSduzYgYCAALRs2VLiaIlIHVOmTMHOnTtx//59mJiYKJ1bu3at0s6/RFQwJCUloW7durCyssLZs2dhZGSUpc7evXvh5eUFW1vb/A+QiIjUwjWrKty/fx9z587FDz/8gHv37inKp0+fjkqVKmHgwIGQy+UAAEdHRxw/fhzW1tYwNDTEjRs3mKgSFSAjRoxAREQEpk+frlS+d+9enDx5UqKoiCg3zM3NsW3bNgQFBWH27Nkq63h7ezNRJSLSc0V2ZFUIoXJX3hUrVmDGjBn49NNPERwcjFu3buHXX3/F8OHDAbxbv1qrVi3MnDkTkydPzu+wiSgPbNiwAb6+vvj888/RrVs33Lx5E7/99huOHj2KqlWrSh0eEWlp3rx5mD59Os6cOYOGDRtKHQ4REWmoSCarDx48gLe3N44cOaK0m2dQUBCaNm2KK1euoFKlShBCYNasWfjxxx9x8uRJtGjRAgCwZs0ajB07FhcvXkTNmjWlugwi0qHjx49jyZIlCAsLQ506dTBt2jRUqFBB6rCIKBfkcjm8vLzw5s0b3Lx5k7eOIyIqYIpkspqRkYFmzZrBwsICx44dU/zn5e/vj7179+LChQtK9du1a4e3b98qlXt7e6Nly5YYP358vsZORERE6gsJCUFcXByqVasmdShERKShrDsOFAGGhobYsmULatWqhWXLlmHChAkAAAsLCzx+/BipqalKG61MmDABHTp0QExMDGxsbAAAf/75JwwMuOSXiIhIn5UqVUrqEIiISEtFNttydHTE+PHjMXXqVNy6dQvAu1tYxMTE4JdfflGq6+TkBJlMppScMlElIiIiIiLKO0Uu40pLS8P48eNRpkwZ7Ny5EykpKejXrx9SU1Ph4eGBadOm4dtvv8WOHTsAAOnp6Vi8eDG6desGKysriaMnIiIiIiIqGopcsjpjxgycPXsWjx8/xoMHD3D06FE8fvwY3333HQBg5syZGDVqFPr27Yty5crB3d0dUVFR2LBhg8SRExERERERFR1FboOlcuXKYcqUKRg2bJii7I8//kCvXr1w4sQJeHl5AQDu3r2LoKAglCtXDvXr15coWiIiIiIioqKpyCWrlStXRp8+fTBz5kyl8tq1a+PNmze4ceOGYhMlIiIiIiIikkahngZ86tQpLFiwANeuXVOUderUCatWrUJ8fLxS3Ro1aiAsLAyjR4/O5yiJiIiIiIjoQ4UyWZXL5RgwYACGDh2KwMBA1K1bFwEBAQCAb7/9FnK5HL1790ZycjIAIDo6Gv/88w9Wr16NIUOGSBk6ERERERERoRDeZ/XYsWMICQnBq1evcO/ePZiYmGDZsmXw8fFB9erVUbVqVQQGBqJjx46oXLkymjdvjpMnT6J3797w9fWVOnwiIiIiIiJCIVuzGhcXh7JlyyI+Ph5//vkn2rdvrzjn7e2Np0+f4uLFizAxMUFUVBQ2b96M8PBwtGvXDu3atZMwciIiIiIiInpfoUpWAWDfvn3w9vbGr7/+ii+//FJR/urVK1SvXh0DBw7EggULJIyQiIiIiIiIPqbAJ6uPHz9GSkoKKlWqBJlMBgDw9fXFoUOHcOvWLdjZ2SnqHjx4EF26dFG6RQ0RERERERHpnwK7wVJoaChatmyJOnXqoF69eqhZsyYeP34MAFi2bBksLCwwcuRIpTYdO3bE3LlzYW9vL0XIREREREREpCa9TlYTExMhl8uzlMfFxcHLywuffvopoqKiEBkZCQsLC3Tp0gXp6ekoVqwYtmzZgt27d2Pr1q1KbadMmYIaNWrk1yUQERERERGRFvQ6We3atavK9aVbt25F1apVMW3aNMjlcvj5+SE8PBzLli2DkdG7DY4bNmyI7777DmPGjMGzZ8/yO3QiIiIiIiLKBb2+dc20adPQsWNHtGvXDrVr11aUP3nyBG5ubrh9+zb69euH8uXL4/r167C3t0daWhqSk5NhZWWFGTNmQC6Xw8rKSsKrICIiIiIiIk3p/QZLkyZNwuHDh3H58mWYm5sDADZt2oQJEybA1NQUCxYswMCBAxX1165di7i4OEycOFGqkImIiIiIiCiX9D5ZTUlJQb169eDl5YWff/4ZABAfH48KFSqgevXqCAwMhImJCQAgKCgIXbp0wcWLF1GyZEkpwyYiIiIiIqJc0PtkFQBu3LiBBg0aYN++fWjbti0A4O+//0anTp1QpkwZ9O3bF+Hh4dixYwe2bt2KDh06SBwxERERERER5YZebrA0Y8YM/Pvvv4rHNWrUwA8//AAfHx+8efMGAODl5YUrV66gcePGOHXqFIyNjXHhwgUmqkRERERERIWA3o2sXr58GY0aNcK+ffvQsWNHRbkQAq1bt4aDgwN27dolYYRERERERESU1/QqWU1JSUHdunXRqFEjrF27Nsv50NBQ1KhRA8uWLcOgQYMkiJCIiIiIiIjyg15NA541axYSEhKwZMkSlefd3d3x66+/Yty4cXj69Gn+BkdERERERET5Rm9GVi9evIimTZvi6NGj8PLyyrFu3759ERoaitOnT8PAQK/ybSIiIiIiItIBvcj0UlJSMHjwYIwePVopUY2NjcVff/2FhQsX4v2cesWKFQgJCcH8+fMliJaIiIiIiIjyml4kqzNmzIBcLsd3332Ho0ePYurUqWjQoAHs7e3xxRdf4OjRo7h//76ivq2tLTZv3ozw8HAJoyYiIiIiIqK8Ivk04Js3b6J27dooXrw4Xr9+DVNTUzRp0gQtWrRAixYtUK9ePRgbG0sZIhEREREREeUzyZPVlJQUjBo1CpUqVUKLFi1Qt25dGBkZSRkSERERERERSUzyZJWIiIiIiIjoQ3qxZpWIiIiIiIjofUxWiYiIiIiISO8wWSUiIiIiIiK9w2SViIiIiIiI9A6TVSIiIiIiItI7TFaJiIiIiIhI7zBZJSIiIiIiIr3DZJWIiIiIiIj0DpNVIiIiIiIi0jtMVomIiIiIiEjvMFklIiICEBERgd9//z3XdYiIiEg3mKwSEZGknj9/jl27dkkdBq5du4a+ffsqHquK68M6RERElHeYrBIRkaSuXr2KAQMGSB0GXFxc0KtXL8VjVXF9WIeIiIjyjpHUARARUe4JIbBz5060atUKSUlJuHXrFkqUKIF69eqprBMbG4ubN2+iUqVKqFy5MgAgODgYd+7cgYODAxo1agRjY2NF27CwMFy8eBHe3t64efMmQkJCUKNGDZQuXRoZGRm4cOEC3rx5g3r16sHJySlLu27duina1a5dGx4eHgCA169f499//4VcLkdAQAAAoGLFiqhdu7bS9X2sn/fldB0AEBsbi0uXLkEul6Nu3bqwt7cHADg5OaFbt245xuXi4qKoo+5zZsbevXt33Lx5E8+ePUPVqlXh6en5sbeViIioSGOySkRUCGRkZKBPnz5o37497ty5gypVquDcuXNo27Ytdu7cCZlMpqjToUMHBAcHo3bt2hg4cCAqV66M4cOHY8eOHWjSpAkePHgAIyMjHDlyBKVLlwYAnD9/HoMGDUK1atVgYmICAwMDnD17FsuWLcNvv/0Gc3NzZGRk4ObNmzh+/LgiSc5sV69ePSQkJMDS0hLnz5/HypUr4ePjg+joaJw7dw4ZGRnYu3cvAKBjx45ZktWP9ZPpY9fx77//olu3bqhcuTJsbGxw7949LFiwAD179lRM8f3iiy+yjSsyMlJRR93nzIy9cePGSEhIQLFixXD69GmsWrVKKXYiIiL6gCAiogIvLS1NABA1a9YUcXFxQgghHj58KCwtLcX27duV6jRv3lwkJycr2v7xxx/C1NRU3Lp1SwghRHJysmjRooXo0qWLos6uXbsEALFy5UpF2dChQwUAsXHjRkVZr169RPfu3bO0mzhxoqJs5cqVolixYuLly5dCCCECAwOFqalpjtenTj/qXEfnzp3FuHHjFI/j4+PFkSNHhBBCHDp0SBgaGirOqYrrwzqavHbLly9XlC1atEiUKFEix2smIiIq6rhmlYioEBk1ahSKFSsGAChbtiw+++yzLLvXjhgxAqamporHAQEB6NatG6pWrQoAMDU1xTfffIPAwEAkJCQo6hkaGmLo0KGKx40aNYKZmRkGDhyoVHb//v0scU2ePFnx92HDhsHY2BgHDx7U+Ppy6ked6zA3N8eTJ08QFxcHALC0tETbtm01jiOTJq/d8OHDFY+9vLzw8uVLvH37VuvnJiIiKuyYrBIRFSKZU08zeXp6IiQkRKnMxcVF6XFISAjKlCmjVFa2bFkAwLNnzxRlxYoVU1qLaWpqChsbGxgYGCiVJScnK/VlZmamtI7V0NAQHh4eWeL6mI/1o851+Pv7Iy4uDk5OTmjZsiUWLlyolFRqKjevHYAsrxURERH9D5NVIqJCJDo6OstjR0dHpTKZTKb02NHREW/evFEqy3z8YVttJCcnIykp6aNx5bYfda6jbNmyOHXqFJ49e4bRo0dj+/bt6NKli0ZxvC+vXzsiIqKijMkqEVEhkrkZEACkpaUhMDAQTZo0ybFN06ZN8ddffyElJUVRtmvXLlSoUAHFixfXSVz79u1T/P3KlSsIDQ1F48aNAbwbdUxLS4NcLs9VP+pcR3h4OIB3iWTPnj0xbdo0XLhwQeVzqRNXfrx2RERERRV3AyYiKkROnDgBHx8fNGrUCAEBAUhLS8P48eNzbDN+/Hhs2rQJrVq1wsCBA3Hr1i2sXr1aKTHMDWNjY3z99dd49OgRLC0tsXDhQvTt2xe1atUCAFStWhUmJiaYMmUK6tatq/LWNer0o851DB8+HNbW1mjWrBmEEFi+fDl69uypMm5VcX0or187IiKioowjq0REhciWLVtQu3ZtXLx4EQ0bNsSFCxdga2sLADAwMECvXr1QokQJpTaWlpaKe5j+999/MDIywvnz59GhQwdFHXd3d3z22WdK7UqXLg1vb2+lsnLlyqFz585KZRYWFvjnn3+QmpqKa9eu4bvvvsPGjRsV54sXL47jx48jJSUF+/btw82bN1Ve28f6Uec6AgMD4e3tjdu3b+POnTuYPn061q9fD+DdWt5evXrlGNeHdbR97WxtbdGrVy+Ym5urvFYiIiICZEIIIXUQRESUO+np6TA2NsapU6fg5eUldTgKf/zxB3x9fXO9662u+iEiIqKCgyOrREREREREpHeYrBIRFQLZTfGVmqopsFL2Q0RERAUHpwETERERERGR3uHIKhEREREREekdJqtERERERESkd5isEhERERERkd5hskpERERERER6h8kqERERERER6R0mq0RERERERKR3mKwSERERERGR3mGySkRERERERHqHySoRERERERHpnf8DCdyAae3PEwIAAAAASUVORK5CYII=",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Near-zero threshold: 1.442e-08\n"
+ ]
+ }
+ ],
+ "source": [
+ "vjp_norms = np.stack(\n",
+ " [layer.output_projection.factor_norms.numpy() for layer in primary_result.layers]\n",
+ ")\n",
+ "near_zero_threshold = max(\n",
+ " float(vjp_norms.max()) * 1e-8, torch.finfo(torch.float32).tiny\n",
+ ")\n",
+ "near_zero_mask = vjp_norms <= near_zero_threshold\n",
+ "log_vjp_norms = np.log10(np.maximum(vjp_norms, near_zero_threshold))\n",
+ "masked_log_vjp_norms = np.ma.masked_where(near_zero_mask, log_vjp_norms)\n",
+ "cmap = plt.colormaps[\"magma\"].copy()\n",
+ "cmap.set_bad(color=\"#d1d5db\")\n",
+ "\n",
+ "fig, ax = plt.subplots(figsize=(10, 4.5))\n",
+ "image = ax.imshow(masked_log_vjp_norms, aspect=\"auto\", cmap=cmap)\n",
+ "ax.set_yticks(range(len(DETAILED_LAYERS)), labels=DETAILED_LAYERS)\n",
+ "ax.set_xticks(\n",
+ " range(len(position_tokens)), labels=position_tokens, rotation=35, ha=\"right\"\n",
+ ")\n",
+ "for layer_index, position_index in np.argwhere(near_zero_mask):\n",
+ " label = \"0\" if vjp_norms[layer_index, position_index] == 0 else \"≈0\"\n",
+ " ax.text(position_index, layer_index, label, ha=\"center\", va=\"center\")\n",
+ "ax.set(\n",
+ " xlabel=\"prompt position\",\n",
+ " ylabel=\"layer\",\n",
+ " title=\"FF2 VJP norms by layer and position (gray = zero/near-zero)\",\n",
+ ")\n",
+ "fig.colorbar(image, ax=ax, label=\"log10 L2 norm\")\n",
+ "fig.tight_layout()\n",
+ "plt.show()\n",
+ "print(f\"Near-zero threshold: {near_zero_threshold:.3e}\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cd704a4a",
+ "metadata": {},
+ "source": [
+ "## Beyond-paper diagnostic: contribution size and cumulative reconstruction\n",
+ "\n",
+ "For one middle-layer FF2 gradient, the Frobenius norm of position $i$'s outer product is $\\lVert x_i\\rVert_2\\lVert\\delta_i\\rVert_2$. The contribution bars retain prompt order. The cumulative curve adds positions from largest to smallest contribution norm and reports how much of the full reconstructed gradient remains."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "id": "22bdaffd",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-09-02T13:05:35.848878Z",
+ "iopub.status.busy": "2026-09-02T13:05:35.848671Z",
+ "iopub.status.idle": "2026-09-02T13:05:36.145144Z",
+ "shell.execute_reply": "2026-09-02T13:05:36.144305Z"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/png": "iVBORw0KGgoAAAANSUhEUgAABKYAAAGGCAYAAABBiol3AAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjExLjEsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvctoD+AAAAAlwSFlzAAAPYQAAD2EBqD+naQAAxhlJREFUeJzs3XdYFFcXBvB3doGl9yIo2BURBRQUFAv2hj1qoondaGLXxBq70STGFo0m9hgTjZrYxa6xKyhWVOwFpDcLq7Dz/UHYzxVQWBZG4P09zz7J3pm5c+bsys6enXtHEEVRBBERERERERERUSGTSR0AERERERERERGVTCxMERERERERERGRJFiYIiIiIiIiIiIiSbAwRUREREREREREkmBhioiIiIiIiIiIJMHCFBERERERERERSYKFKSIiIiIiIiIikgQLU0REREREREREJAkWpoiIiIiIiIiISBIsTBERFYItW7ZAEASEhoaq21auXAlBEHD79m1J4/iQfOjxEREVNkEQMHny5CLTL33Yfv/9dwiCgBs3bkgditqHGBPlrEePHqhUqZJGW6tWreDp6Sl5HIVpx44dcHd3h4GBAQRBwLNnz9CxY0e4urpKFlNRxsIU0TscPHgQgiBg+fLlUoeiMzdv3kTPnj1RqlQpmJqaomHDhti3b997t8vMRXaPNz8UcrtefHw8Fi5ciPr168PKygr29vYICAjA3r17C+S4dSXz5Onq1atSh5KjohAjEVFBe/XqFZYtW4bGjRvD2toahoaGqFChAtq0aYNNmzbh1atXUodYoFJTUyEIAqZNmyZ1KCWGFD84fchxlFRFpThRFOL8UGOMjIxEjx490LVrVzx79gyiKMLU1LRA9vWh5kDXWJgiKkFOnDgBb29v2Nra4syZM4iPj8ePP/6IhQsX5rqPZcuWQRRFjUd2Jz7vW+/rr7/GzJkz8emnn+Lu3bu4fPky6tSpgzZt2uQpnqKia9euEEWx0H9N+lDjyMmHHh8RFQ2xsbGoX78+pk6dih49euDKlStITk7Gvn374OXlhc8++wx///231GFKShRFzJo1S+owqJD16tULoiiWiC+6VDA2btz4QRQ9pYzj5MmTePnyJbp37w4DAwN1+7Zt23jln5b0pA6AiApHamoqPv74Y3Tq1AmLFi1St/v4+EhylVL16tUxdepUODs7q9u+++47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nJycpA6JiIiIiKhYqlGjBlxcXNCrVy/Y29ujadOmMDU1xfHjx1G1alWpwyOiN3COKSIiIiIiIiIikgSvmCIiIiIiIiIiIkmwMEVERERERERERJLQkzqAwqBSqRAREQEzMzMIgiB1OERERFQEiKKIlJQUODk5QSYrub/l8TyKiIiI8iov51ElojAVEREBZ2dnqcMgIiKiIujRo0coU6aM1GFIhudRREREpK3cnEeViMKUmZkZgIyEmJubSxxNwVCpVEhISICVlVWJ/lU3v5hH3WEudYe51B3mUjdKSh6Tk5Ph7OysPo8oqQr6PKqkvJ8+VMy/tJh/aTH/0mL+pVXQ+c/LeVSJKExlXnZubm5erAtTaWlpMDc35z/qfGAedYe51B3mUneYS90oaXks6cPXCvo8qqS9nz40zL+0mH9pMf/SYv6lVVj5z815FF99IiIiIiIiIiKSBAtTREREREREREQkCRamiIiIiIiIiIhIEixMERERERERERGRJErE5OdERERE9OER09OReCoUiXceQlbRBVb1PCHI5VKHRURERIWIhSkiIiIiKnQxO48hfOIiKCNiAACPACic7FD52xGwC2wkbXBERERUaDiUj4iIiIgKVczOY7jad7K6KJVJGRmDq30nI2bnMYkiIyIiosLGwhQRERERFRoxPR3hExcBYnYLM/4TPmkxxPT0Qo2LiIiIpMHCFBEREREVmsTTl7NcKaVBBJRPopF4+nLhBUVERESSYWGKiIiIiArNq6g4na5HRERERRsnPyciIipiOraMkHT/giDCwTEFUZFKiKIgaSzb9jlJun/KOwMHG52uR0REREUbr5giIiIiokJj6VcTCic74B01TZmhAUzcyhdeUERERCQZFqaIiIiIqNAIcjkqfzvivyfZr6NKfYULLQbj2dXbhRcYERERSYKFKSIiIiIqVHaBjeC+ZhYUjnYa7YrS9qg4bQgMXRzx8t4ThLQajKebgiSKkoiIiAoD55giIiIiokJnF9gItm38kXAqFPF3HsK6ogus6nlCkMvh2Ksdrn8+A/GHziLsi9lIOn8NlWcPg0xhIHXYREREpGO8YoqIiIiIJCHI5bCs7wXLdg1gWd8LglwOANC3MkfNjd+j3Nd9AUFAxJptuBg4DKlPoiWOmIiIiHSNhSkiIiIi+uAIMhnKj+uHmn9+Bz1LMySHXEdwk/5I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KY+xMEVEREREREREb5VGo0Hjxo2xbt06vfYSJUrg66+/xq+//orIyEilfciQIUhISEBcXFye5qS8x8IUEREREREREb11n3zyCfbt24f9+/frtXfp0gVOTk567W3atEFMTAycnZ3zOiblMRamiIiIiIiIiOit69atG9q3b49Bgwbhzp07etcqVqyI1NRUvTZTU9O8jEcqYWGKiIiIiIiIiPLE+vXrYW5ujtatW+PatWsAgIsXL+L8+fPo3LmzyulIDSxMEREREREREVGesLGxwZEjR2BlZYVatWqhfv368PLywqJFi1C/fn2145EKNCIiaocgIiIiIiIioqIlPDwc9+/fh6enJ2xsbNSOQyphYYqIiIiIiIiIiFTBpXxERERERERERKQKFqaIiIiIiIiIiEgVLEwREREREREREZEqWJgiIiIiIiIiIiJVsDBFRERERERERESqYGGKiIiIiIiIiIhUwcIUERERERERERGpgoUpIiIiIiIiIiJSBQtTRERERERERESkChamiIiIiIiIiIhIFSxMERERERERERGRKliYIiIiIiIiIiIiVbAwRUREREREREREqvg/hzNSLYSdScMAAAAASUVORK5CYII=",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "middle_layer = DETAILED_LAYERS[len(DETAILED_LAYERS) // 2]\n",
+ "factors = primary_result.layer(middle_layer).output_projection.factors\n",
+ "contribution_norms = (\n",
+ " factors.forward_inputs.norm(dim=-1) * factors.output_gradients.norm(dim=-1)\n",
+ ").numpy()\n",
+ "sorted_positions = np.argsort(-contribution_norms, kind=\"stable\")\n",
+ "running = torch.zeros_like(factors.reconstructed_gradient)\n",
+ "full_norm = factors.reconstructed_gradient.norm().clamp_min(\n",
+ " torch.finfo(torch.float32).eps\n",
+ ")\n",
+ "remaining_error = []\n",
+ "for position in sorted_positions:\n",
+ " x_row = factors.forward_inputs[position]\n",
+ " delta_row = factors.output_gradients[position]\n",
+ " running += torch.outer(x_row, delta_row)\n",
+ " remaining_error.append(\n",
+ " float((factors.reconstructed_gradient - running).norm() / full_norm)\n",
+ " )\n",
+ "sorted_labels = [\n",
+ " f\"{position}:{position_tokens[position]}\" for position in sorted_positions\n",
+ "]\n",
+ "\n",
+ "fig, axes = plt.subplots(1, 2, figsize=(12, 4))\n",
+ "axes[0].bar(range(len(position_tokens)), contribution_norms, color=\"#4f46e5\")\n",
+ "axes[0].set_xticks(\n",
+ " range(len(position_tokens)), labels=position_tokens, rotation=35, ha=\"right\"\n",
+ ")\n",
+ "axes[0].set(\n",
+ " ylabel=\"outer-product Frobenius norm\",\n",
+ " title=f\"Layer {middle_layer} FF2 contribution size\",\n",
+ ")\n",
+ "axes[1].plot(range(len(sorted_positions)), remaining_error, marker=\"o\", color=\"#be123c\")\n",
+ "axes[1].set_xticks(\n",
+ " range(len(sorted_positions)), labels=sorted_labels, rotation=35, ha=\"right\"\n",
+ ")\n",
+ "axes[1].set(\n",
+ " ylabel=\"relative error remaining\",\n",
+ " title=\"Cumulative reconstruction: largest contribution first\",\n",
+ ")\n",
+ "for ax in axes:\n",
+ " ax.grid(alpha=0.25)\n",
+ "fig.tight_layout()\n",
+ "plt.show()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "4f832556",
+ "metadata": {},
+ "source": [
+ "## Predeclared examples: report every outcome\n",
+ "\n",
+ "The remaining examples are analyzed only at GPT-2's final layer to keep the demo compact. The table reports one-decimal vocabulary rank percentiles so nearly tied logits remain stable across numeric backends. It also records whether unit normalization improves, worsens, or leaves unchanged the target's exact ascending raw-gradient rank. No example is removed based on its result."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "id": "5ba7e1da",
+ "metadata": {
+ "execution": {
+ "iopub.execute_input": "2026-09-02T13:05:36.147093Z",
+ "iopub.status.busy": "2026-09-02T13:05:36.146767Z",
+ "iopub.status.idle": "2026-09-02T13:05:36.888196Z",
+ "shell.execute_reply": "2026-09-02T13:05:36.887405Z"
+ }
+ },
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " prompt | \n",
+ " target | \n",
+ " raw target rank percentile | \n",
+ " normalized target rank percentile | \n",
+ " normalization outcome | \n",
+ " VJP norm | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | 0 | \n",
+ " The capital of France is | \n",
+ " Paris | \n",
+ " 0.0 | \n",
+ " 0.0 | \n",
+ " unchanged | \n",
+ " 0.260877 | \n",
+ "
\n",
+ " \n",
+ " | 1 | \n",
+ " The capital of Italy is | \n",
+ " Rome | \n",
+ " 0.0 | \n",
+ " 0.0 | \n",
+ " unchanged | \n",
+ " 0.262014 | \n",
+ "
\n",
+ " \n",
+ " | 2 | \n",
+ " The largest planet in the Solar System is | \n",
+ " Jupiter | \n",
+ " 0.0 | \n",
+ " 0.0 | \n",
+ " unchanged | \n",
+ " 0.280860 | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " prompt target \\\n",
+ "0 The capital of France is Paris \n",
+ "1 The capital of Italy is Rome \n",
+ "2 The largest planet in the Solar System is Jupiter \n",
+ "\n",
+ " raw target rank percentile normalized target rank percentile \\\n",
+ "0 0.0 0.0 \n",
+ "1 0.0 0.0 \n",
+ "2 0.0 0.0 \n",
+ "\n",
+ " normalization outcome VJP norm \n",
+ "0 unchanged 0.260877 \n",
+ "1 unchanged 0.262014 \n",
+ "2 unchanged 0.280860 "
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ },
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Normalization outcomes: {'unchanged': 3}\n"
+ ]
+ }
+ ],
+ "source": [
+ "comparison_rows = []\n",
+ "for example_index, (example_prompt, example_target) in enumerate(EXAMPLES):\n",
+ " if example_index == 0:\n",
+ " result = primary_result\n",
+ " else:\n",
+ " result = lens.analyze(\n",
+ " example_prompt,\n",
+ " example_target,\n",
+ " [DETAILED_LAYERS[-1]],\n",
+ " normalized=True,\n",
+ " )\n",
+ " summary = final_position_summary(result).iloc[-1]\n",
+ " raw_rank = int(summary[\"raw target rank\"])\n",
+ " normalized_rank = int(summary[\"normalized target rank\"])\n",
+ " vocab_size = result.layers[-1].output_projection.vocabulary_size\n",
+ " outcome = (\n",
+ " \"improved\"\n",
+ " if normalized_rank < raw_rank\n",
+ " else \"worsened\" if normalized_rank > raw_rank else \"unchanged\"\n",
+ " )\n",
+ " comparison_rows.append(\n",
+ " {\n",
+ " \"prompt\": example_prompt,\n",
+ " \"target\": example_target,\n",
+ " \"raw target rank percentile\": 100 * raw_rank / vocab_size,\n",
+ " \"normalized target rank percentile\": 100 * normalized_rank / vocab_size,\n",
+ " \"normalization outcome\": outcome,\n",
+ " \"VJP norm\": float(summary[\"final-position VJP norm\"]),\n",
+ " }\n",
+ " )\n",
+ " if example_index != 0:\n",
+ " del result\n",
+ " gc.collect()\n",
+ "\n",
+ "comparison = pd.DataFrame(comparison_rows)\n",
+ "display(\n",
+ " comparison.round(\n",
+ " {\n",
+ " \"raw target rank percentile\": 1,\n",
+ " \"normalized target rank percentile\": 1,\n",
+ " \"VJP norm\": 8,\n",
+ " }\n",
+ " )\n",
+ ")\n",
+ "print(\n",
+ " \"Normalization outcomes:\",\n",
+ " comparison[\"normalization outcome\"].value_counts().to_dict(),\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e3df0a77",
+ "metadata": {},
+ "source": [
+ "## Interpretation checklist\n",
+ "\n",
+ "- FF1 and FF2 tables project different factors; do not compare them as if they were the same signal.\n",
+ "- FF2 uses raw loss-gradient signs. SGD subtracts the gradient, so ascending ranks are highlighted.\n",
+ "- LayerNorm bias and epsilon make projection non-linear enough that negating projected logits is not an exact update readout.\n",
+ "- Normalized Logit Lens isolates direction from factor norm, but it need not improve target rank. The table above records null and contradictory outcomes.\n",
+ "- Small reconstruction error validates the factorization numerically; it does not validate a semantic interpretation.\n",
+ "- This fixed GPT-2 sample demonstrates tooling and diagnostics, not population-level evidence about language-model learning or memory.\n",
+ "\n",
+ "See the [Backward Lens reference documentation](../docs/source/content/backward_lens.md) and the [authors' research repository](https://github.com/shacharKZ/BackwardLens) for more context."
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "transformer-lens",
+ "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/docs/source/content/backward_lens.md b/docs/source/content/backward_lens.md
new file mode 100644
index 000000000..cc9e6fe6d
--- /dev/null
+++ b/docs/source/content/backward_lens.md
@@ -0,0 +1,194 @@
+# Backward Lens
+
+Backward Lens projects factors of MLP weight gradients into a language model's
+vocabulary space. It is useful for inspecting which token directions are associated
+with the forward inputs and backward signals that compose a gradient. A readable
+vocabulary projection is a diagnostic, not by itself evidence that a token or neuron
+causes a model behavior.
+
+TransformerLens currently provides a focused GPT-2 implementation through
+`TransformerBridge`. It follows the method introduced by
+[Katz et al. (2024)](https://aclanthology.org/2024.emnlp-main.142/).
+
+## Gradient factorization
+
+For one linear projection and one prompt, let $x_i \in \mathbb{R}^{d_{in}}$ be
+the input at token position $i$, and let
+$\delta_i = \partial L / \partial y_i \in \mathbb{R}^{d_{out}}$ be the loss
+gradient at its output. GPT-2 stores `Conv1D` weights in `[in, out]` order, so
+
+$$
+\nabla_W L = \sum_i x_i \delta_i^\mathsf{T} = X^\mathsf{T}\Delta.
+$$
+
+`BackwardLens` captures both factors and independently computes the weight gradient.
+Each matrix result includes the reconstructed gradient and maximum absolute and
+scale-aware relative reconstruction errors.
+
+### The two GPT-2 MLP matrices
+
+The two projections expose different residual-width factors:
+
+| Result | Weight shape | Projected factor | Shape before vocabulary projection |
+|---|---:|---|---:|
+| `input_projection` (FF1 / `c_fc`) | `[d_model, d_mlp]` | Forward input $x_i$ | `[position, d_model]` |
+| `output_projection` (FF2 / `c_proj`) | `[d_mlp, d_model]` | Backward signal $\delta_i$ | `[position, d_model]` |
+
+The FF1 readout therefore describes the layer-normalized residual state entering the
+MLP (post-`ln_2`, including its gain and bias).
+The FF2 readout describes raw loss gradients at the MLP output. These are different
+quantities and should not be interpreted interchangeably.
+
+## Vocabulary projection
+
+For each residual-width row $v$, the lens computes a fresh readout
+
+$$
+P(v) = \operatorname{Unembed}(\operatorname{LN}_{final}(v)).
+$$
+
+Final-normalization statistics are recomputed independently for every factor. The
+implementation does not reuse normalization scales cached during the model's forward
+pass. The retained rankings contain signed, pre-softmax values; they do not contain
+probabilities. By default, each matrix keeps only the 10 largest and 10 smallest
+values and token ids per position. Set `top_k` to change that bound or
+`return_full_logits=True` to also retain the full vocabulary tensors.
+
+When `normalized=True`, the analysis also computes the Normalized Logit Lens:
+
+$$
+P_{norm}(v) = P\left(\frac{v}{\lVert v\rVert_2}\right).
+$$
+
+Exact-zero rows remain zero before projection and are identified by `zero_norm_mask`.
+The original float32 norms are retained in `factor_norms`. Normalization is most useful
+when comparing directions whose norms differ greatly, especially very small backward
+signals. Because final LayerNorm has an epsilon and may have a bias, raw and normalized
+projections need not be identical.
+
+## Sign convention
+
+All backward signals and weight gradients preserve the raw `d(loss) / d(tensor)`
+sign. Gradient descent subtracts them:
+
+$$
+W_{new} = W - \eta \nabla_W L.
+$$
+
+For FF2 backward signals, `bottom(...)` and
+`gradient_descent_target_ranks(...)` inspect the smallest raw-gradient logits, which
+are often the most relevant ordering for the subtracted update. Do not simply negate
+projected logits: final LayerNorm bias and epsilon mean that projection is not exactly
+sign-symmetric.
+
+## Minimal example
+
+```python
+import torch
+
+from transformer_lens.model_bridge import TransformerBridge
+from transformer_lens.tools.analysis import BackwardLens
+
+model = TransformerBridge.boot_transformers(
+ "openai-community/gpt2",
+ device="cuda" if torch.cuda.is_available() else "cpu",
+ dtype=torch.float32,
+)
+
+result = BackwardLens(model).analyze(
+ prompt="The capital of France is",
+ target_token=" Paris",
+ layers=[0, 6, 11],
+ normalized=True,
+ top_k=10,
+)
+
+last_layer = result.layer(11)
+ff1 = last_layer.input_projection
+ff2 = last_layer.output_projection
+
+ff1_tokens = ff1.top_tokens(model.tokenizer, k=5)
+ff2_update_tokens = ff2.bottom_tokens(model.tokenizer, k=5)
+target_ranks = ff2.gradient_descent_target_ranks(
+ result.target_token_id,
+ normalized=True,
+)
+```
+
+`target_token` must encode to exactly one token without a beginning-of-sequence token.
+For GPT-2 tokenization, a leading space is often significant. The prompt is tokenized
+according to the model and tokenizer configuration, so it includes a prepended BOS
+only when that configuration requests one. Treat `result.prompt_token_ids` as the
+source of truth for aligning all position-indexed factors and readouts.
+
+## Result structure
+
+`BackwardLens.analyze(...)` returns a detached `BackwardLensResult`:
+
+- `prompt`, `prompt_token_ids`, `target_token`, and `target_token_id` record the inputs.
+- `loss` is final-position cross-entropy against the one-token target.
+- `layers` preserves the requested layer order; `result.layer(index)` retrieves one.
+- Each layer has `input_projection` and `output_projection` matrix results.
+- Each matrix exposes `factors`, `factor_norms`, `zero_norm_mask`, `vocabulary_size`,
+ and retained raw `top_ranking` and `bottom_ranking` values and token ids.
+- `top(...)` and `bottom(...)` return prefixes of the retained signed rankings, so
+ their `k` cannot exceed the `top_k` passed to `analyze(...)`.
+- `top_tokens(...)` and `bottom_tokens(...)` decode ids with a caller-provided
+ tokenizer. Results deliberately retain no model or tokenizer reference.
+- The analyzed target's exact ranks are always retained as zero-based competition
+ ranks, so tied logits receive the same rank. Ranking another token requires full
+ logits.
+- `vocabulary_logits` is present only with `return_full_logits=True`.
+ `normalized_top_ranking`, `normalized_bottom_ranking`, and normalized target ranks
+ are present with `normalized=True`; full `normalized_vocabulary_logits` requires
+ both options.
+- `includes_normalized_logits` and `includes_full_logits` record the requested modes.
+- Maximum reconstruction errors summarize both MLP matrices over all requested layers.
+
+Returned tensors are detached, owned CPU copies. Factors, reconstructed gradients,
+norms, retained values, and optional vocabulary logits use float32; token ids and
+ranks use int64. The bounded default avoids retaining a
+`[layer, matrix, position, d_vocab]` collection of full tensors.
+
+## Requirements and non-goals
+
+The current implementation requires:
+
+- A freshly booted, raw `TransformerBridge` using `GPT2ArchitectureAdapter`.
+- Original, trainable GPT-2 `Conv1D` weights and a dense, non-gated MLP.
+- Compatibility mode and weight processing to remain disabled.
+- One non-empty prompt, one single-token target, and unique valid layer indices.
+
+It does not currently support batched prompts, multi-token target losses, gated MLPs,
+other architecture families, compatibility-mode weights, model editing, or causal
+claims about the displayed vocabulary rankings.
+
+## Model-state safety
+
+An analysis uses one gradient-enabled forward pass and one `torch.autograd.grad` call.
+It does not call `backward()` or modify parameter `.grad` buffers. It preserves model
+weights, `requires_grad` flags, train/eval state, existing hooks, and CPU/CUDA/MPS RNG
+state, and it removes only its own temporary hooks on success or failure. Existing
+activation-editing hooks still affect the analyzed computation.
+
+## Troubleshooting
+
+| Symptom | Cause and resolution |
+|---|---|
+| Raw-Bridge or processed-weight error | Reboot with `TransformerBridge.boot_transformers(...)`; do not enable compatibility mode or process weights. |
+| Target encodes to zero or multiple tokens | Choose text that maps to one GPT-2 token without BOS; check leading whitespace. |
+| Duplicate or out-of-range layer error | Pass a non-empty sequence of unique indices in `[0, model.cfg.n_layers)`. |
+| Normalized logits were not requested | Call `analyze(..., normalized=True)` before using `logits(normalized=True)` or normalized ranks. |
+| Full logits were not retained | Call `analyze(..., return_full_logits=True)` before using `logits(...)` or ranking a token other than the analyzed target. |
+| Requested `k` exceeds retained `top_k` | Increase `top_k` in `analyze(...)`; accessor methods cannot recover discarded rankings. |
+| FF2 ranking appears sign-reversed | Remember that results are raw loss gradients and gradient descent subtracts them; inspect bottom tokens or ascending target ranks. |
+| Results change when custom hooks are installed | Existing hooks are intentionally respected; remove them to analyze the unmodified model computation. |
+
+## References
+
+- [TransformerLens Backward Lens demonstration](https://github.com/TransformerLensOrg/TransformerLens/blob/dev/demos/Backward_Lens_Demo.ipynb).
+- Shahar Katz, Yonatan Belinkov, Mor Geva, and Lior Wolf. 2024.
+ [Backward Lens: Projecting Language Model Gradients into the Vocabulary Space](https://aclanthology.org/2024.emnlp-main.142/).
+ *Proceedings of EMNLP 2024*, pages 2390–2422.
+- [Authors' research demonstration](https://github.com/shacharKZ/BackwardLens).
+ TransformerLens does not import, vendor, or depend on that repository's code.
\ No newline at end of file
diff --git a/docs/source/index.md b/docs/source/index.md
index 1feea3122..565bb91cf 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
+content/backward_lens
content/debugging_numerical_divergence
generated/demos/Main_Demo
generated/demos/Exploratory_Analysis_Demo
diff --git a/makefile b/makefile
index d9655e7d0..cd791941c 100644
--- a/makefile
+++ b/makefile
@@ -45,6 +45,7 @@ docstring-test:
notebook-test:
$(RUN) pytest --nbval-sanitize-with demos/doc_sanitize.cfg demos/BERT.ipynb $(RERUN_ARGS)
+ $(RUN) pytest --nbval-sanitize-with demos/doc_sanitize.cfg demos/Backward_Lens_Demo.ipynb $(RERUN_ARGS)
$(RUN) pytest --nbval-sanitize-with demos/doc_sanitize.cfg demos/Bridge_Evals_Demo.ipynb $(RERUN_ARGS)
$(RUN) pytest --nbval-sanitize-with demos/doc_sanitize.cfg demos/Exploratory_Analysis_Demo.ipynb $(RERUN_ARGS)
$(RUN) pytest --nbval-sanitize-with demos/doc_sanitize.cfg demos/Main_Demo.ipynb $(RERUN_ARGS)
diff --git a/tests/integration/test_backward_lens.py b/tests/integration/test_backward_lens.py
new file mode 100644
index 000000000..918fe9d26
--- /dev/null
+++ b/tests/integration/test_backward_lens.py
@@ -0,0 +1,698 @@
+"""Integration tests for Backward Lens capture on a raw GPT-2 Bridge."""
+
+import warnings
+from collections.abc import Sequence
+from typing import Any, cast
+
+import pytest
+import torch
+import torch.nn.functional as F
+from beartype.roar import BeartypeCallHintParamViolation
+
+PROMPT = "The capital of France is"
+TARGET = " Paris"
+LAYERS = (0, 11)
+OVERLONG_PROMPT = " token" * 1024
+
+DEVICE_DTYPE_CASES = [pytest.param("cpu", torch.bfloat16, id="cpu-bfloat16")]
+if torch.cuda.is_available():
+ DEVICE_DTYPE_CASES.append(pytest.param("cuda", torch.float16, id="cuda-float16"))
+if torch.backends.mps.is_available():
+ DEVICE_DTYPE_CASES.append(pytest.param("mps", torch.float32, id="mps-float32"))
+
+
+@pytest.fixture(scope="module")
+def gpt2_bridge():
+ from transformer_lens.model_bridge import TransformerBridge
+
+ return TransformerBridge.boot_transformers("gpt2", device="cpu", dtype=torch.float32)
+
+
+@pytest.fixture(scope="module")
+def gradient_capture(gpt2_bridge):
+ from transformer_lens.tools.analysis.backward_lens import (
+ _capture_gpt2_mlp_gradient_factors,
+ )
+
+ return _capture_gpt2_mlp_gradient_factors(gpt2_bridge, PROMPT, TARGET, LAYERS)
+
+
+@pytest.fixture(scope="module")
+def backward_result(gpt2_bridge):
+ from transformer_lens.tools.analysis import BackwardLens
+
+ return BackwardLens(gpt2_bridge).analyze(
+ PROMPT,
+ TARGET,
+ LAYERS,
+ normalized=True,
+ top_k=3,
+ return_full_logits=True,
+ )
+
+
+def _projection_hook_snapshots(model, layer: int) -> list[tuple[int, ...]]:
+ mlp = model.blocks[layer].mlp
+ projections = (getattr(mlp, "in"), mlp.out)
+ return [
+ tuple(hook_point._forward_hooks)
+ for projection in projections
+ for hook_point in (projection.hook_in, projection.hook_out)
+ ]
+
+
+def test_real_gpt2_factors_reconstruct_both_mlp_weight_gradients(
+ gradient_capture, gpt2_bridge
+) -> None:
+ assert gradient_capture.target_token_id == 6342
+ assert gradient_capture.loss > 0
+ assert gradient_capture.prompt_token_ids.shape == (1, 6)
+ assert gradient_capture.prompt_token_ids.device.type == "cpu"
+ expected_tokens = gpt2_bridge.to_tokens(PROMPT)
+ assert torch.equal(gradient_capture.prompt_token_ids, expected_tokens)
+ assert gpt2_bridge.tokenizer is not None
+ assert gradient_capture.prompt_token_ids[0, 0].item() == gpt2_bridge.tokenizer.bos_token_id
+ with torch.no_grad():
+ logits = gpt2_bridge(expected_tokens)
+ expected_loss = F.cross_entropy(
+ logits[:, -1, :], torch.tensor([gradient_capture.target_token_id])
+ )
+ assert gradient_capture.loss == pytest.approx(float(expected_loss), abs=1e-6, rel=1e-6)
+ assert [result.layer for result in gradient_capture.layers] == list(LAYERS)
+
+ for result in gradient_capture.layers:
+ first = result.input_projection
+ second = result.output_projection
+ assert first.forward_inputs.shape == (6, 768)
+ assert first.output_gradients.shape == (6, 3072)
+ assert first.weight_gradient.shape == (768, 3072)
+ assert second.forward_inputs.shape == (6, 3072)
+ assert second.output_gradients.shape == (6, 768)
+ assert second.weight_gradient.shape == (3072, 768)
+ for factors in (first, second):
+ assert factors.weight_layout == "in_out"
+ assert factors.reconstructed_gradient.shape == factors.weight_gradient.shape
+ for tensor in (
+ factors.forward_inputs,
+ factors.output_gradients,
+ factors.weight_gradient,
+ factors.reconstructed_gradient,
+ ):
+ assert tensor.dtype == torch.float32
+ assert tensor.device.type == "cpu"
+ assert tensor.grad_fn is None
+ assert torch.isfinite(tensor).all()
+ torch.testing.assert_close(
+ factors.reconstructed_gradient,
+ factors.weight_gradient,
+ atol=2e-6,
+ rtol=2e-5,
+ )
+ assert factors.absolute_reconstruction_error <= 2e-6
+ assert factors.relative_reconstruction_error <= 2e-5
+
+
+def test_gradient_descent_weight_update_increases_target_logit(
+ gradient_capture, gpt2_bridge
+) -> None:
+ layer_result = gradient_capture.layers[-1]
+ weight = gpt2_bridge.blocks[layer_result.layer].mlp.out.original_component.weight
+ original_weight = weight.detach().clone()
+ weight_gradient = layer_result.output_projection.weight_gradient.to(
+ device=weight.device, dtype=weight.dtype
+ )
+ updated_weight = original_weight - 1e-4 * weight_gradient
+ prompt_token_ids = gradient_capture.prompt_token_ids.to(weight.device)
+
+ with torch.no_grad():
+ baseline_output = gpt2_bridge.original_model(prompt_token_ids)
+ weight.copy_(updated_weight)
+ try:
+ updated_output = gpt2_bridge.original_model(prompt_token_ids)
+ finally:
+ weight.copy_(original_weight)
+
+ baseline_target_logit = baseline_output.logits[0, -1, gradient_capture.target_token_id]
+ updated_target_logit = updated_output.logits[0, -1, gradient_capture.target_token_id]
+ assert float(updated_target_logit - baseline_target_logit) > 1e-4
+ torch.testing.assert_close(weight, original_weight, rtol=0, atol=0)
+
+
+@pytest.mark.parametrize("projection", ["input_projection", "output_projection"])
+def test_final_layer_has_the_expected_rank_one_position_structure(
+ gradient_capture, projection: str
+) -> None:
+ last_layer = gradient_capture.layers[-1]
+ factors = getattr(last_layer, projection)
+ row_norms = factors.output_gradients.norm(dim=-1)
+ relative_earlier_norm = row_norms[:-1].max() / row_norms[-1].clamp_min(
+ torch.finfo(row_norms.dtype).eps
+ )
+
+ assert relative_earlier_norm <= 1e-6
+ assert int(torch.linalg.matrix_rank(factors.output_gradients)) == 1
+
+
+def test_public_result_metadata_and_error_summaries(backward_result) -> None:
+ from transformer_lens.tools.analysis import BackwardLensResult
+
+ assert isinstance(backward_result, BackwardLensResult)
+ assert backward_result.prompt == PROMPT
+ assert backward_result.target_token == TARGET
+ assert backward_result.target_token_id == 6342
+ assert backward_result.prompt_token_ids.shape == (6,)
+ assert [layer.layer for layer in backward_result.layers] == list(LAYERS)
+ assert backward_result.includes_normalized_logits is True
+ assert backward_result.includes_full_logits is True
+ assert backward_result.max_absolute_reconstruction_error <= 2e-6
+ assert backward_result.max_relative_reconstruction_error <= 2e-5
+ assert backward_result.layer(11) is backward_result.layers[-1]
+ assert not hasattr(backward_result, "model")
+ with pytest.raises(KeyError, match="was not analyzed"):
+ backward_result.layer(5)
+
+
+def test_public_projections_match_fresh_model_readout(backward_result, gpt2_bridge) -> None:
+ unembed_weight = gpt2_bridge.W_U
+ for layer in backward_result.layers:
+ matrices = (
+ (layer.input_projection, layer.input_projection.factors.forward_inputs),
+ (layer.output_projection, layer.output_projection.factors.output_gradients),
+ )
+ for matrix, rows in matrices:
+ rows_on_model = rows.to(
+ device=unembed_weight.device, dtype=unembed_weight.dtype
+ ).unsqueeze(0)
+ with torch.no_grad():
+ direct = gpt2_bridge.unembed(gpt2_bridge.ln_final(rows_on_model)).squeeze(0)
+ assert matrix.vocabulary_logits is not None
+ torch.testing.assert_close(matrix.vocabulary_logits, direct.float().cpu())
+
+ norms = rows.norm(dim=-1)
+ zero_mask = norms == 0
+ normalized_rows = rows / torch.where(
+ zero_mask, torch.ones_like(norms), norms
+ ).unsqueeze(-1)
+ with torch.no_grad():
+ direct_normalized = gpt2_bridge.unembed(
+ gpt2_bridge.ln_final(
+ normalized_rows.to(
+ device=unembed_weight.device,
+ dtype=unembed_weight.dtype,
+ ).unsqueeze(0)
+ )
+ ).squeeze(0)
+ assert matrix.normalized_vocabulary_logits is not None
+ torch.testing.assert_close(
+ matrix.normalized_vocabulary_logits,
+ direct_normalized.float().cpu(),
+ )
+ torch.testing.assert_close(matrix.factor_norms, norms)
+ assert torch.equal(matrix.zero_norm_mask, zero_mask)
+ for logits in (matrix.vocabulary_logits, matrix.normalized_vocabulary_logits):
+ assert logits.shape == (6, gpt2_bridge.cfg.d_vocab)
+ assert logits.dtype == torch.float32
+ assert logits.device.type == "cpu"
+ assert logits.grad_fn is None
+ assert torch.isfinite(logits).all()
+
+
+def test_public_rankings_decoding_and_target_ranks(backward_result, gpt2_bridge) -> None:
+ output = backward_result.layer(11).output_projection
+ assert output.vocabulary_logits is not None
+ assert output.top_ranking.indices.shape == (6, 3)
+ assert output.bottom_ranking.indices.shape == (6, 3)
+ direct_top = torch.topk(output.vocabulary_logits, k=3, dim=-1, largest=True)
+ direct_bottom = torch.topk(output.vocabulary_logits, k=3, dim=-1, largest=False)
+
+ assert torch.equal(output.top(k=3).indices, direct_top.indices)
+ assert torch.equal(output.bottom(k=3).indices, direct_bottom.indices)
+ assert output.top_tokens(gpt2_bridge.tokenizer, k=3)[0] == [
+ gpt2_bridge.tokenizer.decode([token_id]) for token_id in direct_top.indices[0].tolist()
+ ]
+ assert output.bottom_tokens(gpt2_bridge.tokenizer, k=3)[0] == [
+ gpt2_bridge.tokenizer.decode([token_id]) for token_id in direct_bottom.indices[0].tolist()
+ ]
+ target_ranks = output.gradient_descent_target_ranks(backward_result.target_token_id)
+ normalized_target_ranks = output.gradient_descent_target_ranks(
+ backward_result.target_token_id, normalized=True
+ )
+ assert target_ranks.shape == (6,)
+ assert normalized_target_ranks.shape == (6,)
+ assert target_ranks.dtype == torch.int64
+
+
+def test_public_api_defaults_to_raw_projection_only(gpt2_bridge) -> None:
+ from transformer_lens.tools.analysis import BackwardLens
+
+ result = BackwardLens(gpt2_bridge).analyze(PROMPT, TARGET, [0])
+ assert result.includes_normalized_logits is False
+ assert result.includes_full_logits is False
+ for matrix in (
+ result.layers[0].input_projection,
+ result.layers[0].output_projection,
+ ):
+ assert matrix.vocabulary_logits is None
+ assert matrix.normalized_vocabulary_logits is None
+ assert matrix.top_ranking.indices.shape == (6, 10)
+ assert matrix.bottom_ranking.indices.shape == (6, 10)
+ assert matrix.normalized_top_ranking is None
+ assert matrix.normalized_bottom_ranking is None
+ assert matrix.gradient_descent_target_ranks(result.target_token_id).shape == (6,)
+ with pytest.raises(ValueError, match="return_full_logits=True"):
+ matrix.logits()
+ with pytest.raises(ValueError, match="were not requested"):
+ matrix.logits(normalized=True)
+ with pytest.raises((TypeError, BeartypeCallHintParamViolation), match="normalized"):
+ BackwardLens(gpt2_bridge).analyze(PROMPT, TARGET, [0], normalized=cast(bool, 1))
+
+
+def test_public_api_validates_retention_options_before_capture(gpt2_bridge) -> None:
+ from transformer_lens.tools.analysis import BackwardLens
+
+ lens = BackwardLens(gpt2_bridge)
+ with pytest.raises(ValueError, match="top_k must be in"):
+ lens.analyze(PROMPT, TARGET, [0], top_k=0)
+ with pytest.raises(ValueError, match="top_k must be in"):
+ lens.analyze(PROMPT, TARGET, [0], top_k=gpt2_bridge.cfg.d_vocab + 1)
+ with pytest.raises(TypeError, match="top_k must be an integer"):
+ lens.analyze(PROMPT, TARGET, [0], top_k=True)
+ with pytest.raises((TypeError, BeartypeCallHintParamViolation), match="top_k"):
+ lens.analyze(PROMPT, TARGET, [0], top_k=cast(int, 1.5))
+ with pytest.raises((TypeError, BeartypeCallHintParamViolation), match="return_full_logits"):
+ lens.analyze(PROMPT, TARGET, [0], return_full_logits=cast(bool, 1))
+
+
+@pytest.mark.parametrize(
+ ("prompt", "target", "layers", "error", "match"),
+ [
+ ("", TARGET, [0], ValueError, "prompt must not be empty"),
+ (PROMPT, "", [0], ValueError, "exactly one token"),
+ (PROMPT, " New York", [0], ValueError, "got 2 tokens"),
+ (PROMPT, TARGET, [], ValueError, "at least one"),
+ (PROMPT, TARGET, [0, 0], ValueError, "duplicate"),
+ (PROMPT, TARGET, [-1], ValueError, "must be in"),
+ (PROMPT, TARGET, [12], ValueError, "must be in"),
+ (PROMPT, TARGET, [True], TypeError, "layer"),
+ pytest.param(
+ OVERLONG_PROMPT,
+ TARGET,
+ [0],
+ ValueError,
+ r"token count 1025.*n_ctx=1024",
+ id="over-n-ctx",
+ ),
+ ],
+)
+def test_capture_rejects_invalid_analysis_inputs(
+ gpt2_bridge,
+ prompt: str,
+ target: str,
+ layers: Sequence[int],
+ error: type[Exception],
+ match: str,
+) -> None:
+ from transformer_lens.tools.analysis.backward_lens import (
+ _capture_gpt2_mlp_gradient_factors,
+ )
+
+ with pytest.raises(error, match=match):
+ _capture_gpt2_mlp_gradient_factors(gpt2_bridge, prompt, target, layers)
+
+
+def test_capture_rejects_non_bridge_and_non_raw_states(gpt2_bridge, monkeypatch) -> None:
+ from transformer_lens.tools.analysis.backward_lens import (
+ _capture_gpt2_mlp_gradient_factors,
+ )
+
+ with pytest.raises(TypeError, match="TransformerBridge only"):
+ _capture_gpt2_mlp_gradient_factors(object(), PROMPT, TARGET, [0])
+ monkeypatch.setattr(gpt2_bridge, "compatibility_mode", True)
+ with pytest.raises(ValueError, match="compatibility mode"):
+ _capture_gpt2_mlp_gradient_factors(gpt2_bridge, PROMPT, TARGET, [0])
+ monkeypatch.setattr(gpt2_bridge, "compatibility_mode", False)
+ monkeypatch.setattr(gpt2_bridge, "_weights_processed", True)
+ with pytest.raises(ValueError, match="processed"):
+ _capture_gpt2_mlp_gradient_factors(gpt2_bridge, PROMPT, TARGET, [0])
+ monkeypatch.setattr(gpt2_bridge, "_weights_processed", False)
+ adapter = gpt2_bridge.adapter
+ monkeypatch.setattr(gpt2_bridge, "adapter", object())
+ with pytest.raises(NotImplementedError, match="GPT2ArchitectureAdapter"):
+ _capture_gpt2_mlp_gradient_factors(gpt2_bridge, PROMPT, TARGET, [0])
+ monkeypatch.setattr(gpt2_bridge, "adapter", adapter)
+ monkeypatch.setattr(gpt2_bridge.cfg, "gated_mlp", True)
+ with pytest.raises(NotImplementedError, match="non-gated"):
+ _capture_gpt2_mlp_gradient_factors(gpt2_bridge, PROMPT, TARGET, [0])
+ monkeypatch.setattr(gpt2_bridge.cfg, "gated_mlp", False)
+ monkeypatch.setattr(gpt2_bridge, "tokenizer", None)
+ with pytest.raises(ValueError, match="tokenizer"):
+ _capture_gpt2_mlp_gradient_factors(gpt2_bridge, PROMPT, TARGET, [0])
+
+
+def test_capture_rejects_inference_mode(gpt2_bridge) -> None:
+ from transformer_lens.tools.analysis.backward_lens import (
+ _capture_gpt2_mlp_gradient_factors,
+ )
+
+ with torch.inference_mode():
+ with pytest.raises(ValueError, match="inference_mode"):
+ _capture_gpt2_mlp_gradient_factors(gpt2_bridge, PROMPT, TARGET, [0])
+
+
+def test_capture_rejects_multi_device_before_projection_validation(
+ gpt2_bridge, monkeypatch
+) -> None:
+ from transformer_lens.tools.analysis import backward_lens
+
+ def projection_validation_must_not_run(*_args, **_kwargs) -> None:
+ raise AssertionError("projection validation ran for a multi-device Bridge")
+
+ monkeypatch.setattr(gpt2_bridge.cfg, "n_devices", 2)
+ monkeypatch.setattr(
+ backward_lens,
+ "_get_gpt2_mlp_projections",
+ projection_validation_must_not_run,
+ )
+ with pytest.raises(ValueError, match=r"single-device.*co-located.*n_devices=2"):
+ backward_lens._capture_gpt2_mlp_gradient_factors(gpt2_bridge, PROMPT, TARGET, [0])
+
+
+def test_capture_rejects_a_per_layer_gate(gpt2_bridge, monkeypatch) -> None:
+ from transformer_lens.tools.analysis.backward_lens import _get_gpt2_mlp_projections
+
+ mlp = gpt2_bridge.blocks[0].mlp
+ monkeypatch.setattr(mlp, "gate", torch.nn.Identity(), raising=False)
+ with pytest.raises(ValueError, match="dense, non-gated MLPBridge"):
+ _get_gpt2_mlp_projections(gpt2_bridge, (0,))
+
+
+def test_capture_rejects_a_non_conv1d_component(gpt2_bridge, monkeypatch) -> None:
+ from transformer_lens.tools.analysis.backward_lens import _get_gpt2_mlp_projections
+
+ projection = getattr(gpt2_bridge.blocks[0].mlp, "in")
+ monkeypatch.setitem(projection._modules, "_original_component", torch.nn.Linear(1, 1))
+ with pytest.raises(ValueError, match="input projection must wrap GPT-2 Conv1D"):
+ _get_gpt2_mlp_projections(gpt2_bridge, (0,))
+
+
+@pytest.mark.parametrize(
+ ("invalidity", "match"),
+ [
+ ("shape", r"weight must have shape \(768, 3072\)"),
+ ("dtype", r"floating dtype.*torch.int64"),
+ ],
+ ids=["wrong-shape", "non-floating-dtype"],
+)
+def test_capture_rejects_an_invalid_weight(
+ gpt2_bridge,
+ monkeypatch,
+ invalidity: str,
+ match: str,
+) -> None:
+ from transformer_lens.tools.analysis.backward_lens import _get_gpt2_mlp_projections
+
+ component = getattr(gpt2_bridge.blocks[0].mlp, "in").original_component
+ if invalidity == "shape":
+ replacement_weight = torch.nn.Parameter(torch.empty(1, 1))
+ else:
+ replacement_weight = torch.nn.Parameter(
+ torch.empty_like(component.weight, dtype=torch.int64), requires_grad=False
+ )
+ monkeypatch.setattr(component, "weight", replacement_weight)
+ with pytest.raises(ValueError, match=match):
+ _get_gpt2_mlp_projections(gpt2_bridge, (0,))
+
+
+def test_capture_rejects_a_frozen_original_weight(gpt2_bridge) -> None:
+ from transformer_lens.tools.analysis.backward_lens import (
+ _capture_gpt2_mlp_gradient_factors,
+ )
+
+ weight = getattr(gpt2_bridge.blocks[0].mlp, "in").original_component.weight
+ original_requires_grad = weight.requires_grad
+ weight.requires_grad_(False)
+ try:
+ with pytest.raises(ValueError, match="trainable Parameter"):
+ _capture_gpt2_mlp_gradient_factors(gpt2_bridge, PROMPT, TARGET, [0])
+ finally:
+ weight.requires_grad_(original_requires_grad)
+
+
+def test_capture_preserves_model_state_hooks_and_uses_one_autograd_call(
+ gpt2_bridge, monkeypatch
+) -> None:
+ from transformer_lens.model_bridge.generalized_components.normalization import (
+ NATIVE_PATH_BWD_FALLBACK_WARNING,
+ NATIVE_PATH_EDIT_FALLBACK_WARNING,
+ )
+ from transformer_lens.tools.analysis.backward_lens import (
+ _capture_gpt2_mlp_gradient_factors,
+ )
+
+ mlp = gpt2_bridge.blocks[0].mlp
+ projections = (getattr(mlp, "in"), mlp.out)
+ weights = [projection.original_component.weight for projection in projections]
+ saved_grads = [weight.grad for weight in weights]
+ weight_copies = [weight.detach().clone() for weight in weights]
+ training = gpt2_bridge.training
+ outer_rng = torch.random.get_rng_state()
+ hook_calls = 0
+ autograd_calls = 0
+ original_grad = torch.autograd.grad
+
+ def existing_hook(_tensor, hook=None) -> None:
+ nonlocal hook_calls
+ hook_calls += 1
+
+ def counting_grad(*args, **kwargs):
+ nonlocal autograd_calls
+ autograd_calls += 1
+ return original_grad(*args, **kwargs)
+
+ hook_point = mlp.out.hook_out
+ hook_point.add_hook(existing_hook)
+ existing_handle = hook_point.fwd_hooks[-1]
+ try:
+ gpt2_bridge.train(True)
+ torch.manual_seed(1234)
+ rng_before = torch.random.get_rng_state()
+ for index, weight in enumerate(weights):
+ weight.grad = torch.full_like(weight, index + 1.0)
+ grad_copies = [weight.grad.clone() for weight in weights]
+ requires_grad = [weight.requires_grad for weight in weights]
+ hooks_before = _projection_hook_snapshots(gpt2_bridge, 0)
+ monkeypatch.setattr(torch.autograd, "grad", counting_grad)
+
+ with warnings.catch_warnings(record=True) as caught:
+ warnings.simplefilter("always")
+ result = _capture_gpt2_mlp_gradient_factors(gpt2_bridge, PROMPT, TARGET, [0])
+
+ assert len(result.layers) == 1
+ assert autograd_calls == 1
+ assert hook_calls == 1
+ assert not any(
+ str(warning.message)
+ in (NATIVE_PATH_BWD_FALLBACK_WARNING, NATIVE_PATH_EDIT_FALLBACK_WARNING)
+ for warning in caught
+ )
+ assert torch.equal(torch.random.get_rng_state(), rng_before)
+ assert gpt2_bridge.training is True
+ assert _projection_hook_snapshots(gpt2_bridge, 0) == hooks_before
+ for weight, saved_weight, saved_grad, expected_requires_grad in zip(
+ weights, weight_copies, grad_copies, requires_grad, strict=True
+ ):
+ assert torch.equal(weight, saved_weight)
+ assert torch.equal(weight.grad, saved_grad)
+ assert weight.requires_grad is expected_requires_grad
+ finally:
+ existing_handle.hook.remove()
+ hook_point.fwd_hooks.remove(existing_handle)
+
+ for weight, saved_grad in zip(weights, saved_grads, strict=True):
+ weight.grad = saved_grad
+ gpt2_bridge.train(training)
+ torch.random.set_rng_state(outer_rng)
+
+
+def test_capture_reconstructs_with_existing_activation_edits(gpt2_bridge) -> None:
+ from transformer_lens.tools.analysis.backward_lens import (
+ _capture_gpt2_mlp_gradient_factors,
+ )
+
+ mlp = gpt2_bridge.blocks[0].mlp
+ input_hook_point = getattr(mlp, "in").hook_in
+ output_hook_point = mlp.out.hook_out
+
+ def scale_input(tensor, hook=None):
+ return tensor * 0.5
+
+ def scale_output(tensor, hook=None):
+ return tensor * 3.0
+
+ input_hook_point.add_hook(scale_input)
+ input_handle = input_hook_point.fwd_hooks[-1]
+ output_hook_point.add_hook(scale_output)
+ output_handle = output_hook_point.fwd_hooks[-1]
+ try:
+ result = _capture_gpt2_mlp_gradient_factors(gpt2_bridge, PROMPT, TARGET, [0])
+ assert input_handle in input_hook_point.fwd_hooks
+ assert output_handle in output_hook_point.fwd_hooks
+ finally:
+ input_handle.hook.remove()
+ input_hook_point.fwd_hooks.remove(input_handle)
+ output_handle.hook.remove()
+ output_hook_point.fwd_hooks.remove(output_handle)
+
+ for factors in (
+ result.layers[0].input_projection,
+ result.layers[0].output_projection,
+ ):
+ torch.testing.assert_close(
+ factors.reconstructed_gradient,
+ factors.weight_gradient,
+ atol=2e-6,
+ rtol=2e-5,
+ )
+
+
+def test_capture_cleans_owned_hooks_when_autograd_raises(gpt2_bridge, monkeypatch) -> None:
+ from transformer_lens.tools.analysis.backward_lens import (
+ _capture_gpt2_mlp_gradient_factors,
+ )
+
+ hook_point = gpt2_bridge.blocks[0].mlp.out.hook_out
+ hook_calls = 0
+
+ def existing_hook(tensor, hook=None) -> None:
+ nonlocal hook_calls
+ hook_calls += 1
+
+ def fail_autograd(*args, **kwargs):
+ raise RuntimeError("forced autograd failure")
+
+ hook_point.add_hook(existing_hook)
+ existing_handle = hook_point.fwd_hooks[-1]
+ hooks_before = _projection_hook_snapshots(gpt2_bridge, 0)
+ monkeypatch.setattr(torch.autograd, "grad", fail_autograd)
+ try:
+ with pytest.raises(RuntimeError, match="forced autograd failure"):
+ _capture_gpt2_mlp_gradient_factors(gpt2_bridge, PROMPT, TARGET, [0])
+ assert hook_calls == 1
+ assert existing_handle in hook_point.fwd_hooks
+ assert _projection_hook_snapshots(gpt2_bridge, 0) == hooks_before
+ finally:
+ existing_handle.hook.remove()
+ hook_point.fwd_hooks.remove(existing_handle)
+
+
+def test_capture_removes_only_owned_hooks_when_forward_fails(gpt2_bridge) -> None:
+ from transformer_lens.tools.analysis.backward_lens import (
+ _capture_gpt2_mlp_gradient_factors,
+ )
+
+ mlp = gpt2_bridge.blocks[0].mlp
+ projections = (getattr(mlp, "in"), mlp.out)
+ weights = [projection.original_component.weight for projection in projections]
+ saved_grads = [weight.grad for weight in weights]
+ weight_copies = [weight.detach().clone() for weight in weights]
+ training = gpt2_bridge.training
+ outer_rng = torch.random.get_rng_state()
+ hook_point = mlp.out.hook_out
+
+ def fail(_module, _inputs, _output) -> None:
+ raise RuntimeError("forced existing-hook failure")
+
+ existing_handle = hook_point.register_forward_hook(fail)
+ try:
+ gpt2_bridge.train(True)
+ torch.manual_seed(5678)
+ rng_before = torch.random.get_rng_state()
+ for index, weight in enumerate(weights):
+ weight.grad = torch.full_like(weight, index + 3.0)
+ grad_copies = [weight.grad.clone() for weight in weights]
+ requires_grad = [weight.requires_grad for weight in weights]
+ hooks_before = _projection_hook_snapshots(gpt2_bridge, 0)
+ with pytest.raises(RuntimeError, match="forced existing-hook failure"):
+ _capture_gpt2_mlp_gradient_factors(gpt2_bridge, PROMPT, TARGET, [0])
+ assert _projection_hook_snapshots(gpt2_bridge, 0) == hooks_before
+ assert torch.equal(torch.random.get_rng_state(), rng_before)
+ assert gpt2_bridge.training is True
+ for weight, saved_weight, saved_grad, expected_requires_grad in zip(
+ weights, weight_copies, grad_copies, requires_grad, strict=True
+ ):
+ assert torch.equal(weight, saved_weight)
+ assert torch.equal(weight.grad, saved_grad)
+ assert weight.requires_grad is expected_requires_grad
+ finally:
+ existing_handle.remove()
+ for weight, saved_grad in zip(weights, saved_grads, strict=True):
+ weight.grad = saved_grad
+ gpt2_bridge.train(training)
+ torch.random.set_rng_state(outer_rng)
+
+
+@pytest.mark.parametrize(("device", "dtype"), DEVICE_DTYPE_CASES)
+def test_tiny_gpt2_capture_supports_available_devices_and_reduced_precision(
+ gpt2_bridge, device: str, dtype: torch.dtype
+) -> None:
+ from transformers import GPT2Config, GPT2LMHeadModel
+
+ from transformer_lens.model_bridge import TransformerBridge
+ from transformer_lens.tools.analysis import BackwardLens
+
+ config = GPT2Config(
+ n_layer=2,
+ n_head=4,
+ n_embd=32,
+ n_inner=64,
+ n_positions=32,
+ vocab_size=gpt2_bridge.cfg.d_vocab,
+ resid_pdrop=0.1,
+ embd_pdrop=0.1,
+ attn_pdrop=0.1,
+ )
+ hf_model = cast(Any, GPT2LMHeadModel)(config).to(device=device, dtype=dtype).eval()
+ bridge = TransformerBridge.boot_transformers(
+ "gpt2",
+ hf_model=hf_model,
+ tokenizer=gpt2_bridge.tokenizer,
+ dtype=dtype,
+ )
+ bridge.train(True)
+ if device == "cuda":
+ rng_before = torch.cuda.get_rng_state()
+ elif device == "mps":
+ rng_before = torch.mps.get_rng_state()
+ else:
+ rng_before = torch.random.get_rng_state()
+
+ result = BackwardLens(bridge).analyze("Small test", " token", [0, 1], normalized=True)
+
+ if device == "cuda":
+ rng_after = torch.cuda.get_rng_state()
+ elif device == "mps":
+ rng_after = torch.mps.get_rng_state()
+ else:
+ rng_after = torch.random.get_rng_state()
+ assert torch.equal(rng_after, rng_before)
+ for layer in result.layers:
+ for matrix in (layer.input_projection, layer.output_projection):
+ factors = matrix.factors
+ assert torch.isfinite(factors.weight_gradient).all()
+ assert factors.relative_reconstruction_error <= 5e-2
+ assert matrix.vocabulary_logits is None
+ assert matrix.normalized_vocabulary_logits is None
+ assert torch.isfinite(matrix.top_ranking.values).all()
+ assert torch.isfinite(matrix.bottom_ranking.values).all()
+ assert matrix.normalized_top_ranking is not None
+ assert matrix.normalized_bottom_ranking is not None
+ assert torch.isfinite(matrix.normalized_top_ranking.values).all()
+ assert torch.isfinite(matrix.normalized_bottom_ranking.values).all()
+ for ranking in (
+ matrix.top_ranking,
+ matrix.bottom_ranking,
+ matrix.normalized_top_ranking,
+ matrix.normalized_bottom_ranking,
+ ):
+ assert ranking.values.device.type == "cpu"
+ assert ranking.indices.device.type == "cpu"
diff --git a/tests/unit/tools/test_backward_lens.py b/tests/unit/tools/test_backward_lens.py
new file mode 100644
index 000000000..2095b91c1
--- /dev/null
+++ b/tests/unit/tools/test_backward_lens.py
@@ -0,0 +1,518 @@
+"""Model-free tests for Backward Lens gradient-factor contracts."""
+
+from dataclasses import FrozenInstanceError
+from types import SimpleNamespace
+
+import pytest
+import torch
+import torch.nn.functional as F
+
+from transformer_lens.tools.analysis.backward_lens import (
+ BackwardLensMatrixResult,
+ LinearGradientFactors,
+ _build_linear_gradient_factors,
+ _build_matrix_result,
+ _factor_norms_and_normalized_rows,
+ _project_residual_factors,
+ _rank_vocabulary_logits,
+ _single_batch_matrix,
+)
+
+
+class _ReadoutModel:
+ def __init__(self, *, affine: bool = True):
+ self.cfg = SimpleNamespace(d_model=3)
+ self.ln_final = torch.nn.LayerNorm(3, elementwise_affine=affine)
+ self.unembed = torch.nn.Linear(3, 5, bias=False)
+ with torch.no_grad():
+ self.unembed.weight.copy_(torch.arange(15, dtype=torch.float32).reshape(5, 3) / 10)
+
+ @property
+ def W_U(self) -> torch.Tensor:
+ return self.unembed.weight.T
+
+
+def _matrix_result(
+ logits: torch.Tensor,
+ *,
+ normalized: bool = True,
+ return_full_logits: bool = True,
+ top_k: int = 2,
+) -> BackwardLensMatrixResult:
+ factors = _build_linear_gradient_factors(
+ torch.tensor([[1.0, 2.0], [3.0, 4.0]]),
+ torch.tensor([[0.5, -1.0], [2.0, 1.5]]),
+ torch.tensor([[6.5, 3.5], [9.0, 4.0]]),
+ weight_layout="in_out",
+ )
+ normalized_logits = logits * 2 if normalized else None
+ target_token_id = 2
+ return BackwardLensMatrixResult(
+ factors=factors,
+ projected_factor="forward_inputs",
+ factor_norms=torch.tensor([1.0, 2.0]),
+ zero_norm_mask=torch.tensor([False, False]),
+ vocabulary_size=logits.shape[-1],
+ target_token_id=target_token_id,
+ top_ranking=_rank_vocabulary_logits(logits, k=top_k, largest=True),
+ bottom_ranking=_rank_vocabulary_logits(logits, k=top_k, largest=False),
+ target_largest_ranks=(logits > logits[:, target_token_id, None]).sum(
+ dim=-1, dtype=torch.int64
+ ),
+ target_smallest_ranks=(logits < logits[:, target_token_id, None]).sum(
+ dim=-1, dtype=torch.int64
+ ),
+ normalized_top_ranking=(
+ _rank_vocabulary_logits(normalized_logits, k=top_k, largest=True)
+ if normalized_logits is not None
+ else None
+ ),
+ normalized_bottom_ranking=(
+ _rank_vocabulary_logits(normalized_logits, k=top_k, largest=False)
+ if normalized_logits is not None
+ else None
+ ),
+ normalized_target_largest_ranks=(
+ (normalized_logits > normalized_logits[:, target_token_id, None]).sum(
+ dim=-1, dtype=torch.int64
+ )
+ if normalized_logits is not None
+ else None
+ ),
+ normalized_target_smallest_ranks=(
+ (normalized_logits < normalized_logits[:, target_token_id, None]).sum(
+ dim=-1, dtype=torch.int64
+ )
+ if normalized_logits is not None
+ else None
+ ),
+ vocabulary_logits=logits.clone() if return_full_logits else None,
+ normalized_vocabulary_logits=(
+ normalized_logits.clone()
+ if return_full_logits and normalized_logits is not None
+ else None
+ ),
+ )
+
+
+def test_reconstructs_gpt2_style_in_out_gradient_from_autograd() -> None:
+ torch.manual_seed(1)
+ inputs = torch.randn(7, 3)
+ weight = torch.randn(3, 5, requires_grad=True)
+ output_gradients = torch.randn(7, 5)
+ outputs = inputs @ weight
+ (weight_gradient,) = torch.autograd.grad(outputs, weight, grad_outputs=output_gradients)
+
+ result = _build_linear_gradient_factors(
+ inputs, output_gradients, weight_gradient, weight_layout="in_out"
+ )
+
+ assert isinstance(result, LinearGradientFactors)
+ assert result.reconstructed_gradient.shape == (3, 5)
+ assert torch.allclose(result.reconstructed_gradient, weight_gradient)
+ assert result.absolute_reconstruction_error < 1e-6
+ assert result.relative_reconstruction_error < 1e-6
+
+
+def test_reconstructs_out_in_gradient_from_autograd() -> None:
+ torch.manual_seed(2)
+ inputs = torch.randn(6, 3)
+ weight = torch.randn(5, 3, requires_grad=True)
+ output_gradients = torch.randn(6, 5)
+ outputs = F.linear(inputs, weight)
+ (weight_gradient,) = torch.autograd.grad(outputs, weight, grad_outputs=output_gradients)
+
+ result = _build_linear_gradient_factors(
+ inputs, output_gradients, weight_gradient, weight_layout="out_in"
+ )
+
+ assert result.reconstructed_gradient.shape == (5, 3)
+ assert torch.allclose(result.reconstructed_gradient, weight_gradient)
+ assert result.absolute_reconstruction_error < 1e-6
+ assert result.relative_reconstruction_error < 1e-6
+
+
+def test_asymmetric_dimensions_reject_wrong_orientation() -> None:
+ inputs = torch.randn(4, 2)
+ output_gradients = torch.randn(4, 5)
+ out_in_gradient = output_gradients.T @ inputs
+
+ with pytest.raises(ValueError, match="does not match"):
+ _build_linear_gradient_factors(
+ inputs, output_gradients, out_in_gradient, weight_layout="in_out"
+ )
+
+
+def test_result_owns_detached_float32_copies_of_all_inputs() -> None:
+ inputs = torch.randn(3, 2, dtype=torch.float64, requires_grad=True)
+ output_gradients = torch.randn(3, 4, dtype=torch.float64)
+ weight_gradient = inputs.detach().T @ output_gradients
+ result = _build_linear_gradient_factors(
+ inputs, output_gradients, weight_gradient, weight_layout="in_out"
+ )
+ saved_inputs = result.forward_inputs.clone()
+ saved_output_gradients = result.output_gradients.clone()
+ saved_weight_gradient = result.weight_gradient.clone()
+
+ with torch.no_grad():
+ inputs.add_(100)
+ output_gradients.add_(100)
+ weight_gradient.add_(100)
+
+ assert result.forward_inputs.dtype == torch.float32
+ assert result.forward_inputs.device.type == "cpu"
+ assert result.forward_inputs.grad_fn is None
+ assert torch.equal(result.forward_inputs, saved_inputs)
+ assert torch.equal(result.output_gradients, saved_output_gradients)
+ assert torch.equal(result.weight_gradient, saved_weight_gradient)
+ with pytest.raises(FrozenInstanceError):
+ setattr(result, "weight_layout", "out_in")
+
+
+def test_zero_gradient_has_finite_zero_errors() -> None:
+ result = _build_linear_gradient_factors(
+ torch.zeros(3, 2), torch.zeros(3, 4), torch.zeros(2, 4), weight_layout="in_out"
+ )
+
+ assert result.absolute_reconstruction_error == 0.0
+ assert result.relative_reconstruction_error == 0.0
+
+
+def test_zero_reference_with_nonzero_reconstruction_has_finite_relative_error() -> None:
+ result = _build_linear_gradient_factors(
+ torch.tensor([[1.0, 0.0]]),
+ torch.tensor([[1.0, 0.0, 0.0]]),
+ torch.zeros(2, 3),
+ weight_layout="in_out",
+ )
+
+ assert result.absolute_reconstruction_error == 1.0
+ assert result.relative_reconstruction_error == 1.0
+ assert torch.isfinite(torch.tensor(result.relative_reconstruction_error))
+
+
+@pytest.mark.parametrize(
+ ("inputs", "gradients", "weight", "message"),
+ [
+ (torch.randn(2), torch.randn(3, 4), torch.randn(2, 4), "rank 2"),
+ (torch.randn(3, 2), torch.randn(4, 4), torch.randn(2, 4), "same number"),
+ (torch.empty(0, 2), torch.empty(0, 4), torch.randn(2, 4), "empty"),
+ (torch.full((3, 2), float("nan")), torch.ones(3, 4), torch.ones(2, 4), "finite"),
+ (torch.ones(3, 2), torch.full((3, 4), float("inf")), torch.ones(2, 4), "finite"),
+ (torch.ones(3, 2), torch.ones(3, 4), torch.full((2, 4), float("nan")), "finite"),
+ ],
+)
+def test_factor_validation_errors(inputs, gradients, weight, message) -> None:
+ with pytest.raises(ValueError, match=message):
+ _build_linear_gradient_factors(inputs, gradients, weight, weight_layout="in_out")
+
+
+def test_rejects_invalid_layout_and_integer_factors() -> None:
+ with pytest.raises(ValueError, match="weight_layout"):
+ _build_linear_gradient_factors(
+ torch.randn(3, 2),
+ torch.randn(3, 4),
+ torch.randn(2, 4),
+ weight_layout="other",
+ )
+ with pytest.raises(TypeError, match="floating"):
+ _build_linear_gradient_factors(
+ torch.ones(3, 2, dtype=torch.long),
+ torch.randn(3, 4),
+ torch.randn(2, 4),
+ weight_layout="in_out",
+ )
+
+
+def test_rejects_non_tensor_factors() -> None:
+ with pytest.raises(TypeError, match="torch.Tensor"):
+ _build_linear_gradient_factors(
+ "not a tensor",
+ torch.randn(3, 4),
+ torch.randn(2, 4),
+ weight_layout="in_out",
+ )
+
+
+def test_rejects_values_that_overflow_during_float32_conversion() -> None:
+ with pytest.raises(ValueError, match="remain finite"):
+ _build_linear_gradient_factors(
+ torch.full((3, 2), 1e300, dtype=torch.float64),
+ torch.ones(3, 4, dtype=torch.float64),
+ torch.full((2, 4), 3e300, dtype=torch.float64),
+ weight_layout="in_out",
+ )
+
+
+def test_rejects_nonfinite_float32_reconstruction() -> None:
+ large = torch.full((2, 1), 3e38)
+ with pytest.raises(ValueError, match="reconstruction"):
+ _build_linear_gradient_factors(
+ large,
+ large,
+ torch.zeros(1, 1),
+ weight_layout="in_out",
+ )
+
+
+def test_vocabulary_rankings_match_topk_without_mutation() -> None:
+ logits = torch.tensor([[1.0, -3.0, 7.0, 2.0], [8.0, 0.5, -2.0, 4.0]])
+ original = logits.clone()
+
+ top = _rank_vocabulary_logits(logits, k=2, largest=True)
+ bottom = _rank_vocabulary_logits(logits, k=2, largest=False)
+
+ assert top.indices.tolist() == [[2, 3], [0, 3]]
+ assert top.values.tolist() == [[7.0, 2.0], [8.0, 4.0]]
+ assert bottom.indices.tolist() == [[1, 0], [2, 1]]
+ assert torch.equal(logits, original)
+
+
+def test_one_dimensional_vocabulary_ranking_is_detached_cpu_copy() -> None:
+ logits = torch.tensor([2.0, -4.0, 8.0, 1.0], requires_grad=True)
+ bottom = _rank_vocabulary_logits(logits, k=2, largest=False)
+ saved_values = bottom.values.clone()
+
+ with torch.no_grad():
+ logits.add_(100)
+
+ assert bottom.indices.tolist() == [1, 3]
+ assert bottom.values.tolist() == [-4.0, 1.0]
+ assert bottom.values.device.type == "cpu"
+ assert bottom.values.grad_fn is None
+ assert torch.equal(bottom.values, saved_values)
+
+
+@pytest.mark.parametrize("k", [0, 5, True])
+def test_vocabulary_ranking_rejects_invalid_k(k) -> None:
+ with pytest.raises(ValueError, match="k must"):
+ _rank_vocabulary_logits(torch.randn(2, 4), k=k, largest=True)
+
+
+def test_vocabulary_ranking_rejects_non_integer_k() -> None:
+ with pytest.raises(ValueError, match="k must"):
+ _rank_vocabulary_logits(torch.randn(2, 4), k=1.5, largest=True)
+
+
+@pytest.mark.parametrize("largest", [1, "yes", None])
+def test_vocabulary_ranking_rejects_non_boolean_largest(largest) -> None:
+ with pytest.raises(TypeError, match="largest must be a bool"):
+ _rank_vocabulary_logits(torch.randn(2, 4), k=1, largest=largest)
+
+
+@pytest.mark.parametrize(
+ "logits",
+ [
+ torch.randn(2, 3, 4),
+ torch.empty(2, 0),
+ torch.ones(4, dtype=torch.long),
+ torch.tensor([0.0, float("nan")]),
+ torch.tensor([0.0, float("inf")]),
+ ],
+)
+def test_vocabulary_ranking_rejects_invalid_logits(logits) -> None:
+ with pytest.raises((TypeError, ValueError)):
+ _rank_vocabulary_logits(logits, k=1, largest=True)
+
+
+def test_vocabulary_ranking_rejects_non_tensor_logits() -> None:
+ with pytest.raises(TypeError, match="torch.Tensor"):
+ _rank_vocabulary_logits([1.0, 2.0], k=1, largest=True)
+
+
+def test_projection_matches_fresh_final_norm_and_unembedding() -> None:
+ model = _ReadoutModel()
+ factors = torch.tensor([[1.0, -2.0, 4.0], [0.25, 0.5, -0.75]])
+
+ actual = _project_residual_factors(model, factors)
+ expected = model.unembed(model.ln_final(factors.unsqueeze(0))).squeeze(0)
+
+ torch.testing.assert_close(actual, expected)
+ assert actual.dtype == torch.float32
+ assert actual.device.type == "cpu"
+ assert actual.grad_fn is None
+
+
+def test_normalized_rows_preserve_norms_and_handle_zero_without_nan() -> None:
+ factors = torch.tensor([[3.0, 4.0, 0.0], [0.0, 0.0, 0.0]])
+
+ norms, zero_mask, normalized = _factor_norms_and_normalized_rows(factors)
+
+ assert norms.tolist() == [5.0, 0.0]
+ assert zero_mask.tolist() == [False, True]
+ torch.testing.assert_close(normalized[0], torch.tensor([0.6, 0.8, 0.0]))
+ assert torch.equal(normalized[1], torch.zeros(3))
+ assert torch.isfinite(normalized).all()
+
+
+def test_normalized_projection_changes_low_norm_readout_but_keeps_zero_finite() -> None:
+ model = _ReadoutModel()
+ factors = torch.tensor([[1e-6, -2e-6, 1e-6], [0.0, 0.0, 0.0]])
+ _, _, normalized = _factor_norms_and_normalized_rows(factors)
+
+ raw_logits = _project_residual_factors(model, factors)
+ normalized_logits = _project_residual_factors(model, normalized)
+
+ assert not torch.allclose(raw_logits[0], normalized_logits[0])
+ assert torch.isfinite(normalized_logits).all()
+
+
+def test_projection_sign_symmetry_depends_on_final_norm_bias() -> None:
+ factors = torch.tensor([[1.0, -2.0, 4.0]])
+ bias_free = _ReadoutModel(affine=False)
+ biased = _ReadoutModel(affine=True)
+ with torch.no_grad():
+ biased.ln_final.bias.fill_(0.25)
+
+ torch.testing.assert_close(
+ _project_residual_factors(bias_free, -factors),
+ -_project_residual_factors(bias_free, factors),
+ )
+ assert not torch.allclose(
+ _project_residual_factors(biased, -factors),
+ -_project_residual_factors(biased, factors),
+ )
+
+
+@pytest.mark.parametrize(
+ ("tensor", "message"),
+ [
+ ("not a tensor", "torch.Tensor"),
+ (torch.randn(2, 3), "shape"),
+ (torch.randn(2, 3, 4), "shape"),
+ (torch.ones(1, 3, 4, dtype=torch.long), "floating dtype"),
+ ],
+)
+def test_single_batch_matrix_rejects_invalid_internal_tensors(tensor, message) -> None:
+ with pytest.raises(RuntimeError, match=message):
+ _single_batch_matrix("captured tensor", tensor)
+
+
+def test_matrix_result_rankings_decoding_and_target_rank_conventions() -> None:
+ logits = torch.tensor([[3.0, 1.0, -2.0, 0.0], [0.0, -1.0, 4.0, 2.0]])
+ result = _matrix_result(logits)
+
+ assert result.top(k=2).indices.tolist() == [[0, 1], [2, 3]]
+ assert result.bottom(k=2).indices.tolist() == [[2, 3], [1, 0]]
+ assert result.target_ranks(2, largest=True).tolist() == [3, 0]
+ assert result.gradient_descent_target_ranks(2).tolist() == [0, 3]
+ assert result.target_ranks(1, largest=True).tolist() == [1, 3]
+ assert torch.equal(result.logits(normalized=True), logits * 2)
+
+ tokenizer = SimpleNamespace(decode=lambda ids: f"token-{ids[0]}")
+ assert result.top_tokens(tokenizer, k=1) == [["token-0"], ["token-2"]]
+ assert result.bottom_tokens(tokenizer, k=1) == [["token-2"], ["token-1"]]
+
+
+def test_matrix_result_rejects_missing_normalized_logits_and_invalid_target() -> None:
+ logits = torch.randn(2, 4)
+ result = _matrix_result(logits)
+ result_without_normalized = _matrix_result(logits, normalized=False)
+
+ with pytest.raises(ValueError, match="were not requested"):
+ result_without_normalized.logits(normalized=True)
+ with pytest.raises(ValueError, match="target_token_id"):
+ result.target_ranks(4, largest=True)
+ with pytest.raises(TypeError, match="decode"):
+ result.top_tokens(object(), k=1)
+
+
+@pytest.mark.parametrize("k", [0, 3, True])
+def test_matrix_result_rejects_invalid_retained_ranking_k(k) -> None:
+ result = _matrix_result(torch.randn(2, 4))
+
+ with pytest.raises(ValueError, match="retained top_k=2"):
+ result.top(k=k)
+
+
+def test_matrix_result_keeps_rankings_and_analyzed_target_ranks_without_full_logits() -> None:
+ result = _matrix_result(
+ torch.tensor([[3.0, 1.0, -2.0, 0.0], [0.0, -1.0, 4.0, 2.0]]),
+ return_full_logits=False,
+ )
+
+ assert result.vocabulary_logits is None
+ assert result.normalized_vocabulary_logits is None
+ assert result.top(k=2).indices.tolist() == [[0, 1], [2, 3]]
+ assert result.bottom(k=2).indices.tolist() == [[2, 3], [1, 0]]
+ assert result.gradient_descent_target_ranks(2).tolist() == [0, 3]
+ assert result.gradient_descent_target_ranks(2, normalized=True).tolist() == [0, 3]
+ with pytest.raises(ValueError, match="return_full_logits=True"):
+ result.logits()
+ with pytest.raises(ValueError, match="return_full_logits=True"):
+ result.target_ranks(1, largest=True)
+
+
+@pytest.mark.parametrize("normalized", [False, True])
+@pytest.mark.parametrize("return_full_logits", [False, True])
+def test_build_matrix_result_bounds_storage_and_matches_projection(
+ normalized: bool, return_full_logits: bool
+) -> None:
+ model = _ReadoutModel()
+ inputs = torch.tensor([[1.0, -2.0, 4.0], [0.25, 0.5, -0.75]])
+ output_gradients = torch.tensor([[0.5, -1.0, 2.0], [1.5, 0.25, -0.5]])
+ factors = _build_linear_gradient_factors(
+ inputs,
+ output_gradients,
+ inputs.T @ output_gradients,
+ weight_layout="in_out",
+ )
+ direct = _project_residual_factors(model, inputs)
+
+ result = _build_matrix_result(
+ model,
+ factors,
+ projected_factor="forward_inputs",
+ include_normalized_logits=normalized,
+ target_token_id=2,
+ top_k=2,
+ return_full_logits=return_full_logits,
+ )
+
+ direct_top = torch.topk(direct, k=2, dim=-1, largest=True)
+ direct_bottom = torch.topk(direct, k=2, dim=-1, largest=False)
+ assert torch.equal(result.top_ranking.values, direct_top.values)
+ assert torch.equal(result.top_ranking.indices, direct_top.indices)
+ assert torch.equal(result.bottom_ranking.values, direct_bottom.values)
+ assert torch.equal(result.bottom_ranking.indices, direct_bottom.indices)
+ assert (result.vocabulary_logits is not None) is return_full_logits
+ assert (result.normalized_top_ranking is not None) is normalized
+ assert (result.normalized_bottom_ranking is not None) is normalized
+ assert (result.normalized_vocabulary_logits is not None) is (normalized and return_full_logits)
+
+
+def test_ranking_accessors_return_owned_retained_prefixes() -> None:
+ result = _matrix_result(torch.tensor([[3.0, 1.0, -2.0, 0.0], [0.0, -1.0, 4.0, 2.0]]))
+ saved_top_values = result.top_ranking.values.clone()
+ saved_top_indices = result.top_ranking.indices.clone()
+ assert result.normalized_bottom_ranking is not None
+ saved_bottom_values = result.normalized_bottom_ranking.values.clone()
+ saved_bottom_indices = result.normalized_bottom_ranking.indices.clone()
+ top = result.top(k=1)
+ bottom = result.bottom(k=1, normalized=True)
+
+ top.values.add_(100)
+ top.indices.add_(100)
+ bottom.values.add_(100)
+ bottom.indices.add_(100)
+
+ assert torch.equal(result.top_ranking.values, saved_top_values)
+ assert torch.equal(result.top_ranking.indices, saved_top_indices)
+ assert torch.equal(result.normalized_bottom_ranking.values, saved_bottom_values)
+ assert torch.equal(result.normalized_bottom_ranking.indices, saved_bottom_indices)
+
+
+def test_public_backward_lens_symbols_are_exported() -> None:
+ from transformer_lens.tools.analysis import (
+ BackwardLens,
+ BackwardLensLayerResult,
+ BackwardLensMatrixResult,
+ BackwardLensResult,
+ )
+
+ _ = (
+ BackwardLens,
+ BackwardLensLayerResult,
+ BackwardLensMatrixResult,
+ BackwardLensResult,
+ )
diff --git a/transformer_lens/tools/analysis/__init__.py b/transformer_lens/tools/analysis/__init__.py
index 16e6c752c..bb77a4ec4 100644
--- a/transformer_lens/tools/analysis/__init__.py
+++ b/transformer_lens/tools/analysis/__init__.py
@@ -5,6 +5,8 @@
new analyses may target the ``TransformerBridge`` API exclusively.
Tools:
+ - backward_lens: GPT-2 MLP weight-gradient factors projected into vocabulary
+ space with explicit raw-gradient sign semantics.
- direct_logit_attribution: Direct Logit Attribution (DLA) over components,
layers, or attention heads.
- direct_path_patching: Direct path patching for head-to-head circuit
@@ -16,6 +18,16 @@
attention-head OQ/OK/OV affinity.
"""
+from transformer_lens.tools.analysis.backward_lens import (
+ BackwardLens,
+ BackwardLensLayerResult,
+ BackwardLensMatrixResult,
+ BackwardLensResult,
+ LinearGradientFactors,
+ ProjectedFactor,
+ VocabularyRanking,
+ WeightLayout,
+)
from transformer_lens.tools.analysis.direct_logit_attribution import (
DirectLogitAttribution,
direct_logit_attribution,
@@ -50,6 +62,10 @@
__all__ = [
"AttentionHeadRef",
+ "BackwardLens",
+ "BackwardLensLayerResult",
+ "BackwardLensMatrixResult",
+ "BackwardLensResult",
"DirectLogitAttribution",
"HeadAffinityPair",
"HeadAffinityResult",
@@ -58,9 +74,13 @@
"JSpaceVarianceProfile",
"JacobianLens",
"JacobianLensReadout",
+ "LinearGradientFactors",
+ "ProjectedFactor",
"ProjectionKernelResult",
"RandomSubspaceReference",
"SubspaceBasis",
+ "VocabularyRanking",
+ "WeightLayout",
"attention_head_subspace_affinity",
"direct_logit_attribution",
"estimate_occupancy",
diff --git a/transformer_lens/tools/analysis/backward_lens.py b/transformer_lens/tools/analysis/backward_lens.py
new file mode 100644
index 000000000..419fb2fde
--- /dev/null
+++ b/transformer_lens/tools/analysis/backward_lens.py
@@ -0,0 +1,929 @@
+"""Backward Lens gradient-factor capture and vocabulary projection.
+
+The Backward Lens represents a linear weight gradient as a sum of token-position
+outer products and projects residual-width factors into the model vocabulary.
+The public API currently supports raw GPT-2 ``TransformerBridge`` models.
+"""
+
+from __future__ import annotations
+
+from collections.abc import Callable, Iterator, Sequence
+from contextlib import contextmanager
+from dataclasses import dataclass
+from typing import Any, Literal, cast
+
+import torch
+import torch.nn.functional as F
+from jaxtyping import Bool, Float, Int
+
+WeightLayout = Literal["in_out", "out_in"]
+ProjectedFactor = Literal["forward_inputs", "output_gradients"]
+DEFAULT_TOP_K = 10
+
+
+@dataclass(frozen=True)
+class LinearGradientFactors:
+ """Detached factors and reconstruction for one linear weight gradient.
+
+ ``forward_inputs`` and ``output_gradients`` have shapes ``[position, in]``
+ and ``[position, out]``. ``output_gradients`` and ``weight_gradient`` preserve
+ the raw ``d(loss)/d(tensor)`` sign; they are not negated into update directions.
+ Gradient tensors use the requested storage layout. All tensors are cloned to
+ CPU in float32 so the result owns no autograd graph.
+ """
+
+ forward_inputs: Float[torch.Tensor, "position in_features"]
+ output_gradients: Float[torch.Tensor, "position out_features"]
+ weight_gradient: Float[torch.Tensor, "weight_dim_0 weight_dim_1"]
+ reconstructed_gradient: Float[torch.Tensor, "weight_dim_0 weight_dim_1"]
+ absolute_reconstruction_error: float
+ relative_reconstruction_error: float
+ weight_layout: WeightLayout
+
+
+@dataclass(frozen=True)
+class VocabularyRanking:
+ """Owned CPU copies of signed vocabulary rankings with shape ``[..., k]``.
+
+ ``values`` preserves the floating dtype and sign of ``logits``; ``indices``
+ has dtype ``torch.int64``. Both tensors are detached.
+ """
+
+ values: Float[torch.Tensor, "*leading k"]
+ indices: Int[torch.Tensor, "*leading k"]
+
+
+@dataclass(frozen=True)
+class BackwardLensMatrixResult:
+ """Factors and vocabulary readouts for one GPT-2 MLP weight matrix.
+
+ ``factors`` contains the full linear factorization. ``projected_factor`` says
+ whether its residual-width ``forward_inputs`` or raw-gradient
+ ``output_gradients`` were decoded. ``factor_norms`` and ``zero_norm_mask``
+ have shape ``[position]`` with float32 and bool dtypes. Largest and smallest
+ signed rankings are always retained. Full ``vocabulary_logits`` are present
+ only when explicitly requested. Normalized rankings and optional full logits
+ are present when the Normalized Logit Lens is requested. Every retained tensor
+ is a detached CPU-owned value; gradient descent subtracts raw gradients.
+ """
+
+ factors: LinearGradientFactors
+ projected_factor: ProjectedFactor
+ factor_norms: Float[torch.Tensor, "position"]
+ zero_norm_mask: Bool[torch.Tensor, "position"]
+ vocabulary_size: int
+ target_token_id: int
+ top_ranking: VocabularyRanking
+ bottom_ranking: VocabularyRanking
+ target_largest_ranks: Int[torch.Tensor, "position"]
+ target_smallest_ranks: Int[torch.Tensor, "position"]
+ normalized_top_ranking: VocabularyRanking | None = None
+ normalized_bottom_ranking: VocabularyRanking | None = None
+ normalized_target_largest_ranks: Int[torch.Tensor, "position"] | None = None
+ normalized_target_smallest_ranks: Int[torch.Tensor, "position"] | None = None
+ vocabulary_logits: Float[torch.Tensor, "position d_vocab"] | None = None
+ normalized_vocabulary_logits: Float[torch.Tensor, "position d_vocab"] | None = None
+
+ def logits(self, *, normalized: bool = False) -> Float[torch.Tensor, "position d_vocab"]:
+ """Return opted-in raw or Normalized Logit Lens full logits."""
+ if not isinstance(normalized, bool):
+ raise TypeError("normalized must be a bool")
+ if normalized and self.normalized_top_ranking is None:
+ raise ValueError("normalized logits were not requested during analysis")
+ logits = self.normalized_vocabulary_logits if normalized else self.vocabulary_logits
+ if logits is None:
+ kind = "normalized " if normalized else ""
+ raise ValueError(
+ f"full {kind}logits were not retained; call "
+ "BackwardLens.analyze(..., return_full_logits=True)"
+ )
+ return logits
+
+ def _retained_ranking(self, *, normalized: bool, largest: bool) -> VocabularyRanking:
+ if not isinstance(normalized, bool):
+ raise TypeError("normalized must be a bool")
+ if normalized:
+ ranking = self.normalized_top_ranking if largest else self.normalized_bottom_ranking
+ if ranking is None:
+ raise ValueError("normalized logits were not requested during analysis")
+ return ranking
+ return self.top_ranking if largest else self.bottom_ranking
+
+ def top(self, *, k: int, normalized: bool = False) -> VocabularyRanking:
+ """Return up to the retained largest signed logits and token ids."""
+ return _slice_vocabulary_ranking(
+ self._retained_ranking(normalized=normalized, largest=True), k=k
+ )
+
+ def bottom(self, *, k: int, normalized: bool = False) -> VocabularyRanking:
+ """Return up to the retained smallest signed logits and token ids."""
+ return _slice_vocabulary_ranking(
+ self._retained_ranking(normalized=normalized, largest=False), k=k
+ )
+
+ def top_tokens(self, tokenizer: Any, *, k: int, normalized: bool = False) -> list[list[str]]:
+ """Decode the largest-``k`` vocabulary ids for every position."""
+ return _decode_vocabulary_ranking(self.top(k=k, normalized=normalized), tokenizer)
+
+ def bottom_tokens(self, tokenizer: Any, *, k: int, normalized: bool = False) -> list[list[str]]:
+ """Decode the smallest-``k`` vocabulary ids for every position."""
+ return _decode_vocabulary_ranking(self.bottom(k=k, normalized=normalized), tokenizer)
+
+ def target_ranks(
+ self,
+ target_token_id: int,
+ *,
+ largest: bool,
+ normalized: bool = False,
+ ) -> Int[torch.Tensor, "position"]:
+ """Return zero-based target ranks per position in the requested ordering.
+
+ ``largest=True`` gives rank zero to the largest logit. ``largest=False``
+ gives rank zero to the smallest, which is the useful raw-gradient
+ convention for the second MLP matrix because gradient descent subtracts it.
+ Ties receive the same competition rank. The analyzed target's ranks are
+ always retained; other token ids require opted-in full logits.
+ """
+ if isinstance(target_token_id, bool) or not isinstance(target_token_id, int):
+ raise TypeError("target_token_id must be an integer")
+ if not 0 <= target_token_id < self.vocabulary_size:
+ raise ValueError(
+ f"target_token_id must be in [0, {self.vocabulary_size - 1}]; "
+ f"got {target_token_id}"
+ )
+ if not isinstance(largest, bool):
+ raise TypeError("largest must be a bool")
+ if not isinstance(normalized, bool):
+ raise TypeError("normalized must be a bool")
+ if normalized:
+ ranks = (
+ self.normalized_target_largest_ranks
+ if largest
+ else self.normalized_target_smallest_ranks
+ )
+ if ranks is None:
+ raise ValueError("normalized logits were not requested during analysis")
+ else:
+ ranks = self.target_largest_ranks if largest else self.target_smallest_ranks
+ if target_token_id == self.target_token_id:
+ return ranks.clone()
+ return _target_vocabulary_ranks(
+ self.logits(normalized=normalized),
+ target_token_id=target_token_id,
+ largest=largest,
+ )
+
+ def gradient_descent_target_ranks(
+ self, target_token_id: int, *, normalized: bool = False
+ ) -> Int[torch.Tensor, "position"]:
+ """Return ascending raw-gradient target ranks (rank zero is smallest)."""
+ return self.target_ranks(target_token_id, largest=False, normalized=normalized)
+
+
+@dataclass(frozen=True)
+class BackwardLensLayerResult:
+ """Vocabulary-facing input/output MLP matrix results for one indexed layer."""
+
+ layer: int
+ input_projection: BackwardLensMatrixResult
+ output_projection: BackwardLensMatrixResult
+
+
+@dataclass(frozen=True)
+class BackwardLensResult:
+ """Detached result of one :meth:`BackwardLens.analyze` call.
+
+ ``prompt`` and ``target_token`` echo the analyzed inputs; ``target_token_id``
+ is the single vocabulary id the target text encodes to. ``loss`` is the raw
+ scalar cross-entropy of the final-position next-token prediction against the
+ target; it preserves the ``d(loss)/d(...)`` sign convention and is not negated.
+ ``prompt_token_ids`` is an owned CPU int64 tensor with shape ``[position]``;
+ every residual-width factor in ``layers`` is aligned to these same positions.
+ Position zero is a prepended BOS only when the model and tokenizer configuration
+ requests one. ``layers`` preserves requested order. Maximum errors summarize
+ both matrices over every requested layer.
+ ``includes_normalized_logits`` records whether the Normalized Logit Lens was
+ computed. ``includes_full_logits`` records whether full vocabulary tensors
+ were retained in addition to bounded rankings. No model or tokenizer reference
+ is retained.
+ """
+
+ prompt: str
+ prompt_token_ids: Int[torch.Tensor, "position"]
+ target_token: str
+ target_token_id: int
+ loss: float
+ layers: tuple[BackwardLensLayerResult, ...]
+ max_absolute_reconstruction_error: float
+ max_relative_reconstruction_error: float
+ includes_normalized_logits: bool
+ includes_full_logits: bool
+
+ def layer(self, layer: int) -> BackwardLensLayerResult:
+ """Return one requested layer result or raise ``KeyError``."""
+ for result in self.layers:
+ if result.layer == layer:
+ return result
+ raise KeyError(f"layer {layer} was not analyzed")
+
+
+@dataclass(frozen=True)
+class _GPT2LayerGradientFactors:
+ """Detached gradient factors for both MLP projections in one GPT-2 layer."""
+
+ layer: int
+ input_projection: LinearGradientFactors
+ output_projection: LinearGradientFactors
+
+
+@dataclass(frozen=True)
+class _GPT2GradientCapture:
+ """Private Commit-2 result for one GPT-2 next-token loss.
+
+ Tensor fields are detached, owned CPU copies. Public vocabulary-facing result
+ contracts are introduced with the projection API.
+ """
+
+ prompt_token_ids: Int[torch.Tensor, "1 position"]
+ target_token_id: int
+ loss: float
+ layers: tuple[_GPT2LayerGradientFactors, ...]
+
+
+def _validate_floating_matrix(name: str, tensor: Any) -> Float[torch.Tensor, "rows columns"]:
+ if not isinstance(tensor, torch.Tensor):
+ raise TypeError(f"{name} must be a torch.Tensor")
+ if tensor.ndim != 2:
+ raise ValueError(f"{name} must be rank 2; got shape {tuple(tensor.shape)}")
+ if 0 in tensor.shape:
+ raise ValueError(f"{name} must have no empty dimensions; got shape {tuple(tensor.shape)}")
+ if not tensor.is_floating_point():
+ raise TypeError(f"{name} must have a floating dtype; got {tensor.dtype}")
+ if not bool(torch.isfinite(tensor).all()):
+ raise ValueError(f"{name} must contain only finite values")
+ return cast(Float[torch.Tensor, "rows columns"], tensor)
+
+
+def _reconstruction_errors(
+ reference: Float[torch.Tensor, "rows columns"],
+ reconstruction: Float[torch.Tensor, "rows columns"],
+) -> tuple[float, float]:
+ """Return max absolute and symmetric scale-aware relative errors.
+
+ The relative error is ``||reference - reconstruction||_F`` divided by the
+ maximum of the two input Frobenius norms and float32 epsilon. This remains
+ finite when one or both gradients are zero.
+ """
+ difference = reference - reconstruction
+ absolute = float(difference.abs().max())
+ scale = torch.maximum(reference.norm(), reconstruction.norm()).clamp_min(
+ torch.finfo(reference.dtype).eps
+ )
+ relative = float(difference.norm() / scale)
+ return absolute, relative
+
+
+def _to_detached_float32(
+ name: str, tensor: Float[torch.Tensor, "rows columns"]
+) -> Float[torch.Tensor, "rows columns"]:
+ """Detach and convert a validated tensor, rejecting float32 overflow."""
+ converted = tensor.detach().float()
+ if not bool(torch.isfinite(converted).all()):
+ raise ValueError(f"{name} must remain finite when converted to float32")
+ return converted
+
+
+def _build_linear_gradient_factors(
+ forward_inputs: Any,
+ output_gradients: Any,
+ weight_gradient: Any,
+ *,
+ weight_layout: Any,
+) -> LinearGradientFactors:
+ """Reconstruct a weight gradient from aligned token-position factors.
+
+ Args:
+ forward_inputs: Linear inputs with shape ``[position, in_features]``.
+ output_gradients: Loss gradients with respect to linear outputs, shape
+ ``[position, out_features]``.
+ weight_gradient: Independently computed gradient in ``weight_layout``.
+ weight_layout: ``"in_out"`` for GPT-2 ``Conv1D`` storage or
+ ``"out_in"`` for ``torch.nn.Linear`` storage.
+
+ Returns:
+ Detached factors, the independent gradient, its reconstruction, and
+ reconstruction errors, all on CPU with float32 tensor values.
+ """
+ validated_inputs = _validate_floating_matrix("forward_inputs", forward_inputs)
+ validated_gradients = _validate_floating_matrix("output_gradients", output_gradients)
+ validated_weight = _validate_floating_matrix("weight_gradient", weight_gradient)
+ if weight_layout not in ("in_out", "out_in"):
+ raise ValueError("weight_layout must be 'in_out' or 'out_in'")
+ validated_layout = cast(WeightLayout, weight_layout)
+ if validated_inputs.shape[0] != validated_gradients.shape[0]:
+ raise ValueError(
+ "forward_inputs and output_gradients must have the same number of positions; "
+ f"got {validated_inputs.shape[0]} and {validated_gradients.shape[0]}"
+ )
+ devices = {validated_inputs.device, validated_gradients.device, validated_weight.device}
+ if len(devices) != 1:
+ raise ValueError(
+ "forward_inputs, output_gradients, and weight_gradient must share a device"
+ )
+
+ inputs = _to_detached_float32("forward_inputs", validated_inputs)
+ gradients = _to_detached_float32("output_gradients", validated_gradients)
+ canonical = inputs.T @ gradients
+ reconstruction = canonical if validated_layout == "in_out" else canonical.T
+ reference = _to_detached_float32("weight_gradient", validated_weight)
+ if not bool(torch.isfinite(reconstruction).all()):
+ raise ValueError("the float32 outer-product reconstruction must contain only finite values")
+ if reference.shape != reconstruction.shape:
+ raise ValueError(
+ f"weight_gradient shape {tuple(reference.shape)} does not match the "
+ f"{validated_layout} reconstruction shape {tuple(reconstruction.shape)}"
+ )
+ absolute, relative = _reconstruction_errors(reference, reconstruction)
+ return LinearGradientFactors(
+ forward_inputs=inputs.cpu().clone(),
+ output_gradients=gradients.cpu().clone(),
+ weight_gradient=reference.cpu().clone(),
+ reconstructed_gradient=reconstruction.cpu().clone(),
+ absolute_reconstruction_error=absolute,
+ relative_reconstruction_error=relative,
+ weight_layout=validated_layout,
+ )
+
+
+def _rank_vocabulary_logits(logits: Any, *, k: Any, largest: Any) -> VocabularyRanking:
+ """Return largest or smallest vocabulary logits and token ids per row.
+
+ Ordering among exactly tied logits is intentionally unspecified and follows
+ :func:`torch.topk`.
+ """
+ if not isinstance(logits, torch.Tensor):
+ raise TypeError("logits must be a torch.Tensor")
+ if logits.ndim not in (1, 2) or logits.shape[-1] == 0:
+ raise ValueError(
+ f"logits must have shape [vocab] or [position, vocab]; got {tuple(logits.shape)}"
+ )
+ if not logits.is_floating_point():
+ raise TypeError(f"logits must have a floating dtype; got {logits.dtype}")
+ if not bool(torch.isfinite(logits).all()):
+ raise ValueError("logits must contain only finite values")
+ if not isinstance(largest, bool):
+ raise TypeError(f"largest must be a bool; got {type(largest).__name__}")
+ if isinstance(k, bool) or not isinstance(k, int) or not 1 <= k <= logits.shape[-1]:
+ raise ValueError(f"k must be in [1, {logits.shape[-1]}]; got {k!r}")
+ validated_logits = cast(Float[torch.Tensor, "*leading d_vocab"], logits)
+ ranked = torch.topk(validated_logits.detach(), k=k, dim=-1, largest=largest, sorted=True)
+ return VocabularyRanking(
+ values=ranked.values.cpu().clone(), indices=ranked.indices.cpu().clone()
+ )
+
+
+def _slice_vocabulary_ranking(ranking: VocabularyRanking, *, k: int) -> VocabularyRanking:
+ """Return an owned prefix of an already sorted vocabulary ranking."""
+ retained = ranking.indices.shape[-1]
+ if isinstance(k, bool) or not isinstance(k, int) or not 1 <= k <= retained:
+ raise ValueError(f"k must be in [1, retained top_k={retained}]; got {k!r}")
+ return VocabularyRanking(
+ values=ranking.values[..., :k].clone(),
+ indices=ranking.indices[..., :k].clone(),
+ )
+
+
+def _target_vocabulary_ranks(
+ logits: Float[torch.Tensor, "position d_vocab"], *, target_token_id: int, largest: bool
+) -> Int[torch.Tensor, "position"]:
+ """Return zero-based competition ranks for one vocabulary id per row."""
+ target = logits[:, target_token_id].unsqueeze(-1)
+ comparisons = logits > target if largest else logits < target
+ return comparisons.sum(dim=-1, dtype=torch.int64).cpu().clone()
+
+
+def _decode_vocabulary_ranking(ranking: VocabularyRanking, tokenizer: Any) -> list[list[str]]:
+ """Decode a two-dimensional vocabulary ranking without retaining a tokenizer."""
+ decode = getattr(tokenizer, "decode", None)
+ if not callable(decode):
+ raise TypeError("tokenizer must provide a callable decode method")
+ if ranking.indices.ndim != 2:
+ raise ValueError("decoded matrix rankings must have shape [position, k]")
+ return [[str(decode([token_id])) for token_id in row.tolist()] for row in ranking.indices]
+
+
+@torch.no_grad()
+def _project_residual_factors(
+ model: Any, factors: Float[torch.Tensor, "position d_model"]
+) -> Float[torch.Tensor, "position d_vocab"]:
+ """Apply fresh final normalization and unembedding to residual-width rows."""
+ _validate_floating_matrix("factors", factors)
+ if factors.shape[-1] != int(model.cfg.d_model):
+ raise ValueError(
+ f"factors must have width d_model={model.cfg.d_model}; got {factors.shape[-1]}"
+ )
+ unembed_weight = model.W_U
+ if not isinstance(unembed_weight, torch.Tensor) or unembed_weight.ndim != 2:
+ raise ValueError("the GPT-2 Bridge must expose a rank-2 unembedding weight")
+ batched = (
+ factors.detach().to(device=unembed_weight.device, dtype=unembed_weight.dtype).unsqueeze(0)
+ )
+ logits = model.unembed(model.ln_final(batched)).squeeze(0)
+ if logits.ndim != 2 or logits.shape != (factors.shape[0], unembed_weight.shape[1]):
+ raise RuntimeError(
+ "final normalization and unembedding must return [position, d_vocab]; "
+ f"got {tuple(logits.shape)}"
+ )
+ projected = logits.detach().float()
+ if not bool(torch.isfinite(projected).all()):
+ raise ValueError("vocabulary projection must remain finite in float32")
+ return projected.clone()
+
+
+def _factor_norms_and_normalized_rows(
+ factors: Float[torch.Tensor, "position width"],
+) -> tuple[
+ Float[torch.Tensor, "position"],
+ Bool[torch.Tensor, "position"],
+ Float[torch.Tensor, "position width"],
+]:
+ """Return original L2 norms, exact-zero mask, and safely unit-normalized rows."""
+ _validate_floating_matrix("factors", factors)
+ rows = _to_detached_float32("factors", factors).cpu().clone()
+ norms = rows.norm(dim=-1)
+ zero_mask = norms == 0
+ denominators = torch.where(zero_mask, torch.ones_like(norms), norms)
+ normalized = rows / denominators.unsqueeze(-1)
+ return norms.clone(), zero_mask.clone(), normalized
+
+
+def _build_matrix_result(
+ model: Any,
+ factors: LinearGradientFactors,
+ *,
+ projected_factor: ProjectedFactor,
+ include_normalized_logits: bool,
+ target_token_id: int,
+ top_k: int,
+ return_full_logits: bool,
+) -> BackwardLensMatrixResult:
+ if projected_factor not in ("forward_inputs", "output_gradients"):
+ raise ValueError("projected_factor must be 'forward_inputs' or 'output_gradients'")
+ if not isinstance(include_normalized_logits, bool):
+ raise TypeError("include_normalized_logits must be a bool")
+ if not isinstance(return_full_logits, bool):
+ raise TypeError("return_full_logits must be a bool")
+ rows = (
+ factors.forward_inputs if projected_factor == "forward_inputs" else factors.output_gradients
+ )
+ norms, zero_mask, normalized_rows = _factor_norms_and_normalized_rows(rows)
+ raw_logits = _project_residual_factors(model, rows)
+ normalized_logits = (
+ _project_residual_factors(model, normalized_rows) if include_normalized_logits else None
+ )
+ top_ranking = _rank_vocabulary_logits(raw_logits, k=top_k, largest=True)
+ bottom_ranking = _rank_vocabulary_logits(raw_logits, k=top_k, largest=False)
+ target_largest_ranks = _target_vocabulary_ranks(
+ raw_logits, target_token_id=target_token_id, largest=True
+ )
+ target_smallest_ranks = _target_vocabulary_ranks(
+ raw_logits, target_token_id=target_token_id, largest=False
+ )
+ normalized_top_ranking = None
+ normalized_bottom_ranking = None
+ normalized_target_largest_ranks = None
+ normalized_target_smallest_ranks = None
+ if normalized_logits is not None:
+ normalized_top_ranking = _rank_vocabulary_logits(normalized_logits, k=top_k, largest=True)
+ normalized_bottom_ranking = _rank_vocabulary_logits(
+ normalized_logits, k=top_k, largest=False
+ )
+ normalized_target_largest_ranks = _target_vocabulary_ranks(
+ normalized_logits, target_token_id=target_token_id, largest=True
+ )
+ normalized_target_smallest_ranks = _target_vocabulary_ranks(
+ normalized_logits, target_token_id=target_token_id, largest=False
+ )
+ return BackwardLensMatrixResult(
+ factors=factors,
+ projected_factor=projected_factor,
+ factor_norms=norms,
+ zero_norm_mask=zero_mask,
+ vocabulary_size=raw_logits.shape[-1],
+ target_token_id=target_token_id,
+ top_ranking=top_ranking,
+ bottom_ranking=bottom_ranking,
+ target_largest_ranks=target_largest_ranks,
+ target_smallest_ranks=target_smallest_ranks,
+ normalized_top_ranking=normalized_top_ranking,
+ normalized_bottom_ranking=normalized_bottom_ranking,
+ normalized_target_largest_ranks=normalized_target_largest_ranks,
+ normalized_target_smallest_ranks=normalized_target_smallest_ranks,
+ vocabulary_logits=raw_logits.cpu().clone() if return_full_logits else None,
+ normalized_vocabulary_logits=(
+ normalized_logits.cpu().clone()
+ if return_full_logits and normalized_logits is not None
+ else None
+ ),
+ )
+
+
+def _validate_requested_layers(model: Any, layers: Sequence[int]) -> tuple[int, ...]:
+ if isinstance(layers, (str, bytes)) or not isinstance(layers, Sequence):
+ raise TypeError("layers must be a sequence of integer layer indices")
+ requested = tuple(layers)
+ if not requested:
+ raise ValueError("layers must contain at least one layer index")
+ for layer in requested:
+ if isinstance(layer, bool) or not isinstance(layer, int):
+ raise TypeError(f"each layer must be an integer; got {layer!r}")
+ if len(set(requested)) != len(requested):
+ raise ValueError("layers must not contain duplicate indices")
+ n_layers = int(model.cfg.n_layers)
+ invalid = [layer for layer in requested if not 0 <= layer < n_layers]
+ if invalid:
+ raise ValueError(f"layers must be in [0, {n_layers - 1}]; got {invalid}")
+ return requested
+
+
+def _require_raw_gpt2_bridge(model: Any) -> None:
+ """Require the raw GPT-2 Bridge capabilities used by gradient capture."""
+ from transformer_lens.model_bridge import TransformerBridge
+ from transformer_lens.model_bridge.supported_architectures.gpt2 import (
+ GPT2ArchitectureAdapter,
+ )
+
+ if not isinstance(model, TransformerBridge):
+ raise TypeError(
+ "Backward Lens supports TransformerBridge only; load GPT-2 with "
+ "TransformerBridge.boot_transformers(...)."
+ )
+ if getattr(model, "compatibility_mode", False):
+ raise ValueError(
+ "Backward Lens requires a raw TransformerBridge; compatibility mode is enabled"
+ )
+ if getattr(model, "_weights_processed", False):
+ raise ValueError(
+ "Backward Lens requires original GPT-2 weights; this Bridge processed its weights"
+ )
+ if int(model.cfg.n_devices) > 1:
+ raise ValueError(
+ "Backward Lens requires a single-device TransformerBridge because the MLP "
+ "projections, final normalization, and unembed must be co-located; "
+ f"device-map dispatch with cfg.n_devices={model.cfg.n_devices} is not supported"
+ )
+ if not isinstance(model.adapter, GPT2ArchitectureAdapter):
+ raise NotImplementedError(
+ "Backward Lens currently supports the GPT2ArchitectureAdapter only; "
+ f"got {type(model.adapter).__name__}"
+ )
+ if bool(getattr(model.cfg, "gated_mlp", False)):
+ raise NotImplementedError("Backward Lens currently requires dense, non-gated GPT-2 MLPs")
+ if model.tokenizer is None:
+ raise ValueError("Backward Lens requires a GPT-2 Bridge with a tokenizer")
+ for component in ("blocks", "ln_final", "unembed"):
+ if not hasattr(model, component):
+ raise ValueError(f"Backward Lens requires the standard {component} component")
+
+
+def _get_gpt2_mlp_projections(model: Any, layers: tuple[int, ...]) -> dict[int, tuple[Any, Any]]:
+ """Return validated live GPT-2 Conv1D input/output projection bridges."""
+ from transformers.pytorch_utils import Conv1D
+
+ from transformer_lens.hook_points import HookPoint
+ from transformer_lens.model_bridge.generalized_components import (
+ LinearBridge,
+ MLPBridge,
+ )
+
+ expected_shapes = (
+ (int(model.cfg.d_model), int(model.cfg.d_mlp)),
+ (int(model.cfg.d_mlp), int(model.cfg.d_model)),
+ )
+ projections: dict[int, tuple[Any, Any]] = {}
+ for layer in layers:
+ mlp = model.blocks[layer].mlp
+ if not isinstance(mlp, MLPBridge) or getattr(mlp, "gate", None) is not None:
+ raise ValueError(f"layer {layer} must have a dense, non-gated MLPBridge")
+ pair = (getattr(mlp, "in", None), getattr(mlp, "out", None))
+ for name, projection, expected_shape in zip(
+ ("input", "output"), pair, expected_shapes, strict=True
+ ):
+ if not isinstance(projection, LinearBridge):
+ raise ValueError(f"layer {layer} {name} projection must be a LinearBridge")
+ if not isinstance(projection.original_component, Conv1D):
+ raise ValueError(f"layer {layer} {name} projection must wrap GPT-2 Conv1D")
+ weight = projection.original_component.weight
+ if not isinstance(weight, torch.nn.Parameter):
+ raise ValueError(
+ f"layer {layer} {name} original weight must be a trainable Parameter"
+ )
+ if not weight.is_floating_point() or tuple(weight.shape) != expected_shape:
+ raise ValueError(
+ f"layer {layer} {name} weight must have shape {expected_shape} "
+ f"and floating dtype; got {tuple(weight.shape)} and {weight.dtype}"
+ )
+ if not weight.requires_grad:
+ raise ValueError(
+ f"layer {layer} {name} original weight must be a trainable Parameter"
+ )
+ if not isinstance(projection.hook_in, HookPoint) or not isinstance(
+ projection.hook_out, HookPoint
+ ):
+ raise ValueError(f"layer {layer} {name} projection is missing Bridge hook points")
+ projections[layer] = pair
+ return projections
+
+
+def _capture_once(
+ captured: dict[tuple[int, str, str], torch.Tensor], key: tuple[int, str, str]
+) -> Callable[[torch.nn.Module, tuple[Any, ...], Any], None]:
+ """Build a non-modifying PyTorch hook that records one tensor."""
+
+ def capture(_module: torch.nn.Module, _inputs: tuple[Any, ...], output: Any) -> None:
+ if key in captured:
+ raise RuntimeError(f"Backward Lens hook {key} fired more than once")
+ if not isinstance(output, torch.Tensor):
+ raise RuntimeError(f"Backward Lens hook {key} returned a non-tensor output")
+ captured[key] = output
+
+ return capture
+
+
+@contextmanager
+def _capture_projection_tensors(
+ projections: dict[int, tuple[Any, Any]],
+) -> Iterator[dict[tuple[int, str, str], torch.Tensor]]:
+ """Capture exact linear boundaries while preserving every pre-existing hook."""
+ captured: dict[tuple[int, str, str], torch.Tensor] = {}
+ handles: list[Any] = []
+ try:
+ for layer, pair in projections.items():
+ for name, projection in zip(("input", "output"), pair, strict=True):
+ input_key = (layer, name, "forward_input")
+ output_key = (layer, name, "output")
+ # Existing hook_in edits must run first so this is the actual linear input.
+ handles.append(
+ projection.hook_in.register_forward_hook(_capture_once(captured, input_key))
+ )
+ # Capture the raw linear output before any existing hook_out edits.
+ handles.append(
+ projection.hook_out.register_forward_hook(
+ _capture_once(captured, output_key), prepend=True
+ )
+ )
+ yield captured
+ finally:
+ for handle in reversed(handles):
+ handle.remove()
+
+
+def _single_batch_matrix(name: str, tensor: Any) -> Float[torch.Tensor, "position width"]:
+ if not isinstance(tensor, torch.Tensor):
+ raise RuntimeError(f"{name} must be a torch.Tensor")
+ if tensor.ndim != 3 or tensor.shape[0] != 1:
+ raise RuntimeError(
+ f"{name} must have shape [1, position, width]; got {tuple(tensor.shape)}"
+ )
+ matrix = tensor[0]
+ if not matrix.is_floating_point():
+ raise RuntimeError(f"{name} must have a floating dtype; got {matrix.dtype}")
+ return cast(Float[torch.Tensor, "position width"], matrix)
+
+
+@contextmanager
+def _preserve_model_rng(model: Any) -> Iterator[None]:
+ """Preserve CPU and every CUDA/MPS RNG used by the wrapped model."""
+ parameter_devices = {parameter.device for parameter in model.original_model.parameters()}
+ cuda_devices = sorted(
+ {
+ device.index
+ for device in parameter_devices
+ if device.type == "cuda" and device.index is not None
+ }
+ )
+ uses_mps = any(device.type == "mps" for device in parameter_devices)
+ mps_state = torch.mps.get_rng_state() if uses_mps else None
+ try:
+ with torch.random.fork_rng(devices=cuda_devices):
+ yield
+ finally:
+ if mps_state is not None:
+ torch.mps.set_rng_state(mps_state)
+
+
+def _capture_gpt2_mlp_gradient_factors(
+ model: Any,
+ prompt: str,
+ target_token: str,
+ layers: Sequence[int],
+) -> _GPT2GradientCapture:
+ """Capture exact GPT-2 MLP weight-gradient factors for one next-token loss.
+
+ The analysis performs one grad-enabled forward and exactly one
+ :func:`torch.autograd.grad` call. It does not call ``backward``, touch
+ parameter ``.grad`` buffers, change training state, or remove caller hooks.
+ """
+ if torch.is_inference_mode_enabled():
+ raise ValueError(
+ "Backward Lens cannot capture gradients inside torch.inference_mode(); "
+ "exit inference_mode before running the analysis"
+ )
+ _require_raw_gpt2_bridge(model)
+ requested_layers = _validate_requested_layers(model, layers)
+ projections = _get_gpt2_mlp_projections(model, requested_layers)
+ if not isinstance(prompt, str):
+ raise TypeError("prompt must be a string")
+ if prompt == "":
+ raise ValueError("prompt must not be empty")
+ if not isinstance(target_token, str):
+ raise TypeError("target_token must be a string")
+
+ prompt_tokens = model.to_tokens(prompt, truncate=False)
+ if prompt_tokens.ndim != 2 or prompt_tokens.shape[0] != 1 or prompt_tokens.shape[1] == 0:
+ raise ValueError("prompt must tokenize to one non-empty sequence")
+ prompt_token_count = int(prompt_tokens.shape[1])
+ context_size = int(model.cfg.n_ctx)
+ if prompt_token_count > context_size:
+ raise ValueError(
+ f"prompt token count {prompt_token_count} exceeds model context limit "
+ f"n_ctx={context_size}"
+ )
+ target_tokens = model.to_tokens(target_token, prepend_bos=False)
+ if target_tokens.ndim != 2 or tuple(target_tokens.shape) != (1, 1):
+ count = int(target_tokens.numel())
+ raise ValueError(
+ "target_token must encode to exactly one token without BOS; " f"got {count} tokens"
+ )
+ target_token_id = int(target_tokens.item())
+ input_device = next(model.original_model.parameters()).device
+ prompt_tokens = prompt_tokens.to(input_device)
+ weights = [
+ projection.original_component.weight
+ for layer in requested_layers
+ for projection in projections[layer]
+ ]
+ with _preserve_model_rng(model), torch.enable_grad():
+ with _capture_projection_tensors(projections) as captured:
+ logits = model(prompt_tokens)
+ if not isinstance(logits, torch.Tensor) or logits.ndim != 3 or logits.shape[0] != 1:
+ raise RuntimeError(
+ "GPT-2 Bridge must return logits with shape [1, position, vocab]"
+ )
+ target = torch.tensor([target_token_id], device=logits.device)
+ loss = F.cross_entropy(logits[:, -1, :], target)
+ if not bool(torch.isfinite(loss)):
+ raise ValueError("the next-token loss must be finite")
+ outputs = [
+ captured[(layer, name, "output")]
+ for layer in requested_layers
+ for name in ("input", "output")
+ ]
+ gradients = torch.autograd.grad(loss, (*outputs, *weights), allow_unused=False)
+
+ output_gradients = gradients[: len(outputs)]
+ weight_gradients = gradients[len(outputs) :]
+ layer_results = []
+ for index, layer in enumerate(requested_layers):
+ input_offset = 2 * index
+ input_factors = _build_linear_gradient_factors(
+ _single_batch_matrix(
+ f"layer {layer} input projection input",
+ captured[(layer, "input", "forward_input")],
+ ),
+ _single_batch_matrix(
+ f"layer {layer} input projection gradient", output_gradients[input_offset]
+ ),
+ weight_gradients[input_offset],
+ weight_layout="in_out",
+ )
+ output_factors = _build_linear_gradient_factors(
+ _single_batch_matrix(
+ f"layer {layer} output projection input",
+ captured[(layer, "output", "forward_input")],
+ ),
+ _single_batch_matrix(
+ f"layer {layer} output projection gradient",
+ output_gradients[input_offset + 1],
+ ),
+ weight_gradients[input_offset + 1],
+ weight_layout="in_out",
+ )
+ layer_results.append(
+ _GPT2LayerGradientFactors(
+ layer=layer,
+ input_projection=input_factors,
+ output_projection=output_factors,
+ )
+ )
+ return _GPT2GradientCapture(
+ prompt_token_ids=prompt_tokens.detach().cpu().clone(),
+ target_token_id=target_token_id,
+ loss=float(loss.detach()),
+ layers=tuple(layer_results),
+ )
+
+
+class BackwardLens:
+ """Analyze GPT-2 MLP weight gradients in the output vocabulary basis.
+
+ The analyzer accepts a fresh, raw GPT-2 :class:`TransformerBridge`. Results
+ retain no model or tokenizer reference and contain detached CPU-owned tensors.
+ Raw backward signals are loss gradients; gradient descent subtracts them.
+ """
+
+ def __init__(self, model: Any):
+ """Validate and retain the raw GPT-2 Bridge used for analyses."""
+ _require_raw_gpt2_bridge(model)
+ self._model = model
+
+ def analyze(
+ self,
+ prompt: str,
+ target_token: str,
+ layers: Sequence[int],
+ *,
+ normalized: bool = False,
+ top_k: int = DEFAULT_TOP_K,
+ return_full_logits: bool = False,
+ ) -> BackwardLensResult:
+ """Analyze one final-position, one-token target loss.
+
+ Args:
+ prompt: Non-empty unbatched prompt text.
+ target_token: Text encoding to exactly one token without BOS.
+ layers: Unique GPT-2 layer indices in desired result order.
+ normalized: Also project unit-normalized nonzero factors using the
+ Normalized Logit Lens. Raw projections are always returned.
+ top_k: Number of largest and smallest values and token ids retained
+ per matrix and position. Defaults to 10.
+ return_full_logits: Also retain full vocabulary tensors on CPU.
+ Defaults to ``False`` to keep result size bounded.
+
+ Returns:
+ Detached gradient factors, bounded vocabulary rankings, norms,
+ reconstruction errors, target metadata, and optional full logits.
+ """
+ if not isinstance(normalized, bool):
+ raise TypeError("normalized must be a bool")
+ if isinstance(top_k, bool) or not isinstance(top_k, int):
+ raise TypeError("top_k must be an integer")
+ vocabulary_size = int(self._model.cfg.d_vocab)
+ if not 1 <= top_k <= vocabulary_size:
+ raise ValueError(f"top_k must be in [1, {vocabulary_size}]; got {top_k!r}")
+ if not isinstance(return_full_logits, bool):
+ raise TypeError("return_full_logits must be a bool")
+ capture = _capture_gpt2_mlp_gradient_factors(self._model, prompt, target_token, layers)
+ layer_results: list[BackwardLensLayerResult] = []
+ absolute_errors: list[float] = []
+ relative_errors: list[float] = []
+ for layer in capture.layers:
+ input_result = _build_matrix_result(
+ self._model,
+ layer.input_projection,
+ projected_factor="forward_inputs",
+ include_normalized_logits=normalized,
+ target_token_id=capture.target_token_id,
+ top_k=top_k,
+ return_full_logits=return_full_logits,
+ )
+ output_result = _build_matrix_result(
+ self._model,
+ layer.output_projection,
+ projected_factor="output_gradients",
+ include_normalized_logits=normalized,
+ target_token_id=capture.target_token_id,
+ top_k=top_k,
+ return_full_logits=return_full_logits,
+ )
+ layer_results.append(
+ BackwardLensLayerResult(
+ layer=layer.layer,
+ input_projection=input_result,
+ output_projection=output_result,
+ )
+ )
+ absolute_errors.extend(
+ (
+ layer.input_projection.absolute_reconstruction_error,
+ layer.output_projection.absolute_reconstruction_error,
+ )
+ )
+ relative_errors.extend(
+ (
+ layer.input_projection.relative_reconstruction_error,
+ layer.output_projection.relative_reconstruction_error,
+ )
+ )
+ return BackwardLensResult(
+ prompt=prompt,
+ prompt_token_ids=capture.prompt_token_ids[0].clone(),
+ target_token=target_token,
+ target_token_id=capture.target_token_id,
+ loss=capture.loss,
+ layers=tuple(layer_results),
+ max_absolute_reconstruction_error=max(absolute_errors),
+ max_relative_reconstruction_error=max(relative_errors),
+ includes_normalized_logits=normalized,
+ includes_full_logits=return_full_logits,
+ )