sparse-cafm / src /util /metrics.py
leharris3's picture
Minimal HF Space deployment with gradio 5.x fix
0917e8d
import torch
import numpy as np
from torchmetrics.functional.image.ssim import multiscale_structural_similarity_index_measure as ssim
from torchmetrics.functional.image.psnr import peak_signal_noise_ratio as psnr
from typing import Optional, Tuple
def RMSE_surface_roughness_l1(
pred: torch.Tensor, target: torch.Tensor, dataset_min: float, dataset_max: float
) -> torch.Tensor:
# unnormalize to original topology distribution
pred = pred * (dataset_max - dataset_min) + dataset_min
target = target * (dataset_max - dataset_min) + dataset_min
def calculate_roughness(X: torch.Tensor) -> torch.Tensor:
"""
Per Jayed's specs...
"""
# Zero-centering the data
X -= torch.mean(X)
# RMS roughness in nm
Sq = torch.sqrt(torch.mean(X**2)) * 1e9
# Mean roughness in nm
Sa = torch.mean(torch.abs(X)) * 1e9
return Sq
return (calculate_roughness(pred) - calculate_roughness(target)).abs()
def MAE(preds: torch.Tensor, target: torch.Tensor) -> torch.Tensor:
return (preds - target).abs().mean()
def MSE(preds: torch.Tensor, target: torch.Tensor) -> torch.Tensor:
return (preds - target).pow(2).mean()
def SSIM(
preds: torch.Tensor,
target: torch.Tensor,
_data_range: Optional[Tuple[float, float]] = (-1.0, 1.0),
) -> torch.Tensor:
"""
...
"""
low, high = _data_range
diff = high - low
# check that all vals are in range
if not ((preds >= low) & (preds <= high)).all():
raise ValueError(
f"Values in `preds` are out of the expected range [{low}, {high}]. "
f"Detected min={preds.min().item()}, max={preds.max().item()}"
)
if not ((target >= low) & (target <= high)).all():
raise ValueError(
f"Values in `target` are out of the expected range [{low}, {high}]. "
f"Detected min={target.min().item()}, max={target.max().item()}"
)
# val = ssim(preds.clamp(low, high).float(), target.clamp(low, high).float(), data_range=diff)
# NOTE: don't use explicit range
# this implementation calculates max, min values automatically
val = ssim(preds, target)
return val
def PSNR(
preds: torch.Tensor,
target: torch.Tensor,
data_range: Optional[Tuple[float, float]] = (-1.0, 1.0),
) -> torch.Tensor:
"""
...
"""
# check that all vals are in range
low, high = data_range
if not ((preds >= low) & (preds <= high)).all():
raise ValueError(
f"Values in `preds` are out of the expected range [{low}, {high}]. "
f"Detected min={preds.min().item()}, max={preds.max().item()}"
)
if not ((target >= low) & (target <= high)).all():
raise ValueError(
f"Values in `target` are out of the expected range [{low}, {high}]. "
f"Detected min={target.min().item()}, max={target.max().item()}"
)
# val = psnr(preds, target, data_range=high - low)
# NOTE: don't use explicit range
# this implementation calculates max, min values automatically
val = psnr(preds, target)
return val
def OLDER(y_char: dict, y_sparse_char: dict) -> float:
"""
Offline Domain-Expert Rating.
A weighted average of percent difference of characterization of two current-maps using Celano labs scripts.
Parameters
---
:y_char: dictionary output of celano lab script for y
:y_sparse_char: dictionary output of celano lab script for y_sparse
Returns
---
:val float: mean-abs %-diff in range [0, inf)
"""
# KEYS = ["average_surface_current", "coverage_percentage", "num_extended_shapes", "total_Area Extended Shapes"]
diffs = []
for k1, k2 in zip(y_char.keys(), y_sparse_char.keys()):
# if k1 not in KEYS or k2 not in KEYS: continue
val1, val2 = y_char[k1], y_sparse_char[k2]
if val1 == 0 and val2 == 0:
diffs.append(0.0)
else:
avg_val = (val1 + val2) / 2.0
# || %diff || = || 2 * || val1 - val2 || / (val1 + val2) ||
pdiff = abs(val1 - val2) / avg_val
diffs.append(abs(pdiff))
return np.mean(diffs)
if __name__ == "__main__":
pass