Any-to-Any
Bagel
Safetensors
bagel
HuggingSelf commited on
Commit
acec4e3
·
verified ·
1 Parent(s): 8d58519

Add Unified-Bench old protocol bundle: unified_bench_old_protocol_0p8346/scripts/scorers

Browse files
unified_bench_old_protocol_0p8346/scripts/scorers/__init__.py ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Similarity scorers for Unified-Bench.
3
+
4
+ Each scorer is a class with:
5
+ - __init__(model_path: str, device: str = "cuda")
6
+ - score_pair(ref_image, gen_image) -> float
7
+ - encode_image(image) -> torch.Tensor (optional, enables batch scoring)
8
+
9
+ All scorers return cosine similarity in [-1, 1], higher is better.
10
+
11
+ Ported from model/UAE/Unified-Bench/{CLIP,DINO_v2,DINO_v3,LongCLIP}.py with
12
+ hardcoded paths removed (paths now come from the eval config).
13
+ """
14
+ from __future__ import annotations
15
+
16
+ from typing import Any, Dict
17
+
18
+
19
+ def load_scorer(name: str, model_path: str, device: str = "cuda"):
20
+ """Factory: instantiate a scorer by name. Raises ImportError if deps missing."""
21
+ name_lower = name.strip().lower()
22
+ if name_lower == "clip":
23
+ from .clip_scorer import CLIPScorer
24
+ return CLIPScorer(model_path=model_path, device=device)
25
+ if name_lower in ("dinov2", "dino_v2", "dino-v2"):
26
+ from .dinov2_scorer import DINOv2Scorer
27
+ return DINOv2Scorer(model_path=model_path, device=device)
28
+ if name_lower in ("dinov3", "dino_v3", "dino-v3"):
29
+ from .dinov3_scorer import DINOv3Scorer
30
+ return DINOv3Scorer(model_path=model_path, device=device)
31
+ if name_lower in ("longclip", "long_clip", "long-clip"):
32
+ from .longclip_scorer import LongCLIPScorer
33
+ return LongCLIPScorer(model_path=model_path, device=device)
34
+ raise ValueError(f"Unknown scorer '{name}'. Supported: clip, dinov2, dinov3, longclip")
unified_bench_old_protocol_0p8346/scripts/scorers/clip_scorer.py ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """CLIP vision-encoder similarity (ported from model/UAE/Unified-Bench/CLIP.py).
2
+
3
+ Uses CLIPImageProcessor directly (not CLIPProcessor) and explicitly moves
4
+ pixel_values to the target device. This avoids issues with BatchFeature.to()
5
+ on newer transformers versions where passing only images through the combined
6
+ CLIPProcessor can emit deprecation warnings / silently break.
7
+ """
8
+ from __future__ import annotations
9
+
10
+ import torch
11
+ from torch.nn import functional as F
12
+ from PIL import Image
13
+ from transformers import CLIPImageProcessor, CLIPModel
14
+
15
+
16
+ class CLIPScorer:
17
+ def __init__(self, model_path: str = "openai/clip-vit-large-patch14", device: str = "cuda"):
18
+ self.device = torch.device(device if torch.cuda.is_available() and device == "cuda" else "cpu")
19
+ self.model_path = model_path
20
+ print(f"[clip] loading from {model_path}")
21
+ self.model = CLIPModel.from_pretrained(model_path).to(self.device)
22
+ self.model.eval()
23
+ self.image_processor = CLIPImageProcessor.from_pretrained(model_path)
24
+ self.model_dtype = next(self.model.parameters()).dtype
25
+
26
+ def _to_pil(self, image):
27
+ if isinstance(image, str):
28
+ return Image.open(image).convert("RGB")
29
+ if isinstance(image, Image.Image):
30
+ return image.convert("RGB") if image.mode != "RGB" else image
31
+ raise ValueError(f"CLIPScorer expects PIL.Image or path, got {type(image)}")
32
+
33
+ @torch.no_grad()
34
+ def encode_image(self, image):
35
+ pil = self._to_pil(image)
36
+ processed = self.image_processor(images=pil, return_tensors="pt")
37
+ pixel_values = processed["pixel_values"].to(device=self.device, dtype=self.model_dtype)
38
+ # Bypass CLIPModel.get_image_features — in recent transformers versions
39
+ # it can return the full BaseModelOutputWithPooling dataclass instead
40
+ # of the projected features tensor. Call vision_model + visual_projection
41
+ # directly to stay stable across versions.
42
+ vision_out = self.model.vision_model(pixel_values=pixel_values)
43
+ pooled = vision_out.pooler_output # (batch, hidden_size)
44
+ features = self.model.visual_projection(pooled) # (batch, projection_dim)
45
+ return F.normalize(features, p=2, dim=1)
46
+
47
+ def score_pair(self, ref_image, gen_image) -> float:
48
+ f1 = self.encode_image(ref_image)
49
+ f2 = self.encode_image(gen_image)
50
+ return torch.cosine_similarity(f1, f2, dim=1).item()
unified_bench_old_protocol_0p8346/scripts/scorers/dinov2_scorer.py ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """DINOv2 CLS-token similarity (ported from model/UAE/Unified-Bench/DINO_v2.py)."""
2
+ from __future__ import annotations
3
+
4
+ import torch
5
+ from torch.nn import functional as F
6
+ from PIL import Image
7
+ from transformers import AutoImageProcessor, AutoModel
8
+
9
+
10
+ class DINOv2Scorer:
11
+ def __init__(self, model_path: str = "facebook/dinov2-large", device: str = "cuda"):
12
+ self.device = torch.device(device if torch.cuda.is_available() and device == "cuda" else "cpu")
13
+ self.model_path = model_path
14
+ print(f"[dinov2] loading from {model_path}")
15
+ self.processor = AutoImageProcessor.from_pretrained(model_path)
16
+ self.model = AutoModel.from_pretrained(model_path).to(self.device)
17
+ self.model.eval()
18
+
19
+ def _to_pil(self, image):
20
+ if isinstance(image, str):
21
+ return Image.open(image).convert("RGB")
22
+ if isinstance(image, Image.Image):
23
+ return image.convert("RGB") if image.mode != "RGB" else image
24
+ raise ValueError(f"DINOv2Scorer expects PIL.Image or path, got {type(image)}")
25
+
26
+ @torch.no_grad()
27
+ def encode_image(self, image):
28
+ pil = self._to_pil(image)
29
+ inputs = self.processor(images=pil, return_tensors="pt").to(self.device)
30
+ outputs = self.model(**inputs)
31
+ # CLS token
32
+ features = outputs.last_hidden_state[:, 0, :]
33
+ return F.normalize(features, p=2, dim=1)
34
+
35
+ def score_pair(self, ref_image, gen_image) -> float:
36
+ f1 = self.encode_image(ref_image)
37
+ f2 = self.encode_image(gen_image)
38
+ return torch.cosine_similarity(f1, f2, dim=1).item()
unified_bench_old_protocol_0p8346/scripts/scorers/dinov3_scorer.py ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """DINOv3 CLS-token similarity (ported from model/UAE/Unified-Bench/DINO_v3.py).
2
+
3
+ Requires transformers >= 4.50 with DINOv3 support, or the HF repo contents to load
4
+ via AutoModel with trust_remote_code.
5
+ """
6
+ from __future__ import annotations
7
+
8
+ import torch
9
+ from torch.nn import functional as F
10
+ from PIL import Image
11
+ from transformers import AutoImageProcessor, AutoModel
12
+
13
+
14
+ class DINOv3Scorer:
15
+ def __init__(self, model_path: str, device: str = "cuda"):
16
+ self.device = torch.device(device if torch.cuda.is_available() and device == "cuda" else "cpu")
17
+ self.model_path = model_path
18
+ print(f"[dinov3] loading from {model_path}")
19
+ # DINOv3 checkpoints sometimes use custom modeling code; trust_remote_code
20
+ # keeps us compatible with BAAI/Meta releases that ship model.py alongside weights.
21
+ self.processor = AutoImageProcessor.from_pretrained(model_path, trust_remote_code=True)
22
+ self.model = AutoModel.from_pretrained(model_path, trust_remote_code=True).to(self.device)
23
+ self.model.eval()
24
+
25
+ def _to_pil(self, image):
26
+ if isinstance(image, str):
27
+ return Image.open(image).convert("RGB")
28
+ if isinstance(image, Image.Image):
29
+ return image.convert("RGB") if image.mode != "RGB" else image
30
+ raise ValueError(f"DINOv3Scorer expects PIL.Image or path, got {type(image)}")
31
+
32
+ @torch.no_grad()
33
+ def encode_image(self, image):
34
+ pil = self._to_pil(image)
35
+ inputs = self.processor(images=pil, return_tensors="pt").to(self.device)
36
+ outputs = self.model(**inputs)
37
+ features = outputs.last_hidden_state[:, 0, :]
38
+ return F.normalize(features, p=2, dim=1)
39
+
40
+ def score_pair(self, ref_image, gen_image) -> float:
41
+ f1 = self.encode_image(ref_image)
42
+ f2 = self.encode_image(gen_image)
43
+ return torch.cosine_similarity(f1, f2, dim=1).item()
unified_bench_old_protocol_0p8346/scripts/scorers/longclip_scorer.py ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """LongCLIP similarity (ported from model/UAE/Unified-Bench/LongCLIP.py).
2
+
3
+ LongCLIP weights are a .pt file from BeichenZhang/Long-CLIP. The repo is NOT
4
+ a pip package, so it's cloned into /opt/longclip at image build time (see
5
+ modal/images.py:_unified_bench_image). We add /opt to sys.path and import
6
+ `from longclip.model import longclip`.
7
+
8
+ If the import fails at runtime, this scorer raises ImportError and the
9
+ scoring script will skip it with a warning.
10
+ """
11
+ from __future__ import annotations
12
+
13
+ import os
14
+ import sys
15
+
16
+ import torch
17
+ from torch.nn import functional as F
18
+ from PIL import Image
19
+
20
+
21
+ class LongCLIPScorer:
22
+ def __init__(self, model_path: str, device: str = "cuda"):
23
+ self.device = torch.device(device if torch.cuda.is_available() and device == "cuda" else "cpu")
24
+ self.model_path = model_path
25
+ print(f"[longclip] loading from {model_path}")
26
+
27
+ # Allow overriding the clone location via env var, default /opt.
28
+ longclip_root = os.environ.get("LONGCLIP_ROOT", "/opt")
29
+ if longclip_root not in sys.path:
30
+ sys.path.insert(0, longclip_root)
31
+
32
+ try:
33
+ from longclip.model import longclip
34
+ except ImportError as exc:
35
+ raise ImportError(
36
+ f"LongCLIP module not found at {longclip_root}/longclip. "
37
+ "Expected repo cloned from https://github.com/beichenzbc/Long-CLIP "
38
+ "(done in modal/images.py:_unified_bench_image)."
39
+ ) from exc
40
+
41
+ self._longclip = longclip
42
+ self.model, self.tform = longclip.load(model_path, device=self.device)
43
+ self.model.eval()
44
+
45
+ def _to_pil(self, image):
46
+ if isinstance(image, str):
47
+ return Image.open(image).convert("RGB")
48
+ if isinstance(image, Image.Image):
49
+ return image.convert("RGB") if image.mode != "RGB" else image
50
+ raise ValueError(f"LongCLIPScorer expects PIL.Image or path, got {type(image)}")
51
+
52
+ @torch.no_grad()
53
+ def encode_image(self, image):
54
+ pil = self._to_pil(image)
55
+ tensor = self.tform(pil).unsqueeze(0).to(device=self.device, dtype=self.model.dtype)
56
+ features = self.model.encode_image(tensor)
57
+ return F.normalize(features, p=2, dim=1)
58
+
59
+ def score_pair(self, ref_image, gen_image) -> float:
60
+ f1 = self.encode_image(ref_image)
61
+ f2 = self.encode_image(gen_image)
62
+ return torch.cosine_similarity(f1, f2, dim=1).item()