Compare commits

..

4 Commits

Author SHA1 Message Date
Dan Brown
97a5f3092d remove tip that indicates other YOLO models may be supported. 2025-12-02 21:16:27 +01:00
Dan Brown
756573313e remove unused import and variable 2025-12-02 21:10:05 +01:00
Dan Brown
f5f84a3c53 fix formatting 2025-12-02 21:02:01 +01:00
Dan Brown
6ee36d6ffc check for valid model type 2025-12-02 20:02:40 +01:00
2 changed files with 18 additions and 31 deletions

View File

@ -161,12 +161,6 @@ A Tensorflow Lite is provided in the container at `/openvino-model/ssdlite_mobil
[YOLOv9](https://github.com/dbro/frigate-detector-edgetpu-yolo9/releases/download/v1.0/yolov9-s-relu6-best_320_int8_edgetpu.tflite) models that are compiled for Tensorflow Lite and properly quantized are supported, but not included by default. To provide your own model, bind mount the file into the container and provide the path with `model.path`. Note that the model may require a custom label file (eg. [use this 17 label file](https://raw.githubusercontent.com/dbro/frigate-detector-edgetpu-yolo9/refs/heads/main/labels-coco17.txt) for the model linked above.) [YOLOv9](https://github.com/dbro/frigate-detector-edgetpu-yolo9/releases/download/v1.0/yolov9-s-relu6-best_320_int8_edgetpu.tflite) models that are compiled for Tensorflow Lite and properly quantized are supported, but not included by default. To provide your own model, bind mount the file into the container and provide the path with `model.path`. Note that the model may require a custom label file (eg. [use this 17 label file](https://raw.githubusercontent.com/dbro/frigate-detector-edgetpu-yolo9/refs/heads/main/labels-coco17.txt) for the model linked above.)
:::tip
The YOLO detector has been designed to support YOLOv9 models, and may support other YOLO model architectures as well.
:::
<details> <details>
<summary>YOLOv9 Setup & Config</summary> <summary>YOLOv9 Setup & Config</summary>

View File

@ -9,7 +9,6 @@ from typing_extensions import Literal
from frigate.detectors.detection_api import DetectionApi from frigate.detectors.detection_api import DetectionApi
from frigate.detectors.detector_config import BaseDetectorConfig, ModelTypeEnum from frigate.detectors.detector_config import BaseDetectorConfig, ModelTypeEnum
from frigate.util.model import post_process_yolo
try: try:
from tflite_runtime.interpreter import Interpreter, load_delegate from tflite_runtime.interpreter import Interpreter, load_delegate
@ -114,9 +113,7 @@ class EdgeTpuTfl(DetectionApi):
# to differentiate from (not used) max score tensor # to differentiate from (not used) max score tensor
output_classes_index = i output_classes_index = i
if output_boxes_index is None or output_classes_index is None: if output_boxes_index is None or output_classes_index is None:
logger.warning( logger.warning("Unrecognized model output, unexpected tensor shapes.")
"Unrecognized model output, unexpected tensor shapes."
)
output_classes_index = ( output_classes_index = (
0 0
if (output_boxes_index is None or output_classes_index == 1) if (output_boxes_index is None or output_classes_index == 1)
@ -125,19 +122,14 @@ class EdgeTpuTfl(DetectionApi):
output_boxes_index = 1 if (output_boxes_index == 0) else 0 output_boxes_index = 1 if (output_boxes_index == 0) else 0
scores_details = self.tensor_output_details[output_classes_index] scores_details = self.tensor_output_details[output_classes_index]
classes_count = scores_details["shape"][2]
self.scores_tensor_index = scores_details["index"] self.scores_tensor_index = scores_details["index"]
self.scores_scale, self.scores_zero_point = scores_details[ self.scores_scale, self.scores_zero_point = scores_details["quantization"]
"quantization"
]
# calculate the quantized version of the min_score # calculate the quantized version of the min_score
self.min_score_quantized = int( self.min_score_quantized = int(
(self.min_logit_value / self.scores_scale) + self.scores_zero_point (self.min_logit_value / self.scores_scale) + self.scores_zero_point
) )
self.logit_shift_to_positive_values = ( self.logit_shift_to_positive_values = (
max( max(0, math.ceil((128 + self.scores_zero_point) * self.scores_scale))
0, math.ceil((128 + self.scores_zero_point) * self.scores_scale)
)
+ 1 + 1
) # round up ) # round up
@ -145,11 +137,7 @@ class EdgeTpuTfl(DetectionApi):
self.boxes_tensor_index = boxes_details["index"] self.boxes_tensor_index = boxes_details["index"]
self.boxes_scale, self.boxes_zero_point = boxes_details["quantization"] self.boxes_scale, self.boxes_zero_point = boxes_details["quantization"]
else: elif self.model_type == ModelTypeEnum.ssd:
if self.model_type not in [ModelTypeEnum.ssd, None]:
logger.warning(
f"Unsupported model_type '{self.model_type}' for EdgeTPU detector, falling back to SSD"
)
logger.debug("Using SSD preprocessing/postprocessing") logger.debug("Using SSD preprocessing/postprocessing")
# SSD model indices (4 outputs: boxes, class_ids, scores, count) # SSD model indices (4 outputs: boxes, class_ids, scores, count)
@ -162,6 +150,11 @@ class EdgeTpuTfl(DetectionApi):
self.output_class_ids_index = None self.output_class_ids_index = None
self.output_class_scores_index = None self.output_class_scores_index = None
else:
raise Exception(
f"{self.model_type} is currently not supported for edgetpu. See the docs for more info on supported models."
)
def _generate_anchors_and_strides(self): def _generate_anchors_and_strides(self):
# for decoding the bounding box DFL information into xy coordinates # for decoding the bounding box DFL information into xy coordinates
all_anchors = [] all_anchors = []
@ -244,9 +237,7 @@ class EdgeTpuTfl(DetectionApi):
scores_output_quantized = self.interpreter.get_tensor( scores_output_quantized = self.interpreter.get_tensor(
self.scores_tensor_index self.scores_tensor_index
)[0] # (2100, NC) )[0] # (2100, NC)
max_scores_quantized = np.max( max_scores_quantized = np.max(scores_output_quantized, axis=1) # (2100,)
scores_output_quantized, axis=1
) # (2100,)
mask = max_scores_quantized >= self.min_score_quantized # (2100,) mask = max_scores_quantized >= self.min_score_quantized # (2100,)
if not np.any(mask): if not np.any(mask):
@ -276,9 +267,7 @@ class EdgeTpuTfl(DetectionApi):
# Softmax over the 16 bins # Softmax over the 16 bins
dfl_max = np.max(dfl_distributions, axis=2, keepdims=True) dfl_max = np.max(dfl_distributions, axis=2, keepdims=True)
dfl_exp = np.exp(dfl_distributions - dfl_max) dfl_exp = np.exp(dfl_distributions - dfl_max)
dfl_probs = dfl_exp / np.sum( dfl_probs = dfl_exp / np.sum(dfl_exp, axis=2, keepdims=True) # (N, 4, 16)
dfl_exp, axis=2, keepdims=True
) # (N, 4, 16)
# Weighted sum: (N, 4, 16) * (16,) -> (N, 4) # Weighted sum: (N, 4, 16) * (16,) -> (N, 4)
distances = np.einsum("pcr,r->pc", dfl_probs, self.project) distances = np.einsum("pcr,r->pc", dfl_probs, self.project)
@ -334,8 +323,7 @@ class EdgeTpuTfl(DetectionApi):
detections[:num_detections, 5] = final_boxes[:, 2] / self.model_width detections[:num_detections, 5] = final_boxes[:, 2] / self.model_width
return detections return detections
else: elif self.model_type == ModelTypeEnum.ssd:
# Default SSD model
self.determine_indexes_for_non_yolo_models() self.determine_indexes_for_non_yolo_models()
boxes = self.interpreter.tensor(self.tensor_output_details[0]["index"])()[0] boxes = self.interpreter.tensor(self.tensor_output_details[0]["index"])()[0]
class_ids = self.interpreter.tensor( class_ids = self.interpreter.tensor(
@ -366,3 +354,8 @@ class EdgeTpuTfl(DetectionApi):
] ]
return detections return detections
else:
raise Exception(
f"{self.model_type} is currently not supported for edgetpu. See the docs for more info on supported models."
)