Download scripts/smoke.py from OneScience-Group/TSA-PINN-CylinderWake: direct link, hf CLI and curl.
- Browser
- Download file 4.6 kB
-
https://huggingface.co/OneScience-Group/TSA-PINN-CylinderWake/resolve/main/scripts/smoke.py
- Command line
-
hf download hf://OneScience-Group/TSA-PINN-CylinderWake/scripts/smoke.py
-
curl -L -o smoke.py https://huggingface.co/OneScience-Group/TSA-PINN-CylinderWake/resolve/main/scripts/smoke.py
4.6 kB
| #!/usr/bin/env python3 | |
| """Six-path smoke checks and independent derivative/gradient equivalence checks.""" | |
| from __future__ import annotations | |
| import argparse | |
| import json | |
| import sys | |
| import time | |
| from pathlib import Path | |
| sys.path.insert(0, str(Path(__file__).resolve().parents[1])) | |
| import numpy as np | |
| import torch | |
| from scripts.common import (ROOT, build_model, gather, load_dns, predict, read_config, | |
| relative_l2, sample_indices, save_json, setup, tensor) | |
| from scripts.train import objective | |
| def main(): | |
| parser = argparse.ArgumentParser(description=__doc__) | |
| parser.add_argument("--device", default="cuda") | |
| parser.add_argument("--benchmark", action="store_true") | |
| args = parser.parse_args() | |
| cfg = read_config() | |
| device, dtype = setup(cfg, args.device) | |
| dns = load_dns(cfg) | |
| index = sample_indices(cfg, dns) | |
| bq, buv = gather(dns, index["boundary"]) | |
| rq, _ = gather(dns, index["residual"]) | |
| model = build_model(cfg, device) | |
| q = tensor(rq[:32], device, dtype) | |
| checks = {} | |
| output = model(q) | |
| assert output.shape == (32, 2) and torch.isfinite(output).all() | |
| checks["forward_pass"] = "passed" | |
| values, residuals, div = model.residual_autograd(q) | |
| tvalues, tresiduals, _ = model.residual_taylor(q) | |
| torch.testing.assert_close(tvalues, values, atol=1e-10, rtol=1e-9) | |
| torch.testing.assert_close(tresiduals, residuals, atol=1e-10, rtol=1e-9) | |
| params = tuple(model.parameters()) | |
| aloss = residuals.square().mean() + values[:, :2].square().mean() + 0.25 * model.slope_recovery() | |
| tloss = tresiduals.square().mean() + tvalues[:, :2].square().mean() + 0.25 * model.slope_recovery() | |
| ag = torch.autograd.grad(aloss, params) | |
| tg = torch.autograd.grad(tloss, params) | |
| for left, right in zip(ag, tg): | |
| torch.testing.assert_close(left, right, atol=2e-10, rtol=2e-8) | |
| assert float(div.abs().max()) < 1e-10 | |
| checks["backward_pass"] = "passed: finite parameter gradients; Taylor/reverse-mode equivalence" | |
| bq_t, buv_t, rq_t = (tensor(x, device, dtype) for x in (bq[:64], buv[:64], rq[:64])) | |
| opt = torch.optim.Adam(model.parameters(), lr=cfg["training"]["learning_rate"], eps=1e-7) | |
| losses = [] | |
| for _ in range(3): | |
| opt.zero_grad(set_to_none=True) | |
| value = objective(model, bq_t, buv_t, rq_t, cfg, backward=True) | |
| opt.step() | |
| losses.append(value["loss"]) | |
| assert np.isfinite(losses).all() and losses[-1] < losses[0], losses | |
| checks["train_loop_dry_run"] = {"status": "passed", "losses": losses} | |
| valq, valuv = gather(dns, index["validation"]) | |
| valp = predict(model, valq[:128], device, dtype, 64) | |
| error = relative_l2(valp[:, :2], valuv[:128]) | |
| assert np.isfinite(error).all() | |
| checks["validation_loop_dry_run"] = {"status": "passed", "relative_l2": error.tolist()} | |
| assert np.allclose(relative_l2(dns["uv"].reshape(-1, 2), dns["uv"].reshape(-1, 2)), 0) | |
| assert np.allclose(relative_l2(np.zeros_like(dns["uv"].reshape(-1, 2)), dns["uv"].reshape(-1, 2)), 1) | |
| checks["domain_metric_dry_run"] = "passed: L2 self=0, zero predictor=1; streamfunction divergence <1e-10" | |
| assert len(model.frequencies) == 4 and sum(f.numel() for f in model.frequencies) == 200 | |
| assert [l.out_features for l in model.layers] == [50, 50, 50, 50, 2] | |
| assert index["boundary"].shape == (200, 400) and index["residual"].shape == (200, 1000) | |
| checks["config_consistency"] = "passed: 4x50, 200 frequencies, (x,y,t)->(psi,p), 4000 configured updates, per-time counts" | |
| benchmark = None | |
| if args.benchmark: | |
| model = build_model(cfg, device) | |
| fullb, fulluv, fullr = (tensor(x, device, dtype) for x in (bq, buv, rq)) | |
| started = time.perf_counter() | |
| model.zero_grad(set_to_none=True) | |
| value = objective(model, fullb, fulluv, fullr, cfg, backward=True) | |
| if device.type == "cuda": | |
| torch.cuda.synchronize() | |
| benchmark = {"seconds_one_full_objective_backward": time.perf_counter()-started, "score": value, | |
| "peak_device_memory_bytes": torch.cuda.max_memory_allocated() if device.type == "cuda" else 0} | |
| result = {"status": "passed", "attempt": 1, "checks": checks, "benchmark": benchmark, | |
| "parameter_count": sum(p.numel() for p in model.parameters()), "torch": torch.__version__, | |
| "device": torch.cuda.get_device_name() if device.type == "cuda" else "CPU"} | |
| save_json(ROOT / ".onescience/smoke_result.json", result) | |
| print(json.dumps(result, ensure_ascii=False, indent=2), flush=True) | |
| if __name__ == "__main__": | |
| main() | |