Earthformer / script /metrics.py
yzt15806542928's picture
Upload folder using huggingface_hub
8bfc737 verified
Raw
History Blame
3.16 kB
from __future__ import annotations
import torch
CSI_THRESHOLDS = torch.tensor([16, 74, 133, 160, 181, 219], dtype=torch.float32) / 255.0
def mse(prediction: torch.Tensor, target: torch.Tensor) -> torch.Tensor:
return torch.mean((prediction - target) ** 2)
def _ssim_per_sample(prediction: torch.Tensor, target: torch.Tensor) -> torch.Tensor:
prediction, target = prediction.clamp(0.0, 1.0), target.clamp(0.0, 1.0)
mu_x, mu_y = prediction.mean((2, 3)), target.mean((2, 3))
centered_x = prediction - mu_x[:, :, None, None, :]
centered_y = target - mu_y[:, :, None, None, :]
var_x = centered_x.square().mean((2, 3))
var_y = centered_y.square().mean((2, 3))
covariance = (centered_x * centered_y).mean((2, 3))
c1, c2 = 0.01**2, 0.03**2
score = ((2 * mu_x * mu_y + c1) * (2 * covariance + c2)) / (
(mu_x.square() + mu_y.square() + c1) * (var_x + var_y + c2)
)
return score.mean((1, 2))
def metric_sums(prediction: torch.Tensor, target: torch.Tensor) -> torch.Tensor:
"""Return additive sample-level MSE/MAE/SSIM sums and CSI event counts."""
prediction, target = prediction.float(), target.float()
reduce_dims = tuple(range(1, prediction.ndim))
values = [
(prediction - target).square().mean(reduce_dims).sum(),
(prediction - target).abs().mean(reduce_dims).sum(),
_ssim_per_sample(prediction, target).sum(),
prediction.new_tensor(prediction.shape[0]),
]
for threshold in CSI_THRESHOLDS.to(prediction.device):
predicted, observed = prediction >= threshold, target >= threshold
values.extend([(predicted & observed).sum(), (predicted & ~observed).sum(), (~predicted & observed).sum()])
return torch.stack(values).to(torch.float64)
def metrics_from_sums(sums: torch.Tensor) -> dict[str, float]:
count = sums[3].clamp_min(1)
csi = []
for index in range(len(CSI_THRESHOLDS)):
hits, false_alarms, misses = sums[4 + index * 3 : 7 + index * 3]
csi.append((hits / (hits + false_alarms + misses).clamp_min(1)).item())
return {
"mse": (sums[0] / count).item(),
"mae": (sums[1] / count).item(),
"ssim": (sums[2] / count).item(),
"mean_csi": sum(csi) / len(csi),
}
def metric_sums_light(prediction: torch.Tensor, target: torch.Tensor) -> torch.Tensor:
"""Additive MSE/MAE sums for cheap per-epoch validation: [mse_sum, mae_sum, count]."""
prediction, target = prediction.float(), target.float()
reduce_dims = tuple(range(1, prediction.ndim))
return torch.stack(
[
(prediction - target).square().mean(reduce_dims).sum(),
(prediction - target).abs().mean(reduce_dims).sum(),
prediction.new_tensor(prediction.shape[0]),
]
).to(torch.float64)
def metrics_from_light_sums(sums: torch.Tensor) -> dict[str, float]:
count = sums[2].clamp_min(1)
return {"mse": (sums[0] / count).item(), "mae": (sums[1] / count).item()}
def compute_metrics(prediction: torch.Tensor, target: torch.Tensor) -> dict[str, float]:
return metrics_from_sums(metric_sums(prediction.detach(), target.detach()))