Repository navigation
feat(evals): add four deterministic VQA families - #4541
moshiii-wei wants to merge 2 commits into
Conversation
Extend VQA-Gen with vertical_direction, presence_and, object_color, and camera_bearing so more spatial and attribute questions can be proposed by the author and answered from detector, color, and LiDAR primitives.
7e19576 to
a0d8dc5
Compare
a0d8dc5 to
da23e93
Compare
There was a problem hiding this comment.
go2 replay realtime (arm64)
Details
| Benchmark suite | Current: e5d619b | Previous: 1e7b491 | Ratio |
|---|---|---|---|
peak memory |
1592.867 MB |
1569.52 MB |
1.01 |
peak threads |
344 threads |
352 threads |
0.98 |
network (transport) |
2730.059 MB |
2722.016 MB |
1.00 |
disk write |
1.699 MB |
1.492 MB |
1.14 |
instructions |
115.537 G |
115.634 G |
1.00 |
This comment was automatically generated by workflow using github-action-benchmark.
❌ 1 Tests Failed:
View the top 1 failed test(s) by shortest run time
To view more test analytics, go to the Test Analytics Dashboard |
|
| valid = (sat >= 40) & (val >= 40) | ||
| if int(valid.sum()) < _MIN_VALID_PIXELS: | ||
| raise InsufficientEvidenceError( | ||
| "object color crop lacks enough saturated, well-lit pixels" | ||
| ) |
There was a problem hiding this comment.
dominant_color_in_bbox removes every pixel that could become white, black, or gray before counting colors. Solid neutral-colored objects are rejected, while a mostly neutral object can receive the color of a small saturated patch. A crop containing 95% white and 5% blue was accepted and saved with blue as its expected answer, corrupting evaluation ground truth. This needs fixing before merging.
Count neutral pixels too, and measure the winning color against the full usable crop.
Artifacts
Complete executed neutral-color validation script
- The authored script exercises five synthetic images through the real primitive, family dispatch, and dataset persistence paths, allowing both observed runs to be reproduced.
Neutral-color results with the filter disabled in memory
- The diagnostic control executes the same five images with only the filter disabled and reads back saved labels, showing all neutrals classified and the predominantly white crop labeled white.
Neutral-color results on unmodified PR head
- The unmodified head executes the same five images and reads back saved labels, confirming three neutral rejections and an incorrect blue label for the predominantly white crop.
Full executed script and exact production source excerpts
- A command captures the complete test source, numbered filter and label-persistence excerpts, head revision, and tracked diff, showing the precise tested logic and no production edits.
| if hue < 150: | ||
| return COLOR_CHOICES.index("purple") | ||
| return COLOR_CHOICES.index("brown") |
There was a problem hiding this comment.
_hue_to_bucket treats hues 150–169 as brown, so vivid pink and magenta pixels get labeled brown. Ordinary brown pixels, such as RGB (128, 64, 0), fall in the orange hue range instead. Actual image crops reproduced both errors through answer_question, where these labels become incorrect expected answers. This needs fixing before merging.
Use brightness along with hue to distinguish brown from orange, map pink or magenta to a suitable color group or reject unsupported colors, and add regression tests for both cases.
Artifacts
Complete executable color reproduction script
- The uploaded script constructs real RGB and BGR Image objects, executes the primitive and family dispatcher, and checks the cited hue interval, making the reproduction rerunnable.
Full source of the executed reproduction script
- Captured cat output contains the entire executed script with its command, working directory, and exit code, preserving the full test source.
Base revision run with the color API absent
- The same script ran against base 1e7b491 and exited 3 because the color module does not exist, establishing the honest pre-PR baseline.
PR revision run showing incorrect brown and pink labels
- The script ran against the PR head and exited 1 after six failed color expectations, while controls passed and all 20 cited hues returned brown, confirming candidate1.
Exact source lines and unchanged production files
- Executed git and numbered-source commands captured the faulty bucket branches and answer propagation with no tracked diff, linking the observed failures to unchanged PR code.
| winner = int(counts.argmax()) | ||
| fraction = float(counts[winner] / counts.sum()) | ||
| if fraction < _MIN_BUCKET_FRACTION: |
There was a problem hiding this comment.
Tied colors get arbitrary answers
counts.argmax() accepts a tied winner because _MIN_BUCKET_FRACTION is only 0.4. A crop split equally between red and blue passes with a fraction of 0.5 and saves red solely because it comes first in COLOR_CHOICES. Dataset generation reproduced this arbitrary expected answer; a model choosing the equally common blue would be marked wrong. This needs fixing before merging.
Reject ties and require a clear lead over the runner-up before saving a single dominant color.
Artifacts
Complete tied-color reproduction script
- The uploaded full source executes the base contract and current primitive, dispatcher, and dataset writer, making the confirmed reproduction repeatable.
Before PR: color proposal rejected
- Executed the exact base revision’s proposal contract with object_color and captured its validation rejection, showing the family did not exist before this PR.
After PR: tied colors saved as red
- Ran equal red/blue pixels through the real primitive and dataset writer and read back the red label, confirming ambiguous evidence becomes saved ground truth.
Exact source for tie selection and label persistence
- Captured numbered source excerpts and git diff --exit-code, locating the unchecked tie and label propagation while confirming no production edits.
| requires_pointcloud=True, | ||
| requires_masks=True, |
There was a problem hiding this comment.
CAMERA_BEARING_FAMILY sets requires_pointcloud=True, but the generator uses that flag to require a range_estimator too. A caller of generate_frames_dataset with a point cloud and mask_estimator, leaving the optional range_estimator=None, never gets camera_bearing offered even though its answer needs no range estimator. This is a non-blocking loss of coverage for programmatic callers; the CLI is unaffected because it already provides one.
Separate the point-cloud requirement from the range-estimator requirement and cover this combination in a generation test.
Artifacts
Executable bearing service reproduction
- The full script executed against both revisions captures offered families and exercises generation plus direct answering, demonstrating the unnecessary range-estimator gate.
- Ran the synthetic service reproduction against the PR base and captured source excerpts and responses, showing that camera bearing had not yet been introduced.
Service output after PR4541 with and without a range estimator
- Ran the same reproduction against PR head and captured generated datasets and direct answers, confirming that bearing is hidden without an estimator it never uses.
What is this feature?
Adds four image- and LiDAR-backed VQA families on top of existing VQA-Gen (
QuestionAuthor→answer_question→cases.jsonl):vertical_direction— top / middle / bottom from a single detection bboxpresence_and— both object categories detected (reject if either is missing)object_color— dominant HSV bucket inside one detection cropcamera_bearing— left / ahead / right from LiDAR points in an EdgeTAM maskNew primitives live under
dimos/evals/vqa/primitives/{color,bearing}.py. The OpenAI author already receives family metadata viaAvailable families: …JSON; no separate prompt change.Why do we need this?
Improves coverage toward related-work question types (spatial layout, multi-object presence, color attributes, camera-relative bearing) while keeping deterministic GT. Supports the goal of more families backed by auditable primitives rather than LLM answers.
How to Test
cd dimos uv run pytest dimos/evals/vqa -qOptional smoke on a calibrated recording (needs
OPENAI_API_KEYfor the author):Inspect
audit/run.jsonfor new family names and samplecases.jsonlquestions.Which issue(s) does this PR close?
Fixes
Checklist
Made with Cursor