Skip to content

Commit 29cf6ac

Browse files
committed
Merge branch 'dev' of https://github.com/Project-MONAI/MONAI into fix/metatensor-einops
2 parents 8d7610b + 9ddd5e6 commit 29cf6ac

File tree

4 files changed

+61
-28
lines changed

4 files changed

+61
-28
lines changed

monai/losses/dice.py

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313

1414
import warnings
1515
from collections.abc import Callable, Sequence
16-
from typing import Any
1716

1817
import numpy as np
1918
import torch
@@ -239,11 +238,52 @@ class MaskedDiceLoss(DiceLoss):
239238
240239
"""
241240

242-
def __init__(self, *args: Any, **kwargs: Any) -> None:
241+
def __init__(
242+
self,
243+
include_background: bool = True,
244+
to_onehot_y: bool = False,
245+
sigmoid: bool = False,
246+
softmax: bool = False,
247+
other_act: Callable | None = None,
248+
squared_pred: bool = False,
249+
jaccard: bool = False,
250+
reduction: LossReduction | str = LossReduction.MEAN,
251+
smooth_nr: float = 1e-5,
252+
smooth_dr: float = 1e-5,
253+
batch: bool = False,
254+
weight: Sequence[float] | float | int | torch.Tensor | None = None,
255+
soft_label: bool = False,
256+
) -> None:
243257
"""
244258
Args follow :py:class:`monai.losses.DiceLoss`.
245259
"""
246-
super().__init__(*args, **kwargs)
260+
if other_act is not None and not callable(other_act):
261+
raise TypeError(f"other_act must be None or callable but is {type(other_act).__name__}.")
262+
if sigmoid and softmax:
263+
raise ValueError("Incompatible values: sigmoid=True and softmax=True.")
264+
if other_act is not None and (sigmoid or softmax):
265+
raise ValueError("Incompatible values: other_act is not None and sigmoid=True or softmax=True.")
266+
267+
self.pre_sigmoid = sigmoid
268+
self.pre_softmax = softmax
269+
self.pre_other_act = other_act
270+
271+
super().__init__(
272+
include_background=include_background,
273+
to_onehot_y=to_onehot_y,
274+
sigmoid=False,
275+
softmax=False,
276+
other_act=None,
277+
squared_pred=squared_pred,
278+
jaccard=jaccard,
279+
reduction=reduction,
280+
smooth_nr=smooth_nr,
281+
smooth_dr=smooth_dr,
282+
batch=batch,
283+
weight=weight,
284+
soft_label=soft_label,
285+
)
286+
247287
self.spatial_weighted = MaskedLoss(loss=super().forward)
248288

249289
def forward(self, input: torch.Tensor, target: torch.Tensor, mask: torch.Tensor | None = None) -> torch.Tensor:
@@ -253,6 +293,19 @@ def forward(self, input: torch.Tensor, target: torch.Tensor, mask: torch.Tensor
253293
target: the shape should be BNH[WD].
254294
mask: the shape should B1H[WD] or 11H[WD].
255295
"""
296+
297+
if self.pre_sigmoid:
298+
input = torch.sigmoid(input)
299+
300+
n_pred_ch = input.shape[1]
301+
if self.pre_softmax:
302+
if n_pred_ch == 1:
303+
warnings.warn("single channel prediction, `softmax=True` ignored.", stacklevel=2)
304+
else:
305+
input = torch.softmax(input, 1)
306+
307+
if self.pre_other_act is not None:
308+
input = self.pre_other_act(input)
256309
return self.spatial_weighted(input=input, target=target, mask=mask) # type: ignore[no-any-return]
257310

258311

monai/networks/blocks/fft_utils_t.py

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,6 @@ def roll_1d(x: Tensor, shift: int, shift_dim: int) -> Tensor:
2828
2929
Returns:
3030
1d-shifted version of x
31-
32-
Note:
33-
This function is called when fftshift and ifftshift are not available in the running pytorch version
3431
"""
3532
shift = shift % x.size(shift_dim)
3633
if shift == 0:
@@ -55,9 +52,6 @@ def roll(x: Tensor, shift: list[int], shift_dims: list[int]) -> Tensor:
5552
5653
Returns:
5754
shifted version of x
58-
59-
Note:
60-
This function is called when fftshift and ifftshift are not available in the running pytorch version
6155
"""
6256
if len(shift) != len(shift_dims):
6357
raise ValueError(f"len(shift) != len(shift_dims), got f{len(shift)} and f{len(shift_dims)}.")
@@ -78,9 +72,6 @@ def fftshift(x: Tensor, shift_dims: list[int]) -> Tensor:
7872
7973
Returns:
8074
fft-shifted version of x
81-
82-
Note:
83-
This function is called when fftshift is not available in the running pytorch version
8475
"""
8576
shift = [0] * len(shift_dims)
8677
for i, dim_num in enumerate(shift_dims):
@@ -100,9 +91,6 @@ def ifftshift(x: Tensor, shift_dims: list[int]) -> Tensor:
10091
10192
Returns:
10293
ifft-shifted version of x
103-
104-
Note:
105-
This function is called when ifftshift is not available in the running pytorch version
10694
"""
10795
shift = [0] * len(shift_dims)
10896
for i, dim_num in enumerate(shift_dims):

monai/transforms/utils.py

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1878,11 +1878,7 @@ def shift_fourier(x: NdarrayOrTensor, spatial_dims: int, as_contiguous: bool = F
18781878
dims = tuple(range(-spatial_dims, 0))
18791879
k: NdarrayOrTensor
18801880
if isinstance(x, torch.Tensor):
1881-
if hasattr(torch.fft, "fftshift"): # `fftshift` is new in torch 1.8.0
1882-
k = torch.fft.fftshift(torch.fft.fftn(x, dim=dims), dim=dims)
1883-
else:
1884-
# if using old PyTorch, will convert to numpy array and return
1885-
k = np.fft.fftshift(np.fft.fftn(x.cpu().numpy(), axes=dims), axes=dims)
1881+
k = torch.fft.fftshift(torch.fft.fftn(x, dim=dims), dim=dims)
18861882
else:
18871883
k = np.fft.fftshift(np.fft.fftn(x, axes=dims), axes=dims)
18881884
return ascontiguousarray(k) if as_contiguous else k
@@ -1906,11 +1902,7 @@ def inv_shift_fourier(
19061902
dims = tuple(range(-spatial_dims, 0))
19071903
out: NdarrayOrTensor
19081904
if isinstance(k, torch.Tensor):
1909-
if hasattr(torch.fft, "ifftshift"): # `ifftshift` is new in torch 1.8.0
1910-
out = torch.fft.ifftn(torch.fft.ifftshift(k, dim=dims), dim=dims, norm="backward").real
1911-
else:
1912-
# if using old PyTorch, will convert to numpy array and return
1913-
out = np.fft.ifftn(np.fft.ifftshift(k.cpu().numpy(), axes=dims), axes=dims).real
1905+
out = torch.fft.ifftn(torch.fft.ifftshift(k, dim=dims), dim=dims, norm="backward").real
19141906
else:
19151907
out = np.fft.ifftn(np.fft.ifftshift(k, axes=dims), axes=dims).real
19161908
return ascontiguousarray(out) if as_contiguous else out

tests/losses/test_masked_dice_loss.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
"target": torch.tensor([[[[1.0, 0.0], [1.0, 1.0]]]]),
2828
"mask": torch.tensor([[[[0.0, 0.0], [1.0, 1.0]]]]),
2929
},
30-
0.500,
30+
0.333333,
3131
],
3232
[ # shape: (2, 1, 2, 2), (2, 1, 2, 2)
3333
{"include_background": True, "sigmoid": True, "smooth_nr": 1e-4, "smooth_dr": 1e-4},
@@ -36,7 +36,7 @@
3636
"target": torch.tensor([[[[1.0, 1.0], [1.0, 1.0]]], [[[1.0, 0.0], [1.0, 0.0]]]]),
3737
"mask": torch.tensor([[[[1.0, 1.0], [1.0, 1.0]]], [[[1.0, 1.0], [0.0, 0.0]]]]),
3838
},
39-
0.422969,
39+
0.301128,
4040
],
4141
[ # shape: (2, 2, 3), (2, 1, 3)
4242
{"include_background": False, "to_onehot_y": True, "smooth_nr": 0, "smooth_dr": 0},
@@ -54,7 +54,7 @@
5454
"target": torch.tensor([[[1.0, 0.0, 0.0]], [[1.0, 1.0, 0.0]]]),
5555
"mask": torch.tensor([[[1.0, 1.0, 0.0]]]),
5656
},
57-
0.47033,
57+
0.579184,
5858
],
5959
[ # shape: (2, 2, 3), (2, 1, 3)
6060
{

0 commit comments

Comments
 (0)