ui-test-vision-2b-alpha / code /glint /glint_model.py
yuta24's picture
v0.1.0-alpha: PyTorch LoRA + heads, code, model card
e379257 verified
Raw History Blame Contribute Delete
2.58 kB
"""ClefModel + optional BoxHead. Kept free of transformers/peft imports so it can be unit-tested with a mock backbone."""
from __future__ import annotations
from typing import Any
import torch
from .joint_schema_model import ClefModel, JointSchemaHead
from .box import BoxHead, BoxPrediction
class GlintModel(ClefModel):
"""`forward(batch)` returns the joint-schema logits exactly like ClefModel (list per record).
`decide(batch)` returns `(logits, boxes)`; `boxes[i]` is a BoxPrediction or None."""
def __init__(self, language_model: Any, head: JointSchemaHead, box_head: BoxHead | None = None) -> None:
super().__init__(language_model, head)
self.box_head = box_head
def _base_model(self):
lm = self.language_model
return lm.get_base_model() if hasattr(lm, "get_base_model") else lm
def _hidden(self, batch: dict[str, Any]):
base_model = self._base_model()
media = batch.get("media") or {}
text_model = base_model.model
if not media and hasattr(text_model, "language_model"):
text_model = text_model.language_model
outputs = text_model(input_ids=batch["input_ids"], attention_mask=batch["attention_mask"],
use_cache=False, return_dict=True, **media)
return outputs.last_hidden_state, base_model
def decide(self, batch: dict[str, Any]) -> tuple[list[list[torch.Tensor]], list[BoxPrediction | None]]:
hidden, base_model = self._hidden(batch)
records = batch["records"]
logits: list[list[torch.Tensor]] = [[] for _ in records]
keep = [i for i, r in enumerate(records) if r.questions]
if keep:
sel = keep if len(keep) < len(records) else slice(None)
out = self.head(hidden[sel], batch["input_ids"][sel], batch["attention_mask"][sel], [records[i] for i in keep],
base_model.get_output_embeddings().weight)
for i, z in zip(keep, out):
logits[i] = z
boxes: list[BoxPrediction | None] = [None] * len(records)
if any(getattr(r, "box_questions", ()) for r in records):
if self.box_head is None:
raise ValueError("record has box questions but this checkpoint has no box head (train with --box-head on)")
boxes = self.box_head(hidden, batch["attention_mask"], records)
return logits, boxes
def forward(self, batch: dict[str, Any]) -> list[list[torch.Tensor]]:
return self.decide(batch)[0]