yushuang88's picture
Upload folder using huggingface_hub
0f0d1f4 verified
Raw History Blame Contribute Delete
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()