Skip to content

recommender

sleap_nn.config_generator.recommender

Pipeline and parameter recommendation logic.

This module provides intelligent recommendations for training configuration based on dataset statistics extracted from SLP files.

Classes:

Name Description
ConfigRecommendation

Complete configuration recommendation.

PipelineRecommendation

Recommendation for which pipeline to use.

Functions:

Name Description
recommend_config

Generate complete configuration recommendation.

recommend_pipeline

Recommend the best pipeline based on dataset statistics.

ConfigRecommendation dataclass

Complete configuration recommendation.

Attributes:

Name Type Description
pipeline PipelineRecommendation

Pipeline recommendation.

backbone BackboneType

Recommended backbone architecture.

backbone_reason str

Explanation for backbone choice.

sigma float

Recommended sigma value for confidence maps.

sigma_reason str

Explanation for sigma choice.

input_scale float

Recommended input scaling factor.

scale_reason str

Explanation for scale choice.

batch_size int

Recommended batch size.

batch_reason str

Explanation for batch size choice.

rotation_range Tuple[float, float]

Recommended rotation augmentation range (min, max).

rotation_reason str

Explanation for rotation choice.

crop_size Optional[int]

Recommended crop size for centered_instance models.

anchor_part Optional[str]

Recommended anchor part for top-down models.

Source code in sleap_nn/config_generator/recommender.py
@dataclass
class ConfigRecommendation:
    """Complete configuration recommendation.

    Attributes:
        pipeline: Pipeline recommendation.
        backbone: Recommended backbone architecture.
        backbone_reason: Explanation for backbone choice.
        sigma: Recommended sigma value for confidence maps.
        sigma_reason: Explanation for sigma choice.
        input_scale: Recommended input scaling factor.
        scale_reason: Explanation for scale choice.
        batch_size: Recommended batch size.
        batch_reason: Explanation for batch size choice.
        rotation_range: Recommended rotation augmentation range (min, max).
        rotation_reason: Explanation for rotation choice.
        crop_size: Recommended crop size for centered_instance models.
        anchor_part: Recommended anchor part for top-down models.
    """

    pipeline: PipelineRecommendation
    backbone: BackboneType
    backbone_reason: str
    sigma: float
    sigma_reason: str
    input_scale: float
    scale_reason: str
    batch_size: int
    batch_reason: str
    rotation_range: Tuple[float, float]
    rotation_reason: str
    crop_size: Optional[int] = None
    anchor_part: Optional[str] = None

PipelineRecommendation dataclass

Recommendation for which pipeline to use.

Attributes:

Name Type Description
recommended PipelineType

The recommended pipeline type.

reason str

Human-readable explanation for the recommendation.

alternatives List[PipelineType]

List of alternative pipeline types.

warnings List[str]

List of warning messages.

requires_second_model bool

Whether top-down requires a second model.

second_model_type Optional[PipelineType]

The type of the second model (if required).

Source code in sleap_nn/config_generator/recommender.py
@dataclass
class PipelineRecommendation:
    """Recommendation for which pipeline to use.

    Attributes:
        recommended: The recommended pipeline type.
        reason: Human-readable explanation for the recommendation.
        alternatives: List of alternative pipeline types.
        warnings: List of warning messages.
        requires_second_model: Whether top-down requires a second model.
        second_model_type: The type of the second model (if required).
    """

    recommended: PipelineType
    reason: str
    alternatives: List[PipelineType] = field(default_factory=list)
    warnings: List[str] = field(default_factory=list)
    requires_second_model: bool = False
    second_model_type: Optional[PipelineType] = None

recommend_config(stats, view_type=ViewType.UNKNOWN)

Generate complete configuration recommendation.

Parameters:

Name Type Description Default
stats DatasetStats

DatasetStats from analyze_slp().

required
view_type ViewType

Camera view (side, top, or unknown).

UNKNOWN

Returns:

Type Description
ConfigRecommendation

ConfigRecommendation with all parameter suggestions.

Example

stats = analyze_slp("labels.slp") rec = recommend_config(stats, ViewType.TOP) print(f"Pipeline: {rec.pipeline.recommended}") print(f"Backbone: {rec.backbone}")

Source code in sleap_nn/config_generator/recommender.py
def recommend_config(
    stats: DatasetStats, view_type: ViewType = ViewType.UNKNOWN
) -> ConfigRecommendation:
    """Generate complete configuration recommendation.

    Args:
        stats: DatasetStats from analyze_slp().
        view_type: Camera view (side, top, or unknown).

    Returns:
        ConfigRecommendation with all parameter suggestions.

    Example:
        >>> stats = analyze_slp("labels.slp")
        >>> rec = recommend_config(stats, ViewType.TOP)
        >>> print(f"Pipeline: {rec.pipeline.recommended}")
        >>> print(f"Backbone: {rec.backbone}")
    """
    pipeline = recommend_pipeline(stats)
    backbone, backbone_reason = _recommend_backbone(stats)
    sigma, sigma_reason = _recommend_sigma(stats, pipeline.recommended)
    input_scale, scale_reason = _recommend_scale(stats)
    batch_size, batch_reason = _recommend_batch_size(stats, backbone)
    rotation_range, rotation_reason = _recommend_rotation(view_type)

    # Crop size for centered instance
    crop_size = None
    if pipeline.recommended in ["centered_instance", "multi_class_topdown"] or (
        pipeline.requires_second_model
        and pipeline.second_model_type == "centered_instance"
    ):
        # Rough estimate: 1.5x max bbox, rounded up to stride
        raw_crop = int(stats.max_bbox_size * 1.5)
        max_stride = 32 if "large_rf" in backbone else 16
        crop_size = ((raw_crop + max_stride - 1) // max_stride) * max_stride
        crop_size = max(crop_size, 100)  # Minimum crop size

    return ConfigRecommendation(
        pipeline=pipeline,
        backbone=backbone,
        backbone_reason=backbone_reason,
        sigma=sigma,
        sigma_reason=sigma_reason,
        input_scale=input_scale,
        scale_reason=scale_reason,
        batch_size=batch_size,
        batch_reason=batch_reason,
        rotation_range=rotation_range,
        rotation_reason=rotation_reason,
        crop_size=crop_size,
        anchor_part=None,  # User should specify based on skeleton
    )

recommend_pipeline(stats)

Recommend the best pipeline based on dataset statistics.

Decision tree: 1. Single animal per frame -> single_instance 2. Multiple small animals (<20% frame area) -> top-down (centroid) 3. Multiple large animals with edges -> bottomup 4. Multiple large animals without edges -> top-down (centroid)

Note: Multi-class models are available as alternatives when tracks exist, but are not recommended by default.

Parameters:

Name Type Description Default
stats DatasetStats

DatasetStats from analyze_slp().

required

Returns:

Type Description
PipelineRecommendation

PipelineRecommendation with suggested pipeline and reasoning.

Example

stats = analyze_slp("labels.slp") rec = recommend_pipeline(stats) print(f"Use {rec.recommended}: {rec.reason}")

Source code in sleap_nn/config_generator/recommender.py
def recommend_pipeline(stats: DatasetStats) -> PipelineRecommendation:
    """Recommend the best pipeline based on dataset statistics.

    Decision tree:
    1. Single animal per frame -> single_instance
    2. Multiple small animals (<20% frame area) -> top-down (centroid)
    3. Multiple large animals with edges -> bottomup
    4. Multiple large animals without edges -> top-down (centroid)

    Note: Multi-class models are available as alternatives when tracks exist,
    but are not recommended by default.

    Args:
        stats: DatasetStats from analyze_slp().

    Returns:
        PipelineRecommendation with suggested pipeline and reasoning.

    Example:
        >>> stats = analyze_slp("labels.slp")
        >>> rec = recommend_pipeline(stats)
        >>> print(f"Use {rec.recommended}: {rec.reason}")
    """
    warnings: List[str] = []

    # Single instance case
    if stats.is_single_instance:
        return PipelineRecommendation(
            recommended="single_instance",
            reason="Only one animal detected per frame",
            alternatives=["centered_instance"],
            warnings=[],
            requires_second_model=False,
        )

    # Multi-instance with a single-node skeleton: there are no keypoints to
    # crop-and-refine, so the only meaningful detection target is the centroid
    # itself. Recommend a STANDALONE centroid model (one config, no second
    # centered-instance stage) rather than the paired top-down bundle.
    if stats.num_nodes == 1:
        single_node_alternatives: List[PipelineType] = ["bottomup"]
        if stats.has_identity:
            single_node_alternatives.append("multi_class_bottomup")
        return PipelineRecommendation(
            recommended="centroid_only",
            reason="Single-node skeleton - a standalone centroid model detects "
            "the one point per animal directly (no second model needed)",
            alternatives=single_node_alternatives,
            warnings=[],
            requires_second_model=False,
        )

    # Multi-instance: small animals -> top-down
    if stats.animal_to_frame_ratio < 0.20:
        # Small animals - recommend top-down
        alternatives: List[PipelineType] = ["bottomup"]
        if stats.has_identity:
            alternatives.append("multi_class_topdown")
        return PipelineRecommendation(
            recommended="centroid",
            reason=f"Animals are small relative to frame (~{int(stats.animal_to_frame_ratio * 100)}% area) - "
            "top-down approach recommended",
            alternatives=alternatives,
            warnings=["You'll need to train a centered_instance model as well"],
            requires_second_model=True,
            second_model_type="centered_instance",
        )
    else:
        # Large animals
        if stats.num_edges == 0:
            # No edges - can't use bottom-up
            warnings.append("No edges in skeleton - bottom-up requires edges for PAFs")
            alternatives = []
            if stats.has_identity:
                alternatives.append("multi_class_topdown")
            return PipelineRecommendation(
                recommended="centroid",
                reason="No skeleton edges available for bottom-up",
                alternatives=alternatives,
                warnings=warnings,
                requires_second_model=True,
                second_model_type="centered_instance",
            )
        # Has edges - recommend bottom-up
        alternatives = ["centroid"]
        if stats.has_identity:
            alternatives.append("multi_class_bottomup")
        return PipelineRecommendation(
            recommended="bottomup",
            reason=f"Larger animals (~{int(stats.animal_to_frame_ratio * 100)}% of frame) - "
            "bottom-up handles occlusions well",
            alternatives=alternatives,
            warnings=[],
            requires_second_model=False,
        )