Faithful Heteroscedastic & CRPS Losses¶
← Beta-NLL | Wasserstein Bound →
This page covers two specialized Gaussian loss variants:
- FaithfulGaussianLoss — decouples mean and variance training to prevent the variance head from distorting point predictions
- GaussianCRPSLoss — a proper scoring rule alternative to NLL that is less sensitive to tail miscalibration
FaithfulGaussianLoss¶
The Problem with Joint NLL¶
Standard GaussianNLLLoss couples gradients from the variance head into the mean through the residual term:
The gradient with respect to \(\mu\) is \(\frac{\mu - y}{\sigma^2}\), which means the variance head's outputs directly scale the gradients flowing into the mean head. If the model learns an inflated \(\sigma^2\) in high-error regions, the mean head receives weaker gradients there — effectively "explaining away" prediction errors as aleatoric noise.
The Faithful Solution¶
FaithfulGaussianLoss decouples the two objectives (see API: FaithfulGaussianLoss):
where \(\operatorname{sg}\) is stop-gradient. The mean receives gradients only from the MSE term; the variance head receives gradients from the NLL term with a detached mean. This mirrors the intent of faithful heteroscedastic training: preserve point prediction quality while learning a noise model.
Usage¶
from torchregress.losses import FaithfulGaussianLoss
loss_fn = FaithfulGaussianLoss(mean_weight=1.0, variance_weight=1.0)
# Model outputs (mean, log_variance) tuple
mean, logvar = model(x)
loss = loss_fn((mean, logvar), y_true)
| Parameter | Type | Default | Description |
|---|---|---|---|
mean_weight |
float or 1D sequence |
1.0 |
Multiplier on the mean term. A scalar applies to all outputs; a sequence of length D gives one weight per output. Set to 0 to train variance only. |
mean_loss |
str |
"mse" |
"mse" or "huber". Huber is scaled by 2, so it equals the MSE below huber_delta and is linear beyond it. |
huber_delta |
float |
1.0 |
Huber threshold in target units; used only when mean_loss="huber". |
variance_weight |
float |
1.0 |
Multiplier on the Gaussian NLL terms. Set to 0 to train mean only. |
min_variance |
float |
1e-6 |
Minimum variance for numerical stability |
eps |
float |
1e-8 |
Epsilon for log-stability |
reduction |
str |
"mean" |
"mean", "sum", or "none" |
split_dim |
int |
-1 |
Dimension to split concatenated [mean, log_var] output |
With a vector mean_weight, the weight \(\lambda_{\mu,d}\) multiplies output \(d\) of the mean term, so multi-output problems can give each target its own emphasis (for example to down-weight a target that cannot be measured). Normalise the weights, e.g. to sum to \(D\), so the overall loss scale stays comparable between runs.
# Equal emphasis on three targets except the last, which is down-weighted
loss_fn = FaithfulGaussianLoss(mean_weight=[1.0, 1.0, 0.25], mean_loss="huber", huber_delta=3.0)
Z-score the targets first
The mean term is not scale-invariant. With several outputs, standardise each target so that a weight of 1 means the same thing for all of them.
Comparison: Faithful vs Beta-NLL vs Joint NLL¶
| Feature | GaussianNLLLoss |
BetaNLLLoss |
FaithfulGaussianLoss |
|---|---|---|---|
| Mean/variance coupling | Coupled | Variance-detached reweighting | Explicitly split |
| Mean objective | NLL residual | NLL residual (detached variance) | Pure MSE |
| Variance objective | Joint NLL | Reweighted NLL | Separate NLL term |
| Gradient path | \(\mu\) sees \(\sigma^2\) | \(\mu\) sees detached \(\sigma^{2\beta}\) | \(\mu\) sees only MSE |
| Best for | Standard heteroscedastic | Stabilized variance learning | Preserving point accuracy |
When to use FaithfulGaussianLoss
Use when you care more about point prediction accuracy than perfectly calibrated variance, but still want a meaningful noise model. Common in scientific applications where the mean prediction is the primary deliverable.
Detach tradeoff
Because the mean head only sees MSE gradients, it does not receive curvature information from the NLL about heteroscedasticity. On datasets where mean and variance are strongly coupled (e.g., Poisson-like count data), this decoupling can slow convergence of the mean head.
Shared features
The stop-gradient is on the predicted mean only. If the mean and variance heads share a trunk, the variance term's gradient still reaches the shared features. That gradient is bounded (no \(1/\sigma^2\) factor), but the trunk is not fully decoupled from the variance task. Detach the features inside the model for a stricter separation.
Edge cases
mean_weight=0: The mean head receives zero gradients, but the (detached) mean still feeds the variance head's residual. If the mean is poorly initialized and never trained, the variance head receives a bad signal.variance_weight=0: The variance head receives zero gradients. The loss reduces to plain MSE.
GaussianCRPSLoss¶
Why CRPS Instead of NLL?¶
The Continuous Ranked Probability Score (CRPS) is a proper scoring rule that evaluates the full predictive distribution. See the GaussianCRPSLoss API for parameters and the closed-form definition.
Unlike NLL, CRPS:
- Has the same units as the target variable (interpretable)
- Is less sensitive to tail events than NLL (a single very-low-probability point doesn't dominate)
- Penalizes both calibration and sharpness simultaneously
- Reduces to MAE when the predictive distribution is a point mass
Analytic Gaussian CRPS¶
For a Gaussian predictive distribution \(\mathcal{N}(\mu, \sigma^2)\), the CRPS has a closed form:
where \(z = \frac{y - \mu}{\sigma}\), \(\Phi\) is the standard normal CDF, and \(\phi\) is the standard normal PDF.
Usage¶
from torchregress.losses import GaussianCRPSLoss
loss_fn = GaussianCRPSLoss()
# Same interface as GaussianNLLLoss
mean, logvar = model(x)
loss = loss_fn((mean, logvar), y_true)
Supports the same prediction formats as GaussianNLLLoss:
- Tuple (mean, log_variance)
- Concatenated tensor [mean, log_variance]
- Mean-only when fixed_variance is set
| Parameter | Type | Default | Description |
|---|---|---|---|
min_variance |
float |
1e-6 |
Minimum variance for numerical stability |
eps |
float |
1e-8 |
Epsilon for division stability |
fixed_variance |
float or None |
None |
Fixed variance for homoscedastic models |
reduction |
str |
"mean" |
"mean", "sum", or "none" |
When to Prefer CRPS over NLL¶
Use CRPS when
- You want interpretable loss values in target units
- Your data has heavy tails where NLL is dominated by a few extreme points
- You're comparing models across different distributional families (CRPS is a universal scoring rule)
- You're evaluating ensemble or Bayesian model predictions via the Energy Score (multivariate CRPS)
Performance note
CRPS is approximately 2-3× slower to compute per iteration than NLL, due to the additional ndtr (normal CDF) and exp operations per element. For large-scale training where NLL is adequate, the speed difference may matter.
Use NLL when
- You need the tightest possible likelihood-based training signal
- Your model is well-specified and residuals are approximately Gaussian
- You're computing information criteria (AIC, BIC) or Bayes factors
Complete Example¶
import torch
import torch.nn as nn
from torchregress.losses import FaithfulGaussianLoss, GaussianCRPSLoss
# Heteroscedastic model
class HeteroModel(nn.Module):
def __init__(self, in_dim):
super().__init__()
self.shared = nn.Sequential(nn.Linear(in_dim, 64), nn.ReLU(), nn.Linear(64, 32), nn.ReLU())
self.mean_head = nn.Linear(32, 1)
self.logvar_head = nn.Linear(32, 1)
def forward(self, x):
h = self.shared(x)
return self.mean_head(h), self.logvar_head(h)
torch.manual_seed(42)
x = torch.randn(200, 5)
y = 2.0 * x[:, [0]] + 0.3 * torch.randn(200, 1) * torch.exp(0.5 * x[:, [1]])
model = HeteroModel(5)
faithful_loss = FaithfulGaussianLoss(mean_weight=1.0, variance_weight=1.0)
crps_loss = GaussianCRPSLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)
for epoch in range(100):
mean, logvar = model(x)
# Train with faithful loss
loss = faithful_loss((mean, logvar), y)
optimizer.zero_grad()
loss.backward()
optimizer.step()
# Monitor CRPS
with torch.no_grad():
crps = crps_loss((mean, logvar), y)
if epoch % 20 == 0:
print(f"Epoch {epoch}: Faithful Loss = {loss.item():.4f}, CRPS = {crps.item():.4f}")
Limitations¶
- Detach tradeoff: The
stop_gradienton \(\mu\) in the NLL residual means the mean head receives only MSE gradients — it does not see heteroscedastic curvature information. On datasets where mean and variance are strongly coupled (e.g., Poisson-like count data), this can slow convergence of the mean head. - Edge case
mean_weight=0: The variance head still receives the detached \(\mu\) in its residual term. If \(\mu\) is poorly initialised and never trained, the variance head gets a bad signal. - Edge case
variance_weight=0: The loss reduces to plain MSE. The variance head receives zero gradients. - CRPS cost:
GaussianCRPSLossis 2–3× slower per iteration than NLL due tondtr(normal CDF) andexpoperations. For large-scale training where NLL is adequate, prefer NLL for speed.
Recommendations¶
- Use when point accuracy matters more than variance calibration:
FaithfulGaussianLossis ideal for scientific applications where the mean prediction is the primary deliverable. - Prefer NLL for pure uncertainty quantification: If calibrated variance is your goal, standard
GaussianNLLLossorBetaNLLLossare better choices. - Prefer CRPS for interpretability:
GaussianCRPSLossproduces loss values in target units, is less sensitive to tail events, and penalises both calibration and sharpness. SeeGaussianCRPSLossin the API reference. - Monitor both objectives separately: Track MSE and NLL independently during training to diagnose whether one term is dominating.
Next steps¶
- Gaussian losses — standard NLL and multivariate variants
- Beta-NLL — another approach to decouple mean/variance training
- Ensemble methods — decompose aleatoric + epistemic uncertainty
- Calibration metrics — validate your variance estimates
References¶
| # | Reference |
|---|---|
| 1 | Stirn et al. "Faithful Heteroscedastic Regression with Deep Neural Networks." AISTATS, 2023. |
| 2 | Hersbach, H. "Decomposition of the Continuous Ranked Probability Score for Ensemble Prediction Systems." Weather and Forecasting, 15(5):559–570, 2000. |
| 3 | Gneiting & Raftery. "Strictly Proper Scoring Rules, Prediction, and Estimation." JASA, 102(477):359–378, 2007. |