Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 17 additions & 3 deletions monai/losses/dice.py
Original file line number Diff line number Diff line change
Expand Up @@ -803,9 +803,9 @@ def __init__(
"""
super().__init__()
self.dice = DiceLoss(
sigmoid=sigmoid,
softmax=softmax,
other_act=other_act,
sigmoid=False,
softmax=False,
other_act=None,
squared_pred=squared_pred,
jaccard=jaccard,
reduction=reduction,
Expand All @@ -822,6 +822,9 @@ def __init__(
self.lambda_focal = lambda_focal
self.to_onehot_y = to_onehot_y
self.include_background = include_background
self.sigmoid = sigmoid
self.softmax = softmax
self.other_act = other_act
Comment on lines +825 to +827

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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Preserve activation exclusivity validation.

With DiceLoss activation disabled, configs like sigmoid=True, softmax=True are now silently accepted and resolved by if/elif.

Proposed fix
         self.to_onehot_y = to_onehot_y
         self.include_background = include_background
+        if int(sigmoid) + int(softmax) + int(other_act is not None) > 1:
+            raise ValueError("Only one of sigmoid=True, softmax=True, or other_act may be specified.")
         self.sigmoid = sigmoid
         self.softmax = softmax
         self.other_act = other_act

As per path instructions, "Examine code for logical error or inconsistencies".

📝 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.

Suggested change
self.sigmoid = sigmoid
self.softmax = softmax
self.other_act = other_act
self.to_onehot_y = to_onehot_y
self.include_background = include_background
if int(sigmoid) + int(softmax) + int(other_act is not None) > 1:
raise ValueError("Only one of sigmoid=True, softmax=True, or other_act may be specified.")
self.sigmoid = sigmoid
self.softmax = softmax
self.other_act = other_act
🤖 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/losses/dice.py` around lines 825 - 827, DiceLoss is no longer enforcing
mutually exclusive activation settings, so invalid configs like sigmoid=True and
softmax=True can slip through when the activation path is skipped. Restore the
exclusivity validation in DiceLoss initialization or setup logic by checking the
sigmoid, softmax, and other_act flags together and raising an error when more
than one activation is enabled; use the DiceLoss constructor/validation flow to
locate and fix this.

Source: Path instructions


def forward(self, input: torch.Tensor, target: torch.Tensor) -> torch.Tensor:
"""
Expand All @@ -846,6 +849,17 @@ def forward(self, input: torch.Tensor, target: torch.Tensor) -> torch.Tensor:
else:
target = one_hot(target, num_classes=n_pred_ch)

# Apply activation before removing background to ensure softmax/sigmoid works correctly
if self.sigmoid:
input = torch.sigmoid(input)
elif self.softmax:
if n_pred_ch == 1:
warnings.warn("single channel prediction, `softmax=True` ignored.")

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.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Set stacklevel on the new warning.

Ruff flags this warnings.warn call; use stacklevel=2 so callers see their call site.

Proposed fix
-                warnings.warn("single channel prediction, `softmax=True` ignored.")
+                warnings.warn("single channel prediction, `softmax=True` ignored.", stacklevel=2)
📝 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.

Suggested change
warnings.warn("single channel prediction, `softmax=True` ignored.")
warnings.warn("single channel prediction, `softmax=True` ignored.", stacklevel=2)
🧰 Tools
🪛 Ruff (0.15.18)

[warning] 857-857: No explicit stacklevel keyword argument found

Set stacklevel=2

(B028)

🤖 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/losses/dice.py` at line 857, The warning emitted in the single-channel
prediction branch of `DiceLoss` needs an explicit stack level so the caller sees
the correct source location. Update the `warnings.warn` call in `dice.py` to
pass `stacklevel=2`, keeping the existing message intact and making sure the
change is applied in the `DiceLoss` logic where `softmax=True` is ignored.

Source: Linters/SAST tools

else:
input = torch.softmax(input, 1)
elif self.other_act is not None:
input = self.other_act(input)

if not self.include_background:
if n_pred_ch == 1:
warnings.warn("single channel prediction, `include_background=False` ignored.")
Expand Down