Loss Loglikelihood#

loglikelihood #

CLASS DESCRIPTION
LogLikelihoodLoss

Log-likelihood loss for probability distributions.

MultivariateLogLikelihoodLoss

Multivariate log-likelihood loss for correlated Gaussian distributions.

FUNCTION DESCRIPTION
loglikelihood_loss

Compute log-likelihood loss for specified distribution.

multivariate_loglikelihood_loss

Compute multivariate log-likelihood loss for specified distribution.

Classes#

LogLikelihoodLoss(distribution: Literal['gaussian'] = 'gaussian', reduce: Literal['sum', 'mean'] = 'mean', sign: float = -1.0, eps: float = torch.finfo(torch.float32).eps, context_prefix: str | None = None, **kwargs) #

Bases: Loss

Log-likelihood loss for probability distributions.

Computes the negative log-likelihood of data under a specified distribution.

PARAMETER DESCRIPTION
distribution

Distribution type to use.

TYPE: Literal["gaussian"], optional, by default "gaussian" DEFAULT: 'gaussian'

reduce

Reduction method.

  • "sum": Sum over all elements
  • "mean": Mean over all elements

TYPE: Literal["sum", "mean"], optional, by default "mean" DEFAULT: 'mean'

sign

Loss sign (-1.0 for maximizing likelihood, 1.0 for minimizing).

TYPE: float, optional, by default -1.0 DEFAULT: -1.0

**kwargs

Additional keyword arguments.

TYPE: dict DEFAULT: {}

METHOD DESCRIPTION
forward

Compute log-likelihood loss.

Source code in spectre/loss/loglikelihood.py
def __init__(
    self,
    distribution: Literal["gaussian"] = "gaussian",
    reduce: Literal["sum", "mean"] = "mean",
    sign: float = -1.0,
    eps: float = torch.finfo(torch.float32).eps,
    context_prefix: str | None = None,
    **kwargs,
):
    super().__init__(
        reduce=reduce, sign=sign, context_prefix=context_prefix, **kwargs
    )

    allowed_distributions = ["gaussian"]
    if distribution not in allowed_distributions:
        raise ValueError(
            f"Unknown distribution '{distribution}'. Options: "
            f"{allowed_distributions}."
        )
    self.distribution = distribution

    if not isinstance(eps, float):
        raise ValueError("`eps` must be a float.")
    check_in_interval(eps, "(0, inf)")
    self.eps = eps
Functions#
forward(context: dict, **kwargs) -> torch.Tensor #

Compute log-likelihood loss.

PARAMETER DESCRIPTION
context

Context dictionary containing the required tensors.

TYPE: dict

**kwargs

Additional keyword arguments.

TYPE: dict DEFAULT: {}

RETURNS DESCRIPTION
Tensor

Log-likelihood loss tensor.

Source code in spectre/loss/loglikelihood.py
def forward(self, context: dict, **kwargs) -> torch.Tensor:
    """
    Compute log-likelihood loss.

    Parameters
    ----------
    context : dict
        Context dictionary containing the required tensors.

    **kwargs : dict
        Additional keyword arguments.

    Returns
    -------
    torch.Tensor
        Log-likelihood loss tensor.
    """
    X = self._get_context(context, "X", None)
    Y = self._get_context(context, "Y", None)
    mean = self._get_context(context, "mean", None)
    scale = self._get_context(context, "scale", None)

    if X is None:
        raise ValueError("`LogLikelihoodLoss` requires `X` in context.")

    return loglikelihood_loss(
        X,
        Y,
        distribution=self.distribution,
        mean=mean,
        scale=scale,
        reduce=self.reduce,
        sign=self.sign,
        eps=self.eps,
    )

MultivariateLogLikelihoodLoss(distribution: Literal['gaussian'] = 'gaussian', reduce: Literal['sum', 'mean'] = 'mean', sign: float = -1.0, eps: float = torch.finfo(torch.float32).eps, context_prefix: str | None = None, **kwargs) #

Bases: Loss

Multivariate log-likelihood loss for correlated Gaussian distributions.

Computes the log-likelihood of data under a multivariate Gaussian distribution with full covariance matrix. Useful for evaluating models that preserve correlations between features.

PARAMETER DESCRIPTION
distribution

Distribution type to use.

TYPE: Literal["gaussian"], optional, by default "gaussian" DEFAULT: 'gaussian'

reduce

Reduction method.

  • "sum": Sum over all samples
  • "mean": Mean over all samples

TYPE: Literal["sum", "mean"], optional, by default "mean" DEFAULT: 'mean'

sign

Loss sign (-1.0 for maximizing likelihood, 1.0 for minimizing).

TYPE: float, optional, by default -1.0 DEFAULT: -1.0

eps

Regularization parameter for covariance matrix.

TYPE: float, optional, by default torch.finfo(torch.float32).eps DEFAULT: eps

**kwargs

Additional keyword arguments.

TYPE: dict DEFAULT: {}

METHOD DESCRIPTION
forward

Compute multivariate log-likelihood loss.

Source code in spectre/loss/loglikelihood.py
def __init__(
    self,
    distribution: Literal["gaussian"] = "gaussian",
    reduce: Literal["sum", "mean"] = "mean",
    sign: float = -1.0,
    eps: float = torch.finfo(torch.float32).eps,
    context_prefix: str | None = None,
    **kwargs,
):
    super().__init__(
        reduce=reduce, sign=sign, context_prefix=context_prefix, **kwargs
    )

    allowed_distributions = ["gaussian"]
    if distribution not in allowed_distributions:
        raise ValueError(
            f"Unknown distribution '{distribution}'. Options: "
            f"{allowed_distributions}."
        )
    self.distribution = distribution

    if not isinstance(eps, float):
        raise ValueError("`eps` must be a float.")
    check_in_interval(eps, "(0, inf)")
    self.eps = eps
Functions#
forward(context: dict, **kwargs) -> torch.Tensor #

Compute multivariate log-likelihood loss.

PARAMETER DESCRIPTION
context

Context dictionary containing the required tensors.

TYPE: dict

**kwargs

Additional keyword arguments.

TYPE: dict DEFAULT: {}

RETURNS DESCRIPTION
Tensor

Log-likelihood loss.

Source code in spectre/loss/loglikelihood.py
def forward(self, context: dict, **kwargs) -> torch.Tensor:
    """
    Compute multivariate log-likelihood loss.

    Parameters
    ----------
    context : dict
        Context dictionary containing the required tensors.

    **kwargs : dict
        Additional keyword arguments.

    Returns
    -------
    torch.Tensor
        Log-likelihood loss.
    """
    X = self._get_context(context, "X", None)
    Y = self._get_context(context, "Y", None)
    mean = self._get_context(context, "mean", None)
    covariance = self._get_context(context, "covariance", None)

    if X is None:
        raise ValueError("`MultivariateLogLikelihoodLoss` requires `X` in context.")

    return multivariate_loglikelihood_loss(
        X,
        Y,
        distribution=self.distribution,
        mean=mean,
        covariance=covariance,
        reduce=self.reduce,
        sign=self.sign,
        eps=self.eps,
    )

Functions#

loglikelihood_loss(X: torch.Tensor, Y: torch.Tensor | None = None, distribution: Literal['gaussian'] = 'gaussian', mean: torch.Tensor | None = None, scale: torch.Tensor | None = None, reduce: Literal['sum', 'mean'] = 'mean', sign: float = -1.0, eps: float = torch.finfo(torch.float32).eps) -> torch.Tensor #

Compute log-likelihood loss for specified distribution.

PARAMETER DESCRIPTION
X

Data tensor for parameter estimation (if mean and scale not provided).

TYPE: Tensor

Y

Target data tensor to evaluate likelihood on.

If None, evaluates likelihood of X under estimated distribution.

TYPE: Optional[torch.Tensor], optional, by default None DEFAULT: None

distribution

Distribution type to use.

TYPE: Literal["gaussian"], optional, by default "gaussian" DEFAULT: 'gaussian'

mean

Distribution mean parameter.

If None, estimated from X using X.mean().

TYPE: torch.Tensor, optional, by default None DEFAULT: None

scale

Distribution scale parameter.

If None, estimated from X using X.std().

TYPE: torch.Tensor, optional, by default None DEFAULT: None

reduce

Reduction method.

  • "sum": Sum over all elements
  • "mean": Mean over all elements

TYPE: Literal["sum", "mean"], optional, by default "mean" DEFAULT: 'mean'

sign

Loss sign (-1.0 for maximizing likelihood, 1.0 for minimizing).

TYPE: float, optional, by default -1.0 DEFAULT: -1.0

eps

Small constant added to scale for numerical stability.

TYPE: float, optional, by default torch.finfo(torch.float32).eps DEFAULT: eps

RETURNS DESCRIPTION
Tensor

Log-likelihood loss.

Source code in spectre/loss/loglikelihood.py
def loglikelihood_loss(
    X: torch.Tensor,
    Y: torch.Tensor | None = None,
    distribution: Literal["gaussian"] = "gaussian",
    mean: torch.Tensor | None = None,
    scale: torch.Tensor | None = None,
    reduce: Literal["sum", "mean"] = "mean",
    sign: float = -1.0,
    eps: float = torch.finfo(torch.float32).eps,
) -> torch.Tensor:
    """
    Compute log-likelihood loss for specified distribution.

    Parameters
    ----------
    X : torch.Tensor
        Data tensor for parameter estimation (if `mean` and `scale` not provided).

    Y : Optional[torch.Tensor], optional, by default None
        Target data tensor to evaluate likelihood on.

        If None, evaluates likelihood of X under estimated distribution.

    distribution : Literal["gaussian"], optional, by default "gaussian"
        Distribution type to use.

    mean : torch.Tensor, optional, by default None
        Distribution mean parameter.

        If None, estimated from X using `X.mean()`.

    scale : torch.Tensor, optional, by default None
        Distribution scale parameter.

        If None, estimated from X using `X.std()`.

    reduce : Literal["sum", "mean"], optional, by default "mean"
        Reduction method.

        - "sum": Sum over all elements
        - "mean": Mean over all elements

    sign : float, optional, by default -1.0
        Loss sign (-1.0 for maximizing likelihood, 1.0 for minimizing).

    eps : float, optional, by default torch.finfo(torch.float32).eps
        Small constant added to scale for numerical stability.

    Returns
    -------
    torch.Tensor
        Log-likelihood loss.
    """
    if distribution == "gaussian":
        if mean is None:
            mean = X.mean()
        if scale is None:
            scale = X.std()

        # Ensure scale is positive to avoid invalid Normal distribution.
        scale = torch.clamp(scale, min=eps)

        check_same_shape(mean, scale)

        dist = torch.distributions.Normal(loc=mean, scale=scale)

        loss = dist.log_prob(Y if Y is not None else X)
    else:
        raise ValueError(
            f"Unknown distribution '{distribution}'. Options: ['gaussian']."
        )

    if reduce == "sum":
        loss = loss.sum()
    elif reduce == "mean":
        loss = loss.mean()
    else:
        raise ValueError(
            f"Unknown reduce operation '{reduce}'. Options: 'sum', 'mean'."
        )

    return sign * loss

multivariate_loglikelihood_loss(X: torch.Tensor, Y: torch.Tensor | None = None, distribution: Literal['gaussian'] = 'gaussian', mean: torch.Tensor | None = None, covariance: torch.Tensor | None = None, reduce: Literal['sum', 'mean'] = 'mean', sign: float = -1.0, eps: float = torch.finfo(torch.float32).eps) -> torch.Tensor #

Compute multivariate log-likelihood loss for specified distribution.

Estimates distribution parameters from X and evaluates log-likelihood on Y (or X if Y is None). For Gaussian distribution, computes full covariance matrix to capture correlations between features.

PARAMETER DESCRIPTION
X

Data tensor for parameter estimation of shape (n_samples, n_features).

Used to estimate mean and covariance if not provided.

TYPE: Tensor

Y

Target data tensor to evaluate likelihood on.

If None, evaluates likelihood of X under estimated distribution.

TYPE: torch.Tensor, optional, by default None DEFAULT: None

distribution

Distribution type to use.

TYPE: Literal["gaussian"], optional, by default "gaussian" DEFAULT: 'gaussian'

mean

Distribution mean parameter of shape (n_features, ).

If None, estimated from X using X.mean(dim=0).

TYPE: torch.Tensor, optional, by default None DEFAULT: None

covariance

Covariance matrix of shape (n_features, n_features).

If None, estimated from X.

TYPE: torch.Tensor, optional, by default None DEFAULT: None

reduce

Reduction method.

  • "sum": Sum over all samples
  • "mean": Mean over all samples

TYPE: Literal["sum", "mean"], optional, by default "mean" DEFAULT: 'mean'

sign

Loss sign (-1.0 for maximizing likelihood, 1.0 for minimizing).

TYPE: float, optional, by default -1.0 DEFAULT: -1.0

eps

Regularization parameter added to covariance diagonal for numerical stability.

TYPE: float, optional, by default torch.finfo(torch.float32).eps DEFAULT: eps

RETURNS DESCRIPTION
Tensor

Multivariate log-likelihood loss.

Examples:

>>> import torch
>>> from spectre.loss import multivariate_loglikelihood_loss
>>> X = torch.randn(100, 5)
>>> Y = torch.randn(50, 5)
>>> loss = multivariate_loglikelihood_loss(X, Y, reduce="mean", sign=-1.0)
>>> loss.shape
torch.Size([])
Source code in spectre/loss/loglikelihood.py
def multivariate_loglikelihood_loss(
    X: torch.Tensor,
    Y: torch.Tensor | None = None,
    distribution: Literal["gaussian"] = "gaussian",
    mean: torch.Tensor | None = None,
    covariance: torch.Tensor | None = None,
    reduce: Literal["sum", "mean"] = "mean",
    sign: float = -1.0,
    eps: float = torch.finfo(torch.float32).eps,
) -> torch.Tensor:
    """
    Compute multivariate log-likelihood loss for specified distribution.

    Estimates distribution parameters from `X` and evaluates log-likelihood on `Y`
    (or `X` if `Y` is None). For Gaussian distribution, computes full covariance
    matrix to capture correlations between features.

    Parameters
    ----------
    X : torch.Tensor
        Data tensor for parameter estimation of shape (n_samples, n_features).

        Used to estimate `mean` and `covariance` if not provided.

    Y : torch.Tensor, optional, by default None
        Target data tensor to evaluate likelihood on.

        If None, evaluates likelihood of `X` under estimated distribution.

    distribution : Literal["gaussian"], optional, by default "gaussian"
        Distribution type to use.

    mean : torch.Tensor, optional, by default None
        Distribution mean parameter of shape (n_features, ).

        If None, estimated from `X` using `X.mean(dim=0)`.

    covariance : torch.Tensor, optional, by default None
        Covariance matrix of shape (n_features, n_features).

        If None, estimated from `X`.

    reduce : Literal["sum", "mean"], optional, by default "mean"
        Reduction method.

        - "sum": Sum over all samples
        - "mean": Mean over all samples

    sign : float, optional, by default -1.0
        Loss sign (-1.0 for maximizing likelihood, 1.0 for minimizing).

    eps : float, optional, by default torch.finfo(torch.float32).eps
        Regularization parameter added to covariance diagonal for numerical stability.

    Returns
    -------
    torch.Tensor
        Multivariate log-likelihood loss.

    Examples
    --------
    >>> import torch
    >>> from spectre.loss import multivariate_loglikelihood_loss
    >>> X = torch.randn(100, 5)
    >>> Y = torch.randn(50, 5)
    >>> loss = multivariate_loglikelihood_loss(X, Y, reduce="mean", sign=-1.0)
    >>> loss.shape
    torch.Size([])
    """
    if distribution == "gaussian":
        if mean is None:
            mean = X.mean(dim=0)

        if covariance is None:
            centered = X - mean
            covariance = torch.mm(centered.t(), centered) / (X.shape[0] - 1)

        covariance = covariance + eps * torch.eye(
            covariance.shape[0], dtype=covariance.dtype, device=covariance.device
        )

        try:
            dist = torch.distributions.MultivariateNormal(
                loc=mean, covariance_matrix=covariance
            )
            log_prob = dist.log_prob(Y if Y is not None else X)
        except (RuntimeError, ValueError):
            # Fallback to diagonal covariance if full covariance fails.
            var = torch.diagonal(covariance)
            var = torch.clamp(var, min=eps)
            dist = torch.distributions.Normal(loc=mean, scale=torch.sqrt(var))
            log_prob = dist.log_prob(Y if Y is not None else X).sum(dim=1)
    else:
        raise ValueError(
            f"Unknown distribution '{distribution}'. Options: ['gaussian']."
        )

    if reduce == "sum":
        loss = log_prob.sum()
    elif reduce == "mean":
        loss = log_prob.mean()
    else:
        raise ValueError(
            f"Unknown reduce operation '{reduce}'. Options: 'sum', 'mean'."
        )

    return sign * loss