import json,sys,types
from pathlib import Path
sys.path.insert(0,str(Path('tools').resolve()))
from calibrate_siglip_fixture import Siglip,scale_for,project_f143
import torch
root=Path('artifacts/pretrained-siglip-20260912/fixture')
torch.set_grad_enabled(False);torch.set_num_threads(8)
torch.backends.cuda.matmul.allow_tf32=False
model=Siglip(root,'cuda',64)
cal=json.load(open('artifacts/pretrained-siglip-20260912/role-shared.json'))
model.scales=cal['scales'];model.quantize=True;model.fp16_embedding=True
model.quantize_names=set(model.scales)-{'embedding'}
for name in model.quantize_names:
 model.parameters[name+'.weight']=project_f143(model.parameters[name+'.weight'],model.scales[name]['weight'])
stats={}
original=model.attention

def attention(self,q,k,v,name):
 p=stats.setdefault(name,{'q':0.0,'k':0.0,'v':0.0})
 for key,t in [('q',q),('k',k),('v',v)]:p[key]=max(p[key],t.abs().max().item())
 return original(q,k,v,name)
model.attention=types.MethodType(attention,model)
for case in model.manifest['cases'][:3]:
 model.forward(case);print(case['name'],flush=True)
encoder=max(max(p['q'],p['k']) for name,p in stats.items() if name.startswith('encoder.'))
result={'calibration':[c['name'] for c in model.manifest['cases'][:3]],'ranges':stats,'encoder_shared_qk_scale':scale_for(encoder),'encoder_maximum':encoder}
Path('artifacts/full-qk-20260913/qk-ranges.json').write_text(json.dumps(result,indent=2))
print(json.dumps(result),flush=True)
