def test_to_categorical(): test_tensor = torch.stack([ torch.cat([torch.eye(5, dtype=int), torch.zeros((5, 5), dtype=int)]), torch.cat([torch.zeros((5, 5), dtype=int), torch.eye(5, dtype=int)]) ]).to(torch.float) expected = torch.tensor([[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]]) assert expected.shape == (2, 5) assert test_tensor.shape == (2, 10, 5) result = to_categorical(test_tensor) assert result.shape == expected.shape assert torch.allclose(result, expected.to(result.dtype))
def _stat_scores( preds: Tensor, target: Tensor, class_index: int, argmax_dim: int = 1, ) -> Tuple[Tensor, Tensor, Tensor, Tensor, Tensor]: """ Calculates the number of true positive, false positive, true negative and false negative for a specific class Args: pred: prediction tensor target: target tensor class_index: class to calculate over argmax_dim: if pred is a tensor of probabilities, this indicates the axis the argmax transformation will be applied over Return: True Positive, False Positive, True Negative, False Negative, Support Example: >>> x = torch.tensor([1, 2, 3]) >>> y = torch.tensor([0, 2, 3]) >>> tp, fp, tn, fn, sup = _stat_scores(x, y, class_index=1) >>> tp, fp, tn, fn, sup (tensor(0), tensor(1), tensor(2), tensor(0), tensor(0)) """ if preds.ndim == target.ndim + 1: preds = to_categorical(preds, argmax_dim=argmax_dim) tp = ((preds == class_index) * (target == class_index)).to( torch.long).sum() fp = ((preds == class_index) * (target != class_index)).to( torch.long).sum() tn = ((preds != class_index) * (target != class_index)).to( torch.long).sum() fn = ((preds != class_index) * (target == class_index)).to( torch.long).sum() sup = (target == class_index).to(torch.long).sum() return tp, fp, tn, fn, sup
def stat_scores( pred: torch.Tensor, target: torch.Tensor, class_index: int, argmax_dim: int = 1, ) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]: """ .. deprecated:: Use :func:`torchmetrics.functional.stat_scores`. Will be removed in v1.4.0. """ if pred.ndim == target.ndim + 1: pred = to_categorical(pred, argmax_dim=argmax_dim) tp = ((pred == class_index) * (target == class_index)).to(torch.long).sum() fp = ((pred == class_index) * (target != class_index)).to(torch.long).sum() tn = ((pred != class_index) * (target != class_index)).to(torch.long).sum() fn = ((pred != class_index) * (target == class_index)).to(torch.long).sum() sup = (target == class_index).to(torch.long).sum() return tp, fp, tn, fn, sup
def stat_scores_multiple_classes( pred: torch.Tensor, target: torch.Tensor, num_classes: Optional[int] = None, argmax_dim: int = 1, reduction: str = 'none', ) -> Tuple[torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor, torch.Tensor]: """ .. deprecated:: Use :func:`torchmetrics.functional.stat_scores`. Will be removed in v1.4.0. """ rank_zero_deprecation( "This `stat_scores_multiple_classes` was deprecated in v1.2.0 in favor of" " `from pytorch_lightning.metrics.functional import stat_scores`." " It will be removed in v1.4.0") if pred.ndim == target.ndim + 1: pred = to_categorical(pred, argmax_dim=argmax_dim) num_classes = get_num_classes(pred=pred, target=target, num_classes=num_classes) if pred.dtype != torch.bool: pred = pred.clamp_max(max=num_classes) if target.dtype != torch.bool: target = target.clamp_max(max=num_classes) possible_reductions = ('none', 'sum', 'elementwise_mean') if reduction not in possible_reductions: raise ValueError("reduction type %s not supported" % reduction) if reduction == 'none': pred = pred.view((-1, )).long() target = target.view((-1, )).long() tps = torch.zeros((num_classes + 1, ), device=pred.device) fps = torch.zeros((num_classes + 1, ), device=pred.device) fns = torch.zeros((num_classes + 1, ), device=pred.device) sups = torch.zeros((num_classes + 1, ), device=pred.device) match_true = (pred == target).float() match_false = 1 - match_true tps.scatter_add_(0, pred, match_true) fps.scatter_add_(0, pred, match_false) fns.scatter_add_(0, target, match_false) tns = pred.size(0) - (tps + fps + fns) sups.scatter_add_(0, target, torch.ones_like(match_true)) tps = tps[:num_classes] fps = fps[:num_classes] tns = tns[:num_classes] fns = fns[:num_classes] sups = sups[:num_classes] elif reduction == 'sum' or reduction == 'elementwise_mean': count_match_true = (pred == target).sum().float() oob_tp, oob_fp, oob_tn, oob_fn, oob_sup = stat_scores( pred, target, num_classes, argmax_dim) tps = count_match_true - oob_tp fps = pred.nelement() - count_match_true - oob_fp fns = pred.nelement() - count_match_true - oob_fn tns = pred.nelement() * (num_classes + 1) - (tps + fps + fns + oob_tn) sups = pred.nelement() - oob_sup.float() if reduction == 'elementwise_mean': tps /= num_classes fps /= num_classes fns /= num_classes tns /= num_classes sups /= num_classes return tps.float(), fps.float(), tns.float(), fns.float(), sups.float()