Fix Pad.inverse channel-dimension back-crop#8900
Conversation
Pad.inverse computed the channel-dimension back-crop as min(max(padded[0][1], s + 1), len(data)), where s is the front pad. The max(..., s + 1) term forced the crop to be at least front_pad + 1 even when the recorded back pad was smaller (or zero), so inverting a transform with a non-zero channel pad sliced away the wrong number of channels (often emptying the channel dim) and failed to round-trip. Compute the back-crop directly from the recorded back pad instead: e = min(padded[0][1], len(data) - s). Signed-off-by: Soumya Snigdha Kundu <soumya_snigdha.kundu@kcl.ac.uk>
Covers round-tripping a non-zero channel pad (front-only, back-only, symmetric, and combined channel+spatial) through Pad/Pad.inverse using the NumPy backend, which pads the channel dimension. These cases failed before the back-crop fix. Signed-off-by: Soumya Snigdha Kundu <soumya_snigdha.kundu@kcl.ac.uk>
📝 WalkthroughWalkthroughThe PR fixes a boundary-condition bug in the Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 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
🤖 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/transforms/croppad/test_pad_inverse_channel.py`:
- Around line 32-40: Add a Google-style docstring to the test method
test_inverse_roundtrip_channel_pad describing the test's purpose and its
parameter to_pad (e.g., what padding configuration is being tested and the
expected round-trip behavior), placed immediately below the def line; ensure it
follows Google style with a short description and an Args section for to_pad.
🪄 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: 305f534c-ba43-49b2-9512-d937a43c10e1
📒 Files selected for processing (2)
monai/transforms/croppad/array.pytests/transforms/croppad/test_pad_inverse_channel.py
| def test_inverse_roundtrip_channel_pad(self, to_pad): | ||
| set_track_meta(True) | ||
| img = MetaTensor(torch.arange(3 * 4 * 4).reshape(3, 4, 4).float()) | ||
| pad = Pad(to_pad=to_pad, mode="symmetric") | ||
| padded = pad(img.clone()) | ||
| self.assertEqual(padded.shape[0], img.shape[0] + to_pad[0][0] + to_pad[0][1]) | ||
| inv = pad.inverse(padded) | ||
| self.assertEqual(inv.shape, img.shape) | ||
| self.assertTrue(torch.equal(inv.as_tensor(), img.as_tensor())) |
There was a problem hiding this comment.
Add docstring to test method.
Per coding guidelines, all definitions require Google-style docstrings describing parameters and purpose.
📝 Suggested docstring
`@parameterized.expand`(CHANNEL_PAD_CASES)
def test_inverse_roundtrip_channel_pad(self, to_pad):
+ """Test Pad.inverse correctly restores original tensor after channel-dimension padding.
+
+ Args:
+ to_pad: Padding specification [(ch_pad), (h_pad), (w_pad)].
+ """
set_track_meta(True)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| def test_inverse_roundtrip_channel_pad(self, to_pad): | |
| set_track_meta(True) | |
| img = MetaTensor(torch.arange(3 * 4 * 4).reshape(3, 4, 4).float()) | |
| pad = Pad(to_pad=to_pad, mode="symmetric") | |
| padded = pad(img.clone()) | |
| self.assertEqual(padded.shape[0], img.shape[0] + to_pad[0][0] + to_pad[0][1]) | |
| inv = pad.inverse(padded) | |
| self.assertEqual(inv.shape, img.shape) | |
| self.assertTrue(torch.equal(inv.as_tensor(), img.as_tensor())) | |
| def test_inverse_roundtrip_channel_pad(self, to_pad): | |
| """Test Pad.inverse correctly restores original tensor after channel-dimension padding. | |
| Args: | |
| to_pad: Padding specification [(ch_pad), (h_pad), (w_pad)]. | |
| """ | |
| set_track_meta(True) | |
| img = MetaTensor(torch.arange(3 * 4 * 4).reshape(3, 4, 4).float()) | |
| pad = Pad(to_pad=to_pad, mode="symmetric") | |
| padded = pad(img.clone()) | |
| self.assertEqual(padded.shape[0], img.shape[0] + to_pad[0][0] + to_pad[0][1]) | |
| inv = pad.inverse(padded) | |
| self.assertEqual(inv.shape, img.shape) | |
| self.assertTrue(torch.equal(inv.as_tensor(), img.as_tensor())) |
🤖 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/transforms/croppad/test_pad_inverse_channel.py` around lines 32 - 40,
Add a Google-style docstring to the test method
test_inverse_roundtrip_channel_pad describing the test's purpose and its
parameter to_pad (e.g., what padding configuration is being tested and the
expected round-trip behavior), placed immediately below the def line; ensure it
follows Google style with a short description and an Args section for to_pad.
Source: Coding guidelines
Description
Pad.inversecomputed the channel back-crop asmin(max(padded[0][1], s + 1), len(data)), wheresis the front pad. Themax(..., s + 1)term forced the back-crop to at leastfront_pad + 1even when the recorded back pad was smaller or zero, so inverting aPadwith a non-zero channel pad cropped the wrong number of channels (often emptying the channel dim) and failed to round-trip.For example, inverting a channel pad of
(2, 0)on a 3-channel image produceds = 2,e = min(max(0, 3), 5) = 3, i.e.data[2 : len - 3], an empty slice.The back-crop is now computed directly from the recorded back pad:
e = min(padded[0][1], len(data) - s).Note this only affects the NumPy padding backend (e.g.
mode="symmetric"), which pads the channel dimension; the PyTorch backend ignores channel padding, so the added test usesmode="symmetric"to exercise the channel path.Types of changes
./runtests.sh -f -u --net --coverage../runtests.sh --quick --unittests --disttests.