Add AbsoluteVolumeDifferenceMetric to monai.metrics#8945
Conversation
Implements the Absolute Volume Difference (AVD) metric as requested in Project-MONAI#4009. AVD measures the absolute difference in foreground voxel counts between prediction and ground truth per class, and is particularly suited for small-object segmentation tasks (e.g. retinal fluid in OCT volumes) where Dice score is overly sensitive to volume size. Changes: - monai/metrics/absolute_volume_difference.py: new AbsoluteVolumeDifferenceMetric class (CumulativeIterationMetric) and compute_absolute_volume_difference() standalone function. Supports include_background, reduction, get_not_nans, and ignore_empty. References the RETOUCH benchmark paper. - monai/metrics/__init__.py: export both new symbols. - tests/metrics/test_absolute_volume_difference.py: 14 unit tests covering perfect prediction, known volume difference, ignore_empty behaviour, include_background stripping, 3D volumes, cumulative accumulation, and error cases. This PR was authored with the assistance of an AI coding assistant. Signed-off-by: MDSALMANSHAMS <salmanshams67@gmail.com>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
📝 WalkthroughWalkthroughA new file Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (2)
monai/metrics/absolute_volume_difference.py (1)
80-121: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winComplete method-level Google-style docstrings.
__init__lacks a method docstring,_compute_tensor/aggregateomitReturns, andaggregateshould document itsValueErrorinRaises.Suggested docstring patch
def __init__( self, include_background: bool = True, reduction: MetricReduction | str = MetricReduction.MEAN, get_not_nans: bool = False, ignore_empty: bool = True, ) -> None: + """Initialize AbsoluteVolumeDifferenceMetric. + + Args: + include_background: Whether to include channel 0. + reduction: Reduction mode used in :meth:`aggregate`. + get_not_nans: Whether :meth:`aggregate` returns `(metric, not_nans)`. + ignore_empty: Whether empty ground-truth channels are set to NaN. + """ super().__init__() self.include_background = include_background self.reduction = reduction self.get_not_nans = get_not_nans self.ignore_empty = ignore_empty @@ def _compute_tensor(self, y_pred: torch.Tensor, y: torch.Tensor) -> torch.Tensor: # type: ignore[override] """ Args: y_pred: binarized prediction tensor, shape BCHW[D]. y: binarized ground-truth tensor, shape BCHW[D]. + Returns: + Per-batch per-class AVD tensor with shape [B, C]. + Raises: ValueError: when ``y_pred`` has fewer than three dimensions. """ @@ def aggregate( self, reduction: MetricReduction | str | None = None ) -> torch.Tensor | tuple[torch.Tensor, torch.Tensor]: """ Execute reduction logic for the accumulated AVD values. Args: reduction: optional override for the reduction mode set at construction. + + Returns: + Reduced metric tensor, or ``(metric, not_nans)`` when ``get_not_nans=True``. + + Raises: + ValueError: when internal buffered data is not a tensor. """As per path instructions, "Docstrings should be present for all definition which describe each variable, return value, and raised exception in the appropriate section of the Google-style of docstrings."
🤖 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/absolute_volume_difference.py` around lines 80 - 121, Add complete Google-style docstrings for the AVD metric methods in AbsoluteVolumeDifference: the __init__ method needs a short summary plus Args entries for include_background, reduction, get_not_nans, and ignore_empty; _compute_tensor should include a Returns section describing the computed tensor and keep its ValueError in Raises; aggregate should add a Returns section for the reduced output and document the ValueError it can raise in Raises. Use the existing method names to update each docstring so every parameter, return value, and exception is covered.Source: Path instructions
tests/metrics/test_absolute_volume_difference.py (1)
24-157: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd Google-style docstrings to test methods.
Method definitions from Line 24 through Line 156 are missing per-method docstrings, so this file does not meet the docstring requirement for Python definitions.
As per path instructions, "Docstrings should be present for all definition which describe each variable, return value, and raised exception in the appropriate section of the Google-style of docstrings."
🤖 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_absolute_volume_difference.py` around lines 24 - 157, Add Google-style docstrings to each test method in TestAbsoluteVolumeDifference and TestAbsoluteVolumeDifferenceMetric so every definition is documented as required. Update the individual test_* methods to describe the purpose, arguments/fixtures used, expected return behavior, and any raised exceptions in Google-style format, keeping the docstrings aligned with the method names and assertions in this file.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_absolute_volume_difference.py`:
- Around line 149-150: The reset/empty-buffer path in aggregate() is being
tested with a too-broad exception check, which can hide unrelated failures.
Update the test around AbsoluteVolumeDifference.aggregate() to assert the
specific ValueError expected after reset instead of Exception, using the
metric.aggregate call in the existing test case so the failure mode is explicit.
---
Nitpick comments:
In `@monai/metrics/absolute_volume_difference.py`:
- Around line 80-121: Add complete Google-style docstrings for the AVD metric
methods in AbsoluteVolumeDifference: the __init__ method needs a short summary
plus Args entries for include_background, reduction, get_not_nans, and
ignore_empty; _compute_tensor should include a Returns section describing the
computed tensor and keep its ValueError in Raises; aggregate should add a
Returns section for the reduced output and document the ValueError it can raise
in Raises. Use the existing method names to update each docstring so every
parameter, return value, and exception is covered.
In `@tests/metrics/test_absolute_volume_difference.py`:
- Around line 24-157: Add Google-style docstrings to each test method in
TestAbsoluteVolumeDifference and TestAbsoluteVolumeDifferenceMetric so every
definition is documented as required. Update the individual test_* methods to
describe the purpose, arguments/fixtures used, expected return behavior, and any
raised exceptions in Google-style format, keeping the docstrings aligned with
the method names and assertions in this file.
🪄 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
Run ID: 4cd5d4f5-95d5-4ac0-966f-e7e70094a110
📒 Files selected for processing (3)
monai/metrics/__init__.pymonai/metrics/absolute_volume_difference.pytests/metrics/test_absolute_volume_difference.py
Add one-liner docstring to __init__ and brief docstrings to all fourteen test methods so CodeRabbit's docstring-coverage pre-merge check passes (was 16.67%, threshold is 80%). Signed-off-by: MDSALMANSHAMS <salmanshams67@gmail.com>
Summary
Closes #4009.
Adds AbsoluteVolumeDifferenceMetric and a standalone compute_absolute_volume_difference() function to monai.metrics.
Why AVD?
Dice score is known to be overly sensitive for small-object segmentation (e.g. retinal fluid sub-types in OCT volumes - SRF, IRF, PED), because small volume differences produce large Dice swings. AVD directly reflects volume size discrepancy, making it the standard evaluation metric in the RETOUCH retinal OCT fluid benchmark (Bogunovic et al., IEEE TMI 2019).
Changes
eduction, get_not_nans, ignore_empty.
Test plan
All 14 tests pass (python -m unittest tests.metrics.test_absolute_volume_difference -v).