diff --git a/frigate/config.py b/frigate/config.py index 2e8b25700..387927c6b 100644 --- a/frigate/config.py +++ b/frigate/config.py @@ -1287,44 +1287,59 @@ class FrigateConfig(FrigateBaseModel): config.model.check_and_load_plus_model(plus_api) for key, detector in config.detectors.items(): - detector_config: DetectorConfig = parse_obj_as(DetectorConfig, detector) - if detector_config.model is None: - detector_config.model = config.model - else: - model = detector_config.model - schema = ModelConfig.schema()["properties"] - if ( - model.width != schema["width"]["default"] - or model.height != schema["height"]["default"] - or model.labelmap_path is not None - or model.labelmap is not {} - or model.input_tensor != schema["input_tensor"]["default"] - or model.input_pixel_format - != schema["input_pixel_format"]["default"] - ): - logger.warning( - "Customizing more than a detector model path is unsupported." - ) - merged_model = deep_merge( - detector_config.model.dict(exclude_unset=True), - config.model.dict(exclude_unset=True), + config.detectors[key] = self.generate_detector_config( + config, detector, plus_api ) - if "path" not in merged_model: - if detector_config.type == "cpu": - merged_model["path"] = "/cpu_model.tflite" - elif detector_config.type == "edgetpu": - merged_model["path"] = "/edgetpu_model.tflite" - - detector_config.model = ModelConfig.parse_obj(merged_model) - detector_config.model.check_and_load_plus_model( - plus_api, detector_config.type - ) - detector_config.model.compute_model_hash() - config.detectors[key] = detector_config - return config + def generate_detector_config(self, config: FrigateConfig, detector, plus_api): + detector_config: DetectorConfig = parse_obj_as(DetectorConfig, detector) + if detector_config.model is None: + detector_config.model = config.model + else: + model = detector_config.model + schema = ModelConfig.schema()["properties"] + if ( + model.width != schema["width"]["default"] + or model.height != schema["height"]["default"] + or model.labelmap_path is not None + or model.labelmap is not {} + or model.input_tensor != schema["input_tensor"]["default"] + or model.input_pixel_format + != schema["input_pixel_format"]["default"] + ): + logger.warning( + "Customizing more than a detector model path is unsupported." + ) + merged_model = deep_merge( + detector_config.model.dict(exclude_unset=True), + config.model.dict(exclude_unset=True), + ) + + if "path" not in merged_model: + if detector_config.type == "cpu": + merged_model["path"] = "/cpu_model.tflite" + elif detector_config.type == "edgetpu": + merged_model["path"] = "/edgetpu_model.tflite" + + detector_config.model = ModelConfig.parse_obj(merged_model) + detector_config.model.check_and_load_plus_model( + plus_api, detector_config.type + ) + detector_config.model.compute_model_hash() + + if detector_config.type != "cpu": + fallback_config = config.copy(deep=True) + fallback_config.model = ModelConfig() + detector_config.fallback_config = self.generate_detector_config( + fallback_config, + parse_obj_as(DetectorConfig, DEFAULT_DETECTORS["cpu"]), + plus_api, + ) + + return detector_config + @validator("cameras") def ensure_zones_and_cameras_have_different_names(cls, v: Dict[str, CameraConfig]): zones = [zone for camera in v.values() for zone in camera.zones.keys()] diff --git a/frigate/object_detection.py b/frigate/object_detection.py index 9d00dca46..cb1dca624 100644 --- a/frigate/object_detection.py +++ b/frigate/object_detection.py @@ -81,6 +81,7 @@ def run_detector( out_events: dict[str, mp.Event], avg_speed, start, + using_fallback_detector, detector_config, ): threading.current_thread().name = f"detector:{name}" @@ -99,7 +100,14 @@ def run_detector( signal.signal(signal.SIGINT, receiveSignal) frame_manager = SharedMemoryFrameManager() - object_detector = LocalObjectDetector(detector_config=detector_config) + try: + object_detector = LocalObjectDetector(detector_config=detector_config) + except Exception as ex: + logger.error(f"Got exception when initializing detector: {ex}, falling back to CPU detector") + + object_detector = LocalObjectDetector(detector_config=detector_config.fallback_config) + using_fallback_detector.value = 1 + outputs = {} for name in out_events.keys(): @@ -146,6 +154,7 @@ class ObjectDetectProcess: self.detection_queue = detection_queue self.avg_inference_speed = mp.Value("d", 0.01) self.detection_start = mp.Value("d", 0.0) + self.using_fallback_detector = mp.Value("i", 0) self.detect_process = None self.detector_config = detector_config self.start_or_restart() @@ -176,6 +185,7 @@ class ObjectDetectProcess: self.out_events, self.avg_inference_speed, self.detection_start, + self.using_fallback_detector, self.detector_config, ), ) diff --git a/frigate/stats.py b/frigate/stats.py index addcd4a5b..fc6e3e386 100644 --- a/frigate/stats.py +++ b/frigate/stats.py @@ -284,6 +284,7 @@ def stats_snapshot( # issue https://github.com/python/typeshed/issues/8799 # from mypy 0.981 onwards "pid": pid, + "using_fallback_detector": bool(detector.using_fallback_detector.value), } stats["detection_fps"] = round(total_detection_fps, 2) diff --git a/web/src/routes/System.jsx b/web/src/routes/System.jsx index 77b37686f..e5d944e57 100644 --- a/web/src/routes/System.jsx +++ b/web/src/routes/System.jsx @@ -232,7 +232,7 @@ export default function System() {
{detectorNames.map((detector) => (
-
{detector}
+
{detector}{detectors[detector]['using_fallback_detector'] ? " - CPU FALLBACK MODE" : ""}