diff --git a/mindspore/nn/loss/loss.py b/mindspore/nn/loss/loss.py index 20e60fe04f..a415564b08 100644 --- a/mindspore/nn/loss/loss.py +++ b/mindspore/nn/loss/loss.py @@ -184,9 +184,6 @@ class RMSELoss(_Loss): .. math:: loss = \sqrt{\frac{1}{M}\sum_{m=1}^{M}{(x_m-y_m)^2}} - Args: - reduction (str): Type of reduction to be applied to loss. The optional values are "mean", "sum", and "none". - Default: "mean". Inputs: - **logits** (Tensor) - Tensor of shape :math:`(x_1, x_2, ..., x_R)`. @@ -429,6 +426,10 @@ class DiceLoss(_Loss): Outputs: Tensor, a tensor of shape with the per-example sampled Dice losses. + Raises: + ValueError: If the dimensions are different. + TypeError: If the type of inputs are not Tensor. + Supported Platforms: ``Ascend`` ``GPU`` ``CPU`` @@ -439,10 +440,6 @@ class DiceLoss(_Loss): >>> output = loss(y_pred, y) >>> print(output) [0.7953220862819745] - - Raises: - ValueError: If the dimensions are different. - TypeError: If the type of inputs are not Tensor. """ def __init__(self, smooth=1e-5): super(DiceLoss, self).__init__() @@ -494,6 +491,10 @@ class MultiClassDiceLoss(_Loss): Outputs: Tensor, a tensor of shape with the per-example sampled MultiClass Dice Losses. + Raises: + ValueError: If the shapes are different. + TypeError: If the type of inputs are not Tensor. + Supported Platforms: ``Ascend`` ``GPU`` ``CPU`` @@ -504,10 +505,6 @@ class MultiClassDiceLoss(_Loss): >>> output = loss(y_pred, y) >>> print(output) [0.7761003] - - Raises: - ValueError: If the shapes are different. - TypeError: If the type of inputs are not Tensor. """ def __init__(self, weights=None, ignore_indiex=None, activation="softmax"): super(MultiClassDiceLoss, self).__init__() diff --git a/mindspore/nn/metrics/hausdorff_distance.py b/mindspore/nn/metrics/hausdorff_distance.py index d935487011..7590f1124a 100644 --- a/mindspore/nn/metrics/hausdorff_distance.py +++ b/mindspore/nn/metrics/hausdorff_distance.py @@ -85,6 +85,16 @@ class HausdorffDistance(Metric): crop (bool): Crop input images and only keep the foregrounds. In order to maintain two inputs' shapes, here the bounding box is achieved by (y_pred | y) which represents the union set of two images. Default: True. + + Examples: + >>> x = Tensor(np.array([[3, 0, 1], [1, 3, 0], [1, 0, 2]])) + >>> y = Tensor(np.array([[0, 2, 1], [1, 2, 1], [0, 0, 1]])) + >>> metric = nn.HausdorffDistance + >>> metric.clear() + >>> metric.update(x, y, 0) + >>> mean_average_distance = metric.eval() + >>> print(mean_average_distance) + 1.4142135623730951 """ def __init__(self, distance_metric="euclidean", percentile=None, directed=False, crop=True): super(HausdorffDistance, self).__init__() @@ -205,6 +215,31 @@ class HausdorffDistance(Metric): return surface_distance + def _get_mask_edges_distance(self, y_pred, y): + """ + Do binary erosion and use XOR for input to get the edges. This function is helpful to further + calculate metrics such as Average Surface Distance and Hausdorff Distance. + + Args: + y_pred (np.ndarray): the edge of the predictions. + y (np.ndarray): the edge of the ground truth. + """ + if self.crop: + if not np.any(y_pred | y): + res1 = np.zeros_like(y_pred) + res2 = np.zeros_like(y) + return res1, res2 + + y_pred, y = np.expand_dims(y_pred, 0), np.expand_dims(y, 0) + box_start, box_end = self._create_space_bounding_box(y_pred | y) + cropper = _ROISpatialData(roi_start=box_start, roi_end=box_end) + y_pred, y = np.squeeze(cropper(y_pred)), np.squeeze(cropper(y)) + + y_pred = morphology.binary_erosion(y_pred) ^ y_pred + y = morphology.binary_erosion(y) ^ y + + return y_pred, y + def clear(self): """Clears the internal evaluation result.""" self.y_pred_edges = 0 @@ -223,6 +258,7 @@ class HausdorffDistance(Metric): Raises: ValueError: If the number of the inputs is not 3. """ + self._is_update = True if len(inputs) != 3: raise ValueError('HausdorffDistance need 3 inputs (y_pred, y, label), but got {}'.format(len(inputs))) y_pred = self._convert_data(inputs[0]) @@ -234,21 +270,7 @@ class HausdorffDistance(Metric): y_pred = (y_pred == label_idx) if y_pred.dtype is not bool else y_pred y = (y == label_idx) if y.dtype is not bool else y - - res1, res2 = None, None - if self.crop: - if not np.any(y_pred | y): - res1 = np.zeros_like(y_pred) - res2 = np.zeros_like(y) - - y_pred, y = np.expand_dims(y_pred, 0), np.expand_dims(y, 0) - box_start, box_end = self._create_space_bounding_box(y_pred | y) - cropper = _ROISpatialData(roi_start=box_start, roi_end=box_end) - y_pred, y = np.squeeze(cropper(y_pred)), np.squeeze(cropper(y)) - - self.y_pred_edges = morphology.binary_erosion(y_pred) ^ y_pred if res1 is None else res1 - self.y_edges = morphology.binary_erosion(y) ^ y if res2 is None else res2 - self._is_update = True + self.y_pred_edges, self.y_edges = self._get_mask_edges_distance(y_pred, y) def eval(self): """ diff --git a/mindspore/nn/metrics/mean_surface_distance.py b/mindspore/nn/metrics/mean_surface_distance.py index ddb2caba63..05fcab9485 100644 --- a/mindspore/nn/metrics/mean_surface_distance.py +++ b/mindspore/nn/metrics/mean_surface_distance.py @@ -41,7 +41,6 @@ class MeanSurfaceDistance(Metric): >>> mean_average_distance = metric.eval() >>> print(mean_average_distance) 0.8047378541243649 - """ def __init__(self, symmetric=False, distance_metric="euclidean"):