Text-to-Image
MLX
Safetensors
Diffusion Single File
Anima-mlx / anima_mlx /utils /compare.py
fukujusou's picture
Upload folder using huggingface_hub
3bdc93d verified
Raw
History Blame Contribute Delete
2 kB
"""Numeric comparison helpers for golden parity tests."""
from __future__ import annotations
from dataclasses import dataclass
from typing import Any
@dataclass(frozen=True)
class TensorComparison:
shape: tuple[int, ...]
reference_shape: tuple[int, ...]
max_abs: float
mean_abs: float
rmse: float
max_rel: float
passed: bool
def to_numpy(array: Any) -> Any:
"""Convert PyTorch/MLX/NumPy-like arrays to a NumPy float32 array."""
import numpy as np
if hasattr(array, "detach"):
return array.detach().cpu().float().numpy()
if hasattr(array, "tolist"):
return np.asarray(array.tolist(), dtype=np.float32)
return np.asarray(array, dtype=np.float32)
def compare_tensors(
actual: Any,
expected: Any,
*,
atol: float,
rtol: float = 0.0,
) -> TensorComparison:
"""Return absolute/relative error metrics and threshold result."""
import numpy as np
actual_np = to_numpy(actual).astype(np.float32)
expected_np = to_numpy(expected).astype(np.float32)
if actual_np.shape != expected_np.shape:
return TensorComparison(
shape=tuple(actual_np.shape),
reference_shape=tuple(expected_np.shape),
max_abs=float("inf"),
mean_abs=float("inf"),
rmse=float("inf"),
max_rel=float("inf"),
passed=False,
)
diff = np.abs(actual_np - expected_np)
denom = np.maximum(np.abs(expected_np), 1e-12)
rel = diff / denom
allowed = atol + rtol * np.abs(expected_np)
passed = bool(np.all(diff <= allowed))
return TensorComparison(
shape=tuple(actual_np.shape),
reference_shape=tuple(expected_np.shape),
max_abs=float(diff.max()) if diff.size else 0.0,
mean_abs=float(diff.mean()) if diff.size else 0.0,
rmse=float(np.sqrt(np.mean(np.square(diff)))) if diff.size else 0.0,
max_rel=float(rel.max()) if rel.size else 0.0,
passed=passed,
)