Source code for phenotypic.abc_._gpu_detector

from __future__ import annotations

from abc import ABC, abstractmethod
from typing import TYPE_CHECKING, overload

if TYPE_CHECKING:
    from phenotypic._core._image import Image
    from phenotypic._core._grid_image import GridImage

from ._object_detector import ObjectDetector


# <<Interface>>
[docs] class GpuDetector(ObjectDetector, ABC): """Marker ABC for object detectors that require GPU acceleration. Subclass GpuDetector when your detection algorithm depends on a GPU (e.g., deep-learning foundation models like SAM2 or micro-sam). When a pipeline contains a GpuDetector, the CLI enforces: - **Local execution:** Sequential processing (n_jobs=1) to avoid multiple workers competing for the same GPU. - **SLURM execution:** Automatically requests GPU resources (``--gpus-per-node=1``) if the user hasn't specified GPU args. Raises an error if the target partition has no GPUs. - **No GPU available:** Raises RuntimeError at pipeline validation time with a clear message. **When to subclass GpuDetector vs ObjectDetector** Subclass GpuDetector if your detector relies on GPU-accelerated inference: - Deep-learning models (SAM2, micro-sam, or custom neural networks). - Any algorithm that requires ``torch``, ``tensorflow``, or similar GPU-backed frameworks at inference time. - Detectors where CPU fallback is technically possible but impractically slow for production use. Subclass ObjectDetector directly if your algorithm is CPU-based: - Classical computer vision (thresholding, edge detection, watershed). - Algorithms implemented with NumPy, SciPy, or scikit-image. - Detectors that run in milliseconds on CPU. **Lazy model loading** GpuDetector subclasses should defer model construction to the first ``apply()`` call rather than ``__init__()``. This enables: - Fast construction and serialization round-trips without GPU/torch. - Pipeline ``to_json()``/``from_json()`` without importing heavy dependencies. - Parameter inspection and validation before committing GPU memory. Use a ``_ensure_model_loaded()`` pattern:: class MyGpuDetector(GpuDetector): def __init__(self, model_size="small", device="auto"): super().__init__() self.model_size = model_size self.device = device self._model = None # underscore prefix → skipped by serialization def _ensure_model_loaded(self): if getattr(self, "_model", None) is not None: return import torch # lazy import # ... build model ... def _operate(self, image): self._ensure_model_loaded() # ... run inference ... return image Notes: This is a marker ABC with no additional methods beyond those inherited from ObjectDetector. It exists to categorize GPU-requiring detectors in the class hierarchy and enable the CLI to make informed resource-allocation decisions. """ @overload @abstractmethod def _operate(self, image: Image) -> Image: ... @overload @abstractmethod def _operate(self, image: GridImage) -> GridImage: ... @abstractmethod def _operate(self, image: Image) -> Image: return image