summaryrefslogtreecommitdiff
path: root/logs/verify.py
diff options
context:
space:
mode:
Diffstat (limited to 'logs/verify.py')
-rw-r--r--logs/verify.py59
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)))