yushuang88's picture
Upload folder using huggingface_hub
5c14105 verified
Raw History Blame Contribute Delete
4.96 kB
from __future__ import annotations
import argparse
import json
import sys
import time
from pathlib import Path
from typing import Any
import numpy as np
import torch
from torch.utils.data import DataLoader, Dataset
import yaml
PROJECT_ROOT = Path(__file__).resolve().parents[1]
if str(PROJECT_ROOT) not in sys.path:
sys.path.insert(0, str(PROJECT_ROOT))
from model.neural_convection_fno import build_model_from_config
from scripts.train import load_pair, normalize_x, normalize_y, ssim_2d, tensor_to_numpy
class InferenceDataset(Dataset):
def __init__(self, x: torch.Tensor, y: torch.Tensor, stats: dict[str, torch.Tensor]) -> None:
self.x = x
self.y = y
self.stats = stats
def __len__(self) -> int:
return int(self.x.shape[0])
def __getitem__(self, idx: int) -> tuple[torch.Tensor, torch.Tensor]:
return normalize_x(self.x[idx], self.stats), normalize_y(self.y[idx], self.stats)
def load_config(path: str | Path) -> dict[str, Any]:
with open(path, "r", encoding="utf-8") as handle:
return yaml.safe_load(handle)
def resolve(path: str | Path) -> Path:
path = Path(path)
return path if path.is_absolute() else PROJECT_ROOT / path
def select_device(name: str) -> torch.device:
if name == "auto":
return torch.device("cuda" if torch.cuda.is_available() else "cpu")
return torch.device(name)
def save_json(path: Path, payload: dict[str, Any]) -> None:
path.parent.mkdir(parents=True, exist_ok=True)
with open(path, "w", encoding="utf-8") as handle:
json.dump(payload, handle, indent=2)
@torch.no_grad()
def main() -> None:
parser = argparse.ArgumentParser(description="Run compact FNO inference on a NeuralConvection split.")
parser.add_argument("--config", default=str(PROJECT_ROOT / "config/config.yaml"))
parser.add_argument("--split", default=None)
parser.add_argument("--checkpoint", default=None)
parser.add_argument("--device", default=None)
args = parser.parse_args()
config = load_config(args.config)
data_cfg = config["data"]
infer_cfg = config["inference"]
split = args.split or infer_cfg["split"]
device = select_device(args.device or config["experiment"].get("device", "auto"))
root = resolve(data_cfg["root_dir"])
stats = torch.load(resolve(data_cfg["stats_path"]), map_location="cpu")
x, y = load_pair(root, split, data_cfg["x_file"], data_cfg["y_file"])
loader = DataLoader(
InferenceDataset(x, y, stats),
batch_size=int(infer_cfg["batch_size"]),
shuffle=False,
num_workers=int(data_cfg.get("num_workers", 0)),
pin_memory=bool(data_cfg.get("pin_memory", True)) and device.type == "cuda",
)
model = build_model_from_config(config).to(device)
ckpt_path = resolve(args.checkpoint or infer_cfg["checkpoint_path"])
checkpoint = torch.load(ckpt_path, map_location=device)
model.load_state_dict(checkpoint["model_state_dict"])
model.eval()
preds: list[np.ndarray] = []
targets: list[np.ndarray] = []
inputs: list[np.ndarray] = []
start = time.perf_counter()
for x_batch, y_batch in loader:
x_batch = x_batch.to(device, non_blocking=True)
pred = tensor_to_numpy(model(x_batch))
preds.append(pred)
targets.append(tensor_to_numpy(y_batch))
inputs.append(tensor_to_numpy(x_batch))
elapsed = time.perf_counter() - start
pred_all = np.concatenate(preds, axis=0)
target_all = np.concatenate(targets, axis=0)
input_all = np.concatenate(inputs, axis=0)
channel_names = list(data_cfg["channel_names"])
metrics = {
"split": split,
"checkpoint_path": str(ckpt_path),
"num_samples": int(pred_all.shape[0]),
"time_seconds_per_sample": elapsed / max(1, pred_all.shape[0]),
"per_channel": {},
"paper_table5_compact_fno_2d": config["paper_table5_compact_fno_2d"],
}
for idx, name in enumerate(channel_names):
mse = float(np.mean((pred_all[:, idx] - target_all[:, idx]) ** 2))
ssim = float(np.mean([ssim_2d(pred_all[i, idx], target_all[i, idx]) for i in range(pred_all.shape[0])]))
metrics["per_channel"][name] = {"mse": mse, "ssim": ssim}
paper = config["paper_table5_compact_fno_2d"]["channels"].get(name, {})
print(
f"{name}: mse={mse:.8e} ssim={ssim:.6f} paper_mse={paper.get('mse')} paper_ssim={paper.get('ssim')}",
flush=True,
)
out_path = resolve(infer_cfg["output_path"])
out_path.parent.mkdir(parents=True, exist_ok=True)
np.savez_compressed(out_path, pred_norm=pred_all, target_norm=target_all, input_norm=input_all, channel_names=np.array(channel_names))
save_json(resolve(infer_cfg["metrics_path"]), metrics)
print(f"saved_predictions={out_path}", flush=True)
print(f"saved_metrics={resolve(infer_cfg['metrics_path'])}", flush=True)
if __name__ == "__main__":
main()