Spaces:
Running
Running
| import torch, numpy as np, os, json, time, warnings | |
| from PIL import Image | |
| import torch.nn.functional as F | |
| warnings.filterwarnings('ignore') | |
| DEVICE = "cuda" if torch.cuda.is_available() else "cpu" | |
| DATASET_PATH = "C:/btp/dataset" | |
| RESULTS_FILE = "C:/btp/results.json" | |
| print(f"Device: {DEVICE}") | |
| images, labels = [], [] | |
| for folder in sorted(os.listdir(DATASET_PATH)): | |
| fp = os.path.join(DATASET_PATH, folder) | |
| if not os.path.isdir(fp): continue | |
| for fname in os.listdir(fp): | |
| if fname.lower().endswith(('.jpg','.jpeg','.png')): | |
| images.append(os.path.join(fp, fname)) | |
| labels.append(folder) | |
| print(f"Found {len(images)} images across {len(set(labels))} categories") | |
| def evaluate(embeddings, labels): | |
| emb = torch.tensor(np.array(embeddings)) | |
| emb = F.normalize(emb, dim=-1) | |
| sim = (emb @ emb.T).numpy() | |
| p1, p5, r5, mrr = [], [], [], [] | |
| for i in range(len(labels)): | |
| s = sim[i].copy() | |
| s[i] = -999 | |
| top5 = np.argsort(s)[::-1][:5] | |
| true = labels[i] | |
| if not any(labels[j] == true and j != i for j in range(len(labels))): | |
| continue | |
| p1.append(1.0 if labels[top5[0]] == true else 0.0) | |
| p5.append(sum(1 for idx in top5 if labels[idx] == true) / 5.0) | |
| r5.append(1.0 if any(labels[idx] == true for idx in top5) else 0.0) | |
| for rank, idx in enumerate(top5, 1): | |
| if labels[idx] == true: | |
| mrr.append(1.0/rank) | |
| break | |
| else: | |
| mrr.append(0.0) | |
| return { | |
| "Precision@1": round(float(np.mean(p1))*100, 2), | |
| "Precision@5": round(float(np.mean(p5))*100, 2), | |
| "Recall@5": round(float(np.mean(r5))*100, 2), | |
| "MRR": round(float(np.mean(mrr))*100, 2), | |
| } | |
| results = {} | |
| print("\n[1/4] Testing OpenCLIP...") | |
| import open_clip | |
| m1, _, p1 = open_clip.create_model_and_transforms('ViT-B-32', pretrained='openai') | |
| m1 = m1.to(DEVICE).eval() | |
| embs, t0 = [], time.time() | |
| for path in images: | |
| img = p1(Image.open(path).convert("RGB")).unsqueeze(0).to(DEVICE) | |
| with torch.no_grad(): | |
| embs.append(m1.encode_image(img).cpu().numpy()[0]) | |
| t = round((time.time()-t0)/len(images)*1000, 1) | |
| r = evaluate(embs, labels) | |
| r["inference_ms"] = t | |
| r["text_search"] = "Yes" | |
| r["embedding_dim"] = 512 | |
| results["OpenCLIP"] = r | |
| print(f"Done! P@1={r['Precision@1']}% Speed={t}ms/img") | |
| del m1 | |
| torch.cuda.empty_cache() | |
| print("\n[2/4] Testing SigLIP...") | |
| from transformers import AutoProcessor, AutoModel | |
| proc2 = AutoProcessor.from_pretrained("google/siglip-base-patch16-224") | |
| m2 = AutoModel.from_pretrained("google/siglip-base-patch16-224").to(DEVICE).eval() | |
| embs, t0 = [], time.time() | |
| for path in images: | |
| inp = proc2(images=Image.open(path).convert("RGB"), return_tensors="pt").to(DEVICE) | |
| with torch.no_grad(): | |
| out2 = m2.get_image_features(**inp) | |
| emb2 = out2.pooler_output if hasattr(out2, 'pooler_output') else out2.last_hidden_state[:,0,:] | |
| embs.append(emb2.cpu().numpy()[0]) | |
| t = round((time.time()-t0)/len(images)*1000, 1) | |
| r = evaluate(embs, labels) | |
| r["inference_ms"] = t | |
| r["text_search"] = "Yes" | |
| r["embedding_dim"] = 768 | |
| results["SigLIP"] = r | |
| print(f"Done! P@1={r['Precision@1']}% Speed={t}ms/img") | |
| del m2 | |
| torch.cuda.empty_cache() | |
| print("\n[3/4] Testing DINOv2...") | |
| from transformers import AutoImageProcessor, AutoModel | |
| proc3 = AutoImageProcessor.from_pretrained("facebook/dinov2-base") | |
| m3 = AutoModel.from_pretrained("facebook/dinov2-base").to(DEVICE).eval() | |
| embs, t0 = [], time.time() | |
| for path in images: | |
| inp = proc3(images=Image.open(path).convert("RGB"), return_tensors="pt").to(DEVICE) | |
| with torch.no_grad(): | |
| out = m3(**inp) | |
| embs.append(out.last_hidden_state[:,0,:].cpu().numpy()[0]) | |
| t = round((time.time()-t0)/len(images)*1000, 1) | |
| r = evaluate(embs, labels) | |
| r["inference_ms"] = t | |
| r["text_search"] = "No" | |
| r["embedding_dim"] = 768 | |
| results["DINOv2"] = r | |
| print(f"Done! P@1={r['Precision@1']}% Speed={t}ms/img") | |
| del m3 | |
| torch.cuda.empty_cache() | |
| print("\n[4/4] Testing BLIP-2 on CPU (30-45 mins)...") | |
| from transformers import Blip2Processor, Blip2Model | |
| proc4 = Blip2Processor.from_pretrained("Salesforce/blip2-opt-2.7b") | |
| m4 = Blip2Model.from_pretrained("Salesforce/blip2-opt-2.7b", torch_dtype=torch.float32).to("cpu").eval() | |
| embs, t0 = [], time.time() | |
| for i, path in enumerate(images): | |
| inp = proc4(images=Image.open(path).convert("RGB"), return_tensors="pt") | |
| with torch.no_grad(): | |
| embs.append(m4.get_image_features(**inp).pooler_output.cpu().numpy()[0]) | |
| if (i+1) % 10 == 0: | |
| print(f" Progress: {i+1}/{len(images)}") | |
| t = round((time.time()-t0)/len(images)*1000, 1) | |
| r = evaluate(embs, labels) | |
| r["inference_ms"] = t | |
| r["text_search"] = "Yes" | |
| r["embedding_dim"] = 1408 | |
| results["BLIP-2"] = r | |
| print(f"Done! P@1={r['Precision@1']}% Speed={t}ms/img") | |
| with open(RESULTS_FILE, "w") as f: | |
| json.dump(results, f, indent=2) | |
| print("\n" + "="*65) | |
| print("FINAL RESULTS TABLE") | |
| print("="*65) | |
| print(f"{'Model':<12} {'P@1':>6} {'P@5':>6} {'R@5':>6} {'MRR':>6} {'ms/img':>8} {'Text?':>6}") | |
| print("-"*65) | |
| for name, m in results.items(): | |
| print(f"{name:<12} {m['Precision@1']:>5}% {m['Precision@5']:>5}% {m['Recall@5']:>5}% {m['MRR']:>5}% {m['inference_ms']:>7}ms {m['text_search']:>6}") | |
| print("="*65) | |
| print(f"Results saved to: {RESULTS_FILE}") | |