Skip to content

Perf: single-pass remap_instance_id (unique + bincount + LUT gather)#9009

Open
aymuos15 wants to merge 3 commits into
Project-MONAI:devfrom
aymuos15:perf/remap-instance-id-quadratic
Open

Perf: single-pass remap_instance_id (unique + bincount + LUT gather)#9009
aymuos15 wants to merge 3 commits into
Project-MONAI:devfrom
aymuos15:perf/remap-instance-id-quadratic

Conversation

@aymuos15

Copy link
Copy Markdown
Contributor

Description

Replaces the per-instance loops in remap_instance_id (which scanned the full volume once per instance id — twice with by_size=True — for O(instances * volume) work) with a single torch.unique(return_inverse=True) + bincount + LUT-gather pass, computing the same relabeling in O(volume). Same approach as #8978; by_size tie-breaking (stable, ascending-id) and the int32 output dtype are preserved exactly.

Benchmark

Synthetic instance masks (random sparse ids, by_size=True), median of repeated runs, OMP_NUM_THREADS=8.

2D

Input (H×W, #inst) CPU speedup CUDA speedup
128×128, 40 ~4.2× ~8.2×
256×256, 80 ~10.8× ~10.4×
512×512, 150 ~9.1× ~17.9×
512×512, 300 ~18× ~36×
1024×1024, 150 ~5.7× ~16.6×
1024×1024, 500 ~18.7× ~54.6×

3D

Input (D×H×W, #inst) CPU speedup CUDA speedup
64×64×64, 30 ~2.4× ~3.8×
96×96×96, 50 ~2.8× ~5.8×
128×128×128, 80 ~3.6× ~8.9×
128×128×128, 200 ~8.6× ~21.6×
160×160×160, 120 ~5.8× ~13×

Numerics are bit-identical (torch.equal) at every size. The old implementation was slowest on GPU (e.g. 2720 ms for 1024×1024 with 500 instances, vs 262 ms on CPU) because the per-instance masked scans serialize; that inversion is gone (49.8 ms).

System: 12th Gen Intel Core i7-12800H (20 threads, OMP_NUM_THREADS=8); NVIDIA RTX A1000 Laptop GPU (4 GB); Linux 6.8.0-124-generic x86_64; Python 3.10.12; PyTorch 2.12.1+cu130.

Types of changes

  • Non-breaking change (fix or new feature that would not break existing functionality).
  • New tests added to cover the changes.
  • The metrics tests passed locally (490 passed, including new parameterized cases for non-contiguous ids, size ties, no-background and empty inputs, and randomized 2D/3D equivalence against the previous implementation), along with black/isort/ruff/mypy.

Signed-off-by: Soumya Snigdha Kundu <soumya_snigdha.kundu@kcl.ac.uk>
@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: c42ed244-4e5c-4ddd-8b81-57d4ec5d800c

📥 Commits

Reviewing files that changed from the base of the PR and between e459cff and cd74ae2.

📒 Files selected for processing (2)
  • monai/metrics/utils.py
  • tests/metrics/test_remap_instance_id.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • monai/metrics/utils.py
  • tests/metrics/test_remap_instance_id.py

📝 Walkthrough

Walkthrough

remap_instance_id now uses vectorized PyTorch operations to identify, order, and remap instance IDs through a lookup table. The update also removes the unused Iterable import. A dedicated test suite covers deterministic cases, stable size ordering, passthrough behavior, output dtype, empty and multidimensional inputs, sparse IDs, and randomized equivalence with a reference implementation.

Estimated code review effort: 2 (Simple) | ~10 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely states the main performance change to remap_instance_id.
Description check ✅ Passed The description is detailed, includes the change rationale, benchmark, and the required change-type checklist.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (3)
tests/metrics/test_remap_instance_id.py (2)

78-79: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use a descriptive generator name.

Rename g to generator.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/metrics/test_remap_instance_id.py` around lines 78 - 79, Rename the
local generator variable g to generator in the test setup, and update its use in
the torch.randint call accordingly.

Source: Path instructions


36-84: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add required Google-style docstrings.

Document _reference_remap, TestRemapInstanceId, and each test method, with Args, Returns, and Raises where applicable.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/metrics/test_remap_instance_id.py` around lines 36 - 84, Add
Google-style docstrings to `_reference_remap`, `TestRemapInstanceId`, and every
test method in that class. Document parameters with `Args`, return values with
`Returns` where applicable, and expected exceptions with `Raises` where
applicable; keep the existing test behavior unchanged.

Source: Path instructions

monai/metrics/utils.py (1)

422-433: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Document the return contract.

Add a Google-style Returns: section, including the torch.int output for remapped inputs and passthrough dtype for empty/all-background inputs.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@monai/metrics/utils.py` around lines 422 - 433, Update the documentation for
the function containing the torch.unique remapping logic with a Google-style
Returns: section. Specify that remapped inputs return a torch.int tensor, while
empty or all-background inputs are returned unchanged with their original dtype.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/metrics/test_remap_instance_id.py`:
- Line 43: Update the zip call used to build pair_list so it passes strict=True,
ensuring pred_id and instance_size have matching lengths while preserving the
existing sorting and reverse-order behavior.

---

Nitpick comments:
In `@monai/metrics/utils.py`:
- Around line 422-433: Update the documentation for the function containing the
torch.unique remapping logic with a Google-style Returns: section. Specify that
remapped inputs return a torch.int tensor, while empty or all-background inputs
are returned unchanged with their original dtype.

In `@tests/metrics/test_remap_instance_id.py`:
- Around line 78-79: Rename the local generator variable g to generator in the
test setup, and update its use in the torch.randint call accordingly.
- Around line 36-84: Add Google-style docstrings to `_reference_remap`,
`TestRemapInstanceId`, and every test method in that class. Document parameters
with `Args`, return values with `Returns` where applicable, and expected
exceptions with `Raises` where applicable; keep the existing test behavior
unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 7e01ca0f-c313-4f7e-bce5-f5ff3e022504

📥 Commits

Reviewing files that changed from the base of the PR and between a3d5160 and e459cff.

📒 Files selected for processing (2)
  • monai/metrics/utils.py
  • tests/metrics/test_remap_instance_id.py

Comment thread tests/metrics/test_remap_instance_id.py Outdated
Signed-off-by: Soumya Snigdha Kundu <soumya_snigdha.kundu@kcl.ac.uk>
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