Skip to content

K2-Think UHead offline best-of-N on MBPP+ (medium/low budgets)#257

Open
smirnovlad wants to merge 12 commits into
mainfrom
exp/k2think-uhead-mbpp-offline-bon
Open

K2-Think UHead offline best-of-N on MBPP+ (medium/low budgets)#257
smirnovlad wants to merge 12 commits into
mainfrom
exp/k2think-uhead-mbpp-offline-bon

Conversation

@smirnovlad

Copy link
Copy Markdown
Collaborator

Summary

Adds the offline best-of-N experiment with K2-Think-V2 generating + the new step_reasoning UHead scoring, on MBPP+, for the CSCS Clariden cluster. Medium and low thinking-budget variants, matching the prompts/budgets the UHead was trained on.

Two framework fixes were required because the thinking-mode path previously assumed Qwen-style output.

Framework

  • K2 reasoning-budget thinking tags. </think> was hardcoded across the vLLM generator (completion detection, stop-token registration, mid-step leak truncation, answer-phase close) and the offline-BoN stop override. K2-Think emits a budget-dependent close tag (reasoning_effort=medium -> </think_fast>, low -> </think_faster>, else </think>). Generalized via a per-instance think_close_tag + THINK_CLOSE_TAGS / _find_think_close. Default </think> behaviour is unchanged.
  • <answer>...</answer> extraction. extract_answer only matched <Answer>: / \boxed{} and collapsed to the first line, dropping K2's multi-line fenced-code answers entirely. Added XML-tag handling (multi-line preserved so code blocks survive; \boxed{} wrapper still cleaned).

Experiment

  • config/experiments/offline_best_of_n/mbpp_plus/offline_bon_vllm_k2_think_v2_mbpp_plus_uhead_{medium,low}.yaml — new UHead checkpoint rediska0123/uhead_hs_K2-Think-V2_mixed_code10K_steps_vllm_10epochs, budgets via model.reasoning_effort, <answer> prompt wrapper (config/prompts/k2_think_answer.txt).
  • scripts/slurm/install_step_reasoning_head.sh — ports the author's step_reasoning UHead head (from cant-access-rediska0123/uncertainty4reasoning) into luh, which carries the vLLM hidden-state path but not that head type.
  • scripts/slurm/run_k2_uhead_mbpp_clariden.sh + README — CSCS Clariden launcher (uenv + venv, shared a0142 HF cache).

Validation

Smoke test (subset=8, N=4, medium) on a GH200: 6/8 correct (75%), 0 unextracted answers (no_answer_rate: 0.0), real EvalPlus-graded code. Full path exercised: generation -> step_reasoning UHead scoring -> best-of-N selection -> MBPP+ grading. Answer-extraction regression covered (math <Answer>:/\boxed{}, XML code, XML boxed, empty-tag skip).

Review

codex review against main: PASS (no P1). Two P2 findings addressed in the final commit — the offline-BoN stop_tokens_override now uses the budget close tag (so medium/low stop at end-of-thinking instead of running to EOS and re-generating the answer phase), and XML answers get \boxed{} cleanup.

K2-Think emits a budget-dependent thinking close tag: reasoning_effort=medium
gives <think_fast>...</think_fast>, low gives <think_faster>...</think_faster>,
high/default gives <think>...</think>. The vLLM generator hardcoded </think> for
thinking-completion detection, stop-token registration, the mid-step leak
truncation, and the answer-phase closing step, so the fast/faster budgets never
split the answer out (steps collapsed to 1, no answer extracted). Generalize via
a per-instance think_close_tag derived from reasoning_effort plus tolerant
multi-tag detection (THINK_CLOSE_TAGS / _find_think_close); default </think>
behaviour is unchanged.

Also extend extract_answer to handle <answer>...</answer> XML tags, keeping
multi-line content so fenced code blocks survive for code benchmarks. The
previous extractor only matched <Answer>: and \boxed{} and collapsed to the
first line, which dropped K2-Think's code answers entirely.
Medium/low configs using the new UHead checkpoint
rediska0123/uhead_hs_K2-Think-V2_mixed_code10K_steps_vllm_10epochs and the
prompts/thinking budgets it was trained on, reproduced config-only via
model.reasoning_effort (medium -> <think_fast>, low -> <think_faster>) plus the
k2_think_answer wrapper. install_step_reasoning_head.sh ports the author's
step_reasoning UHead head (from cant-access-rediska0123/uncertainty4reasoning)
into luh, which has the vLLM hidden-state path but not that head. Includes the
CSCS Clariden launcher (uenv + venv, shared a0142 HF cache) and a README.
- Offline best-of-N: stop at the generator's thinking close tag (K2-Think
  </think_fast> / </think_faster>) instead of a hardcoded </think> in the
  stop_tokens_override, so medium/low budgets stop at end-of-thinking rather
  than running to EOS and wastefully re-generating the answer phase.
- extract_answer: clean a \boxed{} wrapper from XML <answer> content too, so the
  <answer>...</answer> path matches the default/boxed paths (otherwise
  <answer>\boxed{42}</answer> would keep the wrapper and fail exact-match).
Two problems only the full 378-problem runs surfaced (the subset=8 smokes
passed):

- OOM: generate_trajectories defaults checkpoint_batch_size to len(dataset), so
  offline best-of-N sent all 378 x N trajectories to vLLM in one chunk and the
  native hidden-state capture OOM'd a 2x GH200. Set checkpoint_batch_size=16 in
  the configs (~64 sequences/chunk, plus progressive saves).

- Extraction: with the low budget K2 emits valid ```python code but usually
  without an <answer> wrapper (only ~20% used it), so extract_answer returned
  empty for 86.5% of low trajectories. Added a fenced-code-block fallback; on the
  real low run this drops no-answer from 87% to 4% (75% now yield runnable code).
…pu_mem)

The full runs cleared chunks 1-2 then OOM'd on chunk 3: across chunks the native
HS capture leaves reserved-but-unallocated GPU memory that fragments until a
large alloc fails (the error itself suggests expandable_segments). Set
PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True in the launcher and drop
gpu_memory_utilization 0.87 -> 0.78 to leave headroom on GPU 0 for HS + UHead.
…nk size

The expandable_segments OOM fix hung vLLM during model loading (logs frozen at
'Starting to load model' for 20+ min, zero shard progress, on two nodes).
Remove it and instead handle the cross-chunk fragmentation OOM with headroom:
gpu_memory_utilization 0.78->0.72 and checkpoint_batch_size 16->8 (~32 seqs/chunk,
the smoke-validated size).
The shared-store K2-Think-V2 snapshot had only the 62 safetensors (no
config.json / tokenizer). Online, vLLM stalled trying to fetch the missing
config from HF on a flaky compute-node network (looked like a load hang);
offline it failed fast. With the config/tokenizer now in the cache,
HF_HUB_OFFLINE=1 makes weight loading fully local and deterministic.
…to 16384

Model loaded but KV-cache init failed: 'Available KV cache memory: -8.89 GiB'.
Lowering gpu_memory_utilization to 0.72 starved KV (non-KV profiling peak ~77 GiB
> 0.72 budget). The real lever is max_model_len: it sets both the profiling peak
(KV init) and per-sequence generation memory (the chunk-3 OOM). Medium/low gens
are short (~2745/~500 tokens), so cut max_context_budget 32768->16384 (and
max_new_tokens 32000->15000) and set gpu_memory_utilization 0.82.
@smirnovlad

Copy link
Copy Markdown
Collaborator Author

Full MBPP+ results (378 problems, offline best-of-N, N=4, new step_reasoning UHead)

K2-Think-V2 generating + the new UHead (rediska0123/uhead_hs_K2-Think-V2_mixed_code10K_steps_vllm_10epochs) scoring, on CSCS Clariden (2× GH200), seed 42.

Budget reasoning_effort MBPP+ (plus) base no-answer avg steps avg out tok
medium <think_fast> 66.9% (253/378) 81.7% 0.5% 3.1 1345
low <think_faster> 2.1% (8/378) 2.6% 2.1% 1.0 535

Takeaway: the K2 thinking budget is decisive on MBPP+ — a ~30× swing between the two budgets the UHead was trained on. With <think_faster> the model barely reasons (1.0 step, ~535 tok) and produces extractable-but-wrong code (low is genuine model weakness, not an extraction failure — no-answer is only 2.1%).

Both runs are extraction-clean thanks to the <answer>/code-fence extraction fix in this PR (no-answer would otherwise have been ~87% for low).

Notes for reproduction (full-scale gotchas the subset smokes didn't surface)

  • The shared-store K2-Think-V2 cache had only the 62 safetensors (no config.json/tokenizer) — online vLLM stalls fetching them on the flaky compute-node network (looks like a load hang). Fix: complete the snapshot from a login node and run HF_HUB_OFFLINE=1.
  • Native HS-capture is memory-tight: gpu_memory_utilization must stay ~0.87 for KV-cache init, the all-378-at-once batch OOMs (use checkpoint_batch_size), and degenerate long generations OOM the HS buffer (cap max_new_tokens; medium avg is ~978). expandable_segments:True hangs weight loading here — do not use it.

…2 on MBPP+

Control for the offline best-of-N + UHead runs: same model, prompt wrapper,
reasoning_effort=medium, seed, and generation settings; only the strategy differs
(1 sample, no UHead selection). Baseline uses raw vLLM (no HS capture).
@smirnovlad

Copy link
Copy Markdown
Collaborator Author

Baseline (single-shot CoT) vs offline BoN + UHead — MBPP+ medium

Matched control for the UHead BoN runs: same model (K2-Think-V2, vLLM TP=2), same prompt, same medium <think_fast> budget, same generation settings and seed (42). The only difference is the strategy — baseline is N=1 raw CoT with no UHead selection.

Run base pass@1 plus pass@1 avg out tok steps
Baseline (N=1, no UHead) 80.7% (305/378) 66.1% (250/378) 718 1.0
Offline BoN + UHead (N=4) 81.7% (309/378) 66.9% (253/378) 1345 3.1
Δ (BoN − baseline) +1.0pp (+4) +0.8pp (+3)

Analysis. The new UHead's best-of-4 selection gives a small but positive lift over single-shot CoT at the medium budget — +3 problems on the plus set, +4 on base — for roughly 4× the generation compute. The direction is right (UHead selection beats no selection), but the margin is a handful of problems on a single seed, so it needs replication (≥3 seeds) for error bars before we call it significant. This is consistent with the paper's broader read that on coding, test-time scaling helps but the per-FLOP return is modest. Low budget stays a non-starter (2.1%), so medium is the only operating point worth scaling on this model/task.

Baseline run: SLURM job 2651567, config config/experiments/baseline/mbpp_plus/baseline_vllm_k2_think_v2_mbpp_plus_medium.yaml. Monitor log saved locally.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant