thegovind commited on
Commit
97b4e95
·
verified ·
1 Parent(s): 10fcfd8

Split the longest sentences and fit the install command on screen (from 338f312)

Browse files
README.md CHANGED
@@ -24,8 +24,8 @@ The first line below installs `uv`, which runs the lab's Python scripts with the
24
  ```bash
25
  curl -LsSf https://astral.sh/uv/install.sh | sh
26
  source $HOME/.local/bin/env
27
- uvx --from huggingface_hub hf download thegovind/weight-space-programming --repo-type space \
28
- --include "code/*" --local-dir ~/weight-space-programming
29
  cd ~/weight-space-programming/code
30
  ```
31
 
 
24
  ```bash
25
  curl -LsSf https://astral.sh/uv/install.sh | sh
26
  source $HOME/.local/bin/env
27
+ uvx --from huggingface_hub hf download thegovind/weight-space-programming \
28
+ --repo-type space --include "code/*" --local-dir ~/weight-space-programming
29
  cd ~/weight-space-programming/code
30
  ```
31
 
code/QUICKSTART.md CHANGED
@@ -7,8 +7,8 @@
7
  ```bash
8
  curl -LsSf https://astral.sh/uv/install.sh | sh
9
  source $HOME/.local/bin/env
10
- uvx --from huggingface_hub hf download thegovind/weight-space-programming --repo-type space \
11
- --include "code/*" --local-dir ~/weight-space-programming
12
  cd ~/weight-space-programming/code
13
  ```
14
 
@@ -54,7 +54,7 @@ ssh sampler
54
  . /nvme/wsp-lab/code/scripts/env.sh && cd /nvme/wsp-lab/code
55
  python labs/lab1_diff.py
56
  ```
57
- - **What to look at:** Confirm that only 2 of 488 tensors (arrays of weights) differ (`layers.15` and `layers.19` `mlp.down_proj.weight`), all changes sit in 64 columns per layer, the first singular value holds `0.999994` and `0.999991` of the squared change, and the fitted $\alpha$ (edit strength) is `6.0003` and `6.0002`. These paired numbers refer to the two layers in the order listed. Read [`labs/lab1_diff.md`](labs/lab1_diff.md) and inspect `results/figures/lab1_diff.png`.
58
 
59
  ### Step 4: Rebuild the edit from the agent's 8 texts (20 minutes)
60
  - **Where:** the same `sampler` terminal (1 GPU, about 1 minute). Run this before Step 5 because Lab 6 reads which way $u$ (the direction from productive toward looping text in the model's internal state) points from `results/lab3/rebuild.json`.
@@ -78,7 +78,7 @@ CUDA_VISIBLE_DEVICES=7 python labs/lab6_steering.py --parts 3,4 # optional
78
  CUDA_VISIBLE_DEVICES=7 python labs/lab7_side_effects.py
79
  exit # back to this machine
80
  ```
81
- - **What to look at:** `p50c` and `rebuilt` raise WikiText-2 perplexity (prediction uncertainty on ordinary text, lower is better; base `20.009`) by `+0.79%` while shifting predictions 2.5 times more on looping texts than on productive ones (`0.0241` vs `0.0097`, measured by KL divergence, the change in next-token probabilities). By contrast, `a12` (a stronger edit) costs `+14.34%`, and `randdir`/`randcols` (random-direction and random-neuron controls) shift looping text no more than productive text (`randdir`: `0.0039` vs `0.0048`). Read [`labs/lab7_side_effects.md`](labs/lab7_side_effects.md) and view `results/figures/lab7_side_effects.png`.
82
 
83
  ### Step 7: Read the finished results of Labs 2, 4, 5, and 8 (30 minutes)
84
  - **Where:** This machine (no GPU; [`results/summary.md`](results/summary.md) and `results/figures/` hold all runs).
@@ -86,4 +86,10 @@ exit # back to this machine
86
  cd ~/weight-space-programming/code
87
  ls results/figures/
88
  ```
89
- - **What to look at:** Read [`labs/lab2_reproduce.md`](labs/lab2_reproduce.md) (`lab2_benchmarks.png`, `lab2_lengths.png`), [`labs/lab4_dose.md`](labs/lab4_dose.md) (`lab4_dose.png`, `lab4_controls.png`, including why $\alpha = -4$ gains `+7.6` points by breaking loops), [`labs/lab5_decoding.md`](labs/lab5_decoding.md) (`lab5_decoding.png`, where turning thinking off reaches `52.1%` at 2,270 tokens), and [`labs/lab8_capstone.md`](labs/lab8_capstone.md) (`lab8_loop_onset.png`, `lab8_data_needed.png`, `lab8_one_answer.png`, where recipe B built from 225 of the model's own loops reaches `58.2%` on `dev256`). To re-run any sheet's GPU jobs, use the move-aside rule in [`README.md`](README.md).
 
 
 
 
 
 
 
7
  ```bash
8
  curl -LsSf https://astral.sh/uv/install.sh | sh
9
  source $HOME/.local/bin/env
10
+ uvx --from huggingface_hub hf download thegovind/weight-space-programming \
11
+ --repo-type space --include "code/*" --local-dir ~/weight-space-programming
12
  cd ~/weight-space-programming/code
13
  ```
14
 
 
54
  . /nvme/wsp-lab/code/scripts/env.sh && cd /nvme/wsp-lab/code
55
  python labs/lab1_diff.py
56
  ```
57
+ - **What to look at:** Confirm that only 2 of 488 tensors (arrays of weights) differ (`layers.15` and `layers.19` `mlp.down_proj.weight`), and that all changes sit in 64 columns per layer. The first singular value holds `0.999994` and `0.999991` of the squared change, and the fitted $\alpha$ (edit strength) is `6.0003` and `6.0002`. These paired numbers refer to the two layers in the order listed. Read [`labs/lab1_diff.md`](labs/lab1_diff.md) and inspect `results/figures/lab1_diff.png`.
58
 
59
  ### Step 4: Rebuild the edit from the agent's 8 texts (20 minutes)
60
  - **Where:** the same `sampler` terminal (1 GPU, about 1 minute). Run this before Step 5 because Lab 6 reads which way $u$ (the direction from productive toward looping text in the model's internal state) points from `results/lab3/rebuild.json`.
 
78
  CUDA_VISIBLE_DEVICES=7 python labs/lab7_side_effects.py
79
  exit # back to this machine
80
  ```
81
+ - **What to look at:** `p50c` and `rebuilt` raise WikiText-2 perplexity (prediction uncertainty on ordinary text, where lower is better and the base is `20.009`) by `+0.79%`. At the same time, they shift predictions 2.5 times more on looping texts than on productive ones (`0.0241` vs `0.0097`, measured by KL divergence, the change in next-token probabilities). By contrast, `a12` (a stronger edit) costs `+14.34%`. The random-direction and random-neuron controls `randdir`/`randcols` shift looping text no more than productive text (`randdir`: `0.0039` vs `0.0048`). Read [`labs/lab7_side_effects.md`](labs/lab7_side_effects.md) and view `results/figures/lab7_side_effects.png`.
82
 
83
  ### Step 7: Read the finished results of Labs 2, 4, 5, and 8 (30 minutes)
84
  - **Where:** This machine (no GPU; [`results/summary.md`](results/summary.md) and `results/figures/` hold all runs).
 
86
  cd ~/weight-space-programming/code
87
  ls results/figures/
88
  ```
89
+ - **What to look at:** Read these four lab pages and their figures:
90
+ - [`labs/lab2_reproduce.md`](labs/lab2_reproduce.md) (`lab2_benchmarks.png`, `lab2_lengths.png`).
91
+ - [`labs/lab4_dose.md`](labs/lab4_dose.md) (`lab4_dose.png`, `lab4_controls.png`, including why $\alpha = -4$ gains `+7.6` points by breaking loops).
92
+ - [`labs/lab5_decoding.md`](labs/lab5_decoding.md) (`lab5_decoding.png`, where turning thinking off reaches `52.1%` at 2,270 tokens).
93
+ - [`labs/lab8_capstone.md`](labs/lab8_capstone.md) (`lab8_loop_onset.png`, `lab8_data_needed.png`, `lab8_one_answer.png`, where recipe B built from 225 of the model's own loops reaches `58.2%` on `dev256`).
94
+
95
+ To re-run any sheet's GPU jobs, use the move-aside rule in [`README.md`](README.md).
code/README.md CHANGED
@@ -2,7 +2,12 @@
2
 
3
  **Big thing:** These nine hands-on labs reproduce and take apart Experiment 8 of the MIT CSAIL blog post "Sparks of Weight-Space Programming" on two 8-GPU A100 machines. In that experiment, an AI agent fixed a small language model (Qwen3.5-0.8B) that got stuck repeating itself on math problems by editing 131,072 of its 873,438,784 weights with arithmetic, without training.
4
 
5
- **Why it matters:** Most model fixes change the prompt or sampling settings, or run gradient descent (training that adjusts weights to reduce errors). Here you inspect the `131,072` edited weights (`130,188` change after bf16 rounding, which stores numbers at reduced precision), rebuild the edit from 8 short texts in one minute, prove that the weight edit equals an input-driven steering vector (a change to the model's internal numbers whose strength depends on the input), and build your own edit from the model's failures.
 
 
 
 
 
6
 
7
  ## The story
8
 
@@ -14,7 +19,11 @@ With thinking on, the model writes a `<think>...</think>` scratchpad before its
14
 
15
  The agent wrote 4 productive and 4 looping scratchpads and compared the model's activations on them. That contrast gave a unit direction vector $u$: a list of 1,024 numbers whose overall length is 1, pointing from productive text toward looping text. It then applied a rank-one projection edit (one column vector times one row vector) in blocks 15 and 19. Each block's MLP (multi-layer perceptron, the block's second half) has an output matrix `down_proj` of shape 1,024 by 3,584. Each column is the 1,024-number vector one neuron adds to the residual stream (the running list of numbers each token carries from block to block) per unit of activation. The agent picked the 64 neurons that push hardest along $u$ during loops and updated their columns $W_S$ via $W' = W - \alpha u (u^T W_S)$ with strength $\alpha = 6$. That edit touches $2 \times 64 \times 1,024 = 131,072$ weights (`p50c`, from the 50-pass run folder `runs/p50c`).
16
 
17
- On three unseen benchmarks, the paper reported that `p50c` raised MATH-500 accuracy from 7.9% to 48.1% (answers cut at the cap fell from 93.0% to 33.05%, mean tokens from 30,868 to 22,037), GSM8K from 13.84% to 67.1% (cut 87.5% to 7.24%, mean tokens 29,289 to 11,993), and IFEval instruction-following accuracy from 21.0% to 62.3% (cut 74.9% to 2.2%, mean tokens 25,296 to 4,241).
 
 
 
 
18
 
19
  ## What we found
20
 
@@ -142,7 +151,7 @@ Then run the plan; `python labs/peek.py quick/base` reads the new run and `pytho
142
  - `cut at the cap %`: Percentage of answers that hit the token limit (32,768 by default) without finishing.
143
  - `mean tokens`: Average generated tokens per answer.
144
  - `correct when finished %`: Accuracy among answers that finished before the token limit (97.5% to 100% for the unedited model on math benchmarks, showing its main failure is not finishing).
145
- - `cut answers ending in repetition %`: Percentage of cap-cut answers ending in repetition: either a word-for-word loop (a block of words repeated at least 3 times in a row) or looser circling (at least half of the 4-word phrase positions in the last 200 words hold a phrase repeated 3 or more times there; see `results/summary.md`).
146
  - `gain vs baseline (pp)`: Accuracy change in percentage points versus the paired baseline on the same problems, plus or minus paired SE (`dev/*` against `dev/base`, `dev/p50c+nothink` against `dev/base+nothink`, `bench/p50c/X` against `bench/base/X`, and `quick/*` against `quick/base`).
147
  - `rescued / lost problems`: `rescued` counts problems where the run got at least one answer right and the baseline got none; `lost` counts the reverse.
148
 
 
2
 
3
  **Big thing:** These nine hands-on labs reproduce and take apart Experiment 8 of the MIT CSAIL blog post "Sparks of Weight-Space Programming" on two 8-GPU A100 machines. In that experiment, an AI agent fixed a small language model (Qwen3.5-0.8B) that got stuck repeating itself on math problems by editing 131,072 of its 873,438,784 weights with arithmetic, without training.
4
 
5
+ **Why it matters:** Most model fixes change the prompt or sampling settings, or run gradient descent (training that adjusts weights to reduce errors). Here you do four things:
6
+
7
+ - Inspect the `131,072` edited weights (`130,188` change after bf16 rounding, which stores numbers at reduced precision).
8
+ - Rebuild the edit from 8 short texts in one minute.
9
+ - Prove that the weight edit equals an input-driven steering vector (a change to the model's internal numbers whose strength depends on the input).
10
+ - Build your own edit from the model's failures.
11
 
12
  ## The story
13
 
 
19
 
20
  The agent wrote 4 productive and 4 looping scratchpads and compared the model's activations on them. That contrast gave a unit direction vector $u$: a list of 1,024 numbers whose overall length is 1, pointing from productive text toward looping text. It then applied a rank-one projection edit (one column vector times one row vector) in blocks 15 and 19. Each block's MLP (multi-layer perceptron, the block's second half) has an output matrix `down_proj` of shape 1,024 by 3,584. Each column is the 1,024-number vector one neuron adds to the residual stream (the running list of numbers each token carries from block to block) per unit of activation. The agent picked the 64 neurons that push hardest along $u$ during loops and updated their columns $W_S$ via $W' = W - \alpha u (u^T W_S)$ with strength $\alpha = 6$. That edit touches $2 \times 64 \times 1,024 = 131,072$ weights (`p50c`, from the 50-pass run folder `runs/p50c`).
21
 
22
+ On three unseen benchmarks, the paper reported these results for `p50c`:
23
+
24
+ - **MATH-500:** Accuracy rose from 7.9% to 48.1%. Answers cut at the cap fell from 93.0% to 33.05%, and mean tokens fell from 30,868 to 22,037.
25
+ - **GSM8K:** Accuracy rose from 13.84% to 67.1%. Answers cut at the cap fell from 87.5% to 7.24%, and mean tokens fell from 29,289 to 11,993.
26
+ - **IFEval:** Instruction-following accuracy rose from 21.0% to 62.3%. Answers cut at the cap fell from 74.9% to 2.2%, and mean tokens fell from 25,296 to 4,241.
27
 
28
  ## What we found
29
 
 
151
  - `cut at the cap %`: Percentage of answers that hit the token limit (32,768 by default) without finishing.
152
  - `mean tokens`: Average generated tokens per answer.
153
  - `correct when finished %`: Accuracy among answers that finished before the token limit (97.5% to 100% for the unedited model on math benchmarks, showing its main failure is not finishing).
154
+ - `cut answers ending in repetition %`: Percentage of cap-cut answers ending in repetition. An answer counts if it ends in a word-for-word loop (a block of words repeated at least 3 times in a row) or in looser circling. Looser circling means at least half of the 4-word phrase positions in the last 200 words hold a phrase repeated 3 or more times there (see `results/summary.md`).
155
  - `gain vs baseline (pp)`: Accuracy change in percentage points versus the paired baseline on the same problems, plus or minus paired SE (`dev/*` against `dev/base`, `dev/p50c+nothink` against `dev/base+nothink`, `bench/p50c/X` against `bench/base/X`, and `quick/*` against `quick/base`).
156
  - `rescued / lost problems`: `rescued` counts problems where the run got at least one answer right and the baseline got none; `lost` counts the reverse.
157
 
code/labs/lab3_rebuild.md CHANGED
@@ -209,7 +209,7 @@ CUDA_VISIBLE_DEVICES=7 python labs/lab7_side_effects.py --models rebuilt rebuilt
209
  - **What we saw:** Blocks 15 and 19 still lead in MLP growth (`[(15, 0.201), (19, 0.188), (22, 0.167), (14, 0.163)]`), while the direction and neuron list get rougher:
210
  - Layer 15: `cos(rebuilt u, released u) = +0.82157` (`0.822`), `42/64` neurons match, and the top 8 / 32 / 64 neurons hold `[0.144, 0.278, 0.386]` (`14.4% / 27.8% / 38.6%`) of the positive score.
211
  - Layer 19: `cos(rebuilt u, released u) = -0.78384` (`-0.784`), `31/64` neurons match, and the top 8 / 32 / 64 neurons hold `[0.219, 0.348, 0.419]` (`21.9% / 34.8% / 41.9%`).
212
- - On `dev256`, `dev/rebuilt-pairs2` reaches `62.3% +/- 2.7` accuracy (`+50.2 +/- 2.6` points over `dev/base`, `129` rescued, `0` lost), matching the 4-pair rebuild (`61.5%`). What changes is how the edit works and how hard it pushes: more answers hit the 32,768-token cap (`25.2%` vs `17.6%`), and more cut answers end in repetition (`74.4%` vs `32.2%`, or `68.2%` vs `15.6%` for verbatim loops; across all 512 answers in `results/lab3/endings-tries.json`, `86` are cut while thinking and `74` close out of a loop, vs `55` and `118` for `rebuilt` in `results/lab3/endings.json`). In Lab 7, it disturbs WikiText-2 less (perplexity `+0.43%` vs `+0.79%`, KL `0.0194` vs `0.0333`) and is less selective on the 8 texts (looping KL over productive KL is `0.0109 / 0.0075 = 1.46`, vs `0.0238 / 0.0096 = 2.48` for `rebuilt`).
213
 
214
  2. **Average neuron activations over 36 tokens instead of 24 (`--windows 36 36`, folder `results/lab3/try-windows36-36/`).**
215
  - **Predict first:** The agent used 36 tokens for the stream (`H_WIN = 36`) and 24 tokens for the neuron scores (`A_WIN = 24`). If you set `A_WIN` to `36`, will `u` change, and will the extra 12 tokens shift the 64 chosen neurons enough to affect `dev256`?
@@ -229,7 +229,7 @@ CUDA_VISIBLE_DEVICES=7 python labs/lab7_side_effects.py --models rebuilt rebuilt
229
  CUDA_VISIBLE_DEVICES="" python scripts/build_models.py --variants results/lab3/try-layers15-19-21/variant.json
230
  python scripts/run_jobs.py results/lab3/try-layers15-19-21/plan.json --gpus 7 --only dev/rebuilt-layers15-19-21
231
  ```
232
- - **What we saw:** Layers 15 and 19 match the main rebuild (`64/64` neurons in both). At layer 21, scores are flatter: the top 8 / 32 / 64 neurons hold `[0.173, 0.292, 0.371]` (`17.3% / 29.2% / 37.1%`) of the positive score (top 12: `[2, 1, 11, 99, 14, 85, 9, 109, 168, 335, 212, 169]`), and the edit's magnitude is `5.8%` of layer 21's `down_proj` matrix magnitude (the square root of the sum of squared entries, not the fraction of entries changed). On `dev256`, `dev/rebuilt-layers15-19-21` scores `61.3% +/- 2.8` (`+49.2 +/- 2.6` points, `21.1%` cut, `122` rescued, `0` lost, with `3` answers stopping mid-thinking before `</think>`), showing no gain over the 2-layer rebuild (`61.5%`, difference `-0.2 +/- 1.9` points). In Lab 7, WikiText-2 perplexity rises by `+1.49%` (nearly double the 2-layer rebuild's `+0.79%`) and KL climbs from `0.0333` to `0.0394`.
233
 
234
  The main rebuild and the three tries line up as follows across Lab 3, `dev256`, and Lab 7:
235
 
 
209
  - **What we saw:** Blocks 15 and 19 still lead in MLP growth (`[(15, 0.201), (19, 0.188), (22, 0.167), (14, 0.163)]`), while the direction and neuron list get rougher:
210
  - Layer 15: `cos(rebuilt u, released u) = +0.82157` (`0.822`), `42/64` neurons match, and the top 8 / 32 / 64 neurons hold `[0.144, 0.278, 0.386]` (`14.4% / 27.8% / 38.6%`) of the positive score.
211
  - Layer 19: `cos(rebuilt u, released u) = -0.78384` (`-0.784`), `31/64` neurons match, and the top 8 / 32 / 64 neurons hold `[0.219, 0.348, 0.419]` (`21.9% / 34.8% / 41.9%`).
212
+ - On `dev256`, `dev/rebuilt-pairs2` reaches `62.3% +/- 2.7` accuracy (`+50.2 +/- 2.6` points over `dev/base`, `129` rescued, `0` lost), matching the 4-pair rebuild (`61.5%`). What changes is how the edit works and how hard it pushes. More answers hit the 32,768-token cap (`25.2%` vs `17.6%`). More cut answers also end in repetition (`74.4%` vs `32.2%`, or `68.2%` vs `15.6%` for verbatim loops). Across all 512 answers in `results/lab3/endings-tries.json`, `86` answers from `rebuilt-pairs2` are cut while thinking and `74` close out of a loop, vs `55` and `118` for `rebuilt` in `results/lab3/endings.json`. In Lab 7, `rebuilt-pairs2` disturbs WikiText-2 less (perplexity `+0.43%` vs `+0.79%`, KL `0.0194` vs `0.0333`) and is less selective on the 8 texts (looping KL over productive KL is `0.0109 / 0.0075 = 1.46`, vs `0.0238 / 0.0096 = 2.48` for `rebuilt`).
213
 
214
  2. **Average neuron activations over 36 tokens instead of 24 (`--windows 36 36`, folder `results/lab3/try-windows36-36/`).**
215
  - **Predict first:** The agent used 36 tokens for the stream (`H_WIN = 36`) and 24 tokens for the neuron scores (`A_WIN = 24`). If you set `A_WIN` to `36`, will `u` change, and will the extra 12 tokens shift the 64 chosen neurons enough to affect `dev256`?
 
229
  CUDA_VISIBLE_DEVICES="" python scripts/build_models.py --variants results/lab3/try-layers15-19-21/variant.json
230
  python scripts/run_jobs.py results/lab3/try-layers15-19-21/plan.json --gpus 7 --only dev/rebuilt-layers15-19-21
231
  ```
232
+ - **What we saw:** Layers 15 and 19 match the main rebuild (`64/64` neurons in both). At layer 21, scores are flatter. The top 8 / 32 / 64 neurons hold `[0.173, 0.292, 0.371]` (`17.3% / 29.2% / 37.1%`) of the positive score (top 12: `[2, 1, 11, 99, 14, 85, 9, 109, 168, 335, 212, 169]`). The edit's magnitude is `5.8%` of layer 21's `down_proj` matrix magnitude (the square root of the sum of squared entries, not the fraction of entries changed). On `dev256`, `dev/rebuilt-layers15-19-21` scores `61.3% +/- 2.8` (`+49.2 +/- 2.6` points, `21.1%` cut, `122` rescued, `0` lost, with `3` answers stopping mid-thinking before `</think>`), showing no gain over the 2-layer rebuild (`61.5%`, difference `-0.2 +/- 1.9` points). In Lab 7, WikiText-2 perplexity rises by `+1.49%` (nearly double the 2-layer rebuild's `+0.79%`) and KL climbs from `0.0333` to `0.0394`.
233
 
234
  The main rebuild and the three tries line up as follows across Lab 3, `dev256`, and Lab 7:
235
 
code/labs/lab4_dose.md CHANGED
@@ -117,7 +117,7 @@ Every row below tests the same 64 neurons per layer and loop direction `u` at la
117
 
118
  ![Four panels against edit strength alpha from -4 to 12: accuracy, percent of answers cut at the token cap, mean answer length, and WikiText perplexity change.](../results/figures/lab4_dose.png)
119
 
120
- How to read `lab4_dose.png`: the four panels plot accuracy, percentage of answers cut at the 32,768-token cap, mean answer length (thousand tokens), and Lab 7's WikiText perplexity change across `alpha = -4, 0, 1, 2, 4, 6, 8, 12`. The dose sweep is blue in the first three panels and red in the fourth. The three open markers to the right of `alpha = 6` (a red square at `x = 6.35` for `rebuilt`, and purple triangles at `x = 6.7` and `x = 7.05` for Lab 8's `capA-a6` and `capB-a6`) also use `alpha = 6`; the plot shifts them right of `6` so their error bars do not overlap `p50c`.
121
 
122
  ### 2. Which parts of the edit matter (layers, neuron subset, and random controls)
123
 
 
117
 
118
  ![Four panels against edit strength alpha from -4 to 12: accuracy, percent of answers cut at the token cap, mean answer length, and WikiText perplexity change.](../results/figures/lab4_dose.png)
119
 
120
+ How to read `lab4_dose.png`: the four panels plot accuracy, percentage of answers cut at the 32,768-token cap, mean answer length (thousand tokens), and Lab 7's WikiText perplexity change across `alpha = -4, 0, 1, 2, 4, 6, 8, 12`. The dose sweep is blue in the first three panels and red in the fourth. The three open markers to the right of `alpha = 6` also use `alpha = 6`. They are a red square at `x = 6.35` for `rebuilt`, and purple triangles at `x = 6.7` and `x = 7.05` for Lab 8's `capA-a6` and `capB-a6`. The plot shifts them right of `6` so their error bars do not overlap `p50c`.
121
 
122
  ### 2. Which parts of the edit matter (layers, neuron subset, and random controls)
123
 
code/labs/lab7_side_effects.md CHANGED
@@ -138,7 +138,7 @@ flowchart TD
138
  R2 --> RO2["Unselective shift:<br/>KL looping 0.0038 vs productive 0.0045"]
139
  ```
140
 
141
- KL has no sign: it measures how far predictions move, not which way. `a-4` pushes the 64 neurons toward loops instead of away, yet it is selective too (looping texts move 2.6 times more than productive ones) because it acts in the same place as `p50c`: where those 64 neurons push hard along $u$, which happens on looping text. Selectivity shows where an edit acts; Lab 4's accuracy runs show whether it helps or hurts.
142
 
143
  Second, trace the WikiText-2 perplexity dose curve across $\alpha$ (`a-4`, `a1`, `a2`, `a4`, `p50c` at $\alpha = 6$, `a8`, `a12`) in the left panel of `lab7_side_effects.png`:
144
  - Setting $\alpha$ to `-4` (`a-4`, pushing 5 times harder in the loop direction) raises perplexity by `+5.39%` (`21.088`).
 
138
  R2 --> RO2["Unselective shift:<br/>KL looping 0.0038 vs productive 0.0045"]
139
  ```
140
 
141
+ KL has no sign: it measures how far predictions move, not which way. `a-4` pushes the 64 neurons toward loops instead of away, yet it is selective too (looping texts move 2.6 times more than productive ones). It is selective because it acts in the same place as `p50c`: where those 64 neurons push hard along $u$, which happens on looping text. Selectivity shows where an edit acts; Lab 4's accuracy runs show whether it helps or hurts.
142
 
143
  Second, trace the WikiText-2 perplexity dose curve across $\alpha$ (`a-4`, `a1`, `a2`, `a4`, `p50c` at $\alpha = 6$, `a8`, `a12`) in the left panel of `lab7_side_effects.png`:
144
  - Setting $\alpha$ to `-4` (`a-4`, pushing 5 times harder in the loop direction) raises perplexity by `+5.39%` (`21.088`).
code/labs/lab8_capstone.md CHANGED
@@ -196,7 +196,7 @@ In `lab8_loop_onset.png` and Lab 6 Part 3, hundreds of tokens before exact repet
196
  Window A (`-68` to `-32` tokens before onset) sits inside that late drift zone, where the stream has already moved about halfway to the loop. When recipe A computes `stream(in the loop) - stream(just before the loop)`, it subtracts out the early drift and keeps mostly the final jump into verbatim repetition. Three results reflect this:
197
 
198
  1. **The raw gap vector is less than half as long:** Recipe A's $\|\overline{\Delta h}\|$ is `0.689` vs `1.418` for recipe B at layer 15 (`1.037` vs `2.234` at layer 19). Because part of the loop signal cancels out, background token differences between the two windows make up a larger share of the normalized unit vector $u_A$, lowering its cosine with the released $u$ (`0.722` vs `0.782`) and its layer-15 neuron overlap (`38` vs `42`).
199
- 2. **Smaller neuron activation gaps:** Because loop neurons are already firing harder in the last 68 pre-loop tokens, subtracting window A's activations shrinks $\overline{\Delta a}_{24}$ on the neurons that build up the drift (the `score` of neuron 11 at layer 19 drops from `0.210` in B to `0.121` in A, and neuron 46 at layer 15 drops from `0.0261` to `0.0120`).
200
  3. **Fewer loops versus more escapes on `dev256`:** Both edits escape a loop about equally often (`141` for recipe A, `145` for recipe B), while recipe B nearly doubles normal endings (`259` vs `133`). A likely reading, which the endings counts fit but do not prove, is that recipe B's direction includes the pre-loop drift, so its edit pushes back before repetition starts, whereas recipe A seems to act mainly once a loop is underway.
201
 
202
  ### 3. What split-half stability and the data-needed curve measure
@@ -249,7 +249,7 @@ We ran two experiment flags on `sampler` to test how the capstone edit behaves w
249
  | `capB-a6` (well before, main) | `225` | `6` | `0.782 / 0.773` | `0.988 / 0.989` | `42 / 28` |
250
  | `capB-max-samples-16` (well before, 16 loops) | `16` | `6` | `0.687 / 0.682` | `0.828 / 0.864` | `34 / 20` |
251
 
252
- With 16 loops from 9 GSM8K problems, recipes A and B still agree (`0.873` at layer 15 and `0.902` at layer 19, vs `0.951` and `0.959` on 225 loops), neuron 11 of layer 19 still ranks first in both, and both directions separate the agent's 8 texts in all 4 pairs (`+0.69, +0.83, +1.67, +1.10` for recipe B at layer 15).
253
 
254
  ### 2. Evaluation on `dev256`, endings, and breakdown by source
255
 
@@ -287,7 +287,7 @@ Using 16 loops instead of 225 costs recipe A `-31.6 +/- 3.4` points on GSM8K and
287
  Two lessons from these runs:
288
 
289
  1. **Turning up $\alpha$ did not help either recipe.** Raising $\alpha$ from `6` to `8` leaves `capA` flat (`-0.2 +/- 2.3` points) and drops `capB` by `-3.7 +/- 1.6` points, while WikiText-2 perplexity damage grows from `+0.51%` and `+0.92%` at $\alpha = 6$ to `+1.61%` and `+2.76%` at $\alpha = 8$. Even the released edit gains nothing at $\alpha = 8$ (`-0.8 +/- 1.6` points, perplexity `+3.33%`). Raising $\alpha$ scales the whole update, including any part of $u$ that points the wrong way. With one stronger setting per recipe, we cannot tell whether a partly wrong direction or a strength already past its peak explains the drop.
290
- 2. **A few loops are enough for recipe B ("well before the loop"), but not for recipe A ("just before the loop").** From 16 loops (9 problems), recipe B still reaches `53.7%` accuracy (`+41.6` points over the unedited model), `4.5 +/- 1.8` points below 225-loop `capB-a6` (`58.2%`), even though its direction is noisier (two halves of 8 loops agree at cosine `0.828` and `0.864`, against `0.988` and `0.989` with halves of 112 and 113 loops) and sits further from the released $u$. The direction table above lists its cosines with the released direction for both layers. Recipe A on the same 16 loops collapses to `17.6%` (`-25.4 +/- 2.3` points vs `capA-a6`), and `82.6%` of its answers are still cut. Its direction is the noisiest of all: two halves of 8 loops agree at only `0.632` and `0.622` at layers 15 and 19, and the direction table above lists its lower cosines with the released $u$. Its WikiText KL is `0.0081` (vs `0.0204` for `capB-max-samples-16` and `0.0178` for `capA-a6`), but [Lab 4](lab4_dose.md) and [Lab 7](lab7_side_effects.md) suggest that KL size does not explain the accuracy gap: random-direction control `randdir` (same 64 neurons, same size of weight change, random direction) has WikiText KL `0.0046` and gains `+2.3` points, while applying the agent's direction to all 3,584 neurons (`all2`) at $\alpha = 2$ has almost the same KL as `capA-max-samples-16` (`0.0078` vs `0.0081`) and gains `+37.3` points. This suggests that, in this setup, the gain depends on where the change points instead of how far it shifts WikiText predictions. Recipe B on 16 loops beats recipe A on 225 loops by `+10.7 +/- 2.1` points (paired), suggesting that window choice matters more than loop count here. One caveat: `--max-samples 16` takes the first 16 loops in file order (all from 9 GSM8K problems). In `data_needed` (`results/lab8/capstone.json`), random 16-loop draws agreed better with the released $u$ at layers `15 / 19` (`0.666 / 0.683` for A and `0.757 / 0.746` for B, vs `0.574 / 0.596` and `0.687 / 0.682` on the first 16), so that narrow sample may explain part of the drop. We did not build or test edits from random 16-loop sets. Data quality, window placement, and sample count trade off against one another.
291
 
292
  ## Check yourself
293
 
 
196
  Window A (`-68` to `-32` tokens before onset) sits inside that late drift zone, where the stream has already moved about halfway to the loop. When recipe A computes `stream(in the loop) - stream(just before the loop)`, it subtracts out the early drift and keeps mostly the final jump into verbatim repetition. Three results reflect this:
197
 
198
  1. **The raw gap vector is less than half as long:** Recipe A's $\|\overline{\Delta h}\|$ is `0.689` vs `1.418` for recipe B at layer 15 (`1.037` vs `2.234` at layer 19). Because part of the loop signal cancels out, background token differences between the two windows make up a larger share of the normalized unit vector $u_A$, lowering its cosine with the released $u$ (`0.722` vs `0.782`) and its layer-15 neuron overlap (`38` vs `42`).
199
+ 2. **Smaller neuron activation gaps:** Because loop neurons are already firing harder in the last 68 pre-loop tokens, subtracting window A's activations shrinks $\overline{\Delta a}_{24}$ on the neurons that build up the drift. For example, the `score` of neuron 11 at layer 19 drops from `0.210` in B to `0.121` in A, and neuron 46 at layer 15 drops from `0.0261` to `0.0120`.
200
  3. **Fewer loops versus more escapes on `dev256`:** Both edits escape a loop about equally often (`141` for recipe A, `145` for recipe B), while recipe B nearly doubles normal endings (`259` vs `133`). A likely reading, which the endings counts fit but do not prove, is that recipe B's direction includes the pre-loop drift, so its edit pushes back before repetition starts, whereas recipe A seems to act mainly once a loop is underway.
201
 
202
  ### 3. What split-half stability and the data-needed curve measure
 
249
  | `capB-a6` (well before, main) | `225` | `6` | `0.782 / 0.773` | `0.988 / 0.989` | `42 / 28` |
250
  | `capB-max-samples-16` (well before, 16 loops) | `16` | `6` | `0.687 / 0.682` | `0.828 / 0.864` | `34 / 20` |
251
 
252
+ With 16 loops from 9 GSM8K problems, the directions of recipes A and B still agree (`0.873` cosine at layer 15 and `0.902` at layer 19, vs `0.951` and `0.959` on 225 loops). Neuron 11 of layer 19 still ranks first in both recipes. Both directions also separate the agent's 8 texts in all 4 pairs (`+0.69, +0.83, +1.67, +1.10` for recipe B at layer 15).
253
 
254
  ### 2. Evaluation on `dev256`, endings, and breakdown by source
255
 
 
287
  Two lessons from these runs:
288
 
289
  1. **Turning up $\alpha$ did not help either recipe.** Raising $\alpha$ from `6` to `8` leaves `capA` flat (`-0.2 +/- 2.3` points) and drops `capB` by `-3.7 +/- 1.6` points, while WikiText-2 perplexity damage grows from `+0.51%` and `+0.92%` at $\alpha = 6$ to `+1.61%` and `+2.76%` at $\alpha = 8$. Even the released edit gains nothing at $\alpha = 8$ (`-0.8 +/- 1.6` points, perplexity `+3.33%`). Raising $\alpha$ scales the whole update, including any part of $u$ that points the wrong way. With one stronger setting per recipe, we cannot tell whether a partly wrong direction or a strength already past its peak explains the drop.
290
+ 2. **A few loops are enough for recipe B ("well before the loop"), but not for recipe A ("just before the loop").** From 16 loops (9 problems), recipe B still reaches `53.7%` accuracy (`+41.6` points over the unedited model), `4.5 +/- 1.8` points below 225-loop `capB-a6` (`58.2%`). It reaches that accuracy even though its direction is noisier and sits further from the released $u$. In a split-half check, two halves of 8 loops agree at cosine `0.828` and `0.864`, against `0.988` and `0.989` with halves of 112 and 113 loops. The `capB-max-samples-16` row in the direction table above gives the cosines with the released direction for both layers. Recipe A on the same 16 loops collapses to `17.6%` (`-25.4 +/- 2.3` points vs `capA-a6`), and `82.6%` of its answers are still cut. Its direction is the noisiest of all: two halves of 8 loops agree at only `0.632` and `0.622` at layers 15 and 19, and the direction table above lists its lower cosines with the released $u$. Its WikiText KL is `0.0081` (vs `0.0204` for `capB-max-samples-16` and `0.0178` for `capA-a6`), but [Lab 4](lab4_dose.md) and [Lab 7](lab7_side_effects.md) suggest that KL size does not explain the accuracy gap. The random-direction control `randdir` (same 64 neurons, same size of weight change, random direction) has WikiText KL `0.0046` and gains `+2.3` points. Applying the agent's direction to all 3,584 neurons (`all2`) at $\alpha = 2$ has almost the same KL as `capA-max-samples-16` (`0.0078` vs `0.0081`) and gains `+37.3` points. This suggests that, in this setup, the gain depends on where the change points instead of how far it shifts WikiText predictions. Recipe B on 16 loops beats recipe A on 225 loops by `+10.7 +/- 2.1` points (paired), suggesting that window choice matters more than loop count here. One caveat: `--max-samples 16` takes the first 16 loops in file order (all from 9 GSM8K problems). In `data_needed` (`results/lab8/capstone.json`), random 16-loop draws agreed better with the released $u$ at layers `15 / 19` (`0.666 / 0.683` for A and `0.757 / 0.746` for B, vs `0.574 / 0.596` and `0.687 / 0.682` on the first 16), so that narrow sample may explain part of the drop. We did not build or test edits from random 16-loop sets. Data quality, window placement, and sample count trade off against one another.
291
 
292
  ## Check yourself
293