示例#1
0
    def forward(self, inputs: torch.Tensor, targets: torch.Tensor):
        """
           Computes the Tversky loss based on https://arxiv.org/pdf/1706.05721.pdf
           Note that PyTorch optimizers minimize a loss. In this case, we would like to maximize the dice loss so we
           return the negated dice loss.
           Args:
               inputs (:obj:`torch.Tensor`) : A tensor of shape (B, C, ..). The model prediction on which the loss has to
                be computed.
               targets (:obj:`torch.Tensor`) : A tensor of shape (B, C, ..). The ground truth.
           Returns:
               :obj:`torch.Tensor`: The Tversky loss for each class or reduced according to reduction method.
           """
        if not inputs.size() == targets.size():
            raise ValueError(
                "'Inputs' and 'Targets' must have the same shape.")

        inputs = flatten(inputs)
        targets = flatten(targets).float()
        ones = torch.Tensor().new_ones((inputs.size()),
                                       dtype=torch.float,
                                       device=inputs.device)

        P_G = (inputs * targets).sum(-1)
        if self.weight is not None:
            P_G = self.weight * P_G

        P_NG = (inputs * (ones - targets)).sum(-1)
        NP_G = ((ones - inputs) * targets).sum(-1)

        ones = torch.Tensor().new_ones((inputs.size(0), ),
                                       dtype=torch.float,
                                       device=inputs.device)
        tversky = P_G / (P_G + self._alpha * P_NG + self._beta * NP_G +
                         EPSILON)

        tversky_loss = ones - tversky

        if self._ignore_index != -100:

            def ignore_index_fn(tversky_vector):
                try:
                    indices = list(range(len(tversky_vector)))
                    indices.remove(self._ignore_index)
                    return tversky_vector[indices]
                except ValueError as e:
                    raise IndexError(
                        "'ignore_index' must be non-negative, and lower than the number of classes in confusion matrix, but {} was given. "
                        .format(self._ignore_index))

            tversky_loss = MetricsLambda(ignore_index_fn,
                                         tversky_loss).compute()

        if self.reduction == "mean":
            tversky_loss = tversky_loss.mean()

        return tversky_loss
示例#2
0
    def forward(self, inputs: torch.Tensor, targets: torch.Tensor):
        """
        Computes the Sørensen–Dice loss.
        Note that PyTorch optimizers minimize a loss. In this case, we would like to maximize the dice loss so we
        return the negated dice loss.
        Args:
            inputs (:obj:`torch.Tensor`) : A tensor of shape (B, C, ..). The model prediction on which the loss has to
             be computed.
            targets (:obj:`torch.Tensor`) : A tensor of shape (B, C, ..). The ground truth.
        Returns:
            :obj:`torch.Tensor`: The Sørensen–Dice loss for each class or reduced according to reduction method.
        """
        if not inputs.size() == targets.size():
            raise ValueError(
                "'Inputs' and 'Targets' must have the same shape.")

        inputs = flatten(inputs)
        targets = flatten(targets).float()

        # Compute per channel Dice Coefficient
        intersection = (inputs * targets).sum(-1)

        if self.weight is not None:
            intersection = self.weight * intersection

        cardinality = (inputs + targets).sum(-1)

        ones = torch.Tensor().new_ones((inputs.size(0), ),
                                       dtype=torch.float,
                                       device=inputs.device)

        dice = ones - (2.0 * intersection / cardinality.clamp(min=EPSILON))

        if self._ignore_index != -100:

            def ignore_index_fn(dice_vector):
                try:
                    indices = list(range(len(dice_vector)))
                    indices.remove(self._ignore_index)
                    return dice_vector[indices]
                except ValueError as e:
                    raise IndexError(
                        "'ignore_index' must be non-negative, and lower than the number of classes in confusion matrix, but {} was given. "
                        .format(self._ignore_index))

            dice = MetricsLambda(ignore_index_fn, dice).compute()

        if self.reduction == "mean":
            dice = dice.mean()

        return dice
示例#3
0
    def create_dice_metric(self, cm: ConfusionMatrix):
        """
        Computes the Sørensen–Dice Coefficient (https://en.wikipedia.org/wiki/Sørensen–Dice_coefficient)
        Args:
            cm (:obj:`ignite.metrics.ConfusionMatrix`): A confusion matrix representing the classification of data.
        Returns:
            array or float: The Sørensen–Dice Coefficient for each class or the mean Sørensen–Dice Coefficient.
        """
        # Increase floating point precision
        cm = cm.type(torch.float64)
        dice = 2 * cm.diag() / (cm.sum(dim=1) + cm.sum(dim=0) + EPSILON)

        if self._ignore_index != -100:

            def remove_index(dice_vector):
                try:
                    indices = list(range(len(dice_vector)))
                    indices.remove(self._ignore_index)
                    return dice_vector[indices]
                except ValueError as e:
                    raise IndexError(
                        "'ignore_index' must be non-negative, and lower than the number of classes in confusion matrix, but {} was given. "
                        .format(self._ignore_index))

            dice = MetricsLambda(remove_index, dice)

        if self._weight is not None:

            def multiply_weights(dice_vector):
                return self._weight * dice_vector

            dice = MetricsLambda(multiply_weights, dice)

        if self._reduction == "mean":
            dice = dice.mean()

        return dice