apocaliss92's picture
camstack-train 0.1.0: YOLOv9 root detector fine-tune (job.json in, result.json + bundle.tar out)
ebeed67 verified
Raw History Blame Contribute Delete
2.73 kB
"""The D739 floor rule (docs/decisions/adr-0739-*.md).
A model's floor for a class is the LOWEST confidence at which it raises no more
false positives on the evaluation set than the baseline does at the baseline's
shipped floor — so switching model keeps the false-alert rate and changes only
what is found. On a small or fine-tuned set two guards apply:
- **support**: a class with fewer than ``min_support`` ground-truth positives
inherits the baseline floor (a floor fitted on a handful of boxes is noise);
- **clamp**: the floor stays within ``±clamp`` of the baseline floor (single
digit false-positive counts carry ±0.05–0.10 of noise).
Floors are on a ``grid_step`` grid and never below ``minimum``, as in the
2026-10-07 calibration.
"""
from __future__ import annotations
from dataclasses import dataclass
from typing import Literal, Optional, Sequence
FloorReason = Literal["fp-budget", "low-support", "clamped"]
@dataclass(frozen=True)
class ScoredDetection:
score: float
true_positive: bool
@dataclass(frozen=True)
class FloorPolicy:
min_support: int = 20
clamp: float = 0.15
grid_step: float = 0.05
minimum: float = 0.25
maximum: float = 0.95
@dataclass(frozen=True)
class ProposedFloor:
value: float
reason: FloorReason
fp_budget: int
#: The unclamped fit, ``None`` when no grid floor meets the budget.
fitted: Optional[float]
def false_positives_at(detections: Sequence[ScoredDetection], floor: float) -> int:
return sum(1 for d in detections if not d.true_positive and d.score >= floor - 1e-9)
def _grid(policy: FloorPolicy) -> list[float]:
steps = int(round((policy.maximum - policy.minimum) / policy.grid_step))
return [round(policy.minimum + i * policy.grid_step, 4) for i in range(steps + 1)]
def propose_floor(
baseline: Sequence[ScoredDetection],
baseline_floor: float,
candidate: Sequence[ScoredDetection],
positives: int,
policy: FloorPolicy = FloorPolicy(),
) -> ProposedFloor:
budget = false_positives_at(baseline, baseline_floor)
if positives < policy.min_support:
return ProposedFloor(baseline_floor, "low-support", budget, None)
fitted = next(
(t for t in _grid(policy) if false_positives_at(candidate, t) <= budget),
None,
)
low = round(max(policy.minimum, baseline_floor - policy.clamp), 4)
high = round(baseline_floor + policy.clamp, 4)
if fitted is None:
return ProposedFloor(high, "clamped", budget, None)
if fitted < low:
return ProposedFloor(low, "clamped", budget, fitted)
if fitted > high:
return ProposedFloor(high, "clamped", budget, fitted)
return ProposedFloor(fitted, "fp-budget", budget, fitted)