Skip to content
Snippets Groups Projects
loss.py 3.21 KiB
import torch
import torch.nn.functional as F
from torchmetrics.regression import PearsonCorrCoef
import numpy as np


def masked_cos_sim(y_true, y_pred):
    """Masked, cosine similarity between true and pred vectors

    """

    # To avoid numerical instability during training on GPUs,
    # we add a fuzzing constant epsilon of 1×10−7 to all vectors
    epsilon = 1e-7
    # Masking: we multiply values by (true + 1) because then the peaks that cannot
    # be there (and have value of -1 as explained above) won't be considered
    pred_masked = ((y_true + 1) * y_pred) / (y_true + 1 + epsilon)
    true_masked = ((y_true + 1) * y_true) / (y_true + 1 + epsilon)
    pred_masked = F.normalize(pred_masked, p=2, dim=1)
    true_masked = F.normalize(true_masked, p=2, dim=1)
    return -(pred_masked * true_masked).sum(dim=1).mean()


def masked_spectral_angle(y_true, y_pred):
    """Masked, cosine similarity between true and pred vectors

    """

    # To avoid numerical instability during training on GPUs,
    # we add a fuzzing constant epsilon of 1×10−7 to all vectors
    epsilon = 1e-7
    # Masking: we multiply values by (true + 1) because then the peaks that cannot
    # be there (and have value of -1 as explained above) won't be considered
    pred_masked = ((y_true + 1) * y_pred) / (y_true + 1 + epsilon)
    true_masked = ((y_true + 1) * y_true) / (y_true + 1 + epsilon)
    pred_masked = F.normalize(pred_masked, p=2, dim=1)
    true_masked = F.normalize(true_masked, p=2, dim=1)
    # print(pred_masked.sum(dim=1))
    # print((pred_masked * true_masked).sum(dim=1).shape)
    return 1 -2 * torch.acos((pred_masked * true_masked).sum(dim=1)).mean() / np.pi


def masked_pearson_correlation_distance(y_true, y_pred, reduce='mean'):
    """
    Calculates the masked Pearson correlation distance between true and predicted intensity vectors.

    The masked Pearson correlation distance is a metric for comparing the similarity between two intensity vectors,
    taking into account only the non-negative values in the true values tensor (which represent valid peaks).

    Parameters:
    -----------
    y_true : Tensor
        A tensor containing the true values, with shape `(batch_size, num_values)`.
    y_pred : Tensor
        A tensor containing the predicted values, with the same shape as `y_true`.

    Returns:
    --------
    Tensor
        A tensor containing the masked Pearson correlation distance between `y_true` and `y_pred`.

    Raises:
    -------
    ValueError
        If `y_true` and `y_pred` have different shapes.
    """
    epsilon = 1e-7

    # Masking: we multiply values by (true + 1) because then the peaks that cannot
    # be there (and have value of -1 as explained above) won't be considered
    pred_masked = ((y_true + 1) * y_pred) / (y_true + 1 + epsilon)
    true_masked = ((y_true + 1) * y_true) / (y_true + 1 + epsilon)
    loss = PearsonCorrCoef()
    if reduce == 'mean':
        return torch.mean(loss(pred_masked, true_masked))
    if reduce == 'sum':
        return torch.sum(loss(pred_masked, true_masked))
    if reduce is None:
        return loss(pred_masked, true_masked)

def distance(x, y):
    return torch.mean(torch.abs(x - y))


def cos_sim_to_sa(cos):
    return 1 - (2 * np.arccos(cos) / np.pi)