garmentiq.segmentation.model_definition.sam
The Segment Anything model family.
Covers SAM 1, SAM 2.1, and SAM 3 behind one registry, together with their bundled
configurations and processors. The model classes are imported lazily, so GarmentIQ
still imports on a transformers release that predates a given generation, and asking
for a model your release does not carry raises a clear ImportError.
The model classes themselves are re-exported from transformers and documented
upstream, so they are not repeated here. They can be imported from this module
directly:
from garmentiq.segmentation.model_definition.sam import (
SamModel, Sam2Model, Sam3Model,
)
The full set is SamModel, SamConfig, SamProcessor, Sam2Model, Sam2Config,
Sam2Processor, Sam2ImageProcessor, Sam3Model, Sam3Config, Sam3Processor,
Sam3ImageProcessor, Sam3TrackerModel, Sam3TrackerConfig, and
Sam3TrackerProcessor.
1# garmentiq/segmentation/model_definition/sam/__init__.py 2"""The Segment Anything model family. 3 4Covers SAM 1, SAM 2.1, and SAM 3 behind one registry, together with their bundled 5configurations and processors. The model classes are imported lazily, so GarmentIQ 6still imports on a `transformers` release that predates a given generation, and asking 7for a model your release does not carry raises a clear `ImportError`. 8 9The model classes themselves are re-exported from `transformers` and documented 10upstream, so they are not repeated here. They can be imported from this module 11directly: 12 13 from garmentiq.segmentation.model_definition.sam import ( 14 SamModel, Sam2Model, Sam3Model, 15 ) 16 17The full set is `SamModel`, `SamConfig`, `SamProcessor`, `Sam2Model`, `Sam2Config`, 18`Sam2Processor`, `Sam2ImageProcessor`, `Sam3Model`, `Sam3Config`, `Sam3Processor`, 19`Sam3ImageProcessor`, `Sam3TrackerModel`, `Sam3TrackerConfig`, and 20`Sam3TrackerProcessor`. 21""" 22from .sam import ( 23 load_sam_config, 24 load_sam_processor, 25 load_sam3_tracker, 26 load_sam3_tracker_config, 27 load_sam3_tracker_processor, 28 sam_family, 29 sam_capabilities, 30 sam_model_class, 31 SAM1_MODELS, 32 SAM2_MODELS, 33 SAM3_MODELS, 34 VALID_SAM_MODELS, 35 ALL_SAM_MODELS, 36 SAM_CAPABILITIES, 37 SAM_PROMPT_DEPTHS, 38) 39 40# Model classes come from transformers and are resolved on first access, so that 41# importing GarmentIQ does not require a transformers release new enough to 42# provide every SAM generation. 43_LAZY = { 44 "Sam3TrackerModel", 45 "Sam3TrackerConfig", 46 "Sam3TrackerProcessor", 47 "Sam3ImageProcessor", 48 "SamModel", 49 "SamConfig", 50 "SamProcessor", 51 "Sam2Model", 52 "Sam2Config", 53 "Sam2Processor", 54 "Sam2ImageProcessor", 55 "Sam3Model", 56 "Sam3Config", 57 "Sam3Processor", 58} 59 60 61def __getattr__(name): 62 """Defer transformers imports until a SAM class is actually requested.""" 63 if name in _LAZY: 64 from . import sam 65 66 return getattr(sam, name) 67 raise AttributeError(f"module {__name__!r} has no attribute {name!r}") 68 69 70__all__ = [ 71 "load_sam_config", 72 "load_sam_processor", 73 "load_sam3_tracker", 74 "load_sam3_tracker_config", 75 "load_sam3_tracker_processor", 76 "sam_family", 77 "sam_capabilities", 78 "sam_model_class", 79 "SAM1_MODELS", 80 "SAM2_MODELS", 81 "SAM3_MODELS", 82 "VALID_SAM_MODELS", 83 "ALL_SAM_MODELS", 84 "SAM_CAPABILITIES", 85 "SAM_PROMPT_DEPTHS", 86] 87 88 89def __dir__(): 90 """List the lazily resolved model classes alongside the eager exports.""" 91 return sorted(set(__all__) | _LAZY)
251def load_sam_config(model_type: str = "sam-vit-b", model_dir: Optional[str] = None): 252 """ 253 Reads and loads the configuration for a specified Segment Anything Model variant. 254 255 This function facilitates strictly offline initialization by dynamically locating the 256 `config.json` file associated with the chosen SAM variant within the local package 257 directory. It reads the JSON file securely and converts it into the Hugging Face 258 configuration object matching the variant's family, entirely bypassing external 259 network requests. 260 261 Configurations for SAM 1 (`sam-vit-*`), SAM 2.1 (`sam2.1-hiera-*`) and SAM 3 (`sam3`) 262 all ship with the package, so no Hugging Face access is needed. SAM 3 weights are still 263 gated, so download the checkpoint once and point `model_path` at it when loading the 264 model; `model_dir` here only overrides the bundled configuration. 265 266 Released SAM 3 configurations describe the video model and nest the image model under 267 `detector_config`. GarmentIQ segments still images, so that nested section is unwrapped 268 automatically. 269 270 Args: 271 model_type (str, optional): The identifier for the desired SAM variant. Must be one 272 of `["sam-vit-b", "sam-vit-l", "sam-vit-h", 273 "sam2.1-hiera-tiny", "sam2.1-hiera-small", 274 "sam2.1-hiera-base-plus", "sam2.1-hiera-large", "sam3"]`. 275 Default is `"sam-vit-b"`. 276 model_dir (str, optional): Path to a local directory containing the variant's 277 `config.json`, used to override the bundled configuration. 278 Default is None. 279 280 Raises: 281 ValueError: If the provided `model_type` is not within the supported variants list. 282 FileNotFoundError: If the corresponding offline `config.json` file cannot be located. 283 284 Returns: 285 Union[SamConfig, Sam2Config, Sam3Config]: The loaded configuration object ready to be 286 passed into the matching SAM model class. 287 """ 288 family = sam_family(model_type) 289 config_path = os.path.join(_variant_dir(model_type, model_dir), "config.json") 290 291 if not os.path.exists(config_path): 292 raise FileNotFoundError(f"Offline config missing at {config_path}.") 293 294 with open(config_path, "r") as f: 295 config_dict = json.load(f) 296 297 config_dict = _unwrap_detector_config(config_dict) 298 299 return _resolve(SAM_FAMILIES[family]["config_class"]).from_dict(config_dict)
Reads and loads the configuration for a specified Segment Anything Model variant.
This function facilitates strictly offline initialization by dynamically locating the
config.json file associated with the chosen SAM variant within the local package
directory. It reads the JSON file securely and converts it into the Hugging Face
configuration object matching the variant's family, entirely bypassing external
network requests.
Configurations for SAM 1 (sam-vit-*), SAM 2.1 (sam2.1-hiera-*) and SAM 3 (sam3)
all ship with the package, so no Hugging Face access is needed. SAM 3 weights are still
gated, so download the checkpoint once and point model_path at it when loading the
model; model_dir here only overrides the bundled configuration.
Released SAM 3 configurations describe the video model and nest the image model under
detector_config. GarmentIQ segments still images, so that nested section is unwrapped
automatically.
Arguments:
- model_type (str, optional): The identifier for the desired SAM variant. Must be one
of
["sam-vit-b", "sam-vit-l", "sam-vit-h", "sam2.1-hiera-tiny", "sam2.1-hiera-small", "sam2.1-hiera-base-plus", "sam2.1-hiera-large", "sam3"]. Default is"sam-vit-b". - model_dir (str, optional): Path to a local directory containing the variant's
config.json, used to override the bundled configuration. Default is None.
Raises:
- ValueError: If the provided
model_typeis not within the supported variants list. - FileNotFoundError: If the corresponding offline
config.jsonfile cannot be located.
Returns:
Union[SamConfig, Sam2Config, Sam3Config]: The loaded configuration object ready to be passed into the matching SAM model class.
319def load_sam_processor( 320 model_type: str = "sam-vit-b", 321 use_fast: Optional[bool] = None, 322 model_dir: Optional[str] = None, 323 backend: Optional[str] = None, 324): 325 """ 326 Loads the offline processor for a specified Segment Anything Model variant. 327 328 This function instantiates the processor matching the variant's family by reading 329 bundled preprocessor (and, for SAM 3, tokenizer) configuration files from the local 330 variant directory. Loading from a local path ensures the package remains completely 331 air-gapped. The image resizing backend can be selected to balance speed against 332 strict backward compatibility. 333 334 Args: 335 model_type (str, optional): The identifier for the desired SAM variant. 336 Default is `"sam-vit-b"`. 337 use_fast (bool, optional): Deprecated alias for `backend`, kept for backwards 338 compatibility. `True` maps to `"torchvision"` and `False` 339 maps to `"pil"`. Only applies to SAM 1. Default is None. 340 model_dir (str, optional): Path to a local directory containing the variant's 341 processor files, used to override the bundled ones. 342 Default is None. 343 backend (str, optional): Image resizing backend, either `"pil"` or `"torchvision"`. 344 `"torchvision"` is faster, while `"pil"` matches the 345 historical GarmentIQ default. Only applies to SAM 1. 346 Default is None, which resolves to `"pil"`. 347 348 Raises: 349 ValueError: If the provided `model_type` is not within the supported variants list, 350 or if `backend` is neither `"pil"` nor `"torchvision"`. 351 FileNotFoundError: If the corresponding offline processor configuration cannot be 352 located. 353 354 Returns: 355 Union[SamProcessor, Sam2Processor, Sam3Processor]: The instantiated processor ready 356 for image and prompt transformations. 357 """ 358 family = sam_family(model_type) 359 variant_dir = _variant_dir(model_type, model_dir) 360 361 if backend is None and use_fast is not None: 362 backend = "torchvision" if use_fast else "pil" 363 if backend is None: 364 # Historical GarmentIQ default. Selected explicitly so results stay identical 365 # across transformers releases, which have shifted their own default over time. 366 backend = "pil" 367 if backend not in ("pil", "torchvision"): 368 raise ValueError( 369 f"Invalid backend {backend!r}. Choose either 'pil' or 'torchvision'." 370 ) 371 372 if family == "sam1": 373 processor_path = os.path.join(variant_dir, "preprocessor_config.json") 374 if not os.path.exists(processor_path): 375 raise FileNotFoundError( 376 f"Offline processor config missing at {processor_path}." 377 ) 378 # transformers 5.4 replaced `use_fast` with `backend`; passing the deprecated 379 # flag to a newer release emits a warning, so select the kwarg by version. 380 backend_kwargs = ( 381 {"backend": backend} 382 if _supports_backend_kwarg() 383 else {"use_fast": backend == "torchvision"} 384 ) 385 # Loading from a local directory disables Hugging Face network calls 386 return _resolve("SamProcessor").from_pretrained( 387 processor_path, **backend_kwargs 388 ) 389 390 if family == "sam2": 391 processor_path = os.path.join(variant_dir, "preprocessor_config.json") 392 if not os.path.exists(processor_path): 393 raise FileNotFoundError( 394 f"Offline processor config missing at {processor_path}." 395 ) 396 with open(processor_path, "r") as f: 397 image_processor_dict = json.load(f) 398 # The bundled config names the deprecated `*Fast` class; build the image 399 # processor explicitly so loading stays offline and warning-free. 400 image_processor_dict.pop("image_processor_type", None) 401 image_processor = _resolve("Sam2ImageProcessor")(**image_processor_dict) 402 return _resolve("Sam2Processor")(image_processor=image_processor) 403 404 # SAM 3 bundles a tokenizer alongside the image processor, so the whole 405 # directory is handed to the processor loader. 406 return _resolve("Sam3Processor").from_pretrained(variant_dir)
Loads the offline processor for a specified Segment Anything Model variant.
This function instantiates the processor matching the variant's family by reading bundled preprocessor (and, for SAM 3, tokenizer) configuration files from the local variant directory. Loading from a local path ensures the package remains completely air-gapped. The image resizing backend can be selected to balance speed against strict backward compatibility.
Arguments:
- model_type (str, optional): The identifier for the desired SAM variant.
Default is
"sam-vit-b". - use_fast (bool, optional): Deprecated alias for
backend, kept for backwards compatibility.Truemaps to"torchvision"andFalsemaps to"pil". Only applies to SAM 1. Default is None. - model_dir (str, optional): Path to a local directory containing the variant's processor files, used to override the bundled ones. Default is None.
- backend (str, optional): Image resizing backend, either
"pil"or"torchvision"."torchvision"is faster, while"pil"matches the historical GarmentIQ default. Only applies to SAM 1. Default is None, which resolves to"pil".
Raises:
- ValueError: If the provided
model_typeis not within the supported variants list, or ifbackendis neither"pil"nor"torchvision". - FileNotFoundError: If the corresponding offline processor configuration cannot be located.
Returns:
Union[SamProcessor, Sam2Processor, Sam3Processor]: The instantiated processor ready for image and prompt transformations.
467def load_sam3_tracker( 468 model_path: str, 469 model_dir: Optional[str] = None, 470 device: Union[str, torch.device] = "cpu", 471): 472 """ 473 Loads SAM 3's point-promptable tracker from a released SAM 3 checkpoint. 474 475 SAM 3 ships as a single checkpoint holding both the detector and the tracker, and the 476 two share one vision encoder that is stored only once under the detector's prefix. This 477 function reassembles the tracker by pairing `tracker_model.*` weights with the shared 478 `detector_model.vision_encoder.*` backbone, then verifies every expected tensor was 479 found so a mismatched checkpoint fails loudly instead of yielding a random model. 480 481 Use this when you want to prompt SAM 3 with points on a still image. For text or box 482 prompts use the detector via `Sam3Model` and `load_sam_config("sam3")` instead. 483 484 Args: 485 model_path (str): Local path to the SAM 3 `model.safetensors` checkpoint. 486 model_dir (str, optional): Directory holding `tracker_config.json`, used to 487 override the bundled configuration. Default is None. 488 device (Union[str, torch.device], optional): The device to load onto, e.g. `"cpu"`, 489 `"cuda"`, or `"mps"`. Default is `"cpu"`. 490 491 Raises: 492 FileNotFoundError: If `model_path` does not exist. 493 ValueError: If the checkpoint does not contain the tensors the tracker expects, or 494 if the requested `device` is unavailable. 495 ImportError: If the installed transformers release does not provide SAM 3. 496 497 Returns: 498 Sam3TrackerModel: The assembled tracker in evaluation mode, placed on `device`. 499 """ 500 from safetensors.torch import load_file 501 502 from garmentiq.utils.device import resolve_device 503 504 if not os.path.exists(model_path): 505 raise FileNotFoundError(f"SAM 3 checkpoint not found at {model_path}.") 506 507 device = resolve_device(device) 508 509 model = _resolve("Sam3TrackerModel")(load_sam3_tracker_config(model_dir)) 510 expected = model.state_dict() 511 512 if model_path.endswith(".safetensors"): 513 state_dict = load_file(model_path, device="cpu") 514 else: 515 state_dict = torch.load(model_path, map_location="cpu", weights_only=True) 516 517 shared_prefix = SAM3_DETECTOR_PREFIX + "vision_encoder." 518 neck_prefix = shared_prefix + "neck." 519 assembled = {} 520 for key, value in state_dict.items(): 521 if key.startswith(neck_prefix): 522 # The detector has its own neck with the same layer names as the tracker's. 523 # Skip it: the tracker's neck is stored separately under `tracker_neck.`, 524 # and using the detector's would silently produce a garbage mask. 525 continue 526 if key.startswith(shared_prefix): 527 # The vision encoder backbone is shared, and stored once under the detector. 528 assembled[key[len(SAM3_DETECTOR_PREFIX) :]] = value 529 elif key.startswith(SAM3_TRACKER_NECK_PREFIX): 530 assembled[ 531 "vision_encoder.neck." + key[len(SAM3_TRACKER_NECK_PREFIX) :] 532 ] = value 533 elif key.startswith(SAM3_TRACKER_PREFIX): 534 stripped = key[len(SAM3_TRACKER_PREFIX) :] 535 if stripped in expected: 536 assembled[stripped] = value 537 538 missing = set(expected) - set(assembled) 539 if missing: 540 raise ValueError( 541 f"SAM 3 tracker weights are incomplete: {len(missing)} of {len(expected)} " 542 f"tensors were not found in {model_path!r} " 543 f"(first missing: {sorted(missing)[:3]}). Check that the checkpoint is a " 544 f"full SAM 3 release." 545 ) 546 547 model.load_state_dict(assembled, strict=True) 548 model = model.to(device) 549 model.eval() 550 return model
Loads SAM 3's point-promptable tracker from a released SAM 3 checkpoint.
SAM 3 ships as a single checkpoint holding both the detector and the tracker, and the
two share one vision encoder that is stored only once under the detector's prefix. This
function reassembles the tracker by pairing tracker_model.* weights with the shared
detector_model.vision_encoder.* backbone, then verifies every expected tensor was
found so a mismatched checkpoint fails loudly instead of yielding a random model.
Use this when you want to prompt SAM 3 with points on a still image. For text or box
prompts use the detector via Sam3Model and load_sam_config("sam3") instead.
Arguments:
- model_path (str): Local path to the SAM 3
model.safetensorscheckpoint. - model_dir (str, optional): Directory holding
tracker_config.json, used to override the bundled configuration. Default is None. - device (Union[str, torch.device], optional): The device to load onto, e.g.
"cpu","cuda", or"mps". Default is"cpu".
Raises:
- FileNotFoundError: If
model_pathdoes not exist. - ValueError: If the checkpoint does not contain the tensors the tracker expects, or
if the requested
deviceis unavailable. - ImportError: If the installed transformers release does not provide SAM 3.
Returns:
Sam3TrackerModel: The assembled tracker in evaluation mode, placed on
device.
409def load_sam3_tracker_config(model_dir: Optional[str] = None): 410 """ 411 Reads and loads the bundled configuration for SAM 3's point-promptable tracker. 412 413 SAM 3's image model is an open-vocabulary detector prompted by text or boxes, and does 414 not accept points. The release also contains a tracker, whose prompt encoder is the 415 SAM-style one that understands points, boxes and masks. This function loads that 416 tracker's configuration so still images can be segmented from a click. 417 418 Args: 419 model_dir (str, optional): Path to a local directory containing 420 `tracker_config.json`, used to override the bundled 421 configuration. Default is None. 422 423 Raises: 424 FileNotFoundError: If the offline `tracker_config.json` cannot be located. 425 ImportError: If the installed transformers release does not provide SAM 3. 426 427 Returns: 428 Sam3TrackerConfig: The configuration for `Sam3TrackerModel`. 429 """ 430 variant_dir = _variant_dir("sam3", model_dir) 431 config_path = os.path.join(variant_dir, "tracker_config.json") 432 433 if not os.path.exists(config_path): 434 # A directly downloaded SAM 3 release nests it inside the video config. 435 fallback = os.path.join(variant_dir, "config.json") 436 if os.path.exists(fallback): 437 with open(fallback, "r") as f: 438 nested = json.load(f).get("tracker_config") 439 if isinstance(nested, dict): 440 return _resolve("Sam3TrackerConfig").from_dict(nested) 441 raise FileNotFoundError(f"Offline tracker config missing at {config_path}.") 442 443 with open(config_path, "r") as f: 444 config_dict = json.load(f) 445 446 return _resolve("Sam3TrackerConfig").from_dict(config_dict)
Reads and loads the bundled configuration for SAM 3's point-promptable tracker.
SAM 3's image model is an open-vocabulary detector prompted by text or boxes, and does not accept points. The release also contains a tracker, whose prompt encoder is the SAM-style one that understands points, boxes and masks. This function loads that tracker's configuration so still images can be segmented from a click.
Arguments:
- model_dir (str, optional): Path to a local directory containing
tracker_config.json, used to override the bundled configuration. Default is None.
Raises:
- FileNotFoundError: If the offline
tracker_config.jsoncannot be located. - ImportError: If the installed transformers release does not provide SAM 3.
Returns:
Sam3TrackerConfig: The configuration for
Sam3TrackerModel.
449def load_sam3_tracker_processor(): 450 """ 451 Builds the processor for SAM 3's point-promptable tracker. 452 453 The tracker takes only geometric prompts, so unlike `load_sam_processor("sam3")` no 454 tokenizer is involved. The image processor is constructed from its defaults, which 455 keeps loading fully offline. 456 457 Raises: 458 ImportError: If the installed transformers release does not provide SAM 3. 459 460 Returns: 461 Sam3TrackerProcessor: The processor for `Sam3TrackerModel`. 462 """ 463 image_processor = _resolve("Sam3ImageProcessor")() 464 return _resolve("Sam3TrackerProcessor")(image_processor=image_processor)
Builds the processor for SAM 3's point-promptable tracker.
The tracker takes only geometric prompts, so unlike load_sam_processor("sam3") no
tokenizer is involved. The image processor is constructed from its defaults, which
keeps loading fully offline.
Raises:
- ImportError: If the installed transformers release does not provide SAM 3.
Returns:
Sam3TrackerProcessor: The processor for
Sam3TrackerModel.
142def sam_family(model_type: str) -> str: 143 """ 144 Returns the Segment Anything family a variant belongs to. 145 146 Args: 147 model_type (str): A SAM variant identifier, e.g. `"sam-vit-b"`, 148 `"sam2.1-hiera-tiny"`, or `"sam3"`. 149 150 Raises: 151 ValueError: If `model_type` is not a recognised SAM variant. 152 153 Returns: 154 str: One of `"sam1"`, `"sam2"`, or `"sam3"`. 155 """ 156 for family, spec in SAM_FAMILIES.items(): 157 if model_type in spec["models"]: 158 return family 159 raise ValueError( 160 f"Invalid model_type '{model_type}'. Choose from: {ALL_SAM_MODELS}" 161 )
Returns the Segment Anything family a variant belongs to.
Arguments:
- model_type (str): A SAM variant identifier, e.g.
"sam-vit-b","sam2.1-hiera-tiny", or"sam3".
Raises:
- ValueError: If
model_typeis not a recognised SAM variant.
Returns:
str: One of
"sam1","sam2", or"sam3".
164def sam_capabilities(model_type: str) -> dict: 165 """ 166 Reports which prompt types a SAM variant accepts natively. 167 168 Args: 169 model_type (str): A SAM variant identifier, e.g. `"sam-vit-b"` or `"sam3"`. 170 171 Raises: 172 ValueError: If `model_type` is not a recognised SAM variant. 173 174 Returns: 175 dict: Mapping of `"points"`, `"labels"`, `"boxes"`, and `"text"` to booleans. 176 SAM 1 and SAM 2 report `text=False` because they contain no text encoder, 177 and SAM 3 reports `points=False` because it accepts only text and box prompts. 178 """ 179 return dict(SAM_CAPABILITIES[sam_family(model_type)])
Reports which prompt types a SAM variant accepts natively.
Arguments:
- model_type (str): A SAM variant identifier, e.g.
"sam-vit-b"or"sam3".
Raises:
- ValueError: If
model_typeis not a recognised SAM variant.
Returns:
dict: Mapping of
"points","labels","boxes", and"text"to booleans. SAM 1 and SAM 2 reporttext=Falsebecause they contain no text encoder, and SAM 3 reportspoints=Falsebecause it accepts only text and box prompts.
182def sam_model_class(model_type: str): 183 """ 184 Returns the Hugging Face model class matching a SAM variant. 185 186 Args: 187 model_type (str): A SAM variant identifier, e.g. `"sam2.1-hiera-tiny"`. 188 189 Raises: 190 ValueError: If `model_type` is not a recognised SAM variant. 191 192 Returns: 193 type: `SamModel`, `Sam2Model`, or `Sam3Model`. 194 """ 195 return _resolve(SAM_FAMILIES[sam_family(model_type)]["model_class"])
Returns the Hugging Face model class matching a SAM variant.
Arguments:
- model_type (str): A SAM variant identifier, e.g.
"sam2.1-hiera-tiny".
Raises:
- ValueError: If
model_typeis not a recognised SAM variant.
Returns:
type:
SamModel,Sam2Model, orSam3Model.