yushuang88's picture
Upload folder using huggingface_hub
be2a41d verified
Raw History Blame Contribute Delete
3.33 kB
"""Configuration, read-only validation and unambiguous metric reductions."""
import hashlib
import json
from pathlib import Path
import numpy as np
import torch
import yaml
from model.comphy_tgv import ComPhyTaylorGreenVortex
ROOT = Path(__file__).resolve().parents[1]
def resolve(path):
p = Path(path)
return p if p.is_absolute() else ROOT / p
def load_config(path):
with open(path) as f:
cfg = yaml.safe_load(f)
if cfg['training']['steps'] != 100000 or cfg['training']['interior_points'] != 1000:
raise ValueError('Formal experiment requires 100000 steps and 1000 interior points.')
if cfg['model']['hidden_layers'] != 2 or cfg['model']['hidden_units'] != 64:
raise ValueError('Table 5 requires two hidden layers of 64 units.')
return cfg
def build_model(cfg, device):
dtype = getattr(torch, cfg['training']['dtype'])
return ComPhyTaylorGreenVortex(**cfg['model']).to(device=device, dtype=dtype)
def load_reference(path):
"""Validation only. No torch tensors with gradients are created here."""
with np.load(path, allow_pickle=False) as data:
coordinates = data['coordinates'].copy()
target = data['target'].copy()
if coordinates.shape != (36864, 3) or target.shape != coordinates.shape:
raise ValueError('Expected coordinates and target [36864,3].')
if coordinates.dtype != np.float64 or target.dtype != np.float64:
raise ValueError('Reference must be float64.')
if not np.isfinite(coordinates).all() or not np.isfinite(target).all():
raise ValueError('Reference has nonfinite values.')
coordinates.flags.writeable = False
target.flags.writeable = False
return coordinates, target
def metrics(prediction, target):
error = np.asarray(prediction, dtype=np.float64) - target
if not np.isfinite(error).all():
raise FloatingPointError('Nonfinite prediction.')
e2 = float(np.mean(np.sum(error**2, axis=1)))
return {'l2_error': e2, 'max_error': float(np.abs(error).max()),
'l2_norm': float(np.sqrt(e2)), 'scalar_mse': e2/3,
'relative_l2': float(np.linalg.norm(error)/np.linalg.norm(target)),
'per_variable_mse': dict(zip(('u','v','p'), np.mean(error**2, axis=0).tolist())),
'per_variable_max': dict(zip(('u','v','p'), np.abs(error).max(axis=0).tolist()))}
@torch.no_grad()
def predict(model, coordinates, batch_size):
model.eval()
p = next(model.parameters())
blocks = []
for start in range(0, len(coordinates), batch_size):
q = torch.tensor(coordinates[start:start+batch_size], device=p.device, dtype=p.dtype)
# forward is strictly the momentum module, never an average/ensemble.
blocks.append(model(q).cpu().double().numpy())
return np.concatenate(blocks)
def atomic_json(path, payload):
path = Path(path)
path.parent.mkdir(parents=True, exist_ok=True)
temp = path.with_suffix(path.suffix + '.tmp')
temp.write_text(json.dumps(payload, indent=2, ensure_ascii=False, allow_nan=False)+'\n')
temp.replace(path)
def atomic_checkpoint(path, payload):
path = Path(path)
temp = path.with_suffix(path.suffix + '.tmp')
torch.save(payload, temp)
temp.replace(path)
def sha256(path):
return hashlib.sha256(Path(path).read_bytes()).hexdigest()