Skip to content

Add imo_proofbench benchmark and imo_proofbench_judge resource server - #1230

Merged
bxyu-nvidia merged 3 commits into
NVIDIA-NeMo:mainfrom
gwarmstrong:georgea/migrate-gym-imo-proofbench
May 8, 2026
Merged

bxyu-nvidia merged 3 commits into
NVIDIA-NeMo:mainfrom
gwarmstrong:georgea/migrate-gym-imo-proofbench

Conversation

@gwarmstrong

Copy link
Copy Markdown
Contributor

Add imo_proofbench benchmark and imo_proofbench_judge resource server

Summary

Migrates the IMO ProofBench benchmark from
NeMo Skills into Gym. Verification is a strong LLM judge
plus sympy-based symbolic equivalence, mirroring
Skills' eval_type=math chained with prompt_config=judge/imo_proofbench.
The new imo_proofbench_judge resource server vendors Skills' boxed-
extraction (search_boxed), the 3-format judgement parser
(is_correct_judgement), the prefill_judgement literal-match
shortcut, and math_equal (sympy via math_verify +
latex2sympy2_extended) — so the headline any_correct = symbolic_correct OR judge_correct matches Skills.

Includes

  • benchmarks/imo_proofbench/ — benchmark configuration, data
    preparation, and the model prompt template.

    • config.yaml — registers imo_proofbench_judge_simple_agent,
      points at the prepared JSONL, declares a Gemini judge model server
      via judge_base_url / judge_api_key / judge_model_name.
    • prepare.py — pulls imobench/proofbench.csv
  • resources_servers/imo_proofbench_judge/ — Skills-parity verifier.

    • app.py — vendors:
      • search_boxed (rightmost \boxed{…} brace-balanced extraction,
        mirroring nemo_skills.evaluation.math_grader.search_boxed)
      • parse_judgement_verdict with Skills' 3-format priority
        (Judgement: Yes/No → \boxed{Correct/Incorrect} →
        <points>N out of 7</points> with points >= PASS_THRESHOLD)
      • parse_points for the score-band metrics
      • math_equal (MCQ short-circuit, latex2sympy2_extended
        normalization, math_verify symbolic fallback) so Gym's
        symbolic_correct is computed independently of the LLM judge,
        matching Skills' MathEvaluator.eval_single step
      • verify() — extracts boxed, runs math_equal first; if
        symbolic-correct, synthesises Reasoning: The two answers are identical.\nJudgement: Yes and skips the judge; on no
        extraction, synthesises Reasoning: No answer was provided.\n Judgement: No; otherwise calls Gemini with the boxed content
        filling {predicted_answer} and parses with the 3-format
        priority.
      • _score_fn exposes any_correct, symbolic_correct,
        judge_correct, and judge_score_{0,1,6,7} for
        compute_pass_majority_metrics; compute_metrics adds
        category / level subset breakdowns.

Skills-parity validation

End-to-end parity numbers

Final 16-seed run on nvidia/NVIDIA-Nemotron-3-Super-120B-A12B-BF16
(960 rollouts per pipeline):

Metric Skills Gym Δ Threshold
pass@1 / any_correct 6.46 % 6.25 %† -0.21 pp <5 pp ✓
pass@1 / symbolic_correct 6.35 % 6.25 % -0.10 pp ✓
pass@1 / judge_correct 1.25 % 1.46 %‡ +0.21 pp ✓
pass@16 / any_correct 16.67 % (10/60) 13.33 % (8/60) -3.34 pp ✓

The model produces near-identical boxed answers in both pipelines —
once the verifier runs the same math_equal Skills does, the headline
metric is identical to within sampling noise.

Migrates the IMO ProofBench benchmark (60 IMO-style proof problems from
google-deepmind/superhuman/imobench/proofbench.csv, pinned to commit
c1ee02e0) from NeMo Skills into Gym. Verification mirrors Skills'
MathEvaluator.eval_single + LLMMathJudgeTask byte-for-byte: boxed-content
extraction (search_boxed), sympy-based symbolic equivalence (math_equal
via math_verify + latex2sympy2_extended), prefill_judgement literal-match
shortcut, and a strong LLM judge (Gemini-2.5-Pro by default) using the
IMO 0-7 rubric prompt byte-identical to
nemo_skills/prompt/config/judge/imo_proofbench.yaml. Headline metric
any_correct = symbolic_correct OR judge_correct matches Skills'
MathMetrics.

Includes:

- benchmarks/imo_proofbench/: data preparation, model prompt template,
  README. prepare.py downloads the pinned proofbench.csv and writes
  60 rows to data/imo_proofbench_benchmark.jsonl.

- resources_servers/imo_proofbench_judge/: full LLM-judge verifier with:
  * search_boxed (rightmost \boxed{...} brace-balanced extraction,
    mirroring nemo_skills.evaluation.math_grader.search_boxed)
  * parse_judgement_verdict with Skills' 3-format priority
    (Judgement: Yes/No -> \boxed{Correct/Incorrect} ->
    <points>N out of 7</points> with N >= PASS_THRESHOLD)
  * math_equal (MCQ short-circuit, latex2sympy2_extended normalisation,
    math_verify symbolic fallback) so symbolic_correct is computed
    independently of the LLM judge, matching Skills'
    MathEvaluator.eval_single
  * verify() flow: extracts boxed; if symbolic-correct, synthesises
    "Reasoning: The two answers are identical. Judgement: Yes" and
    skips the judge; on no extraction, synthesises "Reasoning: No
    answer was provided. Judgement: No"; otherwise calls Gemini with
    the boxed content as {predicted_answer} and parses with the
    3-format priority
  * compute_metrics() exposes pass@k/{any,symbolic,judge}_correct
    plus per-category and per-level subset breakdowns
  * 76 unit tests, 98% coverage
  * data/example.jsonl (5 rows), example_metrics.json, and
    example_rollouts.jsonl (5 sample rollouts)
  * Default-null judge_base_url/judge_api_key/judge_model_name keys at
    config end so ng_prepare_benchmark resolves OmegaConf interpolations
    without needing a judge endpoint

Skills parity validated end-to-end on
nvidia/NVIDIA-Nemotron-3-Super-120B-A12B-BF16 (60 problems x 16 seeds
= 960 rollouts/side):

  pass@1/symbolic_correct  Skills 6.35%  Gym 6.25%  delta -0.10 pp
  pass@1/any_correct       Skills 6.46%  Gym 6.25%  delta -0.21 pp
  pass@1/judge_correct     Skills 1.25%  Gym 1.46%  delta +0.21 pp
  pass@16/any_correct      Skills 16.67% Gym 13.33% delta -3.34 pp
  Distinct problems with prefill hits  Skills 9    Gym 8

Same model, same vLLM container (nemo-skills-vllm-audio-eval-v1, vLLM
0.18.1), same chat template (90 input tokens), same sampling params,
same judge prompt. The model produces near-identical boxed answers in
both pipelines; once Gym's verifier runs the same math_equal Skills
does, the headline metric is identical to within sampling noise.
Residual delta is consistent with vLLM's known non-determinism at
TP > 1 across batching / topology, plus finite-sample noise on a
60-problem benchmark.

Headline READMEs and the judge endpoint references point at
integrate.api.nvidia.com (NVIDIA's public Gemini gateway) and
generativelanguage.googleapis.com (Google's direct public API).

Signed-off-by: gwarmstrong <gwarmstrong@users.noreply.github.com>
@copy-pr-bot

copy-pr-bot Bot commented May 5, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

…mo-proofbench

Signed-off-by: gwarmstrong <gwarmstrong@users.noreply.github.com>

# Conflicts:
#	README.md
@cwing-nvidia cwing-nvidia added the env-integration Integrate with existing environments or gyms external to NeMo Gym label May 7, 2026
…mo-proofbench-fixmerge

Signed-off-by: gwarmstrong <gwarmstrong@users.noreply.github.com>

# Conflicts:
#	README.md
@bxyu-nvidia
bxyu-nvidia merged commit 2f30642 into NVIDIA-NeMo:main May 8, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

env-integration Integrate with existing environments or gyms external to NeMo Gym

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants