File size: 6,127 Bytes
014b14c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# mathcompose — two ≤4B math models that demonstrate the generator–verifier gap

**Thesis:** you can't make a 1.5B model *out-reason* a frontier model, but you can make a small
**specialist** win on the *easy side of the generator–verifier asymmetry* — and you can **measure the
asymmetry itself** with two small models that compose.

- **Model V — a generative process verifier.** Given a problem and a step-by-step solution, it emits
  a paragraph-by-paragraph critique ending in `\boxed{k}` (0-based index of the first wrong step, or
  `-1` if all correct). Evaluated on **ProcessBench** (objective harmonic-mean F1; target: beat
  GPT-4o's ~61.9) with **PRMBench** as the adversarial robustness set.
- **Model G — a step-by-step solution generator.** Distilled from a frontier teacher and filtered so
  only answer-correct traces survive.
- **The headline:** V reranks G's samples (V-weighted majority / best-of-n). We report the recovered
  **generator–verifier gap** (`oracle pass@n − majority`) at ≤4B — the Weaver headroom result, but
  ours.

Every core metric is an **objective checker** (step-label F1, boxed-answer equivalence) — **no
LLM-judge**, so there is no judge bias to argue about.

Both models share **one base** (`Qwen/Qwen2.5-Math-1.5B-Instruct`, apache-2.0) and **one training
path** (a generative verifier is just SFT), which is what makes a two-model build tractable.

---

## Why these choices (grounded in `notes/`)
- `notes/research-small-vs-large-math.md` finds the **only** clean sub-4B "beats GPT-4o" precedent is
  process verification (GenPRM-1.5B on ProcessBench) → **V is the primary model**.
- The generator–verifier asymmetry is "the key lever" → **G + composition** turn two models into one
  coherent demonstration.
- `notes/brainlift.md`: distill the *process* not the label, data quality over quantity, eval before
  training → the whole pipeline follows this.
- Verified constraints baked in: base context is **4096 tokens**; `trl 1.7.1` has **no PRMTrainer**
  (so V is generative SFT, not a discriminative PRM); transformers 5.x renamed `max_seq_length →
  max_length` and `torch_dtype → dtype`.

## Layout
```
configs/            base.yaml + verifier_v.yaml + generator_g.yaml (extends base)
src/mathcompose/
  common/           chat prompts (ProcessBench critic format), \boxed grading, config, io
  teachers/         pluggable Anthropic/OpenAI teacher (+ offline DummyTeacher)
  datagen/          PRM800K parsing, teacher critique synthesis, answer-filtered CoT, dedup
  data/             V output schema + dataset builders (CLI)
  eval/             ProcessBench, PRMBench, MATH, composition, runners, run.py (CLI)
  train/            shared QLoRA SFT (train.py --task {v,g}) + colab_train.ipynb
  infer/            demo.py (incl. base-vs-tuned side-by-side)
tests/              CPU smoke suite (26 tests)   scripts/smoke_all.sh
```

## Quickstart

### 0. Prove the harness on CPU (no GPU, no key)
```bash
pip install -e .
./scripts/smoke_all.sh            # fast logic tests
./scripts/smoke_all.sh --full     # + tiny-model train/eval + HF dataset probes
```

### 1. Build the datasets (needs a teacher key)
The default teacher is the **promptlens gateway** (OpenAI-compatible). Copy
`.env.example``.env` and set `TFY_API_KEY=tfy-...` (auto-loaded). Verify with
`python scripts/check_teacher.py`. (Use `--teacher openai|anthropic` for native
providers instead.)
```bash
cp .env.example .env && $EDITOR .env      # set TFY_API_KEY
# Model V: PRM800K first-error labels + teacher-synthesized critiques (labels stay authoritative)
python -m mathcompose.data.build_verifier_dataset --prm800k data/raw/prm800k/phase2_train.jsonl \
    --teacher promptlens --limit 15000
# Model G: distill CoT, keep only answer-correct traces
python -m mathcompose.data.build_generator_dataset --source AI-MO/NuminaMath-CoT \
    --teacher promptlens --limit 8000
```
Contamination against ProcessBench/MATH-500 is enforced automatically (`--no-dedup` to disable).

### 2. Train (GPU — free Colab T4 works; see `src/mathcompose/train/colab_train.ipynb`)
```bash
python -m mathcompose.train.train --task v --config configs/verifier_v.yaml
python -m mathcompose.train.train --task g --config configs/generator_g.yaml
```

### 3. Evaluate (objective, base vs tuned) + the composition
```bash
python -m mathcompose.eval.run processbench --tag base   --maj-k 1
python -m mathcompose.eval.run processbench --adapter runs/verifier_v --tag tuned --maj-k 8
python -m mathcompose.eval.run prmbench     --adapter runs/verifier_v --tag tuned
python -m mathcompose.eval.run math         --adapter runs/generator_g --tag tuned
python -m mathcompose.eval.run compose --gen-adapter runs/generator_g --ver-adapter runs/verifier_v \
    --dataset Maxwell-Jia/AIME_2024 --split train --problem-field Problem --answer-field Answer
python -m mathcompose.eval.run report        # -> results/RESULTS.md
```

### 4. Demo (for the video)
```bash
python -m mathcompose.infer.demo --task v --adapter runs/verifier_v --compare \
    --problem "..." --steps "step 0" "step 1 (wrong)"
```

## What runs where
| Piece | Where | Needs |
|---|---|---|
| Harness + smoke tests | this repo, CPU | nothing |
| Data generation | anywhere | a teacher API key (Anthropic/OpenAI) |
| QLoRA training | Colab/Modal/RunPod GPU | a CUDA GPU (free T4 ok) |
| Publishing datasets/models | — | your HF token |
| Demo video | — | you record; script in the plan |

## Honest framing (from the research note)
"Beats frontier" means **beats GPT-4o**, not o1-mini/o3. Sub-4B evidence is thin (most precedents are
7B) — expect a step down. The real, defensible claim is the **base-vs-tuned delta** and the
**composition lift**, both measured objectively. PRMBench is reported alongside ProcessBench as the
independent robustness check.

## License / attribution
Code: MIT. Training data derives from **PRM800K** (MIT, OpenAI) and **NuminaMath-CoT** (apache-2.0);
evals use **ProcessBench**, **PRMBench**, **MATH-500**, **AIME-2024** (all apache-2.0). Attribute
these in any published dataset/model card.