Download code/conftest.py from changh95/sam3-p150: direct link, hf CLI and curl.
- Browser
- Download file 5.46 kB
-
https://huggingface.co/changh95/sam3-p150/resolve/main/code/conftest.py
- Command line
-
hf download hf://changh95/sam3-p150/code/conftest.py
-
curl -L -o conftest.py https://huggingface.co/changh95/sam3-p150/resolve/main/code/conftest.py
5.46 kB
| # SPDX-FileCopyrightText: (c) 2026 Tenstorrent AI ULC | |
| # SPDX-License-Identifier: Apache-2.0 | |
| """Minimal pytest fixtures for tt-sam3. | |
| Provides a ``device`` fixture and a ``sam3_model`` fixture so the tt_sam3 tests | |
| can be run without the tt-metal monorepo's own conftest.py. The device is | |
| selected with ``SAM3_DEVICE`` env var (default 0). | |
| """ | |
| from __future__ import annotations | |
| import gc | |
| import os | |
| import unittest.mock as mock | |
| import pytest | |
| import torch | |
| def _gc_between_tests(): | |
| gc.collect() | |
| def reset_seeds(): | |
| """tt-metal's root conftest fixture the legacy tests request (deterministic random inputs).""" | |
| torch.manual_seed(213919) | |
| def device_params(request): | |
| """The legacy tests parametrize ``device_params`` indirectly (``{"l1_small_size": 32768}``, tt-metal's | |
| root conftest contract). Session-scoped like ``device`` (every test here passes the same value, so the | |
| device is opened once per session); ``{}`` for tests that do not parametrize it.""" | |
| return getattr(request, "param", {}) | |
| def device(device_params): | |
| """Opens the device the way the server / benchmark do (``tt_sam3.tt.fused_config.device_open_kwargs``): | |
| bare unless the test's ``device_params`` ask for ``l1_small_size`` (the legacy PCC tests: 32768) or | |
| ``SAM3_L1_SMALL_SIZE`` overrides it (``0`` = the served bare configuration), and the trace region | |
| whenever ``TT_FUSED=1`` selects the fused encoder trace.""" | |
| import ttnn | |
| from tt_sam3.tt.fused_config import FusedConfig, device_open_kwargs | |
| device_id = int(os.environ.get("SAM3_DEVICE", "0")) | |
| env_l1 = os.environ.get("SAM3_L1_SMALL_SIZE") | |
| l1_small = int(env_l1) if env_l1 is not None else int(device_params.get("l1_small_size", 0)) | |
| from tt_sam3.tt.device_open import open_device | |
| # default ETH dispatch + 1 CQ + 12x10 grid (SAM3_DISPATCH=auto), as the server and the Python API | |
| dev = open_device(device_open_kwargs(FusedConfig.from_env(), device_id=device_id, l1_small_size=l1_small), | |
| os.environ.get("SAM3_DISPATCH", "auto"))[0] | |
| yield dev | |
| ttnn.close_device(dev) | |
| def _patch_cuda_to_cpu(): | |
| """Context-manager-free CUDA→CPU patching for SAM3 model loading.""" | |
| orig = { | |
| n: getattr(torch, n) | |
| for n in [ | |
| "zeros", "ones", "arange", "empty", "full", "randn", | |
| "rand", "tensor", "linspace", "logspace", "eye", | |
| ] | |
| } | |
| def _redirect(fn): | |
| def wrapper(*args, **kwargs): | |
| if "device" in kwargs and kwargs["device"] is not None and "cuda" in str(kwargs["device"]): | |
| kwargs["device"] = "cpu" | |
| return fn(*args, **kwargs) | |
| return wrapper | |
| patches = [mock.patch("torch.cuda.is_available", return_value=False)] | |
| for name, fn in orig.items(): | |
| patches.append(mock.patch(f"torch.{name}", _redirect(fn))) | |
| return patches | |
| def _resolve_pinned_checkpoint(): | |
| """``sam3.pt`` the way the server resolves it: ``SAM3_WEIGHTS_DIR`` (offline dir) or the HF cache at | |
| ``TT_WEIGHTS_REVISION``; None when neither is set (sam3 then downloads ``facebook/sam3@main``).""" | |
| weights_dir = os.environ.get("SAM3_WEIGHTS_DIR") | |
| if weights_dir: | |
| return os.path.join(weights_dir, "sam3.pt") | |
| revision = os.environ.get("TT_WEIGHTS_REVISION") | |
| if revision: | |
| from huggingface_hub import hf_hub_download | |
| return hf_hub_download(repo_id="facebook/sam3", filename="sam3.pt", revision=revision) | |
| return None | |
| def _build_sam3_cpu(use_pretrained=False): | |
| # SAM3_BPE_PATH > vendored tt_sam3/assets copy > legacy open_clip path (see tt_sam3.tt.ttnn_sam3_model) | |
| from tt_sam3.tt.ttnn_sam3_model import resolve_bpe_path | |
| bpe_path = resolve_bpe_path() | |
| # --pretrained honours the served pin (TT_WEIGHTS_REVISION / SAM3_WEIGHTS_DIR) instead of facebook/sam3@main | |
| checkpoint_path = _resolve_pinned_checkpoint() if use_pretrained else None | |
| patches = _patch_cuda_to_cpu() | |
| for p in patches: | |
| p.start() | |
| try: | |
| from sam3.model_builder import build_sam3_image_model | |
| model = build_sam3_image_model( | |
| bpe_path=bpe_path, | |
| device="cpu", | |
| eval_mode=True, | |
| load_from_HF=bool(use_pretrained) and checkpoint_path is None, | |
| checkpoint_path=checkpoint_path, | |
| enable_segmentation=True, | |
| enable_inst_interactivity=False, | |
| ) | |
| finally: | |
| for p in patches: | |
| p.stop() | |
| return model | |
| def sam3_model(): | |
| return _build_sam3_cpu(use_pretrained=False) | |
| def sam3_reference_model(sam3_model): | |
| """Alias the segmentation tests request (random-weight shadow, as ``sam3_model``).""" | |
| return sam3_model | |
| def sam3_vit_backbone(sam3_model): | |
| from sam3.model.vitdet import ViT | |
| for _, module in sam3_model.named_modules(): | |
| if isinstance(module, ViT): | |
| return module | |
| raise RuntimeError("Could not find ViT backbone in SAM3 model") | |
| def sam3_neck(sam3_model): | |
| from sam3.model.necks import Sam3DualViTDetNeck | |
| for _, module in sam3_model.named_modules(): | |
| if isinstance(module, Sam3DualViTDetNeck): | |
| return module | |
| raise RuntimeError("Could not find neck in SAM3 model") | |