import sys, json, random from pathlib import Path import numpy as np import torch import torch.nn as nn sys.path.insert(0, '/home/maxwelhelp/all/math2nn') from bench import get_dataset, evaluate, sweep_baseline, make_report TRACK='tabular'; MODEL='mlp'; EPOCHS=24; NTRAIN=400; NTEST=200 SEEDS=tuple(range(8)); SWEEP_SEEDS=(0,1,2,3) LRS=[1e-3, 3e-3, 1e-2]; LAMBDAS=[0.03, 0.1, 0.3] BATCH=128; HIDDEN=32; EMBED=8 class BottleneckMLP(nn.Module): def __init__(self, input_dim, out_dim): super().__init__() self.encoder=nn.Sequential(nn.Linear(input_dim,64),nn.ReLU(),nn.Linear(64,HIDDEN),nn.ReLU()) self.proj=nn.Linear(HIDDEN,EMBED) self.head=nn.Linear(EMBED,out_dim) def hidden(self,x): return self.encoder(x) def embedding(self,x): return self.proj(self.hidden(x)) def forward(self,x): return self.head(self.embedding(x)) def seed_all(s): random.seed(s); np.random.seed(s); torch.manual_seed(s) if torch.cuda.is_available(): torch.cuda.manual_seed_all(s) def centered_geometry_loss(h,z): n=h.shape[0] a=torch.cdist(h,h).pow(2); b=torch.cdist(z,z).pow(2)*(HIDDEN/EMBED) iu=torch.triu_indices(n,n,offset=1,device=h.device) a=a[iu[0],iu[1]]; b=b[iu[0],iu[1]] ac=a-a.mean().detach(); bc=b-b.mean().detach() return (((ac/(ac.std(unbiased=False)+1e-6))-(bc/(bc.std(unbiased=False)+1e-6)))**2).mean() def train_metric(cfg, seed, lam): seed_all(seed); ds=get_dataset(TRACK,seed,n_train=NTRAIN,n_test=NTEST) net=BottleneckMLP(ds['input_shape'][0],ds['out_dim']) ladder=[('cuda',False),('cuda',True)] if torch.cuda.is_available() else [] ladder += [('cpu',False)] for device,no_cudnn in ladder: try: if no_cudnn: torch.backends.cudnn.enabled=False net=net.to(device); xtr,ytr=ds['xtr'].to(device),ds['ytr'].to(device) opt=torch.optim.Adam(net.parameters(),lr=cfg['lr']) task=nn.MSELoss() if ds['task']=='regression' else nn.CrossEntropyLoss() for _ in range(EPOCHS): net.train(); perm=torch.randperm(len(xtr),device=device) for i in range(0,len(xtr),BATCH): q=perm[i:i+BATCH]; h=net.hidden(xtr[q]); z=net.proj(h) loss=task(net.head(z),ytr[q]) if lam>0: loss=loss+lam*centered_geometry_loss(h,z) opt.zero_grad(); loss.backward(); opt.step() net.eval() with torch.no_grad(): out=net(ds['xte'].to(device)); y=ds['yte'].to(device) metric=float(((out-y)**2).mean()) if ds['task']=='regression' else float((out.argmax(1)!=y).float().mean()) return metric except RuntimeError: if device=='cuda': torch.cuda.empty_cache() finally: if no_cudnn: torch.backends.cudnn.enabled=True return float('nan') def baseline_factory(cfg): return lambda seed: train_metric(cfg,seed,0.0) def idea_factory(cfg): return lambda seed: train_metric(cfg,seed,cfg['lambda']) def signature(cfg, seed=0): seed_all(seed); ds=get_dataset(TRACK,seed,n_train=NTRAIN,n_test=NTEST) device='cuda' if torch.cuda.is_available() else 'cpu'; net=BottleneckMLP(ds['input_shape'][0],ds['out_dim']).to(device) x,y=ds['xtr'].to(device),ds['ytr'].to(device); opt=torch.optim.Adam(net.parameters(),lr=cfg['lr']) for _ in range(EPOCHS): perm=torch.randperm(len(x),device=device) for i in range(0,len(x),BATCH): q=perm[i:i+BATCH]; h=net.hidden(x[q]); z=net.proj(h) loss=nn.functional.mse_loss(net.head(z),y[q])+cfg['lambda']*centered_geometry_loss(h,z) opt.zero_grad(); loss.backward(); opt.step() net.eval(); xt=ds['xte'][:100].to(device) with torch.no_grad(): h=net.hidden(xt); z=net.proj(h) a=torch.cdist(h,h).pow(2); b=torch.cdist(z,z).pow(2)*(HIDDEN/EMBED) iu=torch.triu_indices(len(xt),len(xt),1,device=device); a=a[iu[0],iu[1]]; b=b[iu[0],iu[1]] ac=a-a.mean(); bc=b-b.mean(); corr=torch.corrcoef(torch.stack([ac,bc]))[0,1] var_ratio=bc.var(unbiased=False)/(ac.var(unbiased=False)+1e-8) observed=float(corr.cpu()); ratio=float(var_ratio.cpu()) # For a learned nonlinear encoder no universal m/d equality is expected; this is an empirical NN-scale retest. return {'predicted_centered_distance_correlation':'no universal value for learned encoder','observed_centered_distance_correlation':observed,'observed_centered_variance_ratio':ratio,'predicted_variance_ceiling':1.0,'confirmed':bool(observed>0.5 and 0.0