Download scripts/common.py from OneScience-Group/HO-FNO-Pipe-Flow: direct link, hf CLI and curl.
- Browser
- Download file 6.24 kB
-
https://huggingface.co/OneScience-Group/HO-FNO-Pipe-Flow/resolve/main/scripts/common.py
- Command line
-
hf download hf://OneScience-Group/HO-FNO-Pipe-Flow/scripts/common.py
-
curl -L -o common.py https://huggingface.co/OneScience-Group/HO-FNO-Pipe-Flow/resolve/main/scripts/common.py
6.24 kB
| from __future__ import annotations | |
| import json | |
| import os | |
| import random | |
| import sys | |
| from pathlib import Path | |
| from typing import Any | |
| import numpy as np | |
| import torch | |
| import yaml | |
| ROOT = Path(__file__).resolve().parents[1] | |
| if str(ROOT) not in sys.path: | |
| sys.path.insert(0, str(ROOT)) | |
| from model.ho_fno_pipe import HOFNOPipe, count_parameters # noqa: E402 | |
| class UnitTransformer: | |
| def __init__(self, tensor: torch.Tensor, axes: tuple[int, ...] = (0, 1), eps: float = 1e-8) -> None: | |
| self.axes = axes | |
| self.eps = eps | |
| self.mean = tensor.mean(dim=axes, keepdim=True) | |
| self.std = tensor.std(dim=axes, keepdim=True) + eps | |
| def encode(self, tensor: torch.Tensor) -> torch.Tensor: | |
| return (tensor - self.mean) / self.std | |
| def decode(self, tensor: torch.Tensor) -> torch.Tensor: | |
| return tensor * self.std + self.mean | |
| def to(self, device: torch.device) -> "UnitTransformer": | |
| self.mean = self.mean.to(device) | |
| self.std = self.std.to(device) | |
| return self | |
| def state_dict(self) -> dict[str, Any]: | |
| return {"mean": self.mean.cpu(), "std": self.std.cpu(), "axes": self.axes, "eps": self.eps} | |
| def from_state_dict(cls, state: dict[str, Any]) -> "UnitTransformer": | |
| obj = cls.__new__(cls) | |
| obj.mean = state["mean"] | |
| obj.std = state["std"] | |
| obj.axes = tuple(state.get("axes", (0, 1))) | |
| obj.eps = float(state.get("eps", 1e-8)) | |
| return obj | |
| def load_config(path: str | os.PathLike[str] | None = None) -> dict[str, Any]: | |
| cfg_path = Path(path) if path else ROOT / "config" / "config.yaml" | |
| with cfg_path.open("r", encoding="utf-8") as handle: | |
| cfg = yaml.safe_load(handle) | |
| cfg["_config_path"] = str(cfg_path) | |
| return cfg | |
| def set_seed(seed: int) -> None: | |
| random.seed(seed) | |
| np.random.seed(seed) | |
| torch.manual_seed(seed) | |
| if torch.cuda.is_available(): | |
| torch.cuda.manual_seed_all(seed) | |
| def resolve(path: str | os.PathLike[str], base: Path | None = None) -> Path: | |
| p = Path(path) | |
| if p.is_absolute(): | |
| return p | |
| return (base or ROOT) / p | |
| def select_device(require_accelerator: bool = False) -> torch.device: | |
| if torch.cuda.is_available(): | |
| return torch.device("cuda") | |
| if require_accelerator: | |
| raise RuntimeError("accelerator is required, but torch.cuda.is_available() is False") | |
| return torch.device("cpu") | |
| def load_pipe_tensors(cfg: dict[str, Any]) -> tuple[torch.Tensor, torch.Tensor, torch.Tensor]: | |
| data_cfg = cfg["data"] | |
| data_dir = Path(cfg["paths"]["data_dir"]) | |
| train_size = int(data_cfg["train_size"]) | |
| test_size = int(data_cfg["test_size"]) | |
| total_used = int(data_cfg["total_used"]) | |
| r1, r2 = (int(v) for v in data_cfg.get("downsample", [1, 1])) | |
| s1 = int(((int(data_cfg["resolution"][0]) - 1) / r1) + 1) | |
| s2 = int(((int(data_cfg["resolution"][1]) - 1) / r2) + 1) | |
| x_raw = np.load(data_dir / data_cfg["x_file"], mmap_mode="r")[:total_used, ::r1, ::r2][:, :s1, :s2] | |
| y_raw = np.load(data_dir / data_cfg["y_file"], mmap_mode="r")[:total_used, ::r1, ::r2][:, :s1, :s2] | |
| q_raw = np.load(data_dir / data_cfg["q_file"], mmap_mode="r")[ | |
| :total_used, int(data_cfg["output_channel_index"]), ::r1, ::r2 | |
| ][:, :s1, :s2] | |
| coords = np.stack((np.asarray(x_raw, dtype=np.float32), np.asarray(y_raw, dtype=np.float32)), axis=-1) | |
| target = np.asarray(q_raw, dtype=np.float32)[..., None] | |
| x_all = torch.from_numpy(coords.copy()) | |
| y_all = torch.from_numpy(target.copy()) | |
| return x_all[:train_size], y_all[:train_size], x_all[-test_size:], y_all[-test_size:] | |
| def make_normalized_loaders(cfg: dict[str, Any]): | |
| x_train, y_train, x_test, y_test = load_pipe_tensors(cfg) | |
| axes = tuple(int(v) for v in cfg["data"].get("normalizer_axes", [0, 1])) | |
| x_normalizer = UnitTransformer(x_train, axes=axes) | |
| y_normalizer = UnitTransformer(y_train, axes=axes) | |
| x_train_n = x_normalizer.encode(x_train) | |
| x_test_n = x_normalizer.encode(x_test) | |
| y_train_n = y_normalizer.encode(y_train) | |
| y_test_n = y_normalizer.encode(y_test) | |
| batch_size = int(cfg["training"]["batch_size"]) | |
| loader_kwargs = { | |
| "batch_size": batch_size, | |
| "num_workers": int(cfg["data"].get("num_workers", 0)), | |
| "pin_memory": bool(cfg["data"].get("pin_memory", False)), | |
| } | |
| train_ds = torch.utils.data.TensorDataset(x_train_n, y_train_n) | |
| test_ds = torch.utils.data.TensorDataset(x_test_n, y_test_n) | |
| train_loader = torch.utils.data.DataLoader(train_ds, shuffle=True, **loader_kwargs) | |
| test_loader = torch.utils.data.DataLoader(test_ds, shuffle=False, **loader_kwargs) | |
| return train_loader, test_loader, x_normalizer, y_normalizer | |
| def build_model(cfg: dict[str, Any]) -> HOFNOPipe: | |
| m = cfg["model"] | |
| return HOFNOPipe( | |
| input_channels=int(m["input_channels"]), | |
| output_channels=int(m["output_channels"]), | |
| order=int(m["order"]), | |
| layers=int(m["layers"]), | |
| width=int(m["width"]), | |
| modes=tuple(int(v) for v in m["modes"]), | |
| add_unit_grid=bool(m.get("add_unit_grid", True)), | |
| mlp_expansion=int(m.get("mlp_expansion", 4)), | |
| mlp_dropout=float(m.get("mlp_dropout", 0.0)), | |
| drop_path_rate=float(m.get("drop_path_rate", 0.0)), | |
| ) | |
| def relative_l2_per_sample(pred: torch.Tensor, target: torch.Tensor) -> torch.Tensor: | |
| pred_f = pred.reshape(pred.shape[0], -1) | |
| target_f = target.reshape(target.shape[0], -1) | |
| denom = torch.linalg.vector_norm(target_f, dim=1).clamp_min(1e-12) | |
| return torch.linalg.vector_norm(pred_f - target_f, dim=1) / denom | |
| def relative_l2_sum(pred: torch.Tensor, target: torch.Tensor) -> torch.Tensor: | |
| return relative_l2_per_sample(pred, target).sum() | |
| def save_json(path: Path, payload: dict[str, Any]) -> None: | |
| path.parent.mkdir(parents=True, exist_ok=True) | |
| with path.open("w", encoding="utf-8") as handle: | |
| json.dump(payload, handle, indent=2) | |
| __all__ = [ | |
| "ROOT", | |
| "UnitTransformer", | |
| "build_model", | |
| "count_parameters", | |
| "load_config", | |
| "make_normalized_loaders", | |
| "relative_l2_per_sample", | |
| "relative_l2_sum", | |
| "resolve", | |
| "save_json", | |
| "select_device", | |
| "set_seed", | |
| ] | |