class_docstr: Compute channel-wise binary Hausdorff loss based on distance transform. It can support both multi-classes and
  multi-labels tasks. The data `input` (BNHW[D] where N is number of classes) is compared with ground truth `target`
  (BNHW[D]).
  
  Note that axis N of `input` is expected to be logits or probabilities for each class, if passing logits as input,
  must set `sigmoid=True` or `softmax=True`, or specifying `other_act`. And the same axis of `target`
  can be 1 or N (one-hot format).
  
  The original paper: Karimi, D. et. al. (2019) Reducing the Hausdorff Distance in Medical Image Segmentation with
  Convolutional Neural Networks, IEEE Transactions on medical imaging, 39(2), 499-513
docstr: Args:
      input: the shape should be BNHW[D], where N is the number of classes.
      target: the shape should be BNHW[D] or B1HW[D], where N is the number of classes.
  
  Raises:
      ValueError: If the input is not 2D (NCHW) or 3D (NCHWD).
      AssertionError: When input and target (after one hot transform if set)
          have different shapes.
      ValueError: When ``self.reduction`` is not one of ["mean", "sum", "none"].
  
  Example:
      >>> import torch
      >>> from monai.losses.hausdorff_loss import HausdorffDTLoss
      >>> from monai.networks.utils import one_hot
      >>> B, C, H, W = 7, 5, 3, 2
      >>> input = torch.rand(B, C, H, W)
      >>> target_idx = torch.randint(low=0, high=C - 1, size=(B, H, W)).long()
      >>> target = one_hot(target_idx[:, None, ...], num_classes=C)
      >>> self = HausdorffDTLoss(reduction='none')
      >>> loss = self(input, target)
      >>> assert np.broadcast_shapes(loss.shape, input.shape) == input.shape
docstr_tok: ["Args",":","input",":","the","shape","should","be","BNHW","[","D","]",",","where","N","is","the","number","of","classes",".","target",":","the","shape","should","be","BNHW","[","D","]","or","B1HW","[","D","]",",","where","N","is","the","number","of","classes",".","Raises",":","ValueError",":","If","the","input","is","not","2D","(","NCHW",")","or","3D","(","NCHWD",")",".","AssertionError",":","When","input","and","target","(","after","one","hot","transform","if","set",")","have","different","shapes",".","ValueError",":","When","``","self.reduction","``","is","not","one","of","[","``","mean","''",",","``","sum","''",",","``","none","''","]",".","Example",":",">",">",">","import","torch",">",">",">","from","monai.losses.hausdorff_loss","import","HausdorffDTLoss",">",">",">","from","monai.networks.utils","import","one_hot",">",">",">","B",",","C",",","H",",","W","=","7",",","5",",","3",",","2",">",">",">","input","=","torch.rand","(","B",",","C",",","H",",","W",")",">",">",">","target_idx","=","torch.randint","(","low=0",",","high=C","-","1",",","size=","(","B",",","H",",","W",")",")",".long","(",")",">",">",">","target","=","one_hot","(","target_idx","[",":",",","None",",","...","]",",","num_classes=C",")",">",">",">","self","=","HausdorffDTLoss","(","reduction='none","'",")",">",">",">","loss","=","self","(","input",",","target",")",">",">",">","assert","np.broadcast_shapes","(","loss.shape",",","input.shape",")","==","input.shape"]
code: def forward(
      self, input: torch.Tensor, target: torch.Tensor
  ) -> torch.Tensor:
      """
      Args:
          input: the shape should be BNHW[D], where N is the number of classes.
          target: the shape should be BNHW[D] or B1HW[D], where N is the number of classes.
  
      Raises:
          ValueError: If the input is not 2D (NCHW) or 3D (NCHWD).
          AssertionError: When input and target (after one hot transform if set)
              have different shapes.
          ValueError: When ``self.reduction`` is not one of ["mean", "sum", "none"].
  
      Example:
          >>> import torch
          >>> from monai.losses.hausdorff_loss import HausdorffDTLoss
          >>> from monai.networks.utils import one_hot
          >>> B, C, H, W = 7, 5, 3, 2
          >>> input = torch.rand(B, C, H, W)
          >>> target_idx = torch.randint(low=0, high=C - 1, size=(B, H, W)).long()
          >>> target = one_hot(target_idx[:, None, ...], num_classes=C)
          >>> self = HausdorffDTLoss(reduction='none')
          >>> loss = self(input, target)
          >>> assert np.broadcast_shapes(loss.shape, input.shape) == input.shape
      """
      if input.dim() != 4 and input.dim() != 5:
          raise ValueError("Only 2D (NCHW) and 3D (NCHWD) supported")
  
      if self.sigmoid:
          input = torch.sigmoid(input)
  
      n_pred_ch = input.shape[1]
      if self.softmax:
          if n_pred_ch == 1:
              warnings.warn(
                  "single channel prediction, `softmax=True` ignored."
              )
          else:
              input = torch.softmax(input, 1)
  
      if self.other_act is not None:
          input = self.other_act(input)
  
      if self.to_onehot_y:
          if n_pred_ch == 1:
              warnings.warn(
                  "single channel prediction, `to_onehot_y=True` ignored."
              )
          else:
              target = one_hot(target, num_classes=n_pred_ch)
  
      if not self.include_background:
          if n_pred_ch == 1:
              warnings.warn(
                  "single channel prediction, `include_background=False` ignored."
              )
          else:
              # If skipping background, removing first channel
              target = target[:, 1:]
              input = input[:, 1:]
  
      if target.shape != input.shape:
          raise AssertionError(
              f"ground truth has different shape ({target.shape}) from input ({input.shape})"
          )
  
      device = input.device
      all_f = []
      for i in range(input.shape[1]):
          ch_input = input[:, [i]]
          ch_target = target[:, [i]]
          pred_dt = self.distance_field(ch_input.detach()).float()
          target_dt = self.distance_field(ch_target.detach()).float()
  
          pred_error = (ch_input - ch_target) ** 2
          distance = pred_dt**self.alpha + target_dt**self.alpha
  
          running_f = pred_error * distance.to(device)
          reduce_axis: list[int] = torch.arange(
              2, len(input.shape)
          ).tolist()
          if self.batch:
              # reducing spatial dimensions and batch
              reduce_axis = [0] + reduce_axis
          all_f.append(running_f.mean(dim=reduce_axis, keepdim=True))
      f = torch.cat(all_f, dim=1)
      if self.reduction == LossReduction.MEAN.value:
          f = torch.mean(f)  # the batch and channel average
      elif self.reduction == LossReduction.SUM.value:
          f = torch.sum(f)  # sum over the batch and channel dims
      elif self.reduction == LossReduction.NONE.value:
          # If we are not computing voxelwise loss components at least make sure a none reduction maintains a
          # broadcastable shape
          broadcast_shape = list(f.shape[0:2]) + [1] * (
              len(ch_input.shape) - 2
          )
          f = f.view(broadcast_shape)
      else:
          raise ValueError(
              f'Unsupported reduction: {self.reduction}, available options are ["mean", "sum", "none"].'
          )
  
      return f
  
file_path: MONAI/monai/losses/hausdorff_loss.py
imports: from __future__ import annotations
  import warnings
  from typing import Callable
  import torch
  from torch.nn.modules.loss import _Loss
  from monai.networks import one_hot
  from monai.transforms.utils import distance_transform_edt
  from monai.utils import LossReduction
label_desc: Use image node_id 3 for calling the HausdorffDTLoss obj's underlying member method code with example usage: obj.forward(input, target) and returns: f