From 26e3eccf28f5c4acf552eab14b00e4bfab05fb1d Mon Sep 17 00:00:00 2001 From: Mohamed Salah Date: Fri, 21 Nov 2025 21:12:48 +0200 Subject: [PATCH] Fix #8350: Clarify LocalNormalizedCrossCorrelationLoss docstring - Add Returns section documenting value range (-1 to 0) - Clarify optimization direction (minimize) - Add Note section explaining transformations and interpretation - Document that lower values indicate better correlation - Move Args from __init__ to class docstring for better discoverability Signed-off-by: Mohamed Salah --- monai/losses/image_dissimilarity.py | 45 +++++++++++++++++++---------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/monai/losses/image_dissimilarity.py b/monai/losses/image_dissimilarity.py index dd132770ec..8ddfbd000f 100644 --- a/monai/losses/image_dissimilarity.py +++ b/monai/losses/image_dissimilarity.py @@ -51,6 +51,7 @@ def make_gaussian_kernel(kernel_size: int) -> torch.Tensor: class LocalNormalizedCrossCorrelationLoss(_Loss): """ Local squared zero-normalized cross-correlation. + The loss is based on a moving kernel/window over the y_true/y_pred, within the window the square of zncc is calculated. The kernel can be a rectangular / triangular / gaussian window. @@ -59,6 +60,35 @@ class LocalNormalizedCrossCorrelationLoss(_Loss): Adapted from: https://github.com/voxelmorph/voxelmorph/blob/legacy/src/losses.py DeepReg (https://github.com/DeepRegNet/DeepReg) + + Args: + spatial_dims: number of spatial dimensions, {``1``, ``2``, ``3``}. Defaults to 3. + kernel_size: kernel spatial size, must be odd. + kernel_type: {``"rectangular"``, ``"triangular"``, ``"gaussian"``}. Defaults to ``"rectangular"``. + reduction: {``"none"``, ``"mean"``, ``"sum"``} + Specifies the reduction to apply to the output. Defaults to ``"mean"``. + + - ``"none"``: no reduction will be applied. + - ``"mean"``: the sum of the output will be divided by the number of elements in the output. + - ``"sum"``: the output will be summed. + smooth_nr: a small constant added to the numerator to avoid nan. + smooth_dr: a small constant added to the denominator to avoid nan. + + Returns: + torch.Tensor: The computed loss value. The output range is approximately [-1, 0], where: + - Values closer to -1 indicate higher correlation (better match) + - Values closer to 0 indicate lower correlation (worse match) + - This loss should be **minimized** during optimization + + Note: + The implementation computes the squared normalized cross-correlation coefficient + and then negates it, transforming the correlation maximization problem into a + loss minimization problem suitable for standard PyTorch optimizers. + + Interpretation: + - Loss ≈ -1: Perfect correlation between images + - Loss ≈ 0: No correlation between images + - Lower (more negative) values indicate better alignment """ def __init__( @@ -70,21 +100,6 @@ def __init__( smooth_nr: float = 0.0, smooth_dr: float = 1e-5, ) -> None: - """ - Args: - spatial_dims: number of spatial dimensions, {``1``, ``2``, ``3``}. Defaults to 3. - kernel_size: kernel spatial size, must be odd. - kernel_type: {``"rectangular"``, ``"triangular"``, ``"gaussian"``}. Defaults to ``"rectangular"``. - reduction: {``"none"``, ``"mean"``, ``"sum"``} - Specifies the reduction to apply to the output. Defaults to ``"mean"``. - - - ``"none"``: no reduction will be applied. - - ``"mean"``: the sum of the output will be divided by the number of elements in the output. - - ``"sum"``: the output will be summed. - smooth_nr: a small constant added to the numerator to avoid nan. - smooth_dr: a small constant added to the denominator to avoid nan. - - """ super().__init__(reduction=LossReduction(reduction).value) self.ndim = spatial_dims