Project: s41467-025-57717-6 | Function: dice_loss (python)

system: You are an expert Python programmer implementing algorithms from scientific papers.
Complete the masked function based on the algorithm description.
Follow Python best practices and maintain consistent code style.
Return **only** the complete Python function code.

user: Complete this Python function:

**DESCRIPTION:** Computes Sørensen-Dice Coefficient loss for medical image segmentation. Takes model predictions and ground truth segmentation masks, applies softmax normalization, converts targets to one-hot encoding, and calculates intersection over union metrics.

**KEY TERMS:** {
  "input_soft": "softmax predictions",
  "target_one_hot": "ground truth masks",
  "intersection": "overlap between prediction and ground truth",
  "cardinality": "total pixels in prediction and ground truth"
}

**CONTEXT CODE:**         >>> loss = tgm.losses.DiceLoss()
        >>> input = torch.randn(1, N, 3, 5, requires_grad=True)
        >>> target = torch.empty(1, 3, 5, dtype=torch.long).random_(N)
        >>> output = loss(input, target)
        >>> output.backward()
    """

    def __init__(self) -> None:
        super(DiceLoss, self).__init__()
        self.eps: float = 1e-6

    def forward(
            self,
            input: torch.Tensor,
            target: torch.Tensor) -> torch.Tensor:
        if not torch.is_tensor(input):
            raise TypeError("Input type is not a torch.Tensor. Got {}"
                            .format(type(input)))
        if not len(input.shape) == 4:
            raise ValueError("Invalid input shape, we expect BxNxHxW. Got: {}"
                             .format(input.shape))
        if not input.shape[-2:] == target.shape[-2:]:
            raise ValueError("input and target shapes must be the same. Got: {}"
                             .format(input.shape, input.shape))
        if not input.device == target.device:
            raise ValueError(
                "input and target must be in the same device. Got: {}" .format(
                    input.device, target.device))
        # compute softmax over the classes axis
        input_soft = F.softmax(input, dim=1)

        # create the labels one hot tensor
        target_one_hot = one_hot(target, num_classes=input.shape[1],
                                 device=input.device, dtype=input.dtype)

        # compute the actual dice score
        dims = (1, 2, 3)
        intersection = torch.sum(input_soft * target_one_hot, dims)
        cardinality = torch.sum(input_soft + target_one_hot, dims)

        dice_score = 2. * intersection / (cardinality + self.eps)
        return torch.mean(1. - dice_score)



######################
# functional interface
######################


def dice_loss(
        input: torch.Tensor,
        target: torch.Tensor) -> torch.Tensor:
    r"""
    Computes Sørensen-Dice Coefficient loss for medical image segmentation.

    This function implements the Sørensen-Dice coefficient formula specifically for
    vascular mask prediction in histopathology images. It takes model predictions
    and ground truth segmentation masks, applies softmax normalization, converts
    targets to one-hot encoding, and calculates intersection over union metrics
    as described in the mixed DL model approach.

    The Dice coefficient measures overlap between prediction and ground truth:
    Dice(x, class) = (2 |X ∩ Y|) / (|X| + |Y|)
    Loss is calculated as: loss(x, class) = 1 - Dice(x, class)

    Args:
        input (torch.Tensor): Model predictions of shape (N, C, H, W)
        target (torch.Tensor): Ground truth segmentation masks of shape (N, H, W)

    Returns:
        torch.Tensor: Dice loss value for vascular segmentation optimization

    Raises:
        NotImplementedError: Function has been masked for testing purposes
    """
    raise NotImplementedError("This function has been masked for testing purposes")



Complete the function implementation replacing "raise NotImplementedError".