Download scripts/result.py from OneScience-Group/CNO: direct link, hf CLI and curl.
- Browser
- Download file 6.52 kB
-
https://huggingface.co/OneScience-Group/CNO/resolve/main/scripts/result.py
- Command line
-
hf download hf://OneScience-Group/CNO/scripts/result.py
-
curl -L -o result.py https://huggingface.co/OneScience-Group/CNO/resolve/main/scripts/result.py
6.52 kB
| #!/usr/bin/env python3 | |
| """Visualize CNO fields and ID/OOD relative-L1 distributions.""" | |
| from __future__ import annotations | |
| import argparse | |
| import json | |
| from pathlib import Path | |
| import matplotlib | |
| matplotlib.use("Agg") | |
| import matplotlib.pyplot as plt | |
| import numpy as np | |
| PROJECT_ROOT = Path(__file__).resolve().parents[1] | |
| def parse_args() -> argparse.Namespace: | |
| parser = argparse.ArgumentParser(description=__doc__) | |
| parser.add_argument("--results-dir", default=str(PROJECT_ROOT / "results")) | |
| parser.add_argument( | |
| "--sample-index", | |
| type=int, | |
| default=None, | |
| help="array index to plot; default is the sample nearest the split median error", | |
| ) | |
| parser.add_argument("--dpi", type=int, default=180) | |
| return parser.parse_args() | |
| def load_predictions(path: Path) -> dict[str, np.ndarray]: | |
| if not path.is_file(): | |
| raise FileNotFoundError(f"prediction artifact not found: {path}") | |
| with np.load(path) as payload: | |
| required = {"sample_ids", "inputs", "targets", "predictions", "relative_l1"} | |
| missing = sorted(required.difference(payload.files)) | |
| if missing: | |
| raise KeyError(f"{path} is missing arrays: {missing}") | |
| arrays = {key: np.asarray(payload[key]) for key in required} | |
| count = arrays["sample_ids"].shape[0] | |
| for key in ("inputs", "targets", "predictions", "relative_l1"): | |
| if arrays[key].shape[0] != count: | |
| raise ValueError(f"sample count mismatch for {key} in {path}") | |
| if not np.isfinite(arrays[key]).all(): | |
| raise ValueError(f"nonfinite values in {key} from {path}") | |
| if arrays["inputs"].ndim != 4 or arrays["inputs"].shape[1] != 1: | |
| raise ValueError(f"expected N1HW fields in {path}, got {arrays['inputs'].shape}") | |
| return arrays | |
| def representative_index(errors: np.ndarray, requested: int | None) -> int: | |
| if requested is not None: | |
| if requested < 0 or requested >= errors.size: | |
| raise IndexError(f"sample-index {requested} outside [0,{errors.size})") | |
| return requested | |
| median = np.median(errors) | |
| return int(np.argmin(np.abs(errors - median))) | |
| def plot_fields( | |
| split: str, | |
| arrays: dict[str, np.ndarray], | |
| output_path: Path, | |
| requested_index: int | None, | |
| dpi: int, | |
| ) -> None: | |
| errors_percent = arrays["relative_l1"] * 100.0 | |
| index = representative_index(errors_percent, requested_index) | |
| input_field = arrays["inputs"][index, 0] | |
| target = arrays["targets"][index, 0] | |
| prediction = arrays["predictions"][index, 0] | |
| absolute_error = np.abs(prediction - target) | |
| field_min = float(min(target.min(), prediction.min())) | |
| field_max = float(max(target.max(), prediction.max())) | |
| fig, axes = plt.subplots(1, 4, figsize=(16, 3.8), constrained_layout=True) | |
| input_image = axes[0].imshow(input_field, origin="lower", cmap="RdBu_r") | |
| fig.colorbar(input_image, ax=axes[0], shrink=0.78) | |
| target_image = axes[1].imshow( | |
| target, origin="lower", cmap="RdBu_r", vmin=field_min, vmax=field_max | |
| ) | |
| prediction_image = axes[2].imshow( | |
| prediction, origin="lower", cmap="RdBu_r", vmin=field_min, vmax=field_max | |
| ) | |
| error_image = axes[3].imshow(absolute_error, origin="lower", cmap="magma") | |
| fig.colorbar(target_image, ax=[axes[1], axes[2]], shrink=0.78) | |
| fig.colorbar(error_image, ax=axes[3], shrink=0.78) | |
| titles = ("Initial velocity", "Target at T=1", "CNO prediction", "Absolute error") | |
| for axis, title in zip(axes, titles): | |
| axis.set_title(title) | |
| axis.set_xlabel("x index") | |
| axis.set_ylabel("y index") | |
| sample_id = int(arrays["sample_ids"][index]) | |
| fig.suptitle( | |
| f"{split.upper()} Sample_{sample_id} — relative L1={errors_percent[index]:.3f}%" | |
| ) | |
| fig.savefig(output_path, dpi=dpi) | |
| plt.close(fig) | |
| def plot_distribution( | |
| split_arrays: dict[str, dict[str, np.ndarray]], | |
| paper_reference: dict, | |
| output_path: Path, | |
| dpi: int, | |
| ) -> None: | |
| fig, axes = plt.subplots(1, 2, figsize=(11, 4), constrained_layout=True) | |
| colors = {"id": "#2166ac", "ood": "#b2182b"} | |
| for split in ("id", "ood"): | |
| values = split_arrays[split]["relative_l1"] * 100.0 | |
| axes[0].hist(values, bins=20, alpha=0.55, label=split.upper(), color=colors[split]) | |
| axes[0].axvline( | |
| np.median(values), color=colors[split], linewidth=2, linestyle="-" | |
| ) | |
| reference = paper_reference.get(split) | |
| if reference is not None: | |
| axes[0].axvline( | |
| float(reference), color=colors[split], linewidth=1.5, linestyle="--" | |
| ) | |
| axes[0].set_title("Per-sample relative L1") | |
| axes[0].set_xlabel("Relative L1 (%)") | |
| axes[0].set_ylabel("Count") | |
| axes[0].legend(title="solid=reproduction\ndashed=paper") | |
| values = [ | |
| split_arrays["id"]["relative_l1"] * 100.0, | |
| split_arrays["ood"]["relative_l1"] * 100.0, | |
| ] | |
| box = axes[1].boxplot(values, tick_labels=["ID", "OOD"], patch_artist=True) | |
| for patch, color in zip(box["boxes"], (colors["id"], colors["ood"])): | |
| patch.set_facecolor(color) | |
| patch.set_alpha(0.55) | |
| axes[1].set_title("Error distribution summary") | |
| axes[1].set_ylabel("Relative L1 (%)") | |
| fig.savefig(output_path, dpi=dpi) | |
| plt.close(fig) | |
| def main() -> None: | |
| args = parse_args() | |
| results_dir = Path(args.results_dir).expanduser().resolve() | |
| metrics_path = results_dir / "metrics.json" | |
| if not metrics_path.is_file(): | |
| raise FileNotFoundError(f"metrics file not found: {metrics_path}") | |
| with metrics_path.open("r", encoding="utf-8") as handle: | |
| metrics = json.load(handle) | |
| split_arrays = { | |
| split: load_predictions(results_dir / f"{split}_predictions.npz") | |
| for split in ("id", "ood") | |
| } | |
| for split, arrays in split_arrays.items(): | |
| output_path = results_dir / f"{split}_fields.png" | |
| plot_fields(split, arrays, output_path, args.sample_index, args.dpi) | |
| values = arrays["relative_l1"] * 100.0 | |
| print( | |
| f"visualization split={split} median={np.median(values):.6f}% " | |
| f"mean={np.mean(values):.6f}% saved={output_path}", | |
| flush=True, | |
| ) | |
| distribution_path = results_dir / "error_distribution.png" | |
| plot_distribution( | |
| split_arrays, | |
| metrics.get("paper_reference", {}), | |
| distribution_path, | |
| args.dpi, | |
| ) | |
| print(f"visualization saved={distribution_path}", flush=True) | |
| if __name__ == "__main__": | |
| main() | |