diff options
Diffstat (limited to 'logs/verify.py')
| -rw-r--r-- | logs/verify.py | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/logs/verify.py b/logs/verify.py new file mode 100644 index 0000000..17fd643 --- /dev/null +++ b/logs/verify.py @@ -0,0 +1,59 @@ +import sys, numpy as np, ot, torch +sys.path.insert(0,'/home/yurenh2/emm') +from scipy.optimize import linear_sum_assignment +from worldalign.synth_fast_gate import ClosedFormEnergy, fast_pair_descent +from worldalign.synth_triangle_gate import standardized +DEV=torch.device("cuda:1") +def standardise(m): + mask=~np.eye(len(m),dtype=bool); v=m[mask] + o=(m-v.mean())/v.std(); np.fill_diagonal(o,0.0); return o +def tlb(V,S): + n=len(V); a=np.sort(V,1); b=np.sort(S,1) + return (a*a).sum(1)[:,None]/n+(b*b).sum(1)[None,:]/n-2*(a@b.T)/n +st=torch.load("/home/yurenh2/emm/artifacts/synth_v1/omit_size.pt",map_location='cpu',weights_only=False) +V=standardise(st["visual_field"].double().numpy()); T=standardise(st["text_field"].double().numpy()) +n=len(V); w=ot.unif(n) +rng=np.random.default_rng(0); hid=rng.permutation(n); S=T[np.ix_(hid,hid)] +Vg=standardized(torch.from_numpy(V).to(DEV)).double(); Sg=standardized(torch.from_numpy(S).to(DEV)).double() +en=ClosedFormEnergy(Sg,Vg,1.0,0.0,64) +M=tlb(V,S); M=M/M.max() +G=np.outer(w,w) +for a in (0.0,0.2): + G=ot.gromov.fused_gromov_wasserstein(M,V,S,w,w,"square_loss",alpha=a,G0=G,max_iter=200,tol_rel=1e-9) +_,cols=linear_sum_assignment(-G) +fin=fast_pair_descent(Sg,Vg,torch.from_numpy(np.ascontiguousarray(cols)).to(DEV),2000).cpu().numpy() +truth=np.argsort(hid) +Ef=float(en.energy(torch.from_numpy(np.ascontiguousarray(fin)).to(DEV)[None])[0]) +Et=float(en.energy(torch.from_numpy(np.ascontiguousarray(truth)).to(DEV)[None])[0]) +acc=float((hid[fin]==np.arange(n)).mean()) +print("accuracy=%.4f E_found=%.10f E_truth=%.10f diff=%.3e"%(acc,Ef,Et,Ef-Et)) +wrong=np.where(hid[fin]!=np.arange(n))[0] +print("n_wrong=%d"%len(wrong)) +# for each wrong scene i: correlation between S-row of assigned node and S-row of true node +Sal=S # in shuffled index space +corr=[] +vcorr=[] +for i in wrong: + a_idx=fin[i]; t_idx=truth[i] + x=np.delete(Sal[a_idx],[a_idx,t_idx]); y=np.delete(Sal[t_idx],[a_idx,t_idx]) + corr.append(np.corrcoef(x,y)[0,1]) + u=np.delete(V[i],[i]); + # visual side: is the visually-assigned scene similar to i? compare V rows of i and of the scene truly at a_idx + j=hid[a_idx] + v1=np.delete(V[i],[i,j]); v2=np.delete(V[j],[i,j]) + vcorr.append(np.corrcoef(v1,v2)[0,1]) +rng2=np.random.default_rng(7); pairs=rng2.integers(0,n,(len(wrong),2)) +base=[np.corrcoef(np.delete(Sal[p],[p,q]),np.delete(Sal[q],[p,q]))[0,1] for p,q in pairs if p!=q] +print("text-row corr of confused partners: median=%.3f mean=%.3f | random pair baseline median=%.3f"%(np.median(corr),np.mean(corr),np.median(base))) +print("visual-row corr of confused partners: median=%.3f"%np.median(vcorr)) +# cycle structure of the error +perm=hid[fin] +seen=set(); cyc=[] +for i in range(n): + if i in seen or perm[i]==i: continue + c=0; j=i + while j not in seen: + seen.add(j); j=perm[j]; c+=1 + cyc.append(c) +import collections +print("error cycle lengths:", dict(collections.Counter(cyc))) |
