AbstractPhil's picture
Deploy: 12-task vision extraction + fusion ZeroGPU showcase
fed954e verified
Raw
History Blame Contribute Delete
8.09 kB
"""
fuse_schema.py — the FusedScene pydantic schema (fusion tier).
Hand-written nested models (the SubjectValue precedent — the SlotSpec codegen in
schema.py handles one nesting level; FusedScene needs three: entities ->
attributes -> ownership). Deliberately NOT a registered VisionTaskSpec: FusedScene
is a deterministically-produced dataset artifact, not a VLM probe — it needs no
GBNF, no system prompt, no scorer. If a VLM is ever trained to EMIT FusedScene,
register a flattened variant then.
Versioned from day one: this module is a second schema authority next to the
registry, so every instance stamps `fused_scene_version`.
Coordinate policy: all geometry emitted in the declared `coord_space`
(NORM_0_1000 by default, via specialists.box_to_space/poly_to_space); the one
pixel-unit field is `image_size`, documented as such. Scorers convert via
coords.to_canonical.
"""
from __future__ import annotations
from typing import Optional
from pydantic import BaseModel, Field
FUSED_SCENE_VERSION = "1.0"
# Caps (data, referenced by fuse.py — never hardcoded at call sites)
MAX_ENTITIES = 12 # kept by saliency rank
MAX_RELATION_ENTITIES = 8 # pairwise relations among the top-K entities
MASK_POLY_MAX_POINTS = 64 # outline_polygon(max_points=...) per entity
# Basin reasons (closed set, tested)
BASIN_REASONS = ("low_margin", "no_grounding_multi_entity", "ambiguous_binding",
"abstract_unbound")
# Ownership methods (closed set, tested)
OWNERSHIP_METHODS = ("single_entity", "mask_containment", "box_containment",
"caption_binding")
class GridPosition(BaseModel):
grid: str # "{upper|middle|lower} {left|center|right}"
offset_from_center: list[float] # (centroid-center)/half-extents, in [-1,1]
class DepthInfo(BaseModel):
nearness: float # continuous [0,1], bigger = nearer
rank: int # 1 = nearest
class SaliencyInfo(BaseModel):
score: float
rank: int # 1 = most salient
class MaskInfo(BaseModel):
polygon: list[float] = Field(default_factory=list) # flat x,y interleaved, task space
quality: Optional[float] = None # SAM predicted-IoU (retained signal)
class CaptionBinding(BaseModel):
source: str # caption column key
subject_name: str
confidence: float
class Ownership(BaseModel):
confidence: float
margin: Optional[float] = None # f1 - f2 (containment methods only)
method: str # one of OWNERSHIP_METHODS
class RegionOnOwner(BaseModel):
vertical: str # upper | middle | lower
horizontal: str # left | center | right
offset: list[float] # (attr center - owner centroid)/owner half-extents
class AttributeRecord(BaseModel):
text: str # canonical (longest) form after dedup
stratum: str
sources: list[str] # caption columns that carried it
consensus: float # len(sources)/n_caption_sources
grounded: bool = False
box: Optional[list[float]] = None # present iff grounded (task space)
grounding_score: Optional[float] = None # GDINO phrase score
ownership: Ownership
region_on_owner: Optional[RegionOnOwner] = None
class Entity(BaseModel):
id: str # person_1, person_2, dog, ... (left-to-right)
label: str
detection_score: float
box: list[float] # task space
centroid: list[float] # task space
area_frac: float
position: GridPosition
depth: Optional[DepthInfo] = None
saliency: SaliencyInfo
is_primary: bool = False
mask: Optional[MaskInfo] = None
caption_bindings: list[CaptionBinding] = Field(default_factory=list)
attributes: list[AttributeRecord] = Field(default_factory=list)
class Relation(BaseModel):
a: str # entity id (smaller entity index)
b: str
predicates: list[str] # spatial_relations predicate vocab
dx: float # (centroid_b - centroid_a)/W, task-space-free
dy: float
distance: float # centroid distance / image diagonal
iou: float
depth_delta: Optional[float] = None # nearness_a - nearness_b (continuous)
confidence: float # min(detection scores)
class BasinCandidate(BaseModel):
entity_id: str
likelihood: float
class BasinItem(BaseModel):
text: str
stratum: str
sources: list[str]
consensus: float
reason: str # one of BASIN_REASONS
grounded: bool = False
box: Optional[list[float]] = None
candidates: list[BasinCandidate] = Field(default_factory=list)
class VotedValue(BaseModel):
value: Optional[str] = None
votes: dict[str, int] = Field(default_factory=dict)
class StyleValue(BaseModel):
value: Optional[str] = None # specialist wins conflicts (it saw the image)
caption_votes: dict[str, int] = Field(default_factory=dict)
specialist: Optional[str] = None
class MoodValue(BaseModel):
value: Optional[str] = None
per_source: dict[str, str] = Field(default_factory=dict)
class SymmetryInfo(BaseModel):
axis: str = "none"
lr: Optional[float] = None # continuous correlations (retained)
tb: Optional[float] = None
class SceneAttribute(BaseModel):
text: str
stratum: str = "scene_level"
sources: list[str] = Field(default_factory=list)
class SceneOCRLine(BaseModel):
text: str
box: Optional[list[float]] = None
conf: Optional[float] = None # EasyOCR confidence (retained)
class SceneOCR(BaseModel):
full_text: str = ""
lines: list[SceneOCRLine] = Field(default_factory=list)
class LabelScore(BaseModel):
label: str
score: float
class SceneBlock(BaseModel):
setting: VotedValue = Field(default_factory=VotedValue)
style: StyleValue = Field(default_factory=StyleValue)
mood: MoodValue = Field(default_factory=MoodValue)
layout: str = "unknown"
symmetry: SymmetryInfo = Field(default_factory=SymmetryInfo)
actions: list[SceneAttribute] = Field(default_factory=list) # unbound caption actions
scene_attributes: list[SceneAttribute] = Field(default_factory=list)
ocr: SceneOCR = Field(default_factory=SceneOCR)
class_top: list[LabelScore] = Field(default_factory=list)
class Counts(BaseModel):
total_entities: int = 0
people: int = 0 # via the person synonym group
by_label: dict[str, int] = Field(default_factory=dict)
class GroundingStats(BaseModel):
phrases_total: int = 0
phrases_grounded: int = 0
assigned: int = 0
basin: int = 0
scene_level: int = 0
ungroundable: int = 0
class Quality(BaseModel):
n_caption_sources: int = 0
detection_score_mean: float = 0.0
mask_quality_mean: Optional[float] = None
ocr_conf_mean: Optional[float] = None
grounding: GroundingStats = Field(default_factory=GroundingStats)
overall_confidence: float = 0.0 # the fusion_confidence scalar
class FusedScene(BaseModel):
fused_scene_version: str = FUSED_SCENE_VERSION
coord_space: str
image_size: list[int] # (W, H) PIXELS — the one pixel field
counts: Counts = Field(default_factory=Counts)
entities: list[Entity] = Field(default_factory=list)
relations: list[Relation] = Field(default_factory=list)
shared_basin: list[BasinItem] = Field(default_factory=list)
scene: SceneBlock = Field(default_factory=SceneBlock)
quality: Quality = Field(default_factory=Quality)
FUSED_SCENE_JSON_SCHEMA = FusedScene.model_json_schema()