perf(movienet): vectorise eval matching; count frames missing from Image.zip
movienet_eval: replace the per-element dot() with numpy — actor references are loaded once as an ndarray and scored with a single matmul, keeping a whole-library gallery fast. movienet_prep: count and report frames referenced by annotations but absent from Image.zip instead of skipping them silently.
This commit is contained in:
+15
-11
@@ -19,28 +19,32 @@ import json
|
|||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
||||||
from sae_embed_loader import load_embedder
|
from sae_embed_loader import load_embedder
|
||||||
|
|
||||||
|
|
||||||
def load_gallery(path: str) -> dict[str, dict]:
|
def load_gallery(path: str) -> dict[str, dict]:
|
||||||
"""Return {imdb_id: {"name": str, "embeddings": [[float]]}}."""
|
"""Return {imdb_id: {"name": str, "refs": np.ndarray[n_refs, dim]}}."""
|
||||||
with open(path) as f:
|
with open(path) as f:
|
||||||
data = json.load(f)
|
data = json.load(f)
|
||||||
return {a["imdb_id"]: {"name": a["name"], "embeddings": a["embeddings"]}
|
return {a["imdb_id"]: {"name": a["name"],
|
||||||
|
"refs": np.asarray(a["embeddings"], dtype=np.float32)}
|
||||||
for a in data["actors"]}
|
for a in data["actors"]}
|
||||||
|
|
||||||
|
|
||||||
def dot(a: list[float], b: list[float]) -> float:
|
|
||||||
return sum(x * y for x, y in zip(a, b))
|
|
||||||
|
|
||||||
|
|
||||||
def match(embedding: list[float], gallery: dict[str, dict]) -> tuple[str, float, dict[str, float]]:
|
def match(embedding: list[float], gallery: dict[str, dict]) -> tuple[str, float, dict[str, float]]:
|
||||||
"""Return (best_imdb_id, best_similarity, {imdb_id: similarity})."""
|
"""Return (best_imdb_id, best_similarity, {imdb_id: similarity}).
|
||||||
scores: dict[str, float] = {}
|
|
||||||
for imdb_id, actor in gallery.items():
|
Similarity to an actor is the max dot product over that actor's reference
|
||||||
# max similarity across all reference embeddings for this actor
|
embeddings; vectorised with numpy so a whole-library gallery stays fast.
|
||||||
scores[imdb_id] = max(dot(embedding, ref) for ref in actor["embeddings"])
|
"""
|
||||||
|
vec = np.asarray(embedding, dtype=np.float32)
|
||||||
|
scores: dict[str, float] = {
|
||||||
|
imdb_id: float((actor["refs"] @ vec).max())
|
||||||
|
for imdb_id, actor in gallery.items()
|
||||||
|
}
|
||||||
best_id = max(scores, key=lambda k: scores[k])
|
best_id = max(scores, key=lambda k: scores[k])
|
||||||
return best_id, scores[best_id], scores
|
return best_id, scores[best_id], scores
|
||||||
|
|
||||||
|
|||||||
@@ -133,20 +133,24 @@ def main():
|
|||||||
image_zip = movienet_root / "Image.zip"
|
image_zip = movienet_root / "Image.zip"
|
||||||
frame_cache: dict[str, np.ndarray] = {}
|
frame_cache: dict[str, np.ndarray] = {}
|
||||||
|
|
||||||
|
n_missing_in_zip = 0
|
||||||
print(f"[prep] extracting {len(needed_paths)} frames from Image.zip…", file=sys.stderr)
|
print(f"[prep] extracting {len(needed_paths)} frames from Image.zip…", file=sys.stderr)
|
||||||
with zipfile.ZipFile(image_zip) as zf:
|
with zipfile.ZipFile(image_zip) as zf:
|
||||||
for img_path in needed_paths:
|
for img_path in needed_paths:
|
||||||
zip_entry = f"Image/{img_path}"
|
zip_entry = f"Image/{img_path}"
|
||||||
try:
|
try:
|
||||||
data = zf.read(zip_entry)
|
data = zf.read(zip_entry)
|
||||||
|
except KeyError:
|
||||||
|
n_missing_in_zip += 1 # frame referenced by an annotation but absent from Image.zip
|
||||||
|
continue
|
||||||
arr = np.frombuffer(data, dtype=np.uint8)
|
arr = np.frombuffer(data, dtype=np.uint8)
|
||||||
img = cv2.imdecode(arr, cv2.IMREAD_COLOR)
|
img = cv2.imdecode(arr, cv2.IMREAD_COLOR)
|
||||||
if img is not None:
|
if img is not None:
|
||||||
frame_cache[img_path] = img
|
frame_cache[img_path] = img
|
||||||
except KeyError:
|
|
||||||
pass # file missing from zip, skip silently
|
|
||||||
|
|
||||||
print(f"[prep] frames loaded: {len(frame_cache)}/{len(needed_paths)}", file=sys.stderr)
|
print(f"[prep] frames loaded: {len(frame_cache)}/{len(needed_paths)}", file=sys.stderr)
|
||||||
|
if n_missing_in_zip:
|
||||||
|
print(f"[prep] frames absent from Image.zip: {n_missing_in_zip}", file=sys.stderr)
|
||||||
|
|
||||||
per_actor_count: dict[str, int] = {}
|
per_actor_count: dict[str, int] = {}
|
||||||
gt_entries = []
|
gt_entries = []
|
||||||
|
|||||||
Reference in New Issue
Block a user