Qwen3.5-4B Thinking Separability Probe
The one idea you need
Picture clipping a meter onto the model's inner wiring: from a single snapshot taken the instant it finishes writing code, the meter guesses whether that code will actually run. The test is whether making the model think first makes that reading sharper.
The question
After a small model writes code, does its own internal state reveal whether that code is correct, and does making it think first make the signal clearer?
What we found
Yes, but not for the reason you would expect. From one snapshot of internal activity, whether the model's own code is correct is readable well above a coin-flip, about 64 to 76 percent of the time. Thinking first sharpens that signal. But scrambling the thinking words into gibberish sharpens it just as much, so the boost comes from the act of thinking, not its logic.
Why it matters
If you plan to filter a small model's outputs by reading its internal confidence, the signal is real but weak: it appears only after the model generates thinking tokens, and it is never strong enough to trust as a standalone judge.
On this page
Results at a glance 3
How to read
Five conditions along the bottom: no thinking, then real and scrambled thinking at two lengths. The tall bar is how well a probe reads correctness off internal activity (higher is better); the short bar is a scrambled-label control pinned near the 50 percent coin-flip line.
Takeaway → Every thinking bar rises above no-thinking, and the two scrambled-thinking bars are the tallest of all, so content-free thinking reads correctness best.
Data table
| condition | best-layer probe AUC | shuffled-label control |
|---|---|---|
| no thinking | 0.642 | 0.514 |
| real think (512) | 0.708 | 0.482 |
| shuffled think (512) | 0.733 | 0.511 |
| real think (1024) | 0.72 | 0.456 |
| shuffled think (1024) | 0.755 | 0.52 |
Numbers from runs/probe_results.json
Technical framing
Can a linear probe read correctness off the model's own activations? — Thinking makes correctness more decodable, but shuffled thinking matches or beats real thinking - the gain is compute/scaffold, not reasoning.
How to read
The horizontal axis walks through all 33 layers from input to output; the vertical axis is how readable correctness is, higher better. Five lines: no-thinking sits lowest, while real and scrambled thinking at both lengths ride above it across the whole depth.
Takeaway → At nearly every layer the four thinking lines sit above no-thinking, and the scrambled lines match or top the real ones, so the ordering holds throughout the network.
Data table
| layer (hidden state index) | no thinking | real think (512) | shuffled think (512) | real think (1024) | shuffled think (1024) |
|---|---|---|---|---|---|
| 0 | 0.387 | 0.385 | 0.383 | 0.352 | 0.358 |
| 1 | 0.484 | 0.594 | 0.682 | 0.584 | 0.685 |
| 2 | 0.482 | 0.701 | 0.662 | 0.614 | 0.663 |
| 3 | 0.497 | 0.681 | 0.662 | 0.614 | 0.685 |
| 4 | 0.492 | 0.683 | 0.668 | 0.638 | 0.694 |
| 5 | 0.525 | 0.635 | 0.676 | 0.628 | 0.729 |
| 6 | 0.521 | 0.644 | 0.733 | 0.633 | 0.735 |
| 7 | 0.513 | 0.662 | 0.718 | 0.618 | 0.736 |
| 8 | 0.499 | 0.684 | 0.692 | 0.673 | 0.675 |
| 9 | 0.514 | 0.707 | 0.695 | 0.702 | 0.742 |
| 10 | 0.507 | 0.669 | 0.679 | 0.72 | 0.717 |
| 11 | 0.52 | 0.708 | 0.676 | 0.694 | 0.71 |
| 12 | 0.568 | 0.651 | 0.669 | 0.677 | 0.702 |
| 13 | 0.559 | 0.636 | 0.665 | 0.665 | 0.713 |
| 14 | 0.547 | 0.631 | 0.662 | 0.671 | 0.724 |
| 15 | 0.524 | 0.653 | 0.675 | 0.653 | 0.753 |
| 16 | 0.549 | 0.612 | 0.671 | 0.671 | 0.755 |
| 17 | 0.546 | 0.621 | 0.727 | 0.671 | 0.741 |
| 18 | 0.587 | 0.676 | 0.715 | 0.682 | 0.697 |
| 19 | 0.584 | 0.638 | 0.681 | 0.655 | 0.697 |
| 20 | 0.585 | 0.681 | 0.703 | 0.687 | 0.704 |
| 21 | 0.591 | 0.689 | 0.7 | 0.65 | 0.671 |
| 22 | 0.626 | 0.681 | 0.696 | 0.677 | 0.696 |
| 23 | 0.625 | 0.664 | 0.677 | 0.673 | 0.691 |
| 24 | 0.642 | 0.681 | 0.687 | 0.648 | 0.706 |
| 25 | 0.629 | 0.661 | 0.691 | 0.653 | 0.716 |
| 26 | 0.621 | 0.646 | 0.703 | 0.655 | 0.718 |
| 27 | 0.62 | 0.663 | 0.711 | 0.652 | 0.73 |
| 28 | 0.626 | 0.682 | 0.706 | 0.643 | 0.73 |
| 29 | 0.602 | 0.689 | 0.678 | 0.648 | 0.731 |
| 30 | 0.631 | 0.641 | 0.677 | 0.668 | 0.729 |
| 31 | 0.616 | 0.66 | 0.691 | 0.663 | 0.746 |
| 32 | 0.585 | 0.661 | 0.698 | 0.685 | 0.744 |
Numbers from runs/probe_results.json
Technical framing
Probe AUC by layer: shuffled thinking tracks or exceeds real thinking everywhere — Across all 33 layers, any thinking lifts decodability over no-thinking, and scrambled thinking is at least as good as coherent thinking.
How to read
Five conditions along the bottom; bar height is how well the probe ranks truly-correct code above code that passes a quick visible test but fails hidden ones. Higher is better; 50 percent means no better than guessing.
Takeaway → The no-thinking bar sits near 52 percent and is useless; thinking bars reach 60 to 68 percent, a weak but real filter that appears only after the model has thought.
Data table
| condition | visible-passer probe AUC |
|---|---|
| no thinking | 0.518 |
| real think (512) | 0.684 |
| shuffled think (512) | 0.626 |
| real think (1024) | 0.598 |
| shuffled think (1024) | 0.669 |
Numbers from runs/probe_results.json
Technical framing
Deployable spinoff: ranking true passes among visible-test passers (C2 false-pass regime) — Among candidates that already pass the visible test, the probe has weak signal (0.60-0.68) only under thinking; at no-think it is near chance.
In the author’s words from the Overview · “Results”
Best-layer probe AUC (predict full-test pass from the answer-token activation; n=100, 800/cond) (table on the experiment page). Correctness is moderately decodable from one answer-token activation (AUC 0.64–0.76 vs shuffled-label ~0.50) — "models know more than they say," novel on self-generated real code. Thinking raises decodability across essentially every layer (no_think ~0.5–0.64 → thinking ~0.67–0.75): "knows it's right better after thinking." But not via reasoning — hypothesis falsified. Shuffled thinking matches/exceeds real thinking at both budgets and across all layers. So the active ingredient is compute/scaffold/ token-presence, not coherent content — converging with the behavioral C9 shuffle finding at the representational level. … Read the full result →
Overview
Research Program
- Program:
test_time_reasoning_budget - Program question: is the native-thinking gain genuine reasoning, or compute/scaffold? And can the model's internal state predict its own correctness (attacking C2 from inside the model)?
- Prior anchors:
qwen35_4b_thinking_budget_scaling(the shuffle control showed much of the gain is compute/scaffold, and said it could not isolate the coherent-reasoning contribution);qwen35_4b_thinking_budget_controller(bounded by visible-test false-passes — C2); the corpus's synthetic hidden-state probes (qwen_readable_candidate_verifier,qwen_candidate_conditioned_trace_verifier,qwen_prefix_state_process_verifier).
Question
Does native thinking make the model's own correctness more linearly decodable from its activations? Concretely: train a linear probe on the answer-token hidden state of Qwen3.5-4B's own generated MBPP solution (labels = execution pass) and compare its per-layer AUC across no_think, real think, and shuffled-think at matched budgets. "Does it know it's right better after reasoning?"
Hypothesis
The shuffle puzzle left two possibilities. If real thinking raises probe separability beyond shuffled-think (which preserves token-count/scaffold but destroys coherent order), that is the genuine-reasoning-content signal the scaling report could not isolate — reasoning reorganizes the model's internal state toward a more decodable correctness representation. If real ≈ shuffled, then thinking's effect on internal "knowing" is also mostly compute/scaffold, reinforcing C9.
Setup
- Model: Qwen3.5-4B (frozen, bf16, sdpa, fast path enabled). 32 layers → 33 hidden states.
- Dataset: MBPP sanitized
test, first 100 tasks; k=8 sampled solutions per task per condition. - Conditions:
no_think,think_512,shuffle_512,think_1024,shuffle_1024(s1-style budget forcing on</think>; shuffle = permute the model's own thinking tokens before the answer). - Signal: the answer-token (last-token) hidden state of the model's own generated sequence (prompt + thinking + answer), extracted per layer with a clean right-padded forward pass (keeps the linear-attention recurrence uncorrupted).
- Probe: per-layer logistic regression (standardized), GroupKFold by task (no task-identity leakage), out-of-fold AUC for predicting full-test pass; bootstrap CI by resampling tasks.
- Controls: shuffled-label probe (must be ~0.5); think vs shuffle at matched budget; per-layer sweep.
- Deployable / oracle boundary: probe trained on hidden-test outcomes is a non-deployable diagnostic of decodability. The deployable angle is the false-pass test: among candidates that pass the visible test (what the controller commits), can the probe rank the true full-test passes above the C2 false-passes?
Run
Smoke (4 tasks, 2 conds): ../../.venv/bin/python scripts/run.py --smoke
Full:
HF_HUB_OFFLINE=1 PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True \
../../.venv/bin/python scripts/run.py --tasks 100 --k 8 # generate + extract activations
../../.venv/bin/python scripts/verify_probe.py # torch-free execution labels
../../.venv/bin/python analysis/probe.py # per-layer probes + figureResults
Full results in reports/report.md; figure analysis/auc_vs_layer.png. Best-layer probe AUC (predict full-test pass from the answer-token activation; n=100, 800/cond):
| condition | probe AUC | shuffled-label | visible-passer AUC |
|---|---|---|---|
| no_think | 0.642 | 0.514 | 0.518 |
| think_512 | 0.708 | 0.482 | 0.684 |
| shuffle_512 | 0.733 | 0.511 | 0.626 |
| think_1024 | 0.720 | 0.456 | 0.598 |
| shuffle_1024 | 0.755 | 0.520 | 0.669 |
- Correctness is moderately decodable from one answer-token activation (AUC 0.64–0.76 vs shuffled-label ~0.50) — "models know more than they say," novel on self-generated real code.
- Thinking raises decodability across essentially every layer (no_think ~0.5–0.64 → thinking ~0.67–0.75): "knows it's right better after thinking."
- But not via reasoning — hypothesis falsified. Shuffled thinking matches/exceeds real thinking at both budgets and across all layers. So the active ingredient is compute/scaffold/ token-presence, not coherent content — converging with the behavioral C9 shuffle finding at the representational level.
- Deployable spinoff: among visible-passers (C2 false-pass regime), the probe has weak signal under thinking (~0.60–0.68) but ~chance under no-think.
Interpretation
The cleanest evidence yet that this 4B's thinking benefit is largely not coherent reasoning — now shown at two independent levels (behavioral accuracy C9 + internal representation). Thinking makes the model more internally aware of its own correctness, but scrambled thinking does so equally. A weak verifier-free signal (probe vs C2 false-passes) appears only under thinking. Caveats: moderate AUCs, n=100 single seed, real-vs-shuffle within overlapping CIs (robust claim is the across-depth ordering), last-token probe only.
Knowledgebase Update
- Program evidence updated: yes (
research_programs/test_time_reasoning_budget/evidence.md). - Claim ledger updated: C9 extended (reasoning-vs-compute confirmed at the representational level).
Artifacts
src/probe_lib.py(generation + activation extraction),src/tasks.py(MBPP + sandbox verifier).scripts/run.py(extract),scripts/verify_probe.py(labels),analysis/probe.py(probes + figure).data/records.jsonl,data/labels.jsonl,data/tasks.json(small, in-repo).- Activations (~0.7 GB) in
large_artifacts/qwen35_4b_thinking_separability_probe/(external, gitignored; regenerable byscripts/run.py) — seereports/artifact_manifest.yaml.
Report
Rendered from reports/report.md
Summary
We probe whether Qwen3.5-4B's answer-token hidden state linearly encodes whether its own generated MBPP solution is correct, and whether thinking makes that correctness more decodable. Three results. (1) Correctness IS moderately linearly decodable from a single answer-token activation (best-layer AUC ~0.64–0.76; shuffled-label control ~0.50) — a "models know more than they say" effect, here on a self-generated real-code answer token, which prior corpus probes never touched. (2) Thinking robustly raises decodability at essentially every layer (no_think ~0.5–0.64 → thinking ~0.67–0.75): the model "knows it's right better after thinking." (3) But that increase is not coherent reasoning — shuffled thinking matches or exceeds real thinking on separability at both budgets and across all layers, refuting our pre-registered hypothesis. This converges with the behavioral shuffle finding (C9) at the representational level: thinking's benefit, behaviorally and now internally, is largely compute/scaffold/token-presence, not logical content. A modest deployable spinoff: among visible-test passers (the C2 false-pass regime), the probe has weak signal under thinking (AUC ~0.60–0.68) but ~chance under no-think.
Research Program Fit
Third experiment of test_time_reasoning_budget. It turns C9's "reasoning vs compute" debate into a measurable interpretability quantity (probe AUC by layer, think vs shuffle vs no-think) and gives an internal-signal angle on the C2 selection bottleneck. The pre-registered hypothesis — that real thinking would raise separability above shuffled thinking and thereby isolate the genuine-reasoning contribution — is falsified, which is itself the durable lesson.
Method
- Model Qwen3.5-4B frozen (bf16, sdpa, fast path). MBPP sanitized
test, 100 tasks, k=8 sampled solutions per task per condition:no_think,think_512,shuffle_512,think_1024,shuffle_1024. - Signal: the last-token hidden state of the model's own generated sequence (prompt + thinking + answer), extracted per layer (33 states: embeddings + 32 layers) via a clean right-padded forward pass (so the linear-attention recurrence is uncorrupted by padding).
- Probe: per-layer standardized logistic regression, GroupKFold by task (no task-identity leakage), out-of-fold AUC predicting full-test execution pass; bootstrap CI by resampling tasks.
- Controls: shuffled-label probe (must ≈0.5); real vs shuffled thinking at matched budget.
Results
Best-layer probe AUC for predicting full-test pass (n=100 tasks, 800 samples/condition):
| condition | base pass | best layer | probe AUC | 95% CI | shuffled-label | visible-passer AUC (n) |
|---|---|---|---|---|---|---|
| no_think | 0.77 | 24 | 0.642 | [0.55,0.74] | 0.514 | 0.518 (647) |
| think_512 | 0.85 | 11 | 0.708 | [0.65,0.77] | 0.482 | 0.684 (722) |
| shuffle_512 | 0.79 | 6 | 0.733 | [0.67,0.81] | 0.511 | 0.626 (661) |
| think_1024 | 0.85 | 10 | 0.720 | [0.61,0.81] | 0.456 | 0.598 (716) |
| shuffle_1024 | 0.83 | 16 | 0.755 | [0.68,0.81] | 0.520 | 0.669 (696) |
Per-layer AUC (every 4th layer) — the pattern is robust across depth, not a best-layer artifact:
| condition | L4 | L8 | L12 | L16 | L20 | L24 | L28 | L32 |
|---|---|---|---|---|---|---|---|---|
| no_think | 0.49 | 0.50 | 0.57 | 0.55 | 0.59 | 0.64 | 0.63 | 0.59 |
| think_512 | 0.68 | 0.68 | 0.65 | 0.61 | 0.68 | 0.68 | 0.68 | 0.66 |
| shuffle_512 | 0.67 | 0.69 | 0.67 | 0.67 | 0.70 | 0.69 | 0.71 | 0.70 |
| think_1024 | 0.64 | 0.67 | 0.68 | 0.67 | 0.69 | 0.65 | 0.64 | 0.69 |
| shuffle_1024 | 0.69 | 0.68 | 0.70 | 0.76 | 0.70 | 0.71 | 0.73 | 0.74 |
Figure: analysis/auc_vs_layer.png.
Finding 1 — correctness is moderately decodable from one answer-token activation
All conditions beat the shuffled-label control (~0.50) with best-layer AUC 0.64–0.76. So the model's residual stream linearly encodes whether its own just-written solution is correct — a "models know more than they say" effect, novel on a self-generated real-code answer token (prior corpus probes read external candidates on synthetic tasks). Decodability is highest in early–mid layers (best layers 6–16 for thinking conditions), not the final layer.
Finding 2 — thinking robustly raises decodability
Every thinking condition sits above no_think at essentially every layer (thinking ~0.67–0.75 vs no_think ~0.49–0.64). The model's correctness becomes more internally decodable once it has produced thinking tokens — it "knows it's right better after thinking," consistent across depth (so not a best-layer fluke, even though individual best-layer CIs overlap no_think's).
Finding 3 — but it is NOT coherent reasoning (hypothesis falsified)
Shuffled thinking matches or exceeds real thinking on separability at both budgets and across all layers (shuffle_512 ≥ think_512; shuffle_1024 is the single highest curve). The pre-registered hypothesis — real > shuffled would isolate genuine reasoning — is refuted. Whatever makes correctness more decodable after thinking is the presence/length/compute of the thinking region, not its coherent content. This converges with the behavioral shuffle finding (C9: behavioral shuffled-thinking reproduced much of the accuracy gain) — now mirrored at the representational level.
Controls
Shuffled-label probes give AUC 0.46–0.52 (≈ chance) in every condition → the probes are not exploiting task-identity or pipeline leakage (GroupKFold splits by task). The real-vs-shuffled comparison is the mechanism control; the consistent shuffle ≥ real ordering across depth is the load-bearing result (individual best-layer CIs overlap, so we claim "real does not exceed shuffled", not "shuffled is significantly higher").
Oracle Versus Deployable Evidence
The probe is trained on hidden-test pass labels and is a non-deployable decodability diagnostic. The deployable angle is the visible-passer column: among candidates that pass the visible test (what the budget controller commits), can the probe rank true full-test passes above the C2 false-passes? Under thinking the probe has weak-moderate signal (AUC ~0.60–0.68); under no-think it is ~chance (0.518). So an internal probe can partially flag the C2 false-passes the visible test misses — but only once the model has thought, and not strongly enough to be a standalone selector.
Interpretation
This is the cleanest evidence yet that, for this 4B on this task, native thinking's benefit is largely not coherent reasoning — the conclusion now holds at two independent levels: behavioral accuracy (C9 shuffle control) and internal representation (this probe). Thinking does make the model more internally "aware" of its own correctness, but scrambled thinking does so equally, so the active ingredient is compute/scaffold/token-presence. The result also yields a weak verifier-free signal (internal probe vs C2 false-passes) that only appears under thinking.
Limitations
- AUCs are moderate (0.64–0.76), n=100 single seed, and best-layer real-vs-shuffle differences are within overlapping CIs; the robust claim is the across-depth ordering (shuffle ≥ real, thinking > no-think), not precise magnitudes.
- Probes read only the last token; other positions/poolings (e.g. mean over the answer, or a Kadavath P(IK) probe token) could differ.
- One model, one benchmark; MBPP is coverage-limited and likely partly in pretraining (see the contamination direction in the program backlog).
Next Experiments
- Foreign-task-thinking arm (remove token-presence, not just order): does it drop separability below shuffled? If even foreign thinking holds separability up, the active ingredient is pure compute.
- Probe-position sweep (post-
</think>, mean-pooled answer, P(IK) probe token) and an MLP probe. - Combine the internal probe with the visible test as a controller signal (does it lift the controller past the 0.91 deployable / 0.93 oracle wall?).
- Replicate on a contamination-controlled / harder substrate where the no-think baseline is weaker (more headroom for a reasoning-content effect to appear, if it exists).
Artifact Manifest
See artifact_manifest.yaml. Activations (~0.7 GB) are external/regenerable; small records, labels, probe results, and the figure are in-repo.
Experiment log 5
Show the running log (5 entries)
Scaffold
Third experiment of test_time_reasoning_budget. Tests whether native thinking makes the model's own correctness more linearly decodable from its activations — the interpretability complement to the shuffle-control puzzle (C9) and an internal-signal angle on the C2 selection bottleneck.
Design / method notes
- Generation reuses the s1-style budget forcing + shuffled-thinking from the scaling experiment, but
src/probe_lib.pyreturns the FULL clean token sequence (prompt + thinking + </think> + answer) so a forward pass can read the answer-token hidden state. - The sibling experiment did not persist raw thinking tokens (only extracted code), so generations are re-run here to obtain the activations under each condition.
- Right padding for the activation forward (the sibling generation uses left padding): the qwen3_5 linear-attention recurrence is order-sensitive, so left padding would feed pad tokens into the recurrence before real tokens; right padding keeps the last-real-token state clean. Signal = per-layer hidden state at each sequence's last real token (33 states: embeddings + 32 layers).
- Probe = per-layer standardized logistic regression, GroupKFold by task_id (prevents task-identity leakage), out-of-fold AUC for full-test pass; bootstrap CI by resampling tasks; shuffled-label control must give ~0.5.
- Verification runs in a separate torch-free process (fork-safe sandbox), as in the sibling sweep.
Smoke
4 tasks x {no_think, think_1024} x k=2 validated extract -> activations (8, 33, 2560) -> verify (no_think 1.0 full, think_1024 0.75 full). Probe needs the full run's label variance.
Run notes
- First full run crashed after no_think with
CUDA driver error: device not readyattorch.stack(o.hidden_states)— stacking the full [B, 33, ~1000, 2560] tensor doubled a ~3GB allocation on the long thinking sequences (no_think survived only because its sequences are ~8× shorter). Fix: slice each layer's last-token vector BEFORE stacking (the giant tensor never exists) + activation batch 8. Re-run completed all 5 conditions (~1.8h).
Results (see reports/report.md)
Behavioral verify (full-pass): no_think 0.769, think_512 0.851, shuffle_512 0.791, think_1024 0.848, shuffle_1024 0.830 (real > shuffle at both budgets, replicating the sweep).
Probe (best-layer AUC predicting full-pass from the answer-token activation): no_think 0.642, think_512 0.708, shuffle_512 0.733, think_1024 0.720, shuffle_1024 0.755; shuffled-label control ~0.50. Three findings: (1) correctness is moderately decodable (AUC 0.64–0.76); (2) thinking raises decodability at every layer; (3) shuffled thinking matches/exceeds real thinking → the gain is NOT coherent reasoning, falsifying the pre-registered hypothesis and converging with C9 at the representational level. Deployable spinoff: probe vs C2 false-passes (visible-passer AUC) ~0.60–0.68 under thinking, ~chance under no-think.
Figures 1
Data files 1
Result tables and metrics copied from the experiment folder — preview inline or open the raw file.
runs/probe_results.json3.8 kB
Reproduce
Smoke test
../../.venv/bin/python scripts/run.py --smokeFull run
HF_HUB_OFFLINE=1 PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True ../../.venv/bin/python scripts/run.py --tasks 100 --k 8Run steps are documented inside the experiment folder (README and scripts).
