def forward(self, features: torch.Tensor, targets: torch.Tensor) -> torch.Tensor:
        """
        Args:
            features: [bs; feature_len]
            targets: [bs]

        Returns:
            computed loss
        """
        # if ||x|| = ||y|| = 1 then||x-y||^2 = 2 - 2<x,y>
        features = torch.nn.functional.normalize(features)
        cosine_matrix = (2 - torch.cdist(features, features) ** 2) / 2
        exp_cosine_matrix = torch.exp(cosine_matrix / self.tau)
        # positive part of the loss
        pos_place = targets.repeat(targets.shape[0], 1) == targets.reshape(
            targets.shape[0], 1
        )
        # aggregation of postive pairs

        number_of_positives = pos_place.sum(dim=1) - 1

        assert (
            number_of_positives == 0
        ).sum().item() == 0, (
            "There must be at least one positive example for each sample!"
        )

        if self.pos_aggregation == "in":
            pos_loss = (exp_cosine_matrix * pos_place).sum(
                dim=1
            ) - self.exp_self_similarity
            pos_loss = torch.log(pos_loss) - torch.log(number_of_positives.float())
        elif self.pos_aggregation == "out":
            pos_loss = (
                (torch.log(exp_cosine_matrix) * pos_place).sum(dim=1)
                - self.self_similarity
            ) / number_of_positives

        # neg part of the loss
        exp_sim_sum = exp_cosine_matrix.sum(dim=1) - self.exp_self_similarity
        neg_loss = torch.log(exp_sim_sum)

        # 2*poss_loss (i,j) and (j,i)
        loss = -pos_loss + neg_loss
        if self.reduction == "mean":
            loss = loss.mean()
        elif self.reduction == "sum":
            loss = loss.sum()
        return loss

        Args:
            features: [bs; feature_len]
            targets: [bs]

        Returns:
            computed loss
        
catalyst/contrib/losses/supervised_contrastive.py