Skip to content

Jm/sam - #5

Open
parkjinman98 wants to merge 6 commits into
mainfrom
jm/sam
Open

Jm/sam#5
parkjinman98 wants to merge 6 commits into
mainfrom
jm/sam

Conversation

@parkjinman98

Copy link
Copy Markdown
Contributor

No description provided.

- Implemented SAM2HieraLarge model in `mblt_vision/mask_generation/sam2.py` for promptable mask generation using point prompts.
- Added configuration file `SAM2HieraLarge.yaml` for model artifact paths and settings.
- Created unit tests in `tests/test_mask_generation.py` to validate model functionality and backend interactions.
- Introduced hardware tests in `tests/test_mask_generation_hardware.py` for real NPU performance evaluation.
- Added differential tests in `tests/test_mask_generation_prompt_encoding.py` to ensure fidelity with the official `facebookresearch/sam2` predictor.
- Introduced readiness checks for the SA-V dataset in readiness.py, including validation for video IDs, image and annotation directory structure, and mask consistency.
- Implemented evaluation metrics for SA-V mask generation in a new eval_sav.py module, including mean IoU calculations and candidate selection logic.
- Updated dataset organization functions to handle SA-V dataset structure.
- Enhanced CLI validation to support SA-V evaluation parameters.
- Added comprehensive tests for SA-V dataset readiness, organization, and evaluation metrics.
- Updated SAM2HieraLarge.yaml to include ONNX artifact paths and clarify usage.
- Refactored readiness.py to consolidate mask and image path handling for better readability.
- Modified eval_sav.py to introduce Protocols for type safety and improved model interface.
- Adjusted postprocess modules (yolo_anchorless_post.py, yolo_dflfree_post.py) to accommodate wider return types for final outputs.
- Enhanced letterbox.py to ensure proper border value handling for multi-channel images.
- Updated results.py to correctly cast output types from mask generation.
- Expanded CLI tests to validate ONNX path arguments for model predictions.
- Improved eval_sav tests to utilize a structured mock for predictions, enhancing type visibility.
- Added comprehensive tests for ONNX framework integration, ensuring proper input handling and output validation.
- Introduced new tests for SAM2HieraLarge ONNX predictions, verifying segmentation accuracy on synthetic images.
@parkjinman98 parkjinman98 self-assigned this Aug 28, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b8c0da654d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread mblt_vision/cli/val.py
Comment thread mblt_vision/mask_generation/_sam2_host.py Outdated
Comment thread mblt_vision/mask_generation/sam2.py Outdated
Comment thread mblt_vision/mask_generation/sam2.py
Comment thread mblt_vision/mask_generation/sam2.py Outdated
Comment thread mblt_vision/utils/datasets/readiness.py
Comment thread mblt_vision/utils/datasets/organizer.py Outdated
Comment thread mblt_vision/__init__.py
Comment thread mblt_vision/__init__.py
Fixes all nine review comments from the automated review of b8c0da6.

Correctness:
- Reject --model-path/--mxq-path/--onnx-path in every CLI command that builds
  a mask generation engine, not just predict. Validation previously ignored
  them and silently evaluated the downloaded default, invalidating results.
- Build host prompt tensors on the weights' device, and construct the padding
  point/label on the incoming tensors' device, so device="cuda" and .cuda()
  work instead of raising a device mismatch on every predict.
- Pin the SA-V annotated-mask inventory (31967, measured from the organized
  sha256-pinned sav_val.tar). Video and masklet counts alone accepted a source
  truncated to a few annotated frames per masklet.
- Require every non-zero SA-V mask value to be a single object ID, in both the
  organizer's staged check and the readiness check. Counting unique values
  accepted a {1, 2} mask that "> 0" binarization turns entirely foreground.
- Validate point labels as exactly 1/0 and one-dimensional; other values get
  neither learned embedding and yield a meaningless mask instead of an error.

Robustness:
- Dispose a backend that fails after create() inside its builder. The caller
  assigns it only on success, so the constructor's cleanup could not reach it.
- Load onnxruntime before downloading any artifact, so a missing optional
  dependency reports the package extra rather than a network failure.

Packaging and docs:
- Bump __version__ to 0.0.3 for the new public mask_generation surface.
- Document mask generation in the root README (task lists, point-prompt and
  two-artifact CLI usage) and correct the claim that every model uses the
  separate preprocess/raw-call/postprocess steps.
- Sync AGENTS.md and the mblt-vision skill with the new durable contracts.

Verified: prompt-encoder numerics still bit-for-bit against the real
facebookresearch/sam2 predictor; CUDA predict and both NPU/ONNX integration
suites pass on hardware; readiness accepts the real organized SA-V dataset.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@parkjinman98

Copy link
Copy Markdown
Contributor Author

All nine findings from the previous review are addressed in aea76a1. Disposition below, one line per finding — please read this before re-reviewing so settled items are not re-raised.

# Finding Status Where
1 Reject ignored single-artifact paths during SAM validation (P1) Fixed cli/_vision.py — new reject_single_artifact_paths(), called from create_mask_generation_engine() so every command that builds the engine rejects them, not just predict
2 Create prompt tensors on the configured host device (P1) Fixed _sam2_host.py:_decoder_prompt_tensors builds points/labels on the weights' device; _sam2_prompt.py:embed_points builds the padding point/label on the incoming tensors' device
3 Dispose backends when post-creation validation fails (P2) Fixed sam2.py — both _build_backend and _build_onnx_backend dispose on failure (MXQ launch() included, as you noted)
4 Check ONNX Runtime before downloading prompt weights (P2) Fixed sam2.py.__init__ resolves _load_onnxruntime() before any download_hub_artifact call
5 Reject unsupported point-label values (P2) Fixed sam2.py:predict_preprocessed validates labels are 1-D and strictly {0, 1}
6 Verify the complete SA-V annotated-frame inventory (P1) Fixed readiness.py — new SAV_VALIDATION_MASK_COUNT = 31967 pinned alongside the video/masklet counts
7 Reject two-valued masks without a zero background (P2) Fixed organizer.py and readiness.py — the identical weak check existed at both sites; both now require every non-zero value to be one object ID
8 Bump the package version for the new public task (P2) Fixed __version__ = "0.0.3" (pyproject.toml reads this via attr, so nothing else to bump)
9 Update the root README for the new task contract (P2) Fixed README.md — task lists, point-prompt/two-artifact CLI usage, and the incorrect "every model uses preprocess/raw-call/postprocess" claim corrected

Notes for the next pass

  • The 31967 figure is measured, not estimated. Counted from the organized official sav_val.tar (sha256-pinned in datasets/sa-v.yaml): 155 videos / 293 masklets / 31967 masks / 16117 frames, 14–231 masks per masklet. dataset_ready() was run against the real organized dataset and returns True. I deliberately pinned the mask count and not the frame count — frame count is derived from the organizer's annotated-frame selection, so pinning it would couple readiness to organizer internals while catching nothing the mask count misses.
  • AGENTS.md and .claude/skills/mblt-vision/SKILL.md are updated in the same commit, per the guide's own sync requirement. Items 1, 5, 6 and 7 changed durable public facts and are now documented there — please treat those bullets as the current contract rather than re-deriving them.
  • Pre-existing, out of scope: tests/test_wrapper.py::test_dflfree_pose_accepts_decode_true_mxq_parts_with_reducemax and ::test_dflfree_pose_prefers_score_tensor_over_reducemax_duplicate fail on main and on this branch's parent, unrelated to mask generation. Not introduced here and not fixed here.
  • Verification performed: prompt-encoder numerics re-checked bit-for-bit against the real facebookresearch/sam2 predictor (test_mask_generation_prompt_encoding.py, 6 passed) since _sam2_prompt.py was touched; CUDA predict exercised end-to-end for finding 2; NPU and ONNX integration suites pass on real hardware (3 passed); full default suite 664 passed / 2 pre-existing failures; pinned ruff 0.6.9 check and format clean.
  • The disposal fix for finding 3 is covered by a test that was confirmed to fail without it (the decoder session, which is created then rejected and never assigned, was the actual leak — the pre-existing assertion only covered the encoder).

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

�����JFIF������C

P2 Badge Remove the unreferenced image assets

A repo-wide rg for all six added filenames finds no package, test, or documentation consumer, yet these binaries add about 4.3 MB permanently to the repository. They appear to be local inference/test inputs rather than required package data, which the repository guide explicitly says not to commit; remove them from this change.

AGENTS.md reference: AGENTS.md:L189-L190

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread mblt_vision/mask_generation/sam2.py Outdated
Comment thread mblt_vision/mask_generation/sam2.py
Comment thread mblt_vision/mask_generation/_sam2_contracts.py
Comment thread mblt_vision/utils/evaluation/eval_sav.py Outdated
Validation hardening:
- Inspect point labels before the int64 cast. Casting first truncated 0.5,
  1.9 and -0.1 into valid 0/1 labels, defeating the exact-label contract.
- Reject non-finite point coordinates before Fourier prompt encoding, which
  would otherwise contaminate tokens, masks, and IoU scores. Also rejected in
  the CLI's parse_point, since float() accepts "nan"/"inf" and the reported
  repro was `--point nan,240,1`.
- Enforce the three-candidate decoder contract in classify_decoder_outputs so
  a stale or differently exported decoder fails there rather than returning an
  incompatible Results.masks shape to ordinary callers.
- Replace eval_sav's `assert result.selected is not None` with an explicit
  ValueError: the protocol permits None, the evaluator documents ValueError
  for prediction-contract violations, and an assert vanishes under `python -O`.
- Apply the same reasoning to readiness._sav_ready's `assert first_pair`, which
  had identical `-O` exposure in a function documented to answer with False.

Packaging:
- Add MANIFEST.in pruning `assets`. Sample images are development-only inputs
  kept in git deliberately; setuptools already excluded them, so this pins the
  intent rather than fixing a leak. Verified: wheel and sdist contain zero
  images, package data (315 model YAMLs, dataset YAML/txt, py.typed) intact,
  and the built wheel imports and discovers mask_generation in isolation.
- Record that deliberate exception in AGENTS.md and the skill, which
  previously said not to commit test assets at all.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@parkjinman98

Copy link
Copy Markdown
Contributor Author

Second round addressed in e565233. Four inline threads are fixed and resolved; the fifth finding (image assets) is answered below as a maintainer decision. Please read the notes before re-reviewing.

Finding Status Where
Validate labels before the integer cast (P2) Fixed sam2.py — labels read via plain np.asarray, checked for dtype/finiteness/integrality before the int64 cast; 0.5/1.9/-0.1 now rejected instead of truncating
Reject non-finite point coordinates (P2) Fixed sam2.py engine check and cli/_vision.py:parse_point — you named --point nan,240,1, and engine-only validation would have left that path intact
Enforce the three-mask decoder output contract (P2) Fixed _sam2_contracts.py — new MASK_CANDIDATE_COUNT = 3 enforced in classify_decoder_outputs, cross-referenced to eval_sav.CANDIDATES_PER_PROMPT
Validate a missing selected-mask index explicitly (P2) Fixed eval_sav.py — explicit ValueError; also applied to the identical -O exposure in readiness._sav_ready
Remove the unreferenced image assets (P2) Won't fix — deliberate decision See below

On the image assets

Keeping them is a maintainer decision, not an oversight. assets/ holds a small fixed set of sample inputs used for manual QA and the documented CLI examples. They stay in git; they must never ship.

Your point about shipped weight is fully addressed and verified:

  • MANIFEST.in now prunes assets. setuptools already excluded it (only mblt_vision* packages are built), so this pins the intent against future packaging changes rather than fixing a current leak.
  • Built both artifacts and inspected them: wheel and sdist contain zero .jpg/.png files, while package data stays intact (315 model YAMLs, dataset YAML/txt, py.typed). The built wheel was extracted and imported in isolation — list_models("mask_generation") discovers SAM2HieraLarge, and the installed package tree contains 0 images.

Your repository-weight point stands on its own and is not refuted by that check — the 4.3 MB is accepted deliberately. The finding was also correct against the guide as written, since AGENTS.md said not to commit test assets at all. Rather than leave code and guide in conflict, AGENTS.md and the skill now record the exception explicitly: development-only sample images, tracked by deliberate exception, pruned from distribution, not to be grown for new one-off inputs. Please treat that guide bullet as the current contract — this thread is closed by decision, not by code, and a human can reopen it if they disagree.

Notes for the next pass

  • Two findings had a second site your comments did not cover, both fixed in the same commit: parse_point for the non-finite coordinates, and readiness._sav_ready's assert first_pair is not None for the python -O class. That is the third round in a row where a reported issue had a twin elsewhere, so the sweep is now part of how I handle these.
  • Still pre-existing and out of scope: tests/test_wrapper.py::test_dflfree_pose_accepts_decode_true_mxq_parts_with_reducemax and ::test_dflfree_pose_prefers_score_tensor_over_reducemax_duplicate fail on main and on this branch's parent. Unrelated to mask generation, not introduced here, not fixed here.
  • Settled in round one, please do not re-raise: the SAV_VALIDATION_MASK_COUNT = 31967 figure is measured from the sha256-pinned sav_val.tar and validated against the real organized dataset; the frame count is deliberately not pinned.
  • Verification: full default suite 670 passed / 2 pre-existing failures; pinned ruff 0.6.9 check and format clean; wheel + sdist rebuilt and inspected; wheel import smoke-tested in isolation. No numerics changed this round, so the prompt-encoding parity and hardware suites were not re-run.

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e565233647

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread mblt_vision/utils/datasets/organizer.py
Comment thread mblt_vision/utils/datasets/readiness.py Outdated
Comment thread mblt_vision/mask_generation/_sam2_contracts.py
Comment thread mblt_vision/cli/val.py
Security:
- Reject SA-V video ids that fail SAV_VIDEO_ID_PATTERN, and confirm every
  staged path resolves inside the staging tree, before any makedirs/copy.
  Ids come from sav_val.txt contents rather than a directory listing, so an
  entry like `../../escape` could copy attacker-controlled PNGs into the
  output parent before organization failed. COCO already applied the
  equivalent guard to its JSON-declared file names; swept the other
  organizers and SA-V was the only one building paths from file contents
  without it.

Correctness:
- Validate every cached SA-V mask, not just the first pair per video. A cache
  with a valid first mask and a later {1, 2} mask previously passed readiness
  and was then turned entirely to foreground by CustomSAV's `> 0`. Geometry
  and values are now checked per mask; the official split is 1-bit bilevel, a
  format that cannot encode a non-zero background, so those masks validate
  from the header and only non-bilevel masks are decoded. Real-dataset
  dataset_ready stays at 3.2s for all 31967 masks (decoding every mask would
  be ~380s on every val run).
- Reject non-finite decoder outputs in classify_decoder_outputs, so a NaN from
  a numerical/runtime failure cannot reach argmax over the IoU scores or the
  `> 0` mask threshold and silently corrupt predictions and SA-V metrics.
- Never return the organized cache from _find_existing_source. Fixed
  generically rather than by renaming one candidate: both `sa-v` and
  `nyu-depth` name their cache directory identically to a source candidate, so
  `data_path.parent / name` resolved back to `data_path` and organizing from
  the incomplete cache failed instead of downloading the default archive.

Docs: sync AGENTS.md and the mblt-vision skill with the new contracts.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@parkjinman98

Copy link
Copy Markdown
Contributor Author

Third round addressed in 3331848. All four threads fixed and resolved.

Finding Status Where
Reject traversal IDs before constructing SA-V paths (P1) Fixed organizer.py — id-pattern check + staged-path containment, both before any makedirs/copy
Validate every cached SA-V mask (P2) Fixed readiness.py — per-mask geometry and value checks, at unchanged 3.2s cost
Reject non-finite decoder outputs (P2) Fixed _sam2_contracts.py — finiteness enforced before argmax/> 0
Exclude organized SA-V output from source discovery (P2) Fixed cli/val.py — generic self-exclusion in _find_existing_source

Two findings generalized rather than patched at the reported line

  • Traversal: I swept every organizer for the same shape. The discriminator is whether a path component comes from file contents (can carry ../) or a directory listing (cannot). COCO reads file_name from JSON and already had the equivalent guard; DOTA parses numeric fields; WiderFace/Cityscapes/ImageNet use directory listings. SA-V was the only unguarded case, and the fix mirrors COCO's existing precedent.
  • Source discovery: you offered "remove the colliding sa-v source name" as an alternative — I took the general fix instead, because the collision is not unique to SA-V. _resolve_nyu_depth_source searches ["nyu-depth.zip", "nyu-depth"] against a cache directory literally named nyu-depth, so it had the identical defect. Both are now covered.

On the every-mask validation cost

This runs on every val, so the naive fix is expensive. Measured before choosing: decoding all 31,967 masks is ~380s; reading headers is ~1s.

The official masks are 1-bit bilevel (mode "1" — verified across all 31,967), and a 1-bit PNG cannot encode a non-zero background, so for those the value constraint is discharged by the format, not skipped. Non-bilevel masks are decoded and checked directly. Every mask is validated for both geometry and values either way.

Result: dataset_ready() on the real organized dataset stays at 3.2s — identical to before this change — while now covering all 31,967 masks instead of 155.

Notes for the next pass

  • Please treat the guide as current. AGENTS.md and the skill now record: per-mask readiness validation and the bilevel rationale, the sav_val.txt id/containment requirement with the file-contents-vs-directory-listing discriminator, and the decoder finiteness/candidate-count contracts.
  • Deliberately not done, with reasons: no IoU [0, 1] range assertion (would false-positive on int8 dequantization); no duplicate finiteness check on encoder outputs (a non-finite encoder value propagates to the decoder and is caught at the same chokepoint); readiness still decodes only one frame per video in full, which is what catches a truncated JPEG — header reads cover geometry for the rest.
  • Settled earlier, please do not re-raise: SAV_VALIDATION_MASK_COUNT = 31967 is measured from the sha256-pinned archive; assets/ is a recorded deliberate exception in AGENTS.md, kept in git and pruned from all distributed artifacts.
  • Still pre-existing and out of scope: the two tests/test_wrapper.py::*dflfree_pose* failures, which fail on main and this branch's parent.
  • Verification: full default suite 682 passed / 2 pre-existing failures; NPU and ONNX integration suites pass on real hardware (the finiteness check is on both live inference paths); real-dataset dataset_ready re-timed; pinned ruff 0.6.9 clean. No packaging or numerics changes this round.

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 33318481bd

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +179 to +183
resolved_prompt_weights_path = prompt_weights_path or download_hub_artifact(
repo_id=_REPO_ID,
filename=_PROMPT_WEIGHTS_FILENAME,
revision=resolved_revision,
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Validate local artifacts before downloading prompt weights

When a caller supplies a nonexistent encoder_mxq_path/decoder_mxq_path (or ONNX equivalent) without prompt_weights_path, this download runs before either explicit artifact is checked. In an offline environment the constructor therefore reports a Hub/network failure instead of the invalid local path; online it performs an unnecessary download before failing later in backend creation. Validate every explicitly supplied artifact path before resolving downloads, matching MBLT_Engine's fail-fast FileNotFoundError behavior.

AGENTS.md reference: AGENTS.md:L41-L43

Useful? React with 👍 / 👎.

Comment on lines +125 to +127
if len(got) != len(want) or any(
expected_dim != -1 and actual_dim != expected_dim
for actual_dim, expected_dim in zip(got, want)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Enforce a dynamic ONNX prompt-token axis

When a decoder ONNX graph was exported with a fixed token dimension such as (1, 8, 256), this predicate skips the comparison because the expected dimension is -1, so the graph incorrectly passes construction validation. One-point inference then works, but the advertised two- and three-point prompts produce 9- or 10-token feeds and fail inside ONNX Runtime; require the session metadata itself to be dynamic on this axis rather than treating -1 as an unrestricted construction-time wildcard.

AGENTS.md reference: AGENTS.md:L96-L98

Useful? React with 👍 / 👎.

Comment on lines +248 to +250
except Exception:
self.close()
raise

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve construction errors when cleanup also fails

When decoder construction, graph validation, or prompt-weight loading raises after a backend has been assigned, this handler calls the public non-suppressing close(). If either runtime also raises from dispose(), that cleanup exception replaces the original construction failure presented to the caller; the helper-level failure handlers have the same behavior. Suppress disposal failures while unwinding construction, as the base engine does, so the actionable original error remains primary.

AGENTS.md reference: AGENTS.md:L44-L50

Useful? React with 👍 / 👎.

"Candidate masks and ground truth shapes must match: "
f"candidates {candidates.shape[1:]}, ground truth {gt.shape}."
)
return [mask_iou(candidate.astype(bool), gt) for candidate in candidates]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject non-binary candidate masks before scoring

When a structural PointPromptedEngine returns mask logits, probabilities, or non-finite values rather than already-binarized masks, this cast treats every nonzero value—including negative logits and NaNs—as foreground. eval_sav then reports plausible but corrupted IoUs instead of identifying the prediction-contract violation; validate that each candidate is a finite binary map (while allowing conventional binary encodings) before converting it to bool.

AGENTS.md reference: AGENTS.md:L166-L167

Useful? React with 👍 / 👎.

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