Download scripts/common.py from OneScience-Group/vRBA: direct link, hf CLI and curl.
- Browser
- Download file 5.25 kB
-
https://huggingface.co/OneScience-Group/vRBA/resolve/main/scripts/common.py
- Command line
-
hf download hf://OneScience-Group/vRBA/scripts/common.py
-
curl -L -o common.py https://huggingface.co/OneScience-Group/vRBA/resolve/main/scripts/common.py
5.25 kB
| """Configuration, data and checkpoint contracts shared by all entrypoints.""" | |
| import argparse | |
| import hashlib | |
| import json | |
| import os | |
| from pathlib import Path | |
| import numpy as np | |
| import torch | |
| import yaml | |
| from scipy.interpolate import interp1d | |
| ROOT = Path(__file__).resolve().parents[1] | |
| def path(value): | |
| p = Path(value).expanduser() | |
| return p if p.is_absolute() else ROOT / p | |
| def arguments(description): | |
| p = argparse.ArgumentParser(description=description) | |
| p.add_argument('--config', default='config/config.yaml') | |
| return p | |
| def config(filename): | |
| with path(filename).open() as f: | |
| cfg = yaml.safe_load(f) | |
| assert cfg['data']['sensors'] == cfg['model']['sensors'] | |
| assert sum(cfg['data'][s] for s in ['train','validation','test']) == cfg['data']['selected_trajectories'] | |
| return cfg | |
| def accelerator(name): | |
| if name.startswith('cuda'): | |
| if not os.environ.get('SLURM_JOB_ID'): | |
| raise RuntimeError('Accelerator work must run inside a Slurm allocation.') | |
| if not torch.cuda.is_available(): | |
| raise RuntimeError('Configured accelerator is unavailable; CPU fallback forbidden.') | |
| return torch.device(name) | |
| def load_data(cfg, stats=None): | |
| d = cfg['data'] | |
| source = path(d['directory']) / d['file'] | |
| with np.load(source, allow_pickle=False) as f: | |
| p, radius, t = f['del_p'], f['R'], f['t'] | |
| if p.shape != (1500,1000) or radius.shape != p.shape or t.shape != (1000,): | |
| raise ValueError(f'Unexpected public data schema: {p.shape}, {radius.shape}, {t.shape}') | |
| if p.dtype != np.float64 or radius.dtype != np.float64: | |
| raise ValueError('Expected original float64 public trajectories.') | |
| if not all(np.isfinite(a).all() for a in [p,radius,t]) or not np.all(np.diff(t)>0): | |
| raise ValueError('Nonfinite or unordered input data.') | |
| if not np.allclose([t[0],t[-1]],[0,0.0005],rtol=1e-12,atol=1e-14): | |
| raise ValueError('Unexpected time range.') | |
| n = d['selected_trajectories'] | |
| pressure_t = np.linspace(t[0],t[-1],d['sensors']) | |
| output_t = np.linspace(t[0],t[-1],d['output_points']) | |
| x = interp1d(t,p[:n],kind=d['interpolation'],axis=-1)(pressure_t) | |
| y = interp1d(t,radius[:n],kind=d['interpolation'],axis=-1)(output_t) | |
| nt = d['train'] | |
| if stats is None: | |
| stats = dict(pressure_mean=float(x[:nt].mean()),pressure_std=float(x[:nt].std()), | |
| radius_mean=float(y[:nt].mean()),radius_std=float(y[:nt].std()), | |
| time_min=float(t[0]),time_span=float(t[-1]-t[0])) | |
| for key in ['pressure_std','radius_std','time_span']: | |
| if stats[key] <= 0: raise ValueError(f'Invalid normalization: {key}') | |
| xn = ((x-stats['pressure_mean'])/stats['pressure_std']).astype(np.float32) | |
| yn = ((y-stats['radius_mean'])/stats['radius_std']).astype(np.float32) | |
| tn = ((output_t-stats['time_min'])/stats['time_span']).astype(np.float32)[:,None] | |
| val_end = nt+d['validation'] | |
| splits = {'train':slice(0,nt),'validation':slice(nt,val_end),'test':slice(val_end,n)} | |
| return dict(x=xn,y=yn,time=tn,radius=y,pressure=x,output_t=output_t, | |
| pressure_t=pressure_t,stats=stats,splits=splits,source=source) | |
| def metrics(prediction, target): | |
| e = np.asarray(prediction,dtype=np.float64)-np.asarray(target,dtype=np.float64) | |
| rel = np.linalg.norm(e,axis=1)/np.linalg.norm(target,axis=1) | |
| return dict(relative_l2_global=float(np.linalg.norm(e)/np.linalg.norm(target)), | |
| relative_l2_mean=float(rel.mean()),relative_l2_std=float(rel.std()), | |
| relative_l2_max=float(rel.max()),mse=float(np.mean(e*e)), | |
| rmse=float(np.sqrt(np.mean(e*e))),mae=float(np.mean(np.abs(e))), | |
| residual_variance_signed=float(np.var(e)), | |
| residual_variance_absolute=float(np.var(np.abs(e))), | |
| residual_linf=float(np.abs(e).max())) | |
| def write_json(filename, value): | |
| filename = Path(filename) | |
| filename.parent.mkdir(parents=True,exist_ok=True) | |
| temporary = filename.with_suffix(filename.suffix+'.tmp') | |
| temporary.write_text(json.dumps(value,indent=2,ensure_ascii=False,allow_nan=False)+'\n') | |
| temporary.replace(filename) | |
| def save_checkpoint(filename, value): | |
| filename = Path(filename) | |
| filename.parent.mkdir(parents=True,exist_ok=True) | |
| temp = filename.with_suffix('.tmp') | |
| torch.save(value,temp) | |
| temp.replace(filename) | |
| def dataset_manifest(data,cfg): | |
| h=hashlib.sha256() | |
| with data['source'].open('rb') as f: | |
| for block in iter(lambda:f.read(1024*1024),b''):h.update(block) | |
| return dict(source=str(data['source']),sha256=h.hexdigest(),original_shape=[1500,1000], | |
| selection='first 1000 trajectories in original file order; remaining 500 excluded', | |
| train_indices=list(range(800)),validation_indices=list(range(800,900)),test_indices=list(range(900,1000)), | |
| split_provenance='User-specified reproducible convention; authors original indices are unknown.', | |
| pressure_sensor_times=data['pressure_t'].tolist(),radius_output_times=data['output_t'].tolist(), | |
| interpolation=cfg['data']['interpolation'],normalization=data['stats'],statistics_fit_on='training split only') | |