Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
12 changes: 6 additions & 6 deletions monai/losses/image_dissimilarity.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from torch.nn import functional as F
from torch.nn.modules.loss import _Loss

from monai.networks.layers import gaussian_1d, separable_filtering
from monai.networks.layers import separable_filtering
from monai.utils import LossReduction
from monai.utils.module import look_up_option

Expand All @@ -34,11 +34,11 @@ def make_triangular_kernel(kernel_size: int) -> torch.Tensor:


def make_gaussian_kernel(kernel_size: int) -> torch.Tensor:
sigma = torch.tensor(kernel_size / 3.0)
kernel = gaussian_1d(sigma=sigma, truncated=kernel_size // 2, approx="sampled", normalize=False) * (
2.5066282 * sigma
)
return kernel[:kernel_size]
sigma = kernel_size / 3.0
half = kernel_size // 2
x = torch.arange(-half, half + 1, dtype=torch.float)
kernel = torch.exp(-0.5 / (sigma * sigma) * x**2)
return kernel
Comment thread
ericspod marked this conversation as resolved.


kernel_dict = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
import torch
from parameterized import parameterized

from monai.losses.image_dissimilarity import LocalNormalizedCrossCorrelationLoss
from monai.losses.image_dissimilarity import LocalNormalizedCrossCorrelationLoss, make_gaussian_kernel

device = "cuda" if torch.cuda.is_available() else "cpu"

Expand Down Expand Up @@ -113,6 +113,25 @@
},
-0.95406944,
],
# Regression tests for gh-8780: gaussian kernel_size > 3 was broken due to
# truncated parameter being passed as pixel radius instead of sigma multiplier.
# Identical images must yield loss == -1.0 for any kernel size.
[
{"spatial_dims": 1, "kernel_type": "gaussian", "kernel_size": 5},
{
"pred": torch.arange(0, 5).reshape(1, 1, -1).to(dtype=torch.float, device=device),
"target": torch.arange(0, 5).reshape(1, 1, -1).to(dtype=torch.float, device=device),
},
-1.0,
],
[
{"spatial_dims": 1, "kernel_type": "gaussian", "kernel_size": 9},
{
"pred": torch.arange(0, 9).reshape(1, 1, -1).to(dtype=torch.float, device=device),
"target": torch.arange(0, 9).reshape(1, 1, -1).to(dtype=torch.float, device=device),
},
-1.0,
],
]


Expand All @@ -138,6 +157,15 @@ def test_ill_shape(self):
torch.ones((1, 3, 4, 4, 4), dtype=torch.float, device=device),
)

def test_gaussian_kernel_shape_and_symmetry(self):
# gh-8780: kernel must have correct length, be symmetric, and peak at center
for kernel_size in [3, 5, 7, 9, 11, 15]:
k = make_gaussian_kernel(kernel_size)
self.assertEqual(len(k), kernel_size)
self.assertTrue(torch.allclose(k, k.flip(0)), f"kernel_size={kernel_size} not symmetric")
self.assertEqual(k.argmax().item(), kernel_size // 2)
np.testing.assert_allclose(k.max().item(), 1.0, rtol=1e-6)

def test_ill_opts(self):
pred = torch.ones((1, 3, 3, 3, 3), dtype=torch.float)
target = torch.ones((1, 3, 3, 3, 3), dtype=torch.float)
Expand Down
Loading