The current implementation of PearsonCorrelation in ignite.metrics.regression uses the naive "sum of squares" algorithm to compute variance and covariance:
[
Var(X) = E[X^2] - (E[X])^2
]
Although mathematically valid, this approach is numerically unstable when the input values have large magnitudes relative to their variance.
This leads to catastrophic cancellation, where two very large numbers (E[X^2] and (E[X])^2) are subtracted, causing loss of precision in float32. As a result, the metric can produce incorrect results, such as returning 0.0 when the true correlation is ≈ 0.707.
Steps to Reproduce
import torch
from ignite.metrics.regression import PearsonCorrelation
import numpy as np
# Magnitude that triggers precision loss in float32
offset = 1e8
y_true = torch.tensor([1.0, 2.0, 3.0, 4.0, 5.0]) + offset
y_pred = torch.tensor([1.1, 2.1, 3.1, 4.1, 5.1]) + offset
metric = PearsonCorrelation()
metric.update((y_pred, y_true))
ignite_res = metric.compute()
# Ground truth using PyTorch's stable corrcoef
combined = torch.stack([y_pred, y_true])
torch_res = torch.corrcoef(combined)[0, 1].item()
print(f"Offset used: {offset}")
print(f"Ignite Result: {ignite_res}")
print(f"Torch Ground Truth: {torch_res}")
actual output
Offset used: 100000000.0
Ignite Result: 0.0
Torch Ground Truth: 0.7071067690849304
Expected Behavior
The Pearson correlation metric should be invariant to constant offsets in the input data.
Therefore, the result should be consistent with numerically stable implementations such as:
torch.corrcoef
scipy.stats.pearsonr
Expected Result
Proposed Fix
To improve numerical stability, the implementation can be updated as follows:
Use a Numerically Stable Online Algorithm
Implement Welford’s Online Algorithm (or a similar one-pass algorithm) to compute:
incrementally.
Use Higher Precision Accumulators
Maintain internal accumulators using torch.float64 to prevent precision loss during batch updates.
Ensure Compatibility with Ignite Metrics
The updated implementation should still support batch-wise streaming updates used by Ignite metrics.
Benefit
These changes will prevent catastrophic cancellation and ensure correct results even when the data has:
- Large offsets
- High magnitude values
Hi @vfdev-5, I would like to work on a PR to resolve this issue if this looks good to you!
The current implementation of
PearsonCorrelationinignite.metrics.regressionuses the naive "sum of squares" algorithm to compute variance and covariance:[
Var(X) = E[X^2] - (E[X])^2
]
Although mathematically valid, this approach is numerically unstable when the input values have large magnitudes relative to their variance.
This leads to catastrophic cancellation, where two very large numbers (
E[X^2]and(E[X])^2) are subtracted, causing loss of precision in float32. As a result, the metric can produce incorrect results, such as returning 0.0 when the true correlation is ≈ 0.707.Steps to Reproduce
actual output
Expected Behavior
The Pearson correlation metric should be invariant to constant offsets in the input data.
Therefore, the result should be consistent with numerically stable implementations such as:
torch.corrcoefscipy.stats.pearsonrExpected Result
Proposed Fix
To improve numerical stability, the implementation can be updated as follows:
Use a Numerically Stable Online Algorithm
Implement Welford’s Online Algorithm (or a similar one-pass algorithm) to compute:
incrementally.
Use Higher Precision Accumulators
Maintain internal accumulators using
torch.float64to prevent precision loss during batch updates.Ensure Compatibility with Ignite Metrics
The updated implementation should still support batch-wise streaming updates used by Ignite metrics.
Benefit
These changes will prevent catastrophic cancellation and ensure correct results even when the data has:
Hi @vfdev-5, I would like to work on a PR to resolve this issue if this looks good to you!