nur-dev's picture
Publish reproducibility artifacts (part 2)
fe31b61 verified
Raw History Blame Contribute Delete
15.8 kB
"""Locked independent-day retest of unchanged full-hypothesis models.
The preceding dynamic-mixture study failed its source-clock requirement.
It stays failed. This separately registered study reports every day and control.
"""
from __future__ import annotations
import argparse,hashlib,io,json,math,re,time,urllib.request,zipfile
from pathlib import Path
import numpy as np
import torch
from unionmind.continuous_decision import source,factorial
from unionmind.continuous_decision.factor_study import MODELS,fit_one,predict,metrics
from unionmind.continuous_decision.factor_analysis import STRONG
from unionmind.continuous_decision.factor_acquisition import episode
ROOT=Path('artifacts/day_transfer_01');PROTOCOL=Path('configs/day_transfer_protocol_01.json')
def write(name,value):
path=ROOT/name;path.parent.mkdir(parents=True,exist_ok=True);path.write_text(json.dumps(value,indent=2)+'\n')
def verify():
lock=json.loads((ROOT/'lock.json').read_text())
assert all(source.sha(p)==h for p,h in lock['files'].items())
def lock():
assert not ROOT.exists();ROOT.mkdir()
files=[Path(__file__),PROTOCOL,*Path('unionmind/continuous_decision').glob('*.py'),Path('tests/test_continuous_decision.py')]
write('lock.json',dict(files={str(p):source.sha(p) for p in files},before_archive_or_numerical_access=True,
timestamp_utc=time.strftime('%Y-%m-%dT%H:%M:%SZ',time.gmtime()),
previous_strict_clock_study_not_amended=True,unchanged_algorithms_and_hyperparameters=True))
print('INDEPENDENT DAY STUDY LOCKED',flush=True)
def text_array(payload):
text=payload.decode('utf-8-sig');lines=text.strip().splitlines();header=[]
number=re.compile(r'^[-+]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][-+]?\d+)?$')
while lines and not number.match(re.split(r'[\s,;]+',lines[0].strip())[0]):header.append(lines.pop(0))
body=re.sub('[,;]',' ','\n'.join(lines));array=np.fromstring(body,sep=' ',dtype=np.float64)
assert array.size==len(lines)*20,(array.size,len(lines))
return array.reshape(-1,20),header
def prepare(device='cuda:1'):
verify();config=json.loads(PROTOCOL.read_text());torch.cuda.set_device(device);start=time.perf_counter()
path=ROOT/'source.zip';assert not path.exists();urllib.request.urlretrieve(config['source']['url'],path)
write('source.json',dict(**config['source'],sha256=source.sha(path),bytes=path.stat().st_size,download_seconds=time.perf_counter()-start))
sources=[];outer=zipfile.ZipFile(path)
for entry in outer.infolist():
if entry.filename.endswith('.zip'):
inner=zipfile.ZipFile(io.BytesIO(outer.read(entry)));sources.append(inner)
if not sources:sources=[outer]
members=sorted([(z,a) for z in sources for a in z.infolist() if re.search(r'\d{8}_\d{6}',a.filename) and not a.is_dir()],key=lambda item:item[1].filename)
assert len(members)==13,[(a.filename,a.file_size) for z,a in members]
rows=[];labels=[];days=[];records=[];audits=[];excluded=[];headers={}
for day,(archive,entry) in enumerate(members):
values,header=text_array(archive.read(entry));headers[entry.filename]=header
raw=torch.as_tensor(values,device=device,dtype=torch.float64)
valid=bool(torch.isfinite(raw).all()) and bool((raw[1:,0]>=raw[:-1,0]).all())
audit=dict(day=day,file=entry.filename,raw_rows=len(raw),finite=bool(torch.isfinite(raw).all()),
duplicate_timestamps=int((raw[1:,0]==raw[:-1,0]).sum()),nondecreasing_clock=bool((raw[1:,0]>=raw[:-1,0]).all()))
if not valid:audits.append({**audit,'valid':False});continue
time_zero=raw[0,0];blocks=((raw[:,0]-time_zero)/900).floor().long()
for block in blocks.unique(sorted=True).tolist():
ids=torch.where(blocks==block)[0];a=int(ids[0]);b=int(ids[-1])+1
duration=float(raw[b-1,0]-raw[a,0])
if duration<850:
excluded.append(dict(day=day,file=entry.filename,block=block,duration=duration,reason='less_than_850_seconds'));continue
quarter=((raw[a:b,0]-time_zero-block*900)/225).floor().long().clamp(0,3)
means=torch.stack([raw[a:b,6:][quarter==q].mean(0) for q in range(4)],-1)
last=quarter==3;co=raw[a:b,1][last].median();rh=raw[a:b,2][last].mean()
h0=(co*9/20).round().long().clamp(0,9);h1=(rh>rh.new_tensor([35.,55.])).sum()
rows.append(means.flatten());labels.append(torch.stack((h0,h1)));days.append(day)
records.append(dict(id=f'{entry.filename}:block{block}',day=day,file=entry.filename,block=block,
first_row=a,last_row_exclusive=b,start_seconds=float(raw[a,0]),end_seconds=float(raw[b-1,0]),
reference_co_ppm=float(co),reference_humidity_percent=float(rh)))
audit.update(valid=True,episodes=sum(d==day for d in days));audits.append(audit)
print(json.dumps(audit),flush=True);del raw,values
x=torch.stack(rows);h=torch.stack(labels);day_tensor=torch.tensor(days,device=device)
grid=factorial.hypotheses([10,3],device)
ordering=sorted(grid.tolist(),key=lambda row:hashlib.sha256(('20821:'+','.join(map(str,row))).encode()).hexdigest())
held_bindings=ordering[:6];unseen=torch.zeros(len(x),device=device,dtype=torch.bool)
for binding in held_bindings:unseen|=(h==h.new_tensor(binding)).all(-1)
source_mask=(day_tensor<9)&~unseen;target=day_tensor>=9
eligibility=len(audits)==13 and all(a.get('valid') and a.get('episodes',0)>=90 for a in audits)
eligibility &= int(source_mask.sum())>=128 and all(int((target&unseen&(day_tensor==d)).sum())>=8 for d in range(9,13))
torch.save(dict(x=x,h=h,days=day_tensor,source=source_mask,target=target,unseen=unseen),ROOT/'prepared.pt')
torch.cuda.synchronize();write('preparation.json',dict(eligible=eligibility,records=records,audits=audits,headers=headers,
held_bindings=held_bindings,source_records=int(source_mask.sum()),held_records=int(target.sum()),
unseen_held_records=int((target&unseen).sum()),exclusions=excluded,seconds=time.perf_counter()-start,
measurements_are_episodes_not_independent_raw_rows=True,reference_columns_are_never_features=True))
verify();print(json.dumps(dict(eligible=eligibility,source_records=int(source_mask.sum()),held_records=int(target.sum()))),flush=True)
def run(device='cuda:1'):
verify();torch.cuda.set_device(device);torch.backends.cuda.matmul.allow_tf32=False
config=json.loads(PROTOCOL.read_text());start=time.perf_counter();prep=json.loads((ROOT/'preparation.json').read_text())
if not prep['eligible']:write('decision.json',dict(promotion=False,reason='locked_cohort_eligibility_failure'));return
p=torch.load(ROOT/'prepared.pt',map_location=device,weights_only=True);pool=torch.where(p['source'])[0];held=torch.where(p['target'])[0]
sizes=[10,3];grid=factorial.hypotheses(sizes,device);true=factorial.joint_index(p['h'][held],sizes);results=[]
for n in config['sample_budgets']:
for seed in config['seeds']:
rng=torch.Generator(device=device).manual_seed(seed);ids=pool[torch.randperm(len(pool),device=device,generator=rng)[:n]]
t=time.perf_counter();mean=p['x'][ids].mean(0);scale=p['x'][ids].std(0).clamp_min(1e-6)
x=(p['x'][ids]-mean)/scale;target=(p['x'][held]-mean)/scale;torch.cuda.synchronize();normalization=time.perf_counter()-t
supported=torch.ones(len(held),device=device,dtype=torch.bool)
for f,k in enumerate(sizes):supported &= torch.bincount(p['h'][ids,f],minlength=k)[p['h'][held,f]]>0
directory=ROOT/'models'/f'n{n}_s{seed}';directory.mkdir(parents=True,exist_ok=True)
for name in MODELS:
torch.cuda.synchronize();t=time.perf_counter();model=fit_one(x,p['h'][ids],sizes,name,seed)
torch.cuda.synchronize();fit_seconds=time.perf_counter()-t;t=time.perf_counter()
with torch.no_grad():prob=predict(model,target,range(x.shape[-1]));v=metrics(prob,true,grid,p['h'][held])
torch.cuda.synchronize();prediction=time.perf_counter()-t
checkpoint=directory/f'{name}.pt';torch.save(dict(model=model,mean=mean,scale=scale,fit_ids=ids),checkpoint)
row=dict(samples=n,seed=seed,model=name,held_rows=held,days=p['days'][held],unseen=p['unseen'][held],
supported_levels=supported,metrics=v,normalization_seconds=normalization,fit_seconds=fit_seconds,
prediction_seconds=prediction,neural_parameters=model.get('neural_parameters',0),
checkpoint_bytes=checkpoint.stat().st_size,adaptation_fits=model.get('adaptation_fits',1))
results.append(row)
print(json.dumps(dict(samples=n,seed=seed,model=name,top3_unseen=float(v['top3'][row['unseen']].mean()))),flush=True)
torch.save(dict(results=results),ROOT/'results.pt');write('execution.json',dict(seconds=time.perf_counter()-start,
peak_gpu_bytes=torch.cuda.max_memory_allocated(device),device=device,cells=len(results),backbone_executions=0,
timings=[{k:r[k] for k in ('samples','seed','model','normalization_seconds','fit_seconds','prediction_seconds','neural_parameters','checkpoint_bytes','adaptation_fits')} for r in results]))
verify()
@torch.no_grad()
def analyze(device='cuda:2'):
verify();torch.cuda.set_device(device);config=json.loads(PROTOCOL.read_text());start=time.perf_counter()
results=torch.load(ROOT/'results.pt',map_location=device,weights_only=True)['results'];rng=torch.Generator(device=device).manual_seed(20891)
summary=[];comparisons=[];gates=[]
for n in config['sample_budgets']:
records=[r for r in results if r['samples']==n];template=records[0];mask=template['unseen'];day=template['days'][mask]
matrix=torch.stack([torch.stack([r['metrics']['top3'] for r in records if r['model']==name]).mean(0)[mask] for name in MODELS],-1)
points=[];boot=[]
for d in range(9,13):
a=matrix[day==d];points.append(a.mean(0));sample=torch.randint(len(a),(20000,len(a)),device=device,generator=rng);boot.append(a[sample].mean(1))
day_points=torch.stack(points);point=day_points.mean(0);conditional_boot=torch.stack(boot).mean(0)
sampled_days=torch.randint(4,(20000,4),device=device,generator=rng)
day_boot=day_points[sampled_days].mean(1)
for name in MODELS:
rows=[r for r in records if r['model']==name];assert len(rows)==3
for stratum,include in (('unseen',mask),('seen',~mask)):
for d in (None,9,10,11,12):
m=include if d is None else include&(template['days']==d)
summary.append(dict(samples=n,model=name,stratum=stratum,day=d,records=int(m.sum()),
**{f:float(torch.stack([r['metrics'][f][m].mean() for r in rows]).mean()) for f in ('top1','top3','nll','confidence','top3_mass')}))
for support in (False,True):
count=correct=0
for r in rows:
m=r['unseen']&(r['supported_levels']==support);count+=int(m.sum());correct+=float(r['metrics']['top3'][m].sum())
summary.append(dict(samples=n,model=name,stratum='supported' if support else 'novel_level',records_across_seeds=count,top3=correct/count if count else None))
for threshold in (.5,.7,.9):
accepted=correct=0
for r in rows:
m=r['unseen']&(r['metrics']['confidence']>=threshold);accepted+=int(m.sum());correct+=float(r['metrics']['top1'][m].sum())
summary.append(dict(samples=n,model=name,stratum='selective_unseen',threshold=threshold,
coverage=accepted/(3*int(mask.sum())),accuracy=correct/accepted if accepted else None))
for candidate in config['candidates']:
ci=MODELS.index(candidate);rows=[];alpha=.05/(2*40)
for ri,reference in enumerate(MODELS):
if ci==ri:continue
diff=conditional_boot[:,ci]-conditional_boot[:,ri];lo,hi=torch.quantile(diff,diff.new_tensor([alpha,1-alpha]))
dd=day_boot[:,ci]-day_boot[:,ri];dlo,dhi=torch.quantile(dd,dd.new_tensor([alpha,1-alpha]))
row=dict(samples=n,candidate=candidate,control=reference,gain=float(point[ci]-point[ri]),
fixed_day_simultaneous_interval=[float(lo),float(hi)],day_cluster_simultaneous_interval=[float(dlo),float(dhi)],
day_gains=(day_points[:,ci]-day_points[:,ri]).tolist())
rows.append(row);comparisons.append(row)
strong=[r for r in rows if r['control'] in STRONG]
substantial=all(r['gain']>=.10 and r['fixed_day_simultaneous_interval'][0]>0 and r['day_cluster_simultaneous_interval'][0]>0 and min(r['day_gains'])>0 for r in strong)
best=all(r['fixed_day_simultaneous_interval'][0]>0 and r['day_cluster_simultaneous_interval'][0]>0 for r in rows)
learned=next((r['fixed_day_simultaneous_interval'][0]>0 and r['day_cluster_simultaneous_interval'][0]>0 for r in rows if r['control']=='additive_full'),False) if candidate=='factorized_neural' else None
gates.append(dict(samples=n,candidate=candidate,top3=float(point[ci]),substantial_gain=substantial,strongest_available=best,
learning_specific=learned,promotion=n==64 and substantial and best,
strongest_observed_model=MODELS[int(point.argmax())],strongest_top3=float(point.max())))
write('summary.json',dict(rows=summary,comparisons=comparisons,gates=gates,all_thirteen_days_retained=True,
confirmation_days=[9,10,11,12],one_physical_platform=True,draws=20000,comparison_family=40,
original_dynamic_mixture_source_gate_remains_failed=True))
write('analysis_execution.json',dict(seconds=time.perf_counter()-start,device=device));verify();print(json.dumps(gates),flush=True)
def acquisition(device='cuda:1'):
verify();torch.cuda.set_device(device);torch.backends.cuda.matmul.allow_tf32=False
config=json.loads(PROTOCOL.read_text());p=torch.load(ROOT/'prepared.pt',map_location=device,weights_only=True);prep=json.loads((ROOT/'preparation.json').read_text())
rows=[]
for day in range(9,13):
eligible=torch.where(p['target']&p['unseen']&(p['days']==day))[0].tolist()
rows+=sorted(eligible,key=lambda i:hashlib.sha256(('20901:'+prep['records'][i]['id']).encode()).hexdigest())[:8]
ids=torch.tensor(rows,device=device);true=factorial.joint_index(p['h'][ids],[10,3]);results=[];start=time.perf_counter()
for name in config['candidates']:
checkpoint=torch.load(ROOT/'models'/f'n64_s{config["seeds"][0]}'/f'{name}.pt',map_location=device,weights_only=True)
x=(p['x'][ids]-checkpoint['mean'])/checkpoint['scale'];model=checkpoint['model']
for policy in config['acquisition']['policies']:
snapshots,trace=episode(model,x,policy,20911,(2,4,8),.01)
for budget,out in snapshots.items():
credit=factorial.topk_credit(out['probability'],true,3)
results.append(dict(model=name,policy=policy,budget=budget,rows=ids,days=p['days'][ids],top3=credit,queries=out['queries'],trace=trace))
print(json.dumps(dict(model=name,policy=policy,seconds=trace['seconds'])),flush=True)
torch.save(dict(results=results),ROOT/'acquisition.pt');write('acquisition_execution.json',dict(seconds=time.perf_counter()-start,
peak_gpu_bytes=torch.cuda.max_memory_allocated(device),secondary_only=True));verify()
if __name__=='__main__':
parser=argparse.ArgumentParser();parser.add_argument('command',choices=['lock','prepare','run','analyze','acquisition']);a=parser.parse_args()
{'lock':lock,'prepare':prepare,'run':run,'analyze':analyze,'acquisition':acquisition}[a.command]()