Language models write out their working when they solve a math problem, and some of those steps are just wrong. This is a small study around one question: while the model is writing a step, do its hidden states already "know" whether that step is correct — enough that a cheap linear probe can read it off?
Short answer: mostly yes, and the signal lives in the hidden states specifically — not in attention patterns, not in output confidence. Mean-pooling the hidden states over a step beats using the last token, and it's the only feature set that still works on a dataset the probe never trained on.
I generated step-by-step solutions with Qwen2.5-0.5B-Instruct (greedy decoding, a structured Step N: format), then labeled each step correct or incorrect with a process reward model — ThinkPRM-1.5B — prompted as a strict examiner so it catches a broken step early instead of rubber-stamping the whole trace.
From every step I pulled five kinds of features and trained a plain logistic-regression probe on each, to see which ones actually carry the error signal:
Probes train on GSM8K, and I test on held-out GSM8K and on AQuA — the AQuA number is the one I actually care about, since it tells you whether the probe learned something about reasoning or just something about GSM8K.
| Features | Dim | GSM8K (val) AUC / Acc | AQuA (OOD) AUC / Acc |
|---|---|---|---|
| Hidden states, last token | 4480 | 0.683 / 0.639 | 0.598 / 0.643 |
| Hidden states, mean-pooled | 3584 | 0.745 / 0.687 | 0.634 / 0.583 |
| Attention only | 4 | 0.500 / 0.543 | 0.500 / 0.302 |
| Logits only | 3 | 0.534 / 0.549 | 0.466 / 0.447 |
| All combined | 8071 | 0.719 / 0.650 | 0.612 / 0.651 |
Step N: regex, which won't line up perfectly with the model's real thought boundaries — that leaks some noise into the extracted states.Things I'd try next: probing individual attention heads instead of aggregate stats, non-linear probes, and larger models to see whether the error representation gets sharper with scale.
pip install -r requirements.txt
python main_experiments.py
That generates the traces (GSM8K train ~1024, then GSM8K + AQuA test), trains all five probes, evaluates them, and writes everything to results_experiments/. Budget roughly 3–4 hours on a GPU.
Two flags worth knowing:
--debug-single-exp — runs only the first experiment, for a quick sanity check--use-existing-traces — skips trace generation and reuses saved traces, so you can iterate on features without re-running the modelOutputs in results_experiments/: per-experiment JSON (exp{N}_results.json), the traces each ran on, and all_experiments_summary.json with the combined table.
4 commits
Python
100.0%
Language models write out their working when they solve a math problem, and some of those steps are just wrong. This is a small study around one question: while the model is writing a step, do its hidden states already "know" whether that step is correct — enough that a cheap linear probe can read it off?
Short answer: mostly yes, and the signal lives in the hidden states specifically — not in attention patterns, not in output confidence. Mean-pooling the hidden states over a step beats using the last token, and it's the only feature set that still works on a dataset the probe never trained on.
I generated step-by-step solutions with Qwen2.5-0.5B-Instruct (greedy decoding, a structured Step N: format), then labeled each step correct or incorrect with a process reward model — ThinkPRM-1.5B — prompted as a strict examiner so it catches a broken step early instead of rubber-stamping the whole trace.
From every step I pulled five kinds of features and trained a plain logistic-regression probe on each, to see which ones actually carry the error signal:
Probes train on GSM8K, and I test on held-out GSM8K and on AQuA — the AQuA number is the one I actually care about, since it tells you whether the probe learned something about reasoning or just something about GSM8K.
| Features | Dim | GSM8K (val) AUC / Acc | AQuA (OOD) AUC / Acc |
|---|---|---|---|
| Hidden states, last token | 4480 | 0.683 / 0.639 | 0.598 / 0.643 |
| Hidden states, mean-pooled | 3584 | 0.745 / 0.687 | 0.634 / 0.583 |
| Attention only | 4 | 0.500 / 0.543 | 0.500 / 0.302 |
| Logits only | 3 | 0.534 / 0.549 | 0.466 / 0.447 |
| All combined | 8071 | 0.719 / 0.650 | 0.612 / 0.651 |
Step N: regex, which won't line up perfectly with the model's real thought boundaries — that leaks some noise into the extracted states.Things I'd try next: probing individual attention heads instead of aggregate stats, non-linear probes, and larger models to see whether the error representation gets sharper with scale.
pip install -r requirements.txt
python main_experiments.py
That generates the traces (GSM8K train ~1024, then GSM8K + AQuA test), trains all five probes, evaluates them, and writes everything to results_experiments/. Budget roughly 3–4 hours on a GPU.
Two flags worth knowing:
--debug-single-exp — runs only the first experiment, for a quick sanity check--use-existing-traces — skips trace generation and reuses saved traces, so you can iterate on features without re-running the modelOutputs in results_experiments/: per-experiment JSON (exp{N}_results.json), the traces each ran on, and all_experiments_summary.json with the combined table.
4 commits
Python
100.0%