| """13-model Ultimate WBF eval""" |
| import sys,os,json,gc,numpy as np |
| from PIL import Image,ImageEnhance |
| from tqdm import tqdm |
| PROJECT_DIR='/home/user/goat' |
| os.chdir(PROJECT_DIR);sys.path.insert(0,PROJECT_DIR) |
| from ultralytics import YOLO |
| import torch |
|
|
| def iou_fn(b1,b2): |
| x1,y1=max(b1[0],b2[0]),max(b1[1],b2[1]) |
| x2,y2=min(b1[2],b2[2]),min(b1[3],b2[3]) |
| inter=max(0,x2-x1)*max(0,y2-y1) |
| a1=(b1[2]-b1[0])*(b1[3]-b1[1]);a2=(b2[2]-b2[0])*(b2[3]-b2[1]) |
| return inter/(a1+a2-inter+1e-8) |
|
|
| def wbf_fn(bl,sl,thr=0.55): |
| if not bl or all(len(b)==0 for b in bl): return np.array([]) |
| ab,as_=[],[] |
| for bx,sx in zip(bl,sl): ab.extend(bx);as_.extend(sx) |
| if not ab: return np.array([]) |
| ab=np.array(ab);as_=np.array(as_) |
| o=np.argsort(-as_);ab=ab[o];as_=as_[o] |
| cl,us=[],np.zeros(len(ab),dtype=bool) |
| for i in range(len(ab)): |
| if us[i]: continue |
| c=[(ab[i],as_[i])];us[i]=True |
| for j in range(i+1,len(ab)): |
| if us[j]: continue |
| tw=sum(s for _,s in c) |
| ct=sum(b*s/tw for b,s in c) |
| if iou_fn(ct.tolist(),ab[j].tolist())>thr: c.append((ab[j],as_[j]));us[j]=True |
| cl.append(c) |
| rb,rs=[],[] |
| for c in cl: |
| tw=sum(s for _,s in c) |
| rb.append(sum(b*s/tw for b,s in c));rs.append(tw) |
| return np.array(rb) |
|
|
| def pred_fn(model,img,sz,flip=False,bright=1.0): |
| ia=img |
| if bright!=1.0: ia=ImageEnhance.Brightness(ia).enhance(bright) |
| if flip: ia=ia.transpose(Image.FLIP_LEFT_RIGHT) |
| r=model.predict(ia,imgsz=sz,conf=0.25,iou=0.7,max_det=100,verbose=False) |
| if not r or len(r[0].boxes)==0: return np.array([]),np.array([]) |
| b=r[0].boxes.xyxy.cpu().numpy();s=r[0].boxes.conf.cpu().numpy() |
| if flip: w=img.size[0];b[:,[0,2]]=w-b[:,[2,0]] |
| return b,s |
|
|
| def main(): |
| val_dir='Data/Detection_dataset/images/val' |
| lbl_dir='Data/Detection_dataset/labels/val' |
| vfs=sorted([f for f in os.listdir(val_dir) if f.endswith('.jpg')]) |
| exp='runs/detect/Detection_experiments' |
| mpaths=[ |
| ('v6_1',f'{exp}/v6_1_s_refined/weights/best.pt'), |
| ('EL',f'{exp}/v19_eastleft/weights/best.pt'), |
| ('s666',f'{exp}/v19_seed_666/weights/best.pt'), |
| ('s222',f'{exp}/v19_seed_222/weights/best.pt'), |
| ('s111',f'{exp}/v17_seed_111/weights/best.pt'), |
| ('s888',f'{exp}/v18_seed_888/weights/best.pt'), |
| ('s777',f'{exp}/v17_seed_777/weights/best.pt'), |
| ('s333',f'{exp}/v15_seed_333/weights/best.pt'), |
| ('s123',f'{exp}/v12_seed_123/weights/best.pt'), |
| ('s555',f'{exp}/v18_seed_555/weights/best.pt'), |
| ('s42',f'{exp}/v12_seed_42/weights/best.pt'), |
| ('s444',f'{exp}/v18_seed_444/weights/best.pt'), |
| ('M11m',f'{exp}/v16_yolo11m/weights/best.pt'), |
| ] |
| mpaths=[(n,p) for n,p in mpaths if os.path.exists(p)] |
| print('{} models: {}'.format(len(mpaths),[n for n,_ in mpaths])) |
| iou_thrs=[round(0.5+i*0.05,2) for i in range(10)] |
|
|
| def eval_boxes(name,boxes_per_img): |
| tp={t:0 for t in iou_thrs};tg=0 |
| for idx,vf in enumerate(vfs): |
| img=Image.open(os.path.join(val_dir,vf)) |
| gb=[] |
| lf=vf.replace('.jpg','.txt') |
| with open(os.path.join(lbl_dir,lf)) as f: |
| for line in f: |
| p=line.strip().split() |
| if len(p)>=5: |
| cx,cy,w,h=[float(x) for x in p[1:5]] |
| gb.append([(cx-w/2)*img.size[0],(cy-h/2)*img.size[1],(cx+w/2)*img.size[0],(cy+h/2)*img.size[1]]) |
| tg+=len(gb) |
| if not gb: continue |
| for t in iou_thrs: |
| mt=set() |
| for pb in boxes_per_img[idx]: |
| if len(pb)==0: continue |
| bi,bg=0,-1 |
| for gi,gt in enumerate(gb): |
| if gi in mt: continue |
| ii=iou_fn(pb.tolist(),gt) |
| if ii>bi: bi=ii;bg=gi |
| if bi>=t and bg>=0: tp[t]+=1;mt.add(bg) |
| rec=[tp[t]/tg for t in iou_thrs] |
| mAP=np.mean(rec) |
| print('{}: mAP50-95={:.4f} IoU@75={:.4f}'.format(name,mAP,rec[5])) |
| return mAP,rec[5] |
|
|
| m0=YOLO(mpaths[0][1]) |
| bp=[] |
| for vf in tqdm(vfs,desc='Baseline'): |
| img=Image.open(os.path.join(val_dir,vf)) |
| b,_=pred_fn(m0,img,1536);bp.append(b) |
| del m0;gc.collect();torch.cuda.empty_cache() |
| mAP_base,r75_base=eval_boxes('Baseline',bp) |
|
|
| all_preds={} |
| for name,path in mpaths: |
| print('Processing {}...'.format(name)) |
| m=YOLO(path) |
| ip=[] |
| for vf in tqdm(vfs,desc=name,leave=False): |
| img=Image.open(os.path.join(val_dir,vf)) |
| bl,sl=[],[] |
| for sz in [1280,1536,1920]: |
| for fl in [False,True]: |
| for br in [1.0,1.2]: |
| b,s=pred_fn(m,img,sz,fl,br) |
| if len(b)>0: bl.append(b);sl.append(s) |
| ip.append((bl,sl)) |
| all_preds[name]=ip |
| del m;gc.collect();torch.cuda.empty_cache() |
|
|
| ksp=[] |
| for idx in range(len(vfs)): |
| ab,as_=[],[] |
| for name,_ in mpaths: |
| bl,sl=all_preds[name][idx] |
| for b,s in zip(bl,sl): |
| if len(b)>0: ab.append(b);as_.append(s) |
| ksp.append(wbf_fn(ab,as_)) |
| mAP_ks,r75_ks=eval_boxes('KS 13m',ksp) |
|
|
| sep='='*60 |
| print('\n{}'.format(sep)) |
| print('13-MODEL ULTIMATE') |
| print(sep) |
| print('Baseline: {:.4f}'.format(mAP_base)) |
| print('KS 13m: {:.4f} (+{:.4f})'.format(mAP_ks,mAP_ks-mAP_base)) |
|
|
| with open('logs/ultimate13_results.json','w') as f: |
| json.dump({'baseline':round(mAP_base,4),'ks_13m':round(mAP_ks,4),'n_models':len(mpaths)},f,indent=2) |
| print('Saved.') |
|
|
| if __name__=='__main__': |
| main() |
|
|