feat(perception): prewarm RF-DETR before source admission

This commit is contained in:
DCCONSTRUCTIONS
2026-08-25 19:09:53 +03:00
parent 477886d100
commit 84624ae3ea
4 changed files with 124 additions and 24 deletions
+70
View File
@@ -101,6 +101,31 @@ class DetectorFrameTiming:
DetectorTimingObserver = Callable[[DetectorFrameTiming], None]
@dataclass(frozen=True, slots=True)
class DetectorWarmupSnapshot:
completed: bool
inference_passes: int
preprocess_duration_ns: int
inference_transport_duration_ns: int
postprocess_duration_ns: int
total_duration_ns: int
def __post_init__(self) -> None:
durations = (
self.preprocess_duration_ns,
self.inference_transport_duration_ns,
self.postprocess_duration_ns,
self.total_duration_ns,
)
if (
self.completed is not True
or self.inference_passes != 1
or any(value < 0 for value in durations)
or sum(durations[:3]) != self.total_duration_ns
):
raise DetectorProviderError("detector warmup snapshot is incompatible")
class FrozenYoloxDetectorProvider:
"""One image payload produces one frozen inference request and proposal tuple."""
@@ -259,6 +284,50 @@ class RfDetrShadowDetectorProvider:
self._proposal_count = 0
self._rejected: Counter[str] = Counter()
self._core_duration_ns = 0
self._warmup_started = False
self._warmup_snapshot: DetectorWarmupSnapshot | None = None
def warm_up(self) -> DetectorWarmupSnapshot:
"""Prime preprocessing, transport and postprocessing before source admission."""
with self._lock:
if self._warmup_snapshot is not None:
return self._warmup_snapshot
if self._warmup_started:
raise DetectorProviderError("RF-DETR warmup is already in progress")
self._warmup_started = True
started_ns = int(self._clock_ns())
try:
image = np.zeros(
(self.config.source_height, self.config.source_width, 3),
dtype=np.uint8,
)
tensor = preprocess_raw_kb4_rf_detr(
image,
self.mask,
config=self.config,
resizer=self.resizer,
)
preprocessed_ns = int(self._clock_ns())
output = self.backend.infer(tensor)
inferred_ns = int(self._clock_ns())
postprocess_rf_detr(output, self.mask, config=self.config)
completed_ns = int(self._clock_ns())
except Exception:
with self._lock:
self._warmup_started = False
raise
snapshot = DetectorWarmupSnapshot(
completed=True,
inference_passes=1,
preprocess_duration_ns=max(0, preprocessed_ns - started_ns),
inference_transport_duration_ns=max(0, inferred_ns - preprocessed_ns),
postprocess_duration_ns=max(0, completed_ns - inferred_ns),
total_duration_ns=max(0, completed_ns - started_ns),
)
with self._lock:
self._warmup_snapshot = snapshot
return snapshot
def detect(self, packet: SourcePacket) -> tuple[ObjectProposal2D, ...]:
payload = packet.image_payload
@@ -357,6 +426,7 @@ __all__ = [
"DetectorProviderSnapshot",
"DetectorFrameTiming",
"DetectorTimingObserver",
"DetectorWarmupSnapshot",
"AllCocoYoloxDetectorProvider",
"FrozenYoloxDetectorProvider",
"RfDetrShadowDetectorProvider",