apoorvrajdev's picture
deploy: 17ac72a6e2a5a8c6e90ff79748114d9b6dd6aa91 with Space config header
d1ecac0
Raw History Blame Contribute Delete
2.44 kB
"""The captioner interface shared by every Phase 3 model."""
from __future__ import annotations
from abc import ABC, abstractmethod
from collections.abc import Mapping, Sequence
from dataclasses import dataclass, field
from pathlib import Path
from types import MappingProxyType
from captioning.evaluation.tokenization import strip_sentinels
from captioning.preprocessing.caption import preprocess_caption
@dataclass(frozen=True)
class CaptionerIdentity:
"""What a run records about the model behind its captions.
Attributes:
model_id: The ``run_meta.json`` model id (``EVAL_METHODOLOGY.md`` § 8.1).
hub_repo: Hugging Face Hub repository the weights come from, if any.
revision: Pinned commit SHA of ``hub_repo``, if any.
decode_settings: The decoding parameters actually used. Read-only.
"""
model_id: str
hub_repo: str | None
revision: str | None
decode_settings: Mapping[str, object] = field(default_factory=dict)
def __post_init__(self) -> None:
object.__setattr__(self, "decode_settings", MappingProxyType(dict(self.decode_settings)))
class Captioner(ABC):
"""Captions a batch of images and normalises the result.
Subclasses produce raw captions; :meth:`caption` normalises every one of
them through the existing training path (``preprocess_caption``, then
``strip_sentinels``), so all compared models are scored on the same
footing (``EVAL_METHODOLOGY.md`` § 8.3).
"""
def __init__(self, identity: CaptionerIdentity) -> None:
self.identity = identity
def load(self) -> None: # noqa: B027 - optional hook, a no-op by default
"""Load model weights if they aren't loaded yet. Safe to call repeatedly."""
def caption(self, image_paths: Sequence[str | Path]) -> list[str]:
"""Return one normalised caption per image, in input order."""
paths = [Path(p) for p in image_paths]
if not paths:
return []
raw = self._raw_captions(paths)
if len(raw) != len(paths):
raise RuntimeError(
f"{self.identity.model_id}: {len(raw)} captions for {len(paths)} images"
)
return [strip_sentinels(preprocess_caption(text)) for text in raw]
@abstractmethod
def _raw_captions(self, image_paths: list[Path]) -> list[str]:
"""Return the model's captions for ``image_paths``, before normalisation."""