Loading files
import math
from typing import Optional
import torch
import torch.nn.functional as F
__all__ = [
"focal_loss_with_logits",
"sigmoid_focal_loss",
"soft_jaccard_score",
"soft_dice_score",
"wing_loss",
]
def focal_loss_with_logits(
input: torch.Tensor,
target: torch.Tensor,
gamma=2.0,
alpha: Optional[float] = 0.25,
reduction="mean",
normalized=False,
threshold: Optional[float] = None,
) -> torch.Tensor:
"""Compute binary focal loss between target and output logits.
See :class:`~pytorch_toolbelt.losses.FocalLoss` for details.
Args:
input: Tensor of arbitrary shape
target: Tensor of the same shape as input
reduction (string, optional): Specifies the reduction to apply to the output:
'none' | 'mean' | 'sum' | 'batchwise_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. Note: :attr:`size_average`
and :attr:`reduce` are in the process of being deprecated, and in the meantime,
specifying either of those two args will override :attr:`reduction`.
'batchwise_mean' computes mean loss per sample in batch. Default: 'mean'
normalized (bool): Compute normalized focal loss (https://arxiv.org/pdf/1909.07829.pdf).
threshold (float, optional): Compute reduced focal loss (https://arxiv.org/abs/1903.01347).
References::
https://github.com/open-mmlab/mmdetection/blob/master/mmdet/core/loss/losses.py
"""
target = target.type(input.type())
logpt = -F.binary_cross_entropy_with_logits(input, target, reduction="none")
pt = torch.exp(logpt)
# compute the loss
if threshold is None:
focal_term = (1 - pt).pow(gamma)
else:
focal_term = ((1.0 - pt) / threshold).pow(gamma)
focal_term[pt < threshold] = 1
loss = -focal_term * logpt
if alpha is not None:
loss = loss * (alpha * target + (1 - alpha) * (1 - target))
if normalized:
norm_factor = focal_term.sum()
loss = loss / norm_factor
if reduction == "mean":
loss = loss.mean()
if reduction == "sum":
loss = loss.sum()
if reduction == "batchwise_mean":
loss = loss.sum(0)
return loss
# TODO: Mark as deprecated and emit warning
sigmoid_focal_loss = focal_loss_with_logits
# TODO: Mark as deprecated and emit warning
def reduced_focal_loss(
input: torch.Tensor,
target: torch.Tensor,
threshold=0.5,
gamma=2.0,
reduction="mean",
):
return focal_loss_with_logits(
input, target, alpha=None, gamma=gamma, reduction=reduction, threshold=threshold
)
def soft_jaccard_score(
y_pred: torch.Tensor, y_true: torch.Tensor, smooth=0.0, eps=1e-7, dims=None
) -> torch.Tensor:
"""
:param y_pred:
:param y_true:
:param smooth:
:param eps:
:return:
Shape:
- Input: :math:`(N, NC, *)` where :math:`*` means
any number of additional dimensions
- Target: :math:`(N, NC, *)`, same shape as the input
- Output: scalar.
"""
assert y_pred.size() == y_true.size()
if dims is not None:
intersection = torch.sum(y_pred * y_true, dim=dims)
cardinality = torch.sum(y_pred + y_true, dim=dims)
else:
intersection = torch.sum(y_pred * y_true)
cardinality = torch.sum(y_pred + y_true)
union = cardinality - intersection
jaccard_score = (intersection + smooth) / (union + smooth + eps)
return jaccard_score
def soft_dice_score(
y_pred: torch.Tensor, y_true: torch.Tensor, smooth=0, eps=1e-7, dims=None
) -> torch.Tensor:
"""
:param y_pred:
:param y_true:
:param smooth:
:param eps:
:return:
Shape:
- Input: :math:`(N, NC, *)` where :math:`*` means any number
of additional dimensions
- Target: :math:`(N, NC, *)`, same shape as the input
- Output: scalar.
"""
assert y_pred.size() == y_true.size()
if dims is not None:
intersection = torch.sum(y_pred * y_true, dim=dims)
cardinality = torch.sum(y_pred + y_true, dim=dims)
else:
intersection = torch.sum(y_pred * y_true)
cardinality = torch.sum(y_pred + y_true)
dice_score = (2.0 * intersection + smooth) / (cardinality + smooth + eps)
return dice_score
def wing_loss(
prediction: torch.Tensor,
target: torch.Tensor,
width=5,
curvature=0.5,
reduction="mean",
):
"""
https://arxiv.org/pdf/1711.06753.pdf
:param prediction:
:param target:
:param width:
:param curvature:
:param reduction:
:return:
"""
diff_abs = (target - prediction).abs()
loss = diff_abs.clone()
idx_smaller = diff_abs < width
idx_bigger = diff_abs >= width
loss[idx_smaller] = width * torch.log(1 + diff_abs[idx_smaller] / curvature)
C = width - width * math.log(1 + width / curvature)
loss[idx_bigger] = loss[idx_bigger] - C
if reduction == "sum":
loss = loss.sum()
if reduction == "mean":
loss = loss.mean()
return loss
b150d1354This file is pinned to the selected release. Download the original to open it in your design tool.