QCPINN-CavityFlow / scripts /inference.py
yushuang88's picture
Upload folder using huggingface_hub
d647964 verified
Raw History Blame Contribute Delete
5.71 kB
"""Reload a trained checkpoint; stream evaluation from the supplied MATLAB HDF5."""
import argparse
import json
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
import h5py
import numpy as np
import torch
from common import (ROOT, atomic_json, build_model, load_checkpoint, load_config,
predict, relative_metrics, resolved, seed_everything, sha256,
validation_indices)
def infer(config, checkpoint_path, output_dir, metrics_only=False):
seed_everything(0, config["training"]["num_threads"])
model = build_model(config)
checkpoint = load_checkpoint(checkpoint_path, model)
if checkpoint["config"]["model"] != config["model"]:
raise ValueError("Checkpoint and requested model configuration differ")
model.eval()
out = Path(output_dir)
out.mkdir(parents=True, exist_ok=True)
source_path = resolved(config, "reference")
report = {"checkpoint": str(Path(checkpoint_path).resolve()), "checkpoint_sha256": sha256(checkpoint_path),
"source": str(source_path), "source_sha256": sha256(source_path),
"seed": checkpoint["seed"], "epoch": checkpoint["epoch"], "selection_score": checkpoint["selection_score"],
"validation_metrics": checkpoint["validation_metrics"],
"metric": "raw ||pred-ref||2/||ref||2; no pressure gauge alignment",
"groups": {}, "reference_regenerated": False, "checkpoint_reloaded": True}
size = config["inference"]["batch_size"]
global_num, global_den = np.zeros(3), np.zeros(3)
output = None if metrics_only else h5py.File(out/"predictions.h5.tmp", "w")
try:
with h5py.File(source_path, "r") as source:
for key in config["inference"]["reference_keys"]:
data = source[key]
if data.ndim != 2 or data.shape[0] != 6: raise ValueError(f"Invalid {key} shape: {data.shape}")
count = data.shape[1]
numer, denom, hold_num, hold_den = [np.zeros(3) for _ in range(4)]
if key == config["validation"]["reference_key"]:
valids = validation_indices(config, count)
group = None
if output is not None:
group = output.create_group(key)
group.create_dataset("coordinates", (count, 3), dtype="f8", chunks=True)
group.create_dataset("prediction", (count, 3), dtype="f4", chunks=True)
for start in range(0, count, size):
end = min(start+size, count)
rows = data[:, start:end].T
if not np.isfinite(rows).all(): raise ValueError(f"Nonfinite input in {key} at {start}")
preds = predict(model, rows[:, :3], size)
if not np.isfinite(preds).all(): raise FloatingPointError("Nonfinite predictions")
error2 = (preds.astype(np.float64)-rows[:, 3:])**2
ref2 = rows[:, 3:]**2
numer += error2.sum(0)
denom += ref2.sum(0)
if key == config["validation"]["reference_key"]:
keep = ~np.isin(np.arange(start, end), valids, assume_unique=True)
hold_num += error2[keep].sum(0)
hold_den += ref2[keep].sum(0)
if group is not None:
group["coordinates"][start:end] = rows[:, :3]
group["prediction"][start:end] = preds
metrics = relative_metrics(numer, denom)
report["groups"][key] = {"count": count, "metrics": metrics}
global_num += numer
global_den += denom
if key == config["validation"]["reference_key"]:
report["internal_holdout"] = {"count": count-len(valids), "metrics": relative_metrics(hold_num, hold_den)}
print(f"INFERENCE key={key} count={count} metrics={json.dumps(metrics)}", flush=True)
report["all_reference"] = {"metrics": relative_metrics(global_num, global_den),
"count": sum(v["count"] for v in report["groups"].values())}
if output is not None:
output.attrs["provenance"] = json.dumps({k: v for k, v in report.items() if k not in ["groups", "internal_holdout", "all_reference"]})
output.close()
output = None
(out/"predictions.h5.tmp").replace(out/"predictions.h5")
atomic_json(out/"metrics.json", report)
finally:
if output is not None: output.close()
print("INFERENCE_COMPLETED", flush=True)
return report
if __name__ == "__main__":
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--config", default=str(ROOT/"config/config.yaml"))
parser.add_argument("--checkpoint", type=Path)
parser.add_argument("--output-dir", type=Path)
parser.add_argument("--seed", type=int)
parser.add_argument("--kind", choices=["best", "last"], default="best")
parser.add_argument("--metrics-only", action="store_true")
args = parser.parse_args()
cfg = load_config(args.config)
checkpoint = args.checkpoint or (resolved(cfg, "weights")/f"seed_{args.seed}"/("best_model.pt" if args.kind == "best" else "last_model.pt") if args.seed is not None else resolved(cfg, "weights")/"best_model.pt")
output = args.output_dir or (resolved(cfg, "results")/f"seed_{args.seed}"/("best_eval" if args.kind == "best" else "final_eval") if args.seed is not None else resolved(cfg, "results")/"best_model")
infer(cfg, checkpoint, output, args.metrics_only)