README: TL;DR with pairwise contrasts (fixed nested code fences)
Browse files
README.md
CHANGED
|
@@ -12,52 +12,55 @@ language:
|
|
| 12 |
|
| 13 |
# Compositional-generalization checkpoints (recall-then-assemble, Qwen3-4B-Base)
|
| 14 |
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
|
|
|
| 20 |
|
| 21 |
```python
|
| 22 |
from transformers import AutoModelForCausalLM, AutoTokenizer
|
| 23 |
import torch
|
| 24 |
-
repo = "Physicsru/compgen-checkpoints"
|
| 25 |
-
sub = "sft-eco-s1" # any folder name from the table below
|
| 26 |
tok = AutoTokenizer.from_pretrained(repo, subfolder=sub)
|
| 27 |
model = AutoModelForCausalLM.from_pretrained(repo, subfolder=sub, torch_dtype=torch.float32)
|
| 28 |
```
|
| 29 |
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
A library of 25 string operators with opaque names `func_0` β¦ `func_24` (e.g. `func_3` = sort the
|
| 33 |
-
characters, `func_24` = a backtracking palindrome transform with an unused `depth` parameter). The model
|
| 34 |
-
first learns every operator **as an atomic skill** (closed-book: given `def main_solution(x): return
|
| 35 |
-
func_3(x)` and an input, recall the body of `func_3` and write a program). Then it is trained on
|
| 36 |
-
**compositions** (`func_5(func_3(func_1(x, 2)), 'ab')`) built **only from the 13 train operators**. The
|
| 37 |
-
12 **held-out operators** are never composed in any training data. The test question is whether the
|
| 38 |
-
model can compose the held-out operators anyway. The answer format is *recall-then-assemble* (RA):
|
| 39 |
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
```
|
| 43 |
-
|
| 44 |
-
```
|
| 45 |
-
|
| 46 |
-
```
|
| 47 |
-
|
| 48 |
-
```
|
| 49 |
-
|
| 50 |
-
```
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
```
|
|
|
|
|
|
|
|
|
|
| 54 |
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
(
|
| 59 |
-
|
| 60 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 61 |
|
| 62 |
## Lineage
|
| 63 |
|
|
@@ -67,59 +70,56 @@ Qwen3-4B-Base
|
|
| 67 |
ββ stage 1.5 "closed-book": 20k depth-1 atomic tasks over all 25 ops + 12k depth-2..4 TRAIN-op
|
| 68 |
compositions, prose + one code block (no RA format) β stage15b-init
|
| 69 |
ββ RA bootstrap SFT cells (2 epochs, batch 128, LR 2e-5, seed 1) β sft-*
|
| 70 |
-
β all cells share the SAME 10,000 atomic tasks (400 per op, all 25 ops)
|
| 71 |
-
β
|
| 72 |
-
β composition rows are added
|
| 73 |
ββ (from sft-eco-s1) GRPO, KL 0.01 to the init, 100 steps β rl-*
|
| 74 |
```
|
| 75 |
|
| 76 |
## Checkpoints
|
| 77 |
|
| 78 |
-
| folder | init | atomic side (10k single-op tasks) | composition side | RL pool | steps | held-out numbers |
|
| 79 |
-
|---|---|---|---|---|---|---|
|
| 80 |
-
| `stage15b-init` | stage 1 | 20k closed-book depth-1 rows, prose + one code block | 12k depth-2..4 train-op comps (same format) | β | 500 | d4 / d8 = 0.03 / 0.00 (no RA format yet) |
|
| 81 |
-
| `sft-d1-s1` | stage15b-init | **single-task**: one op per answer | **none** | β | 152 | 0.00 / 0.00 |
|
| 82 |
-
| `sft-v1-s1` | stage15b-init | single-task | 15,979 mixed-structure train-op comps, depth 2-4 | β | 400 | 0.53Β±0.15 / 0.09Β±0.05 (3 seeds; this seed 0.75 / 0.15) |
|
| 83 |
-
| `sft-c1-s1` | stage15b-init | **co-occurrence groups**: 1-4 independent single-op tasks in one answer (all ops) | **none** | β | 58 | 0.66Β±0.14 / 0.08Β±0.04 |
|
| 84 |
-
| `sft-eco-s1` ("E-co") | stage15b-init | co-occurrence groups | the same 15,979 comps | β | 308 | 0.97Β±0.02 / 0.73Β±0.15 (this seed 0.98 / 0.83);
|
| 85 |
-
| `sft-c4-s1` | stage15b-init | co-occurrence groups | 12,452 mixed comps, **depth 2 only** | β | 252 | 0.70Β±0.03 / 0.12Β±0.05 |
|
| 86 |
-
| `sft-c4b-s1` | stage15b-init | co-occurrence groups | 12,436 mixed comps, **depth 2-4** (same count as c4) | β | 252 | 0.90Β±0.04 / 0.62Β±0.13 |
|
| 87 |
-
| `sft-matched-isolated-s1` | stage15b-init | per step: 48 atomic tasks as 48 single-task rows | per step: 76 comps (same stream as grouped) | β | 400 | 0.65Β±0.08 / 0.16Β±0.02 (3 paired seeds) |
|
| 88 |
-
| `sft-matched-grouped-s1` | stage15b-init | per step: the SAME 48 atomic tasks packed into 20 grouped rows | the same 76 comps | β | 400 | 0.93Β±0.03 / 0.47Β±0.04 |
|
| 89 |
-
| `rl-r1a-step100` | sft-eco-s1 | β | β | 1:1 mix of train-op serial chains d10-20 and all-op multi-task atomic prompts (widths 1-12) | 100 |
|
| 90 |
-
| `rl-r1b-step100` | sft-eco-s1 | β | β | same pool, different seed | 100 | 0.94 / 0.97 / 0.89;
|
| 91 |
-
| `rl-mda-step5` | sft-eco-s1 | β | β | **mixed-depth pool**: chains + prompts holding one deep train-op chain task followed by 1-2 long-literal atomic tasks over all ops | 5 | 0.95 / 0.92 / 0.82;
|
| 92 |
-
| `rl-mda-step50` | sft-eco-s1 | β | β | same run | 50 | 0.91 / 0.63 / 0.57;
|
| 93 |
-
| `rl-mda-step100` | sft-eco-s1 | β | β | same run | 100 | 0.97 / 0.97 / 0.93;
|
| 94 |
-
| `rl-mdb-step100` | sft-eco-s1 | β | β | mixed-depth pool, second replicate | 100 | 0.99 / 0.98 / 0.95;
|
| 95 |
-
|
| 96 |
-
"
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
## What each
|
| 102 |
-
|
| 103 |
-
|
| 104 |
-
|
| 105 |
-
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
|
| 111 |
-
|
| 112 |
-
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
|
| 117 |
-
|
| 118 |
-
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
which are teacher-forced prefixes usable as fixed inputs across checkpoints); the RL reward never sees the
|
| 122 |
-
error in a legal (held-out-free) context, so RL acts through rewarded correct samples.
|
| 123 |
|
| 124 |
## Evaluation inputs (`eval/`)
|
| 125 |
|
|
@@ -134,13 +134,11 @@ error in a legal (held-out-free) context, so RL acts through rewarded correct sa
|
|
| 134 |
| `probe_1f.parquet` | 2,048 | builtin-method argument tails in front of the op's own argument |
|
| 135 |
| `probe_1g.parquet` | 1,280 | long literal (8-200 chars) as the op's first argument |
|
| 136 |
|
| 137 |
-
Rows are in the verl code-execution format: `prompt` (chat messages), `reward_model.ground_truth`
|
| 138 |
-
|
| 139 |
-
condition). Greedy decoding, 3,072 new tokens, was used for every number above.
|
| 140 |
|
| 141 |
## Provenance
|
| 142 |
|
| 143 |
-
Every number
|
| 144 |
RESULT, C1βC5 CAUSAL TABLE, MATCHED SFT, DEEP CHAINS, Mixed-depth arm RESULT, PROBES) to a job id, a
|
| 145 |
-
sweep directory and a CI/classification report; 3-seed bands are mean Β± sd over trainer seeds 1 / 7 / 123.
|
| 146 |
-
Checkpoints marked *pending* in the table are not yet uploaded (storage-quota decision pending).
|
|
|
|
| 12 |
|
| 13 |
# Compositional-generalization checkpoints (recall-then-assemble, Qwen3-4B-Base)
|
| 14 |
|
| 15 |
+
## TL;DR
|
| 16 |
+
|
| 17 |
+
15 checkpoints of Qwen3-4B-Base from **one controlled study of whether a model can compose skills it has
|
| 18 |
+
only ever seen in isolation**. Every checkpoint is one cell of that study; cells differ in exactly one
|
| 19 |
+
training variable, so pairs of folders isolate one effect each. One subfolder = one complete HF model
|
| 20 |
+
directory (fp32 `model.safetensors` β 16 GB, tokenizer, chat template).
|
| 21 |
|
| 22 |
```python
|
| 23 |
from transformers import AutoModelForCausalLM, AutoTokenizer
|
| 24 |
import torch
|
| 25 |
+
repo, sub = "Physicsru/compgen-checkpoints", "sft-eco-s1" # any folder from the table below
|
|
|
|
| 26 |
tok = AutoTokenizer.from_pretrained(repo, subfolder=sub)
|
| 27 |
model = AutoModelForCausalLM.from_pretrained(repo, subfolder=sub, torch_dtype=torch.float32)
|
| 28 |
```
|
| 29 |
|
| 30 |
+
**Which two folders compare what** (held-out compositional accuracy at depth 4 / depth 8 unless stated):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 31 |
|
| 32 |
+
| contrast | without | with | effect |
|
| 33 |
+
|---|---|---|---|
|
| 34 |
+
| **Co-occurrence atomic data** (several independent single-skill tasks in one prompt/answer, width 2-4) β cleanest version: identical task stream and steps | `sft-matched-isolated-s1` | `sft-matched-grouped-s1` | 0.65 / 0.16 β 0.93 / 0.47 |
|
| 35 |
+
| **Co-occurrence atomic data** β the paper's two models (same compositions; E-co has fewer rows) | `sft-v1-s1` | `sft-eco-s1` | 0.53 / 0.09 β 0.97 / 0.73 |
|
| 36 |
+
| **Composition demos (depth 2-4, train skills only)**, atomics single-task | `sft-d1-s1` | `sft-v1-s1` | 0.00 / 0.00 β 0.53 / 0.09 |
|
| 37 |
+
| **Composition demos**, atomics in co-occurrence groups | `sft-c1-s1` | `sft-eco-s1` | 0.66 / 0.08 β 0.97 / 0.73 |
|
| 38 |
+
| **Depth of the demos** (depth-2 only vs depth 2-4, same row count) | `sft-c4-s1` | `sft-c4b-s1` | 0.70 / 0.12 β 0.90 / 0.62 |
|
| 39 |
+
| **RL** (GRPO on train-skill chains + atomic prompts; held-out skills never composed) β good outcome | `sft-eco-s1` | `rl-mdb-step100` | held-out chains d20 0.50 β 0.95 |
|
| 40 |
+
| **RL** β drifted outcome (one held-out skill loses a parameter) | `sft-eco-s1` | `rl-r1a-step100` | d20 0.50 β 0.61; `func_24` arity error 25% |
|
| 41 |
+
| **Seed only** (same RL pool, same init) | `rl-r1a-step100` | `rl-r1b-step100` | d20 0.61 vs 0.89; arity error 25% vs 1% |
|
| 42 |
+
| **Same RL run over time** (drift switches on, then off) | `rl-mda-step5` β `rl-mda-step50` | β `rl-mda-step100` | arity error 6% β 44% β 0.3%; d20 0.82 β 0.57 β 0.93 |
|
| 43 |
+
| **The recall-then-assemble format itself** | `stage15b-init` | any `sft-*` | 0.03 / 0.00 β β¦ |
|
| 44 |
+
|
| 45 |
+
The four SFT cells `sft-d1-s1`, `sft-v1-s1`, `sft-c1-s1`, `sft-eco-s1` form a 2Γ2 (co-occurrence no/yes Γ
|
| 46 |
+
demos no/yes); all SFT cells start from `stage15b-init`; all RL runs start from `sft-eco-s1`.
|
| 47 |
+
|
| 48 |
+
## The task
|
| 49 |
|
| 50 |
+
A library of 25 string operators with opaque names `func_0` β¦ `func_24` (e.g. `func_3` = sort the
|
| 51 |
+
characters; `func_24` = a backtracking palindrome transform with a semantically unused `depth` parameter).
|
| 52 |
+
The model first learns every operator **as an atomic skill** (closed-book: given `def main_solution(x):
|
| 53 |
+
return func_3(x)` and an input, recall the body of `func_3` and write a program). It is then trained on
|
| 54 |
+
**compositions** (`func_5(func_3(func_1(x, 2)), 'ab')`) built **only from the 13 train operators**; the 12
|
| 55 |
+
**held-out operators** are never composed in any training data. The test asks the model to compose the
|
| 56 |
+
held-out operators. The answer format is *recall-then-assemble* (RA): one `Recall func_N: <gloss>` block
|
| 57 |
+
with the definition per operator, then one `Assemble:` block with all definitions plus `main_solution`.
|
| 58 |
+
|
| 59 |
+
Metrics: **held-out d4 / d8** = program accuracy on held-out-operator programs of expression depth 4 / 8
|
| 60 |
+
(256 per depth, `eval/heldout_trees_d1-8.parquet`); **chains d20** = pure nesting chains f1(f2(β¦f20(x)))
|
| 61 |
+
over held-out operators (`eval/heldout_chains_d1-20.parquet`); **arity error** = fraction of `Recall
|
| 62 |
+
func_24` blocks that drop the second parameter (`def func_24(s):`), the single failure that separates good
|
| 63 |
+
and bad RL outcomes. Greedy decoding, 3,072 new tokens.
|
| 64 |
|
| 65 |
## Lineage
|
| 66 |
|
|
|
|
| 70 |
ββ stage 1.5 "closed-book": 20k depth-1 atomic tasks over all 25 ops + 12k depth-2..4 TRAIN-op
|
| 71 |
compositions, prose + one code block (no RA format) β stage15b-init
|
| 72 |
ββ RA bootstrap SFT cells (2 epochs, batch 128, LR 2e-5, seed 1) β sft-*
|
| 73 |
+
β all cells share the SAME 10,000 atomic tasks (400 per op, all 25 ops) and differ in
|
| 74 |
+
β (a) how atomic tasks are packed into answers and (b) which composition rows are added
|
|
|
|
| 75 |
ββ (from sft-eco-s1) GRPO, KL 0.01 to the init, 100 steps β rl-*
|
| 76 |
```
|
| 77 |
|
| 78 |
## Checkpoints
|
| 79 |
|
| 80 |
+
| folder | init | atomic side (10k single-op tasks) | composition side | RL pool | steps | held-out numbers |
|
| 81 |
+
|---|---|---|---|---|---|---|
|
| 82 |
+
| `stage15b-init` | stage 1 | 20k closed-book depth-1 rows, prose + one code block | 12k depth-2..4 train-op comps (same format) | β | 500 | d4 / d8 = 0.03 / 0.00 (no RA format yet) |
|
| 83 |
+
| `sft-d1-s1` | stage15b-init | **single-task**: one op per answer | **none** | β | 152 | 0.00 / 0.00 |
|
| 84 |
+
| `sft-v1-s1` | stage15b-init | single-task | 15,979 mixed-structure train-op comps, depth 2-4 | β | 400 | 0.53Β±0.15 / 0.09Β±0.05 (3 seeds; this seed 0.75 / 0.15) |
|
| 85 |
+
| `sft-c1-s1` | stage15b-init | **co-occurrence groups**: 1-4 independent single-op tasks in one answer (all ops) | **none** | β | 58 | 0.66Β±0.14 / 0.08Β±0.04 |
|
| 86 |
+
| `sft-eco-s1` ("E-co") | stage15b-init | co-occurrence groups | the same 15,979 comps | β | 308 | 0.97Β±0.02 / 0.73Β±0.15 (this seed 0.98 / 0.83); chains d20 0.50 |
|
| 87 |
+
| `sft-c4-s1` | stage15b-init | co-occurrence groups | 12,452 mixed comps, **depth 2 only** | β | 252 | 0.70Β±0.03 / 0.12Β±0.05 |
|
| 88 |
+
| `sft-c4b-s1` | stage15b-init | co-occurrence groups | 12,436 mixed comps, **depth 2-4** (same count as c4) | β | 252 | 0.90Β±0.04 / 0.62Β±0.13 |
|
| 89 |
+
| `sft-matched-isolated-s1` | stage15b-init | per step: 48 atomic tasks as 48 single-task rows | per step: 76 comps (same stream as grouped) | β | 400 | 0.65Β±0.08 / 0.16Β±0.02 (3 paired seeds) |
|
| 90 |
+
| `sft-matched-grouped-s1` | stage15b-init | per step: the SAME 48 atomic tasks packed into 20 grouped rows | the same 76 comps | β | 400 | 0.93Β±0.03 / 0.47Β±0.04 |
|
| 91 |
+
| `rl-r1a-step100` | sft-eco-s1 | β | β | 1:1 mix of train-op serial chains d10-20 and all-op multi-task atomic prompts (widths 1-12) | 100 | chains d8/d12/d20 0.85 / 0.63 / 0.61; arity error 226/903 = 25% |
|
| 92 |
+
| `rl-r1b-step100` | sft-eco-s1 | β | β | same pool, different seed | 100 | 0.94 / 0.97 / 0.89; 9/903 = 1% |
|
| 93 |
+
| `rl-mda-step5` | sft-eco-s1 | β | β | **mixed-depth pool**: chains + prompts holding one deep train-op chain task followed by 1-2 long-literal atomic tasks over all ops | 5 | 0.95 / 0.92 / 0.82; 57/903 = 6% |
|
| 94 |
+
| `rl-mda-step50` | sft-eco-s1 | β | β | same run | 50 | 0.91 / 0.63 / 0.57; 396/903 = **44%** |
|
| 95 |
+
| `rl-mda-step100` | sft-eco-s1 | β | β | same run | 100 | 0.97 / 0.97 / 0.93; 3/903 = 0.3% |
|
| 96 |
+
| `rl-mdb-step100` | sft-eco-s1 | β | β | mixed-depth pool, second replicate | 100 | 0.99 / 0.98 / 0.95; 33/903 = 3.7% |
|
| 97 |
+
|
| 98 |
+
"Mixed-structure comps" = train-op compositions whose expression trees mix unary nesting, binary operators
|
| 99 |
+
and literals (the benchmark's native generator). "Co-occurrence groups" put several *independent* atomic
|
| 100 |
+
tasks into one prompt/answer so each definition is recalled next to others (no data flow between them).
|
| 101 |
+
Held-out operators appear in every cell only as depth-1 atomic tasks. All steps: batch 128; SFT 2 epochs.
|
| 102 |
+
|
| 103 |
+
## What each contrast shows (for choosing an analysis)
|
| 104 |
+
|
| 105 |
+
- **Co-occurrence** (`isolated` vs `grouped`, `v1` vs `eco`): the failure of the "without" model is a
|
| 106 |
+
*chimera* β a held-out name written with a train operator's body (1,102 of 1,175 wrong bodies in v1).
|
| 107 |
+
Decomposed inference (each helper recalled in its own forward pass, then assembled mechanically) scores
|
| 108 |
+
1.00 for v1, so the whole gap is nameβdefinition retrieval under multi-definition load, not missing
|
| 109 |
+
knowledge. In the matched pair the gap opens from step 100.
|
| 110 |
+
- **Composition demos** (`d1` vs `v1`, `c1` vs `eco`): without co-occurrence the demos are what makes any
|
| 111 |
+
multi-helper program possible (d1 never writes one); with co-occurrence the model already composes at
|
| 112 |
+
mid depth without a single demo (c1 0.66) and the demos buy depth (d8 0.08 β 0.73). Demo *diversity*
|
| 113 |
+
matters (c4 vs c4b), demo *volume* does not (2k vs 12k depth-2 demos: 0.77 vs 0.70).
|
| 114 |
+
- **RL** (`eco` vs `mdb` / `r1a`, `r1a` vs `r1b`, `mda` over time): RL on train-operator chains lifts deep
|
| 115 |
+
serial execution for every operator (d20 0.50 β 0.9+), but in some seeds one held-out operator
|
| 116 |
+
(`func_24`, whose dropped parameter is semantically inert) loses its second parameter when its call is
|
| 117 |
+
nested among other library calls. The drift is latent in the SFT init (E-co writes `func_24(s)` in
|
| 118 |
+
0 / 5 / 18% of blocks at nameβargument distance <40 / 40-150 / 150+ chars), tracks the number of other
|
| 119 |
+
library calls' argument tails between the name and the own argument, is not triggered by builtin-method
|
| 120 |
+
tails, long literals, definition load or a preceding chain (probe families 1b/1d/1f/1g in `eval/`), and
|
| 121 |
+
reverses inside one run (`mda` 44% β 0.3%). KL 0.01 keeps RL weights close to `sft-eco-s1`, so
|
| 122 |
+
weight-difference analyses between `eco` and any `rl-*` folder, or between `mda` steps, are meaningful.
|
|
|
|
|
|
|
| 123 |
|
| 124 |
## Evaluation inputs (`eval/`)
|
| 125 |
|
|
|
|
| 134 |
| `probe_1f.parquet` | 2,048 | builtin-method argument tails in front of the op's own argument |
|
| 135 |
| `probe_1g.parquet` | 1,280 | long literal (8-200 chars) as the op's first argument |
|
| 136 |
|
| 137 |
+
Rows are in the verl code-execution format: `prompt` (chat messages), `reward_model.ground_truth` (JSON
|
| 138 |
+
with `ref_code`, `ref_input`, `ref_output`), `extra_info` (depth, k = distinct ops, probe condition).
|
|
|
|
| 139 |
|
| 140 |
## Provenance
|
| 141 |
|
| 142 |
+
Every number is traceable in the project ledger `verl/analysis/RESULTS_PROVENANCE.md` (sections MAIN
|
| 143 |
RESULT, C1βC5 CAUSAL TABLE, MATCHED SFT, DEEP CHAINS, Mixed-depth arm RESULT, PROBES) to a job id, a
|
| 144 |
+
sweep directory and a CI / classification report; 3-seed bands are mean Β± sd over trainer seeds 1 / 7 / 123.
|
|
|