OneScience's picture
Upload folder using huggingface_hub
21e6c23 verified
Raw
History Blame Contribute Delete
7.78 kB
from __future__ import annotations
import json
import logging
import random
import sys
from pathlib import Path
import numpy as np
import torch
import torch.nn as nn
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT))
from onescience.distributed.manager import DistributedManager
from onescience.utils.YParams import YParams
from train import build_datapipe, build_model, resolve_path
def setup_logging() -> logging.Logger:
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
return logging.getLogger("transolver-inference")
def load_checkpoint(path: Path, device: torch.device):
if not path.exists():
raise FileNotFoundError(f"Checkpoint not found: {path}. Run scripts/train.py first or provide a compatible weight.")
try:
return torch.load(path, map_location=device, weights_only=False)
except TypeError:
return torch.load(path, map_location=device)
def run_fake_inference(cfg_model, cfg_data, cfg_train, logger: logging.Logger, device: torch.device) -> int:
model_params = cfg_model.specific_params[cfg_model.name]
datapipe = build_datapipe(cfg_data, model_params, distributed=False)
test_loader = datapipe._loader(datapipe.test_dataset, False)[0]
model = build_model(cfg_model).to(device)
checkpoint_path = resolve_path(cfg_train.checkpoint_dir) / f"{cfg_model.name}.pth"
checkpoint = load_checkpoint(checkpoint_path, device)
model.load_state_dict(checkpoint["model_state_dict"])
model.eval()
result_dir = resolve_path(cfg_train.result_dir)
result_dir.mkdir(parents=True, exist_ok=True)
mean_out, std_out = datapipe.coef_norm[2], datapipe.coef_norm[3]
preds, targets = [], []
criterion = nn.MSELoss()
with torch.no_grad():
for data in test_loader:
data = data.to(device)
out = model(data)
pred = out.cpu().numpy() * (std_out + 1e-8) + mean_out
target = data.y.cpu().numpy() * (std_out + 1e-8) + mean_out
preds.append(pred)
targets.append(target)
pred_arr = np.concatenate(preds, axis=0)
target_arr = np.concatenate(targets, axis=0)
mse = float(criterion(torch.from_numpy(pred_arr), torch.from_numpy(target_arr)))
np.savez(result_dir / "predictions.npz", pred=pred_arr, target=target_arr, mse=np.array(mse, dtype=np.float32))
(result_dir / "score.json").write_text(json.dumps({"model_name": cfg_model.name, "mse": mse}, indent=2), encoding="utf-8")
logger.info("Saved fake inference outputs to %s", result_dir)
logger.info("MSE: %.6f", mse)
return 0
def run_airfrans_inference(cfg_model, cfg_data, cfg_train, logger: logging.Logger, device: torch.device) -> int:
import pyvista as pv
import scipy.stats as sc
from tqdm import tqdm
from onescience.utils.transolver.metrics import (
Airfoil_test,
Compute_coefficients,
Infer_test,
NumpyEncoder,
rel_err,
)
model_params = cfg_model.specific_params[cfg_model.name]
hparams = model_params
hparams["subsampling"] = cfg_data.data.subsampling
datapipe = build_datapipe(cfg_data, model_params, distributed=False)
coef_norm = datapipe.coef_norm
test_loader = datapipe.test_dataloader()
test_names = datapipe.test_dataset.data_list_names
model = build_model(cfg_model).to(device)
checkpoint_path = resolve_path(cfg_train.checkpoint_dir) / f"{cfg_model.name}.pth"
checkpoint = load_checkpoint(checkpoint_path, device)
model.load_state_dict(checkpoint["model_state_dict"])
model.eval()
path_in = resolve_path(cfg_data.source.data_dir)
path_out = resolve_path(cfg_train.result_dir) / cfg_data.data.splits.task
path_out.mkdir(parents=True, exist_ok=True)
sample_count = min(int(cfg_train.n_test), len(test_names))
chosen = sorted(random.sample(range(len(test_names)), k=sample_count)) if sample_count else []
criterion = nn.MSELoss(reduction="none")
scores_vol, scores_surf, scores_force, scores_p, scores_wss = [], [], [], [], []
times, true_coefs, pred_coefs = [], [], []
for j, data in enumerate(tqdm(test_loader, desc="Testing")):
sim_name = test_names[j]
u_inf, angle = float(sim_name.split("_")[2]), float(sim_name.split("_")[3])
outs, elapsed = Infer_test(device, [model], [hparams], data, coef_norm=coef_norm)
times.append(elapsed)
intern = pv.read(path_in / sim_name / f"{sim_name}_internal.vtu")
aerofoil = pv.read(path_in / sim_name / f"{sim_name}_aerofoil.vtp")
tc, true_intern, true_airfoil = Compute_coefficients([intern], [aerofoil], data.surf.cpu(), u_inf, angle, keep_vtk=True)
tc, true_airfoil = tc[0], true_airfoil[0]
intern_pred, aerofoil_pred = Airfoil_test(intern, aerofoil, outs, coef_norm, data.surf.cpu())
pc, intern_pred_vtk, aerofoil_pred_vtk = Compute_coefficients(intern_pred, aerofoil_pred, data.surf.cpu(), u_inf, angle, keep_vtk=True)
true_coefs.append(tc)
pred_coefs.append(pc)
out = outs[0]
scores_vol.append(criterion(out[~data.surf], data.y[~data.surf]).mean(dim=0).cpu().numpy())
scores_surf.append(criterion(out[data.surf], data.y[data.surf]).mean(dim=0).cpu().numpy())
scores_force.append(rel_err(tc, pc[0]))
scores_wss.append(rel_err(true_airfoil.point_data["wallShearStress"], aerofoil_pred_vtk[0].point_data["wallShearStress"]).mean(axis=0))
scores_p.append(rel_err(true_airfoil.point_data["p"], aerofoil_pred_vtk[0].point_data["p"]).mean(axis=0))
if j in chosen:
intern_pred_vtk[0].save(path_out / f"{sim_name}_pred_internal.vtu")
aerofoil_pred_vtk[0].save(path_out / f"{sim_name}_pred_aerofoil.vtp")
true_coefs_arr = np.array(true_coefs)
pred_coefs_arr = np.array(pred_coefs)
spear = [
sc.spearmanr(true_coefs_arr[:, 0], pred_coefs_arr[:, 0, 0])[0],
sc.spearmanr(true_coefs_arr[:, 1], pred_coefs_arr[:, 0, 1])[0],
]
score = {
"model_name": cfg_model.name,
"mean_time": np.array(times).mean(axis=0),
"std_time": np.array(times).std(axis=0),
"mean_score_vol": np.array(scores_vol).mean(axis=0),
"mean_score_surf": np.array(scores_surf).mean(axis=0),
"mean_score_force": np.array(scores_force).mean(axis=0),
"mean_rel_p": np.array(scores_p).mean(axis=0),
"mean_rel_wss": np.array(scores_wss).mean(axis=0),
"spearman_coef": np.array(spear),
}
(path_out / f"score_{cfg_model.name}.json").write_text(json.dumps(score, indent=2, cls=NumpyEncoder), encoding="utf-8")
logger.info("Saved AirfRANS inference outputs to %s", path_out)
return 0
def main() -> int:
config_path = ROOT / "conf" / "config.yaml"
cfg_model = YParams(str(config_path), "model")
cfg_data = YParams(str(config_path), "datapipe")
cfg_train = YParams(str(config_path), "training")
logger = setup_logging()
DistributedManager.initialize()
device_name = getattr(cfg_train, "device", "auto")
if device_name == "cpu":
device = torch.device("cpu")
elif device_name.startswith("cuda"):
device = torch.device(device_name if torch.cuda.is_available() else "cpu")
else:
device = torch.device(f"cuda:{cfg_train.gpuid}" if torch.cuda.is_available() else "cpu")
if cfg_data.backend == "fake_airfrans":
return run_fake_inference(cfg_model, cfg_data, cfg_train, logger, device)
if cfg_data.backend == "airfrans":
return run_airfrans_inference(cfg_model, cfg_data, cfg_train, logger, device)
raise ValueError(f"Unsupported datapipe.backend: {cfg_data.backend}")
if __name__ == "__main__":
raise SystemExit(main())