Skip to content

[Bug] Numerical instability in PearsonCorrelation due to naive variance formula #3662

Description

@Prathamesh8989

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

≈ 0.7071067

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:

  • Mean
  • Variance
  • Covariance

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!

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions