Skip to main content

VQA Generation Pipeline

1. Run Generation

skip
Flags:
  • --recording: Memory2 Go2 recording path or named recording.
  • --start-index, --stop-index, --stride: sampled recording frames.
  • --question-mode: constrained or agentic; default is constrained.
  • --min-mask-area-px: minimum accepted segmentation-mask area; default 128.
  • --min-foreground-points: minimum point-cloud support inside a mask; default 3.
  • --output: dataset root; frames with a completed frame.json marker are skipped, while partial frame directories are safely rewritten on rerun.
To generate one frame, set --start-index to that frame and --stop-index to the next index. For example, use --start-index 40 --stop-index 41 for frame 40.

Generation Specification

dimos vqa generate --spec <generation.json> is an alternative to the explicit generation flags. Do not combine --spec with --recording, frame bounds, question mode, grounding thresholds, or output flags. A specification is a reproducible generation request:
Generation writes the resolved request, model IDs, and aggregate counts to private audit/run.json. This is an output record, not the input specification.

2. Preprocess Each Frame

Generation creates one Go2FramePreprocessor for the complete recording run. Setup performed once:
  • Open the Memory2 recording.
  • Discover and order image, LiDAR, camera-info, and TF streams.
  • Initialize reusable nearest-time alignment and TF access.
  • Cache OpenCV rectification maps for each distinct camera calibration.
For each requested image index, the preprocessor:
  1. Loads the image and nearest LiDAR/camera-info observations within tolerance.
  2. Rectifies the image and emits matching zero-distortion pinhole intrinsics.
  3. Resolves camera-from-point-cloud using recorded TF or captured-pose fallback.
  4. Returns one read-only CalibratedFrame.
The image pixels must be remapped for every frame because the scene changes. The expensive rectification maps, recording streams, and TF access are reused. Preprocessing does not run MoonDream, EdgeTAM, point-cloud projection, or grounding.

3. Create Questions

Constrained

The image author inspects the scene and returns structured intents in one JSON array. Malformed JSON is retried once. Strict per-item parsing rejects unsupported kinds, unexpected fields, and invalid family parameters into the private author audit. The author selects only families likely to be useful for the visible arrangement, rather than expanding every object into every family. Private grounding still rejects unsupported or ambiguous candidates. A non-empty response with no valid intents fails the frame instead of publishing a resumable zero-question completion marker.

Agentic

The image-only author returns a frozen question with one contract:
  • Boolean: {"kind":"boolean"}; public choices are yes, no.
  • Choice: {"kind":"choice","choices":[...]}; at least two choices.
The same strict array and per-item validation applies. Invalid proposals are retained as private author rejections; accepted proposal IDs are made unique within the frame before oracle execution. A non-empty response with no valid proposals fails the frame. The agentic oracle is not bound to a constrained family. It can inspect individual detection, mask, and object handles, choose its own tool sequence, and either return a cited answer or privately reject the proposal with the missing evidence.

4. Pre-Answer Evidence Checks

Presence, visible count, and image direction use valid MoonDream detections directly. They do not segment objects or project LiDAR. Range and pairwise geometry families need an EdgeTAM mask with enough visible 3D point support. Questions are authored from RGB only; private LiDAR evidence establishes geometric labels.
  • Presence and count: accepted visual detections. 0 is an exhaustive distractor; empty detector output is unverified absence and rejects rather than producing a zero label.
  • Range: accepted grounded instances only. If boxes are absent or box segmentation fails, MoonDream can return positive image points that EdgeTAM expands into masks.
  • Left/right comparison: one grounded instance per named object with clear separation.
Missing, sparse, or ambiguous evidence rejects the question.

5. Create Answers

Constrained

Each deterministic family runs its own fixed sequence. ground(A) below is one cached ground_objects(A) call through the shared frame perception facade. The deterministic answerer only dispatches the intent to the matching family; the family owns evidence requirements, quality gates, selection, and answer policy:
project_visible_points() transforms source points into the camera frame, drops points behind or outside the camera, maps the remainder into rectified image pixels, and keeps the nearest point per pixel. Each ground_object(mask) then filters that cached sparse projection by the mask. Calibration and projection are not rerun for every object.

Agentic

The private oracle calls only read-only perception and geometry primitives shared with constrained recipes. It interprets their measurements and selects an answer itself: Opaque IDs chain tool results; raw masks and point-cloud arrays are not exposed to the oracle. The oracle returns a candidate answer and cited evidence IDs.

6. Post-Answer Validation

The candidate is rejected unless:
  1. Its normalized answer matches one of the fixed public choices.
  2. It cites one or more known evidence IDs.
Tool failures, quality-gate failures, invalid citations, and invalid answer formats are retained as rejected generation records. The tool-calling oracle currently interprets whether its cited evidence supports a freeform question without a second model judge.

7. Write Dataset Artifacts

The generated root is directly evaluable while retaining private audit state:
Each line in cases.jsonl is one public evaluation case. Formatted for readability, one record is:
  • id: unique case identifier.
  • image: dataset-relative path to the public image.
  • question: question shown to the evaluated vision model.
  • choices: at least two allowed answer strings.
Each line in labels.jsonl is the corresponding private correct answer. Formatted for readability, one record is:
  • id: case identifier matching exactly one cases.jsonl row.
  • answer: one of that case’s choices.
The files store each record as one JSON object per physical line; the examples above are expanded only for documentation readability. Each frame.json records the question-author and parser versions. Resume accepts a completed frame only when those versions, model IDs, generation mode, recording, frame index, and grounding settings match the current run. Run the generated dataset through the standard evaluation framework:
The VQA suite loader reads public cases.jsonl, public images, and private labels.jsonl. It does not read generation evidence or point-cloud data.