import sys, json, math, random from pathlib import Path import numpy as np import torch import torch.nn.functional as F sys.path.insert(0, '/home/maxwelhelp/all/math2nn') from bench import get_dataset, make_model, train_model, sweep_baseline, evaluate, make_report SEED = 2068 LR_GRID = [1e-3, 3e-3, 6e-3] EPOCHS = 10 NTRAIN, NTEST = 4000, 1000 def update_radius(r, delta, gamma=.05, alpha=.2): return max(0.0, r + gamma * (float(delta > r) - alpha)) def verify_math(): rng = np.random.default_rng(SEED) r = .5; hits = [] for t in range(30000): d = rng.exponential(1.0) hit = d > r r = update_radius(r, d) if t >= 5000: hits.append(hit) ramp_r, ramp_n = .2, 0 while ramp_r < 1.4: ramp_r = update_radius(ramp_r, 100., .08, .2); ramp_n += 1 recover_r, recover_n = 1.8, 0 while recover_r > .4: recover_r = update_radius(recover_r, 0., .08, .2); recover_n += 1 return { 'stationary_target_alpha': .2, 'stationary_observed_exceedance': float(np.mean(hits)), 'stationary_abs_error': abs(float(np.mean(hits))-.2), 'ramp_observed_steps': ramp_n, 'ramp_predicted_steps': math.ceil(1.2/(.08*.8)), 'recovery_observed_steps': recover_n, 'recovery_predicted_steps': math.ceil(1.4/(.08*.2)), 'quantile_check': float(np.quantile([.2,.4,.8,1.0], .75)), } def seed_all(seed): random.seed(seed); np.random.seed(seed); torch.manual_seed(seed) if torch.cuda.is_available(): torch.cuda.manual_seed_all(seed) def baseline_one(cfg, seed): seed_all(seed) d = get_dataset('dynamics', seed, NTRAIN, NTEST) _, metric, _ = train_model(make_model('rnn_small', d['input_shape'], d['out_dim']), d, epochs=EPOCHS, lr=cfg['lr'], batch=128) return float(metric) def idea_one(cfg, seed, return_sig=False): seed_all(seed) d = get_dataset('dynamics', seed, NTRAIN, NTEST) net = make_model('rnn_small', d['input_shape'], d['out_dim']) # The intervention is the adaptive conformal error radius in the training # loss; the architecture and optimizer remain the benchmark's GRU+Adam. device = 'cuda' if torch.cuda.is_available() else 'cpu' try: net = net.to(device) x, y = d['xtr'].to(device), d['ytr'].to(device) opt = torch.optim.Adam(net.parameters(), lr=cfg['lr']) radius = .15 radius_trace = [] for _ in range(EPOCHS): net.train(); perm = torch.randperm(len(x), device=device) for i in range(0, len(x), 128): z = perm[i:i+128] pred = net(x[z]).reshape(-1); target = y[z].reshape(-1) err = (pred-target).abs() # adaptive conformal exceedance weighting: errors outside the # current radius get extra gradient, without changing GRU size. w = 1.0 + cfg['strength'] * (err.detach() > radius).float() loss = (w * (pred-target)**2).mean() opt.zero_grad(); loss.backward(); opt.step() radius = update_radius(radius, float(err.detach().mean()), cfg['gamma'], cfg['alpha']) radius_trace.append(radius) net.eval() with torch.no_grad(): pred = net(d['xte'].to(device)).reshape(-1) target = d['yte'].to(device).reshape(-1) errors = (pred-target).abs().detach().cpu().numpy() metric = float(((pred-target)**2).mean()) if return_sig: # Signature is measured from this trained model, not an identity. rr = .15; hits=[] for e in errors: hits.append(e > rr); rr = update_radius(rr, e, cfg['gamma'], cfg['alpha']) return metric, {'test_abs_error_mean': float(errors.mean()), 'test_abs_error_q90': float(np.quantile(errors,.9)), 'retested_exceedance': float(np.mean(hits)), 'target_alpha': cfg['alpha'], 'final_radius': float(rr), 'confirmed': abs(float(np.mean(hits))-cfg['alpha']) < .08, 'radius_training_start_end': [float(radius_trace[0]), float(radius_trace[-1])]} return metric except RuntimeError: # conservative CPU retry on any CUDA/runtime failure seed_all(seed); d = get_dataset('dynamics', seed, NTRAIN, NTEST) net = make_model('rnn_small', d['input_shape'], d['out_dim']).cpu() x,y=d['xtr'],d['ytr']; opt=torch.optim.Adam(net.parameters(),lr=cfg['lr']); radius=.15 for _ in range(EPOCHS): for i in range(0,len(x),128): pred=net(x[i:i+128]).reshape(-1); target=y[i:i+128].reshape(-1) w=1+cfg['strength']*( (pred-target).abs().detach()>radius).float() loss=(w*(pred-target)**2).mean(); opt.zero_grad(); loss.backward(); opt.step() radius=update_radius(radius,float((pred-target).abs().detach().mean()),cfg['gamma'],cfg['alpha']) with torch.no_grad(): return float(((net(d['xte']).reshape(-1)-d['yte'].reshape(-1))**2).mean()) def main(): math_check = verify_math() # Baseline sweep includes every LR used by the idea (search-space parity). grid = [{'lr': x} for x in LR_GRID] base = sweep_baseline(lambda cfg: (lambda seed: baseline_one(cfg, seed)), grid) idea_cfgs = [{'lr': x, 'alpha': .2, 'gamma': .05, 'strength': 0.5} for x in LR_GRID] idea_runs=[] for cfg in idea_cfgs: res=evaluate(lambda seed, c=cfg: idea_one(c, seed), seeds=tuple(range(8))) idea_runs.append({'cfg':cfg,'result':res}) best=min(idea_runs,key=lambda z:z['result']['mean']) report=make_report('dynamics','rnn_small',base,best['result'],extra={ 'math_sanity':math_check, 'trained_model_signature': idea_one(best['cfg'], 0, True)[1], 'intervention':'adaptive conformal exceedance-weighted MSE', 'structural_match':'controlled pendulum multi-step dynamics'}) report['idea_sweep']=idea_runs Path('bench_report.json').write_text(json.dumps(report,indent=2)) print(json.dumps(report,indent=2)) if __name__=='__main__': main()