Source code for pyFDN.train.losses.reductions

from __future__ import annotations

from abc import ABC, abstractmethod
from typing import Any

import torch


[docs] class Reduction(ABC): """Base class for aggregation strategies.""" @abstractmethod def __call__(self, x: torch.Tensor) -> torch.Tensor: ...
[docs] class Mean(Reduction): """Arithmetic mean reduction.""" def __call__(self, x: torch.Tensor) -> torch.Tensor: return x.mean()
[docs] class MeanPerGroup(Reduction): """Mean averaged per first-dimension group, then across groups. Each group is normalized by its actual element count, giving equal weight to each group regardless of its size (unlike :meth:`Mean` which weights by total element count). Multi-resolution features (:class:`~pyFDN.train.losses.features.SpectrogramFeature`, :class:`~pyFDN.train.losses.features.PhaseSpectrogramFeature`) pad every resolution to a common shape and record each resolution's number of real (unpadded) entries in ``_group_counts`` on every call. Pass that feature here so each group is divided by its real count; the padding must then contribute zero distance (it does for the distances those features are used with). Without such a feature, each group is averaged over its full, padded size. """ def __init__(self, feature: Any = None) -> None: self.feature = feature def __call__(self, x: torch.Tensor) -> torch.Tensor: if self.feature is not None and hasattr(self.feature, "_group_counts"): counts = torch.tensor( self.feature._group_counts, device=x.device, dtype=x.dtype ) group_sums = x.sum(dim=tuple(range(1, x.ndim))) return (group_sums / counts).mean() return x.mean(dim=tuple(range(1, x.ndim))).mean()
[docs] class Sum(Reduction): """Sum reduction.""" def __call__(self, x: torch.Tensor) -> torch.Tensor: return x.sum()
[docs] class Rms(Reduction): """Root-mean-square of squared errors: ``sqrt(mean(x))`` over all entries.""" def __call__(self, x: torch.Tensor) -> torch.Tensor: return x.mean().sqrt()
[docs] class MeanRmsOverGroups(Reduction): """Mean of per-group RMS values, groups split along dim 0.""" def __call__(self, x: torch.Tensor) -> torch.Tensor: flat = x.reshape(x.shape[0], -1) return flat.mean(dim=1).sqrt().mean()