Cubic-Rate Third-Order Langevin Optimizer / stage2_official_bench.py

Failed on benchmark

Raw ⬇ ZIP
  1import json, random, time
  2from pathlib import Path
  3import numpy as np
  4import torch
  5import torch.nn as nn
  6import sys
  7sys.path.insert(0, '/home/maxwelhelp/all/math2nn')
  8from bench import get_dataset, make_model, train_model, evaluate, sweep_baseline, make_report
  9from third_order_optimizer import ThirdOrderLangevin
 10
 11TRACK, MODEL = 'tabular', 'mlp_tiny'
 12SEEDS = (0,1,2,3,4,5,6,7)
 13SWEEP_SEEDS = (0,1,2,3)
 14EPOCHS, BATCH = 30, 128
 15# Union of all step sizes is shared by both systems. Adam's method knob is WD.
 16LRS = (1e-3, 3e-3, 1e-2)
 17BASE_GRID = [{'lr': lr, 'weight_decay': wd} for lr in LRS for wd in (0.0, 1e-4)]
 18IDEA_GRID = [{'lr': lr, 'gamma': gamma, 'temperature': 0.0}
 19             for lr, gamma in zip(LRS, (0.5, 1.0, 2.0))]
 20
 21IDEA_SIGNATURE = {}
 22
 23def seed_all(seed):
 24    random.seed(seed); np.random.seed(seed); torch.manual_seed(seed)
 25    if torch.cuda.is_available(): torch.cuda.manual_seed_all(seed)
 26
 27def baseline_fn(cfg):
 28    def train(seed):
 29        seed_all(seed)
 30        d = get_dataset(TRACK, seed, n_train=400, n_test=400)
 31        net = make_model(MODEL, d['input_shape'], d['out_dim'])
 32        _, metric, _ = train_model(net, d, epochs=EPOCHS, lr=cfg['lr'], batch=BATCH,
 33                                   weight_decay=cfg['weight_decay'], log=lambda *_: None)
 34        return metric
 35    return train
 36
 37def idea_fn(cfg):
 38    def train(seed):
 39        seed_all(seed)
 40        d = get_dataset(TRACK, seed, n_train=400, n_test=400)
 41        requested = 'cuda' if torch.cuda.is_available() else 'cpu'
 42        try:
 43            return idea_train(d, cfg, seed, requested)
 44        except Exception:
 45            return idea_train(d, cfg, seed, 'cpu')
 46    return train
 47
 48def idea_train(d, cfg, seed, device):
 49    # This is intentionally custom: changing the optimizer is the intervention.
 50    net = make_model(MODEL, d['input_shape'], d['out_dim']).to(device)
 51    x,y,xt,yt = [d[k].to(device) for k in ('xtr','ytr','xte','yte')]
 52    opt = ThirdOrderLangevin(net.parameters(), dt=cfg['lr'], gamma=cfg['gamma'],
 53                             temperature=cfg['temperature'])
 54    lossf = nn.MSELoss(); acc_norms=[]; grad_norms=[]
 55    for _ in range(EPOCHS):
 56        net.train(); perm=torch.randperm(len(x), device=device)
 57        for ix in perm.split(BATCH):
 58            opt.zero_grad(set_to_none=True); loss=lossf(net(x[ix]), y[ix]); loss.backward()
 59            gn=0.; an=0.
 60            for p in net.parameters():
 61                if p.grad is not None: gn += float(p.grad.detach().float().norm().cpu())
 62            opt.step()
 63            for p in net.parameters():
 64                st=opt.state.get(p)
 65                if st and 'a' in st: an += float(st['a'].detach().float().norm().cpu())
 66            grad_norms.append(gn); acc_norms.append(an)
 67    net.eval()
 68    with torch.no_grad(): metric=float(lossf(net(xt),yt).cpu())
 69    # Measured from trained model dynamics, not an analytic toy identity.
 70    IDEA_SIGNATURE[int(seed)]={'observed_gradient_norm_mean':float(np.mean(grad_norms)),
 71        'observed_acceleration_norm_mean':float(np.mean(acc_norms)),
 72        'observed_acceleration_to_gradient_ratio':float(np.mean(acc_norms)/(np.mean(grad_norms)+1e-12))}
 73    return metric
 74
 75def main():
 76    base = sweep_baseline(baseline_fn, BASE_GRID, seeds=SWEEP_SEEDS)
 77    # Evaluate all three idea settings on the full paired seed set.
 78    idea_runs=[]
 79    for cfg in IDEA_GRID:
 80        r=evaluate(idea_fn(cfg), seeds=SEEDS)
 81        idea_runs.append((cfg,r))
 82    best_cfg,best_res=min(idea_runs, key=lambda z:z[1]['mean'])
 83    # Re-run best to ensure its per-seed signature corresponds to reported systems.
 84    best_res=evaluate(idea_fn(best_cfg), seeds=SEEDS)
 85    sigvals=[IDEA_SIGNATURE[s] for s in SEEDS if s in IDEA_SIGNATURE]
 86    signature={'prediction':'noise enters acceleration only; at temperature=0 injected-noise std is zero',
 87      'predicted_injected_noise_std':0.0,
 88      'observed_trained_acceleration_norm_mean':float(np.mean([v['observed_acceleration_norm_mean'] for v in sigvals])),
 89      'observed_trained_gradient_norm_mean':float(np.mean([v['observed_gradient_norm_mean'] for v in sigvals])),
 90      'observed_acceleration_to_gradient_ratio_mean':float(np.mean([v['observed_acceleration_to_gradient_ratio'] for v in sigvals])),
 91      'confirmed':False,
 92      'note':'State acceleration is nonzero from deterministic gradients, so this does not confirm a zero total-state prediction; it directly measures trained-model behavior.'}
 93    rep=make_report(TRACK, MODEL, base, best_res, extra=signature)
 94    rep['idea_sweep']=[{'cfg':c,'result':r} for c,r in idea_runs]
 95    rep['protocol_notes']={'paired_seeds':list(SEEDS),'baseline_sweep_seeds':list(SWEEP_SEEDS),
 96      'dataset_sizes':[400,400],'epochs':EPOCHS,'batch':BATCH,'baseline':'Adam via bench.train_model',
 97      'idea':'third-order Langevin; only optimizer loop differs','search_space_union_learning_rates':list(LRS)}
 98    Path('bench_report.json').write_text(json.dumps(rep,indent=2))
 99    print(json.dumps(rep,indent=2))
100if __name__=='__main__': main()