feat(spartqa): add SpartQA spatial-reasoning benchmark#2072
Open
pachmu wants to merge 2 commits into
Open
Conversation
Native gym port of SpartQA (mteb/SpartQA) — a spatial-reasoning benchmark where the model is shown a scene-description query and must return the matching answer phrase. The scorer is pure rule-based: extract the model's "Final answer: <phrase>" line, normalize (lowercase, strip punctuation, collapse whitespace), and compare against every accepted phrase in all_targets (exact match sets reward 1.0 and exact=true; substring containment sets reward 1.0 with exact=false; no match → 0.0). - resources_servers/spartqa/app.py — SpartqaResourcesServer.verify() extracts the answer via _extract_answer (strips <think> reasoning blocks, matches "Final answer:" / "Answer:" patterns with fallbacks, cleans markdown artifacts), normalizes, and compares against all_targets (falling back to verifier_metadata when the nemo-evaluator native driver drops the top-level list field). compute_metrics reports mean_reward (= corpus accuracy), exact_match_rate, and parse_rate; get_key_metrics surfaces mean_reward and exact_match_rate. - prepare_spartqa.py joins the MTEB mteb/SpartQA queries/corpus/qrels splits into one row per query, porting build_records from byob_spartqa.py. The all_targets list is mirrored into verifier_metadata so the native driver can forward it intact to verify(). Prompt and scoring logic are ported verbatim from byob_spartqa.py so the metric is identical to the BYOB baseline. - spartqa.yaml wires the server + simple_agent for local eval/training; spartqa_serve.yaml serves the scorer for nemo-evaluator via the gym:// adapter (rule-based verify needs no model on the gym side). - No extra runtime deps — scoring is pure stdlib. Dataset prep requires the HF datasets package (prep-time only, not in requirements.txt). - 25 unit tests covering _extract_answer, _strip_reasoning, _normalize, verify() exact/contains/empty/multi-target/metadata-fallback paths, compute_metrics, get_key_metrics, _response_text, and acceptance parity against every example.jsonl row. Signed-off-by: mbagdasarova <mbagdasarova@nvidia.com>
…ce tests Signed-off-by: mbagdasarova <mbagdasarova@nvidia.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
SpartQA — spatial-reasoning benchmark
Adds a native gym port of SpartQA
— a spatial-reasoning QA benchmark where the model is shown a scene-description
query and must return the matching answer phrase.
What it does
Every task is single-turn generation — no agent fork, no judge model.
verify()is pure, rule-based scoring (stdlibre/stringonly).The model is prompted to end its response with
Final answer: <phrase>.verify()extracts that phrase, normalizes it, and compares against everyaccepted phrase in
all_targets:rewardexacttruefalsefalsefalsecompute_metrics'smean_rewardequals corpus-level accuracy (the headlinemetric).
exact_match_rateandparse_rateare reported alongside fordownstream inspection.
Scoring details
_extract_answerhandles:<think>…</think>reasoning-block stripping (reasoning models)Final answer: …/Selected answer: …/Answer: …patterns withfallback to last non-empty line when no explicit marker is present
**,`,*, bullet prefixes)Field placement and
all_targetssurvivalThe primary accepted answer phrase lives at
target(a top-level scalar,forwarded intact by the nemo-evaluator
gym://...protocol=nativedriver). Thefull accepted set (
all_targets) is a list and dropped by the driver — itis mirrored into
verifier_metadata(forwarded intact), soverify()alwayssees every phrase via the fallback chain:
Contents
resources_servers/spartqa/app.py—SpartqaResourcesServer(/verify+compute_metrics/get_key_metrics) with answer extraction, normalization,and multi-target scoring.
prepare_spartqa.py— joinsmteb/SpartQA(HFdatasets) intodata/spartqa_test.jsonl. Committeddata/example.jsonlis the 5-row smokeset.
configs/spartqa.yaml— server +simple_agentwiring for localeval/training.
configs/spartqa_serve.yaml— serve-only scorer for nemo-evaluator via thegym://adapter (rule-based verify needs no model on the gym side).requirements.txt— no extra runtime deps;-e nemo-gym[dev]editableinstall only.
tests/test_app.py— 25 tests over_extract_answer,_strip_reasoning,_normalize,verify()(exact / contains / empty / multi-target /metadata-fallback),
compute_metrics,get_key_metrics,_response_text,and acceptance parity against every
example.jsonlrow.Testing
gym env test --resources-server spartqa ruff check resources_servers/spartqa/app.py resources_servers/spartqa/prepare_spartqa.py resources_servers/spartqa/tests/Notes
verify()strips leading<think>…</think>blocksbefore extracting the answer, so thinking-model outputs score correctly.
verified: false— not yet baselined. Reward-profiling across anopen-instruct / open-thinking / closed-source model suite is a follow-up
before flipping to
verified: true.datasets) are opt-in and not inrequirements.txt— install only when running
prepare_spartqa.py.