mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-04-24 15:47:43 +03:00
parent
0286da5ee8
commit
5bfb10398d
@ -243,11 +243,9 @@ RUN wget -q https://bootstrap.pypa.io/get-pip.py -O get-pip.py \
|
|||||||
RUN --mount=type=bind,from=wheels,source=/wheels,target=/deps/wheels \
|
RUN --mount=type=bind,from=wheels,source=/wheels,target=/deps/wheels \
|
||||||
pip3 install -U /deps/wheels/*.whl
|
pip3 install -U /deps/wheels/*.whl
|
||||||
|
|
||||||
# Copy memryx setup script
|
# Install MemryX runtime (requires libgomp (OpenMP) in the final docker image)
|
||||||
COPY ./docker/main/install_memryx.sh /deps/install_memryx.sh
|
RUN --mount=type=bind,source=docker/main/install_memryx.sh,target=/deps/install_memryx.sh \
|
||||||
|
bash -c "apt update && apt install libgomp1 && bash /deps/install_memryx.sh && rm -rf /var/lib/apt/lists/*"
|
||||||
# Install MemryX runtime for Frigate
|
|
||||||
RUN chmod +x /deps/install_memryx.sh && /deps/install_memryx.sh
|
|
||||||
|
|
||||||
COPY --from=deps-rootfs / /
|
COPY --from=deps-rootfs / /
|
||||||
|
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
# Update and install required system packages
|
# Download the MxAccl for Frigate github release
|
||||||
apt-get update && apt-get install -y git libgomp1
|
wget https://github.com/memryx/mx_accl_frigate/archive/refs/heads/main.zip -O /tmp/mxaccl.zip
|
||||||
|
unzip /tmp/mxaccl.zip -d /tmp
|
||||||
# Clone the MemryX runtime repo
|
mv /tmp/mx_accl_frigate-main /opt/mx_accl_frigate
|
||||||
git clone https://github.com/memryx/mx_accl_frigate.git /opt/mx_accl_frigate
|
rm /tmp/mxaccl.zip
|
||||||
|
|
||||||
# Install Python dependencies
|
# Install Python dependencies
|
||||||
pip3 install -r /opt/mx_accl_frigate/freeze
|
pip3 install -r /opt/mx_accl_frigate/freeze
|
||||||
|
|||||||
@ -9,6 +9,8 @@ arch=$(uname -m)
|
|||||||
|
|
||||||
# Purge existing packages and repo
|
# Purge existing packages and repo
|
||||||
echo "Removing old MemryX installations..."
|
echo "Removing old MemryX installations..."
|
||||||
|
# Remove any holds on MemryX packages (if they exist)
|
||||||
|
sudo apt-mark unhold memx-* mxa-manager || true
|
||||||
sudo apt purge -y memx-* mxa-manager || true
|
sudo apt purge -y memx-* mxa-manager || true
|
||||||
sudo rm -f /etc/apt/sources.list.d/memryx.list /etc/apt/trusted.gpg.d/memryx.asc
|
sudo rm -f /etc/apt/sources.list.d/memryx.list /etc/apt/trusted.gpg.d/memryx.asc
|
||||||
|
|
||||||
|
|||||||
@ -241,155 +241,7 @@ Hailo8 supports all models in the Hailo Model Zoo that include HailoRT post-proc
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## MemryX MX3
|
|
||||||
|
|
||||||
This detector is available for use with the MemryX MX3 accelerator M.2 module. Frigate supports the MX3 on compatible hardware platforms, providing efficient and high-performance object detection.
|
|
||||||
|
|
||||||
See the [installation docs](../frigate/installation.md#memryx-mx3) for information on configuring the MemryX hardware.
|
|
||||||
|
|
||||||
To configure a MemryX detector, simply set the `type` attribute to `memryx` and follow the configuration guide below.
|
|
||||||
|
|
||||||
### Configuration
|
|
||||||
|
|
||||||
To configure the MemryX detector, use the following example configuration:
|
|
||||||
|
|
||||||
#### Single PCIe MemryX MX3
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
detectors:
|
|
||||||
memx0:
|
|
||||||
type: memryx
|
|
||||||
device: PCIe:0
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Multiple PCIe MemryX MX3 Modules
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
detectors:
|
|
||||||
memx0:
|
|
||||||
type: memryx
|
|
||||||
device: PCIe:0
|
|
||||||
|
|
||||||
memx1:
|
|
||||||
type: memryx
|
|
||||||
device: PCIe:1
|
|
||||||
|
|
||||||
memx2:
|
|
||||||
type: memryx
|
|
||||||
device: PCIe:2
|
|
||||||
```
|
|
||||||
|
|
||||||
### Supported Models
|
|
||||||
|
|
||||||
MemryX `.dfp` models are automatically downloaded at runtime, if enabled, to the container at `/memryx_models/model_folder/`.
|
|
||||||
|
|
||||||
#### YOLO-NAS
|
|
||||||
|
|
||||||
The [YOLO-NAS](https://github.com/Deci-AI/super-gradients/blob/master/YOLONAS.md) model included in this detector is downloaded from the [Models Section](#downloading-yolo-nas-model) and compiled to DFP with [mx_nc](https://developer.memryx.com/tools/neural_compiler.html#usage).
|
|
||||||
|
|
||||||
The input size for **YOLO-NAS** can be set to either **320x320** (default) or **640x640**.
|
|
||||||
|
|
||||||
- The default size of **320x320** is optimized for lower CPU usage and faster inference times.
|
|
||||||
|
|
||||||
##### Configuration
|
|
||||||
|
|
||||||
Below is the recommended configuration for using the **YOLO-NAS** (small) model with the MemryX detector:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
detectors:
|
|
||||||
memx0:
|
|
||||||
type: memryx
|
|
||||||
device: PCIe:0
|
|
||||||
|
|
||||||
model:
|
|
||||||
model_type: yolonas
|
|
||||||
width: 320 # (Can be set to 640 for higher resolution)
|
|
||||||
height: 320 # (Can be set to 640 for higher resolution)
|
|
||||||
input_tensor: nchw
|
|
||||||
input_dtype: float
|
|
||||||
# path: yolo_nas_s.dfp ##Model is normally fetched through the runtime, so 'path' can be omitted.##
|
|
||||||
labelmap_path: /labelmap/coco-80.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
#### YOLOX
|
|
||||||
|
|
||||||
The model is sourced from the [OpenCV Model Zoo](https://github.com/opencv/opencv_zoo) and precompiled to DFP.
|
|
||||||
|
|
||||||
##### Configuration
|
|
||||||
|
|
||||||
Below is the recommended configuration for using the **YOLOX** (small) model with the MemryX detector:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
detectors:
|
|
||||||
memx0:
|
|
||||||
type: memryx
|
|
||||||
device: PCIe:0
|
|
||||||
|
|
||||||
model:
|
|
||||||
model_type: yolox
|
|
||||||
width: 640
|
|
||||||
height: 640
|
|
||||||
input_tensor: nchw
|
|
||||||
input_dtype: float_denorm
|
|
||||||
# path: YOLOX_640_640_3_onnx.dfp ##Model is normally fetched through the runtime, so 'path' can be omitted.##
|
|
||||||
labelmap_path: /labelmap/coco-80.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
#### YOLOv9
|
|
||||||
|
|
||||||
The YOLOv9s model included in this detector is downloaded from [the original GitHub](https://github.com/WongKinYiu/yolov9) like in the [Models Section](#yolov9-1) and compiled to DFP with [mx_nc](https://developer.memryx.com/tools/neural_compiler.html#usage).
|
|
||||||
|
|
||||||
##### Configuration
|
|
||||||
|
|
||||||
Below is the recommended configuration for using the **YOLOv9** (small) model with the MemryX detector:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
detectors:
|
|
||||||
memx0:
|
|
||||||
type: memryx
|
|
||||||
device: PCIe:0
|
|
||||||
|
|
||||||
model:
|
|
||||||
model_type: yolo-generic
|
|
||||||
width: 320 # (Can be set to 640 for higher resolution)
|
|
||||||
height: 320 # (Can be set to 640 for higher resolution)
|
|
||||||
input_tensor: nchw
|
|
||||||
input_dtype: float
|
|
||||||
# path: YOLO_v9_small_onnx.dfp ##Model is normally fetched through the runtime, so 'path' can be omitted.##
|
|
||||||
labelmap_path: /labelmap/coco-80.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
#### SSDLite MobileNet v2
|
|
||||||
|
|
||||||
The model is sourced from the [OpenMMLab Model Zoo](https://mmdeploy-oss.openmmlab.com/model/mmdet-det/ssdlite-e8679f.onnx) and has been converted to DFP.
|
|
||||||
|
|
||||||
##### Configuration
|
|
||||||
|
|
||||||
Below is the recommended configuration for using the **SSDLite MobileNet v2** model with the MemryX detector:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
detectors:
|
|
||||||
memx0:
|
|
||||||
type: memryx
|
|
||||||
device: PCIe:0
|
|
||||||
|
|
||||||
model:
|
|
||||||
model_type: ssd
|
|
||||||
width: 320
|
|
||||||
height: 320
|
|
||||||
input_tensor: nchw
|
|
||||||
input_dtype: float
|
|
||||||
# path: SSDlite_MobileNet_v2_320_320_3_onnx.dfp ##Model is normally fetched during runtime, so 'path' can be omitted.##
|
|
||||||
labelmap_path: /labelmap/coco-80.txt
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Using a Custom Model
|
|
||||||
|
|
||||||
To use your own model, bind-mount the path to your compiled `.dfp` file into the container and specify its path using `model.path`. You will also have to update the `labelmap` accordingly.
|
|
||||||
|
|
||||||
For detailed instructions on compiling models, refer to the [MemryX Compiler](https://developer.memryx.com/tools/neural_compiler.html#usage) docs and [Tutorials](https://developer.memryx.com/tutorials/tutorials.html).
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## OpenVINO Detector
|
## OpenVINO Detector
|
||||||
|
|
||||||
@ -850,6 +702,196 @@ To verify that the integration is working correctly, start Frigate and observe t
|
|||||||
|
|
||||||
# Community Supported Detectors
|
# Community Supported Detectors
|
||||||
|
|
||||||
|
## MemryX MX3
|
||||||
|
|
||||||
|
This detector is available for use with the MemryX MX3 accelerator M.2 module. Frigate supports the MX3 on compatible hardware platforms, providing efficient and high-performance object detection.
|
||||||
|
|
||||||
|
See the [installation docs](../frigate/installation.md#memryx-mx3) for information on configuring the MemryX hardware.
|
||||||
|
|
||||||
|
To configure a MemryX detector, simply set the `type` attribute to `memryx` and follow the configuration guide below.
|
||||||
|
|
||||||
|
### Configuration
|
||||||
|
|
||||||
|
To configure the MemryX detector, use the following example configuration:
|
||||||
|
|
||||||
|
#### Single PCIe MemryX MX3
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
detectors:
|
||||||
|
memx0:
|
||||||
|
type: memryx
|
||||||
|
device: PCIe:0
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Multiple PCIe MemryX MX3 Modules
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
detectors:
|
||||||
|
memx0:
|
||||||
|
type: memryx
|
||||||
|
device: PCIe:0
|
||||||
|
|
||||||
|
memx1:
|
||||||
|
type: memryx
|
||||||
|
device: PCIe:1
|
||||||
|
|
||||||
|
memx2:
|
||||||
|
type: memryx
|
||||||
|
device: PCIe:2
|
||||||
|
```
|
||||||
|
|
||||||
|
### Supported Models
|
||||||
|
|
||||||
|
MemryX `.dfp` models are automatically downloaded at runtime, if enabled, to the container at `/memryx_models/model_folder/`.
|
||||||
|
|
||||||
|
#### YOLO-NAS
|
||||||
|
|
||||||
|
The [YOLO-NAS](https://github.com/Deci-AI/super-gradients/blob/master/YOLONAS.md) model included in this detector is downloaded from the [Models Section](#downloading-yolo-nas-model) and compiled to DFP with [mx_nc](https://developer.memryx.com/tools/neural_compiler.html#usage).
|
||||||
|
|
||||||
|
**Note:** The default model for the MemryX detector is YOLO-NAS 320x320.
|
||||||
|
|
||||||
|
The input size for **YOLO-NAS** can be set to either **320x320** (default) or **640x640**.
|
||||||
|
|
||||||
|
- The default size of **320x320** is optimized for lower CPU usage and faster inference times.
|
||||||
|
|
||||||
|
##### Configuration
|
||||||
|
|
||||||
|
Below is the recommended configuration for using the **YOLO-NAS** (small) model with the MemryX detector:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
detectors:
|
||||||
|
memx0:
|
||||||
|
type: memryx
|
||||||
|
device: PCIe:0
|
||||||
|
|
||||||
|
model:
|
||||||
|
model_type: yolonas
|
||||||
|
width: 320 # (Can be set to 640 for higher resolution)
|
||||||
|
height: 320 # (Can be set to 640 for higher resolution)
|
||||||
|
input_tensor: nchw
|
||||||
|
input_dtype: float
|
||||||
|
labelmap_path: /labelmap/coco-80.txt
|
||||||
|
# Optional: The model is normally fetched through the runtime, so 'path' can be omitted unless you want to use a custom or local model.
|
||||||
|
# path: /config/yolonas.zip
|
||||||
|
# The .zip file must contain:
|
||||||
|
# ├── yolonas.dfp (a file ending with .dfp)
|
||||||
|
# └── yolonas_post.onnx (optional; only if the model includes a cropped post-processing network)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### YOLOv9
|
||||||
|
|
||||||
|
The YOLOv9s model included in this detector is downloaded from [the original GitHub](https://github.com/WongKinYiu/yolov9) like in the [Models Section](#yolov9-1) and compiled to DFP with [mx_nc](https://developer.memryx.com/tools/neural_compiler.html#usage).
|
||||||
|
|
||||||
|
##### Configuration
|
||||||
|
|
||||||
|
Below is the recommended configuration for using the **YOLOv9** (small) model with the MemryX detector:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
detectors:
|
||||||
|
memx0:
|
||||||
|
type: memryx
|
||||||
|
device: PCIe:0
|
||||||
|
|
||||||
|
model:
|
||||||
|
model_type: yolo-generic
|
||||||
|
width: 320 # (Can be set to 640 for higher resolution)
|
||||||
|
height: 320 # (Can be set to 640 for higher resolution)
|
||||||
|
input_tensor: nchw
|
||||||
|
input_dtype: float
|
||||||
|
labelmap_path: /labelmap/coco-80.txt
|
||||||
|
# Optional: The model is normally fetched through the runtime, so 'path' can be omitted unless you want to use a custom or local model.
|
||||||
|
# path: /config/yolov9.zip
|
||||||
|
# The .zip file must contain:
|
||||||
|
# ├── yolov9.dfp (a file ending with .dfp)
|
||||||
|
# └── yolov9_post.onnx (optional; only if the model includes a cropped post-processing network)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### YOLOX
|
||||||
|
|
||||||
|
The model is sourced from the [OpenCV Model Zoo](https://github.com/opencv/opencv_zoo) and precompiled to DFP.
|
||||||
|
|
||||||
|
##### Configuration
|
||||||
|
|
||||||
|
Below is the recommended configuration for using the **YOLOX** (small) model with the MemryX detector:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
detectors:
|
||||||
|
memx0:
|
||||||
|
type: memryx
|
||||||
|
device: PCIe:0
|
||||||
|
|
||||||
|
model:
|
||||||
|
model_type: yolox
|
||||||
|
width: 640
|
||||||
|
height: 640
|
||||||
|
input_tensor: nchw
|
||||||
|
input_dtype: float_denorm
|
||||||
|
labelmap_path: /labelmap/coco-80.txt
|
||||||
|
# Optional: The model is normally fetched through the runtime, so 'path' can be omitted unless you want to use a custom or local model.
|
||||||
|
# path: /config/yolox.zip
|
||||||
|
# The .zip file must contain:
|
||||||
|
# ├── yolox.dfp (a file ending with .dfp)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### SSDLite MobileNet v2
|
||||||
|
|
||||||
|
The model is sourced from the [OpenMMLab Model Zoo](https://mmdeploy-oss.openmmlab.com/model/mmdet-det/ssdlite-e8679f.onnx) and has been converted to DFP.
|
||||||
|
|
||||||
|
##### Configuration
|
||||||
|
|
||||||
|
Below is the recommended configuration for using the **SSDLite MobileNet v2** model with the MemryX detector:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
detectors:
|
||||||
|
memx0:
|
||||||
|
type: memryx
|
||||||
|
device: PCIe:0
|
||||||
|
|
||||||
|
model:
|
||||||
|
model_type: ssd
|
||||||
|
width: 320
|
||||||
|
height: 320
|
||||||
|
input_tensor: nchw
|
||||||
|
input_dtype: float
|
||||||
|
labelmap_path: /labelmap/coco-80.txt
|
||||||
|
# Optional: The model is normally fetched through the runtime, so 'path' can be omitted unless you want to use a custom or local model.
|
||||||
|
# path: /config/ssdlite_mobilenet.zip
|
||||||
|
# The .zip file must contain:
|
||||||
|
# ├── ssdlite_mobilenet.dfp (a file ending with .dfp)
|
||||||
|
# └── ssdlite_mobilenet_post.onnx (optional; only if the model includes a cropped post-processing network)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Using a Custom Model
|
||||||
|
|
||||||
|
To use your own model:
|
||||||
|
|
||||||
|
1. Package your compiled model into a `.zip` file.
|
||||||
|
|
||||||
|
2. The `.zip` must contain the compiled `.dfp` file.
|
||||||
|
|
||||||
|
3. Depending on the model, the compiler may also generate a cropped post-processing network. If present, it will be named with the suffix `_post.onnx`.
|
||||||
|
|
||||||
|
4. Bind-mount the `.zip` file into the container and specify its path using `model.path` in your config.
|
||||||
|
|
||||||
|
5. Update the `labelmap_path` to match your custom model's labels.
|
||||||
|
|
||||||
|
For detailed instructions on compiling models, refer to the [MemryX Compiler](https://developer.memryx.com/tools/neural_compiler.html#usage) docs and [Tutorials](https://developer.memryx.com/tutorials/tutorials.html).
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# The detector automatically selects the default model if nothing is provided in the config.
|
||||||
|
#
|
||||||
|
# Optionally, you can specify a local model path as a .zip file to override the default.
|
||||||
|
# If a local path is provided and the file exists, it will be used instead of downloading.
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
|
# path: /config/yolonas.zip
|
||||||
|
#
|
||||||
|
# The .zip file must contain:
|
||||||
|
# ├── yolonas.dfp (a file ending with .dfp)
|
||||||
|
# └── yolonas_post.onnx (optional; only if the model includes a cropped post-processing network)
|
||||||
|
```
|
||||||
|
---
|
||||||
|
|
||||||
## NVidia TensorRT Detector
|
## NVidia TensorRT Detector
|
||||||
|
|
||||||
Nvidia Jetson devices may be used for object detection using the TensorRT libraries. Due to the size of the additional libraries, this detector is only provided in images with the `-tensorrt-jp6` tag suffix, e.g. `ghcr.io/blakeblackshear/frigate:stable-tensorrt-jp6`. This detector is designed to work with Yolo models for object detection.
|
Nvidia Jetson devices may be used for object detection using the TensorRT libraries. Due to the size of the additional libraries, this detector is only provided in images with the `-tensorrt-jp6` tag suffix, e.g. `ghcr.io/blakeblackshear/frigate:stable-tensorrt-jp6`. This detector is designed to work with Yolo models for object detection.
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
|
import glob
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
import shutil
|
||||||
import time
|
import time
|
||||||
import urllib.request
|
import urllib.request
|
||||||
import zipfile
|
import zipfile
|
||||||
@ -184,10 +186,72 @@ class MemryXDetector(DetectionApi):
|
|||||||
self.const_C = np.load(f"{base}/_model_22_Constant_12_output_0.npy")
|
self.const_C = np.load(f"{base}/_model_22_Constant_12_output_0.npy")
|
||||||
|
|
||||||
def check_and_prepare_model(self):
|
def check_and_prepare_model(self):
|
||||||
"""Check if models exist; if not, download and extract them."""
|
|
||||||
if not os.path.exists(self.cache_dir):
|
if not os.path.exists(self.cache_dir):
|
||||||
os.makedirs(self.cache_dir)
|
os.makedirs(self.cache_dir, exist_ok=True)
|
||||||
|
|
||||||
|
# ---------- CASE 1: user provided a custom model path ----------
|
||||||
|
if self.memx_model_path:
|
||||||
|
if not self.memx_model_path.endswith(".zip"):
|
||||||
|
raise ValueError(
|
||||||
|
f"Invalid model path: {self.memx_model_path}. "
|
||||||
|
"Only .zip files are supported. Please provide a .zip model archive."
|
||||||
|
)
|
||||||
|
if not os.path.exists(self.memx_model_path):
|
||||||
|
raise FileNotFoundError(
|
||||||
|
f"Custom model zip not found: {self.memx_model_path}"
|
||||||
|
)
|
||||||
|
|
||||||
|
logger.info(f"User provided zip model: {self.memx_model_path}")
|
||||||
|
|
||||||
|
# Extract custom zip into a separate area so it never clashes with MemryX cache
|
||||||
|
custom_dir = os.path.join(
|
||||||
|
self.cache_dir, "custom_models", self.model_folder
|
||||||
|
)
|
||||||
|
if os.path.isdir(custom_dir):
|
||||||
|
shutil.rmtree(custom_dir)
|
||||||
|
os.makedirs(custom_dir, exist_ok=True)
|
||||||
|
|
||||||
|
with zipfile.ZipFile(self.memx_model_path, "r") as zip_ref:
|
||||||
|
zip_ref.extractall(custom_dir)
|
||||||
|
logger.info(f"Custom model extracted to {custom_dir}.")
|
||||||
|
|
||||||
|
# Find .dfp and optional *_post.onnx recursively
|
||||||
|
dfp_candidates = glob.glob(
|
||||||
|
os.path.join(custom_dir, "**", "*.dfp"), recursive=True
|
||||||
|
)
|
||||||
|
post_candidates = glob.glob(
|
||||||
|
os.path.join(custom_dir, "**", "*_post.onnx"), recursive=True
|
||||||
|
)
|
||||||
|
|
||||||
|
if not dfp_candidates:
|
||||||
|
raise FileNotFoundError(
|
||||||
|
"No .dfp file found in custom model zip after extraction."
|
||||||
|
)
|
||||||
|
|
||||||
|
self.memx_model_path = dfp_candidates[0]
|
||||||
|
|
||||||
|
# Handle post model requirements by model type
|
||||||
|
if self.memx_model_type in [
|
||||||
|
ModelTypeEnum.yologeneric,
|
||||||
|
ModelTypeEnum.yolonas,
|
||||||
|
ModelTypeEnum.ssd,
|
||||||
|
]:
|
||||||
|
if not post_candidates:
|
||||||
|
raise FileNotFoundError(
|
||||||
|
f"No *_post.onnx file found in custom model zip for {self.memx_model_type.name}."
|
||||||
|
)
|
||||||
|
self.memx_post_model = post_candidates[0]
|
||||||
|
elif self.memx_model_type == ModelTypeEnum.yolox:
|
||||||
|
# Explicitly ignore any post model even if present
|
||||||
|
self.memx_post_model = None
|
||||||
|
else:
|
||||||
|
# Future model types can optionally use post if present
|
||||||
|
self.memx_post_model = post_candidates[0] if post_candidates else None
|
||||||
|
|
||||||
|
logger.info(f"Using custom model: {self.memx_model_path}")
|
||||||
|
return
|
||||||
|
|
||||||
|
# ---------- CASE 2: no custom model path -> use MemryX cached models ----------
|
||||||
model_subdir = os.path.join(self.cache_dir, self.model_folder)
|
model_subdir = os.path.join(self.cache_dir, self.model_folder)
|
||||||
dfp_path = os.path.join(model_subdir, self.expected_dfp_model)
|
dfp_path = os.path.join(model_subdir, self.expected_dfp_model)
|
||||||
post_path = (
|
post_path = (
|
||||||
@ -207,7 +271,10 @@ class MemryXDetector(DetectionApi):
|
|||||||
self.load_yolo_constants()
|
self.load_yolo_constants()
|
||||||
return
|
return
|
||||||
|
|
||||||
logger.info(f"Model files not found. Downloading from {self.model_url}...")
|
# ---------- CASE 3: download MemryX model (no cache) ----------
|
||||||
|
logger.info(
|
||||||
|
f"Model files not found locally. Downloading from {self.model_url}..."
|
||||||
|
)
|
||||||
zip_path = os.path.join(self.cache_dir, f"{self.model_folder}.zip")
|
zip_path = os.path.join(self.cache_dir, f"{self.model_folder}.zip")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -231,14 +298,13 @@ class MemryXDetector(DetectionApi):
|
|||||||
if self.memx_model_type == ModelTypeEnum.yologeneric:
|
if self.memx_model_type == ModelTypeEnum.yologeneric:
|
||||||
self.load_yolo_constants()
|
self.load_yolo_constants()
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"Failed to prepare model: {e}")
|
|
||||||
raise
|
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
if os.path.exists(zip_path):
|
if os.path.exists(zip_path):
|
||||||
os.remove(zip_path)
|
try:
|
||||||
logger.info("Cleaned up ZIP file after extraction.")
|
os.remove(zip_path)
|
||||||
|
logger.info("Cleaned up ZIP file after extraction.")
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"Failed to remove downloaded zip {zip_path}: {e}")
|
||||||
|
|
||||||
def send_input(self, connection_id, tensor_input: np.ndarray):
|
def send_input(self, connection_id, tensor_input: np.ndarray):
|
||||||
"""Pre-process (if needed) and send frame to MemryX input queue"""
|
"""Pre-process (if needed) and send frame to MemryX input queue"""
|
||||||
@ -545,91 +611,102 @@ class MemryXDetector(DetectionApi):
|
|||||||
def process_output(self, *outputs):
|
def process_output(self, *outputs):
|
||||||
"""Output callback function -- receives frames from the MX3 and triggers post-processing"""
|
"""Output callback function -- receives frames from the MX3 and triggers post-processing"""
|
||||||
if self.memx_model_type == ModelTypeEnum.yologeneric:
|
if self.memx_model_type == ModelTypeEnum.yologeneric:
|
||||||
conv_out1 = outputs[0]
|
if not self.memx_post_model:
|
||||||
conv_out2 = outputs[1]
|
conv_out1 = outputs[0]
|
||||||
conv_out3 = outputs[2]
|
conv_out2 = outputs[1]
|
||||||
conv_out4 = outputs[3]
|
conv_out3 = outputs[2]
|
||||||
conv_out5 = outputs[4]
|
conv_out4 = outputs[3]
|
||||||
conv_out6 = outputs[5]
|
conv_out5 = outputs[4]
|
||||||
|
conv_out6 = outputs[5]
|
||||||
|
|
||||||
concat_1 = self.onnx_concat([conv_out1, conv_out2], axis=1)
|
concat_1 = self.onnx_concat([conv_out1, conv_out2], axis=1)
|
||||||
concat_2 = self.onnx_concat([conv_out3, conv_out4], axis=1)
|
concat_2 = self.onnx_concat([conv_out3, conv_out4], axis=1)
|
||||||
concat_3 = self.onnx_concat([conv_out5, conv_out6], axis=1)
|
concat_3 = self.onnx_concat([conv_out5, conv_out6], axis=1)
|
||||||
|
|
||||||
shape = np.array([1, 144, -1], dtype=np.int64)
|
shape = np.array([1, 144, -1], dtype=np.int64)
|
||||||
|
|
||||||
reshaped_1 = self.onnx_reshape_with_allowzero(concat_1, shape, allowzero=0)
|
reshaped_1 = self.onnx_reshape_with_allowzero(
|
||||||
reshaped_2 = self.onnx_reshape_with_allowzero(concat_2, shape, allowzero=0)
|
concat_1, shape, allowzero=0
|
||||||
reshaped_3 = self.onnx_reshape_with_allowzero(concat_3, shape, allowzero=0)
|
)
|
||||||
|
reshaped_2 = self.onnx_reshape_with_allowzero(
|
||||||
|
concat_2, shape, allowzero=0
|
||||||
|
)
|
||||||
|
reshaped_3 = self.onnx_reshape_with_allowzero(
|
||||||
|
concat_3, shape, allowzero=0
|
||||||
|
)
|
||||||
|
|
||||||
concat_4 = self.onnx_concat([reshaped_1, reshaped_2, reshaped_3], 2)
|
concat_4 = self.onnx_concat([reshaped_1, reshaped_2, reshaped_3], 2)
|
||||||
|
|
||||||
axis = 1
|
axis = 1
|
||||||
split_sizes = [64, 80]
|
split_sizes = [64, 80]
|
||||||
|
|
||||||
# Calculate indices at which to split
|
# Calculate indices at which to split
|
||||||
indices = np.cumsum(split_sizes)[
|
indices = np.cumsum(split_sizes)[
|
||||||
:-1
|
:-1
|
||||||
] # [64] — split before the second chunk
|
] # [64] — split before the second chunk
|
||||||
|
|
||||||
# Perform split along axis 1
|
# Perform split along axis 1
|
||||||
split_0, split_1 = np.split(concat_4, indices, axis=axis)
|
split_0, split_1 = np.split(concat_4, indices, axis=axis)
|
||||||
|
|
||||||
num_boxes = 2100 if self.memx_model_height == 320 else 8400
|
num_boxes = 2100 if self.memx_model_height == 320 else 8400
|
||||||
shape1 = np.array([1, 4, 16, num_boxes])
|
shape1 = np.array([1, 4, 16, num_boxes])
|
||||||
reshape_4 = self.onnx_reshape_with_allowzero(split_0, shape1, allowzero=0)
|
reshape_4 = self.onnx_reshape_with_allowzero(
|
||||||
|
split_0, shape1, allowzero=0
|
||||||
|
)
|
||||||
|
|
||||||
transpose_1 = reshape_4.transpose(0, 2, 1, 3)
|
transpose_1 = reshape_4.transpose(0, 2, 1, 3)
|
||||||
|
|
||||||
axis = 1 # As per ONNX softmax node
|
axis = 1 # As per ONNX softmax node
|
||||||
|
|
||||||
# Subtract max for numerical stability
|
# Subtract max for numerical stability
|
||||||
x_max = np.max(transpose_1, axis=axis, keepdims=True)
|
x_max = np.max(transpose_1, axis=axis, keepdims=True)
|
||||||
x_exp = np.exp(transpose_1 - x_max)
|
x_exp = np.exp(transpose_1 - x_max)
|
||||||
x_sum = np.sum(x_exp, axis=axis, keepdims=True)
|
x_sum = np.sum(x_exp, axis=axis, keepdims=True)
|
||||||
softmax_output = x_exp / x_sum
|
softmax_output = x_exp / x_sum
|
||||||
|
|
||||||
# Weight W from the ONNX initializer (1, 16, 1, 1) with values 0 to 15
|
# Weight W from the ONNX initializer (1, 16, 1, 1) with values 0 to 15
|
||||||
W = np.arange(16, dtype=np.float32).reshape(1, 16, 1, 1) # (1, 16, 1, 1)
|
W = np.arange(16, dtype=np.float32).reshape(
|
||||||
|
1, 16, 1, 1
|
||||||
|
) # (1, 16, 1, 1)
|
||||||
|
|
||||||
# Apply 1x1 convolution: this is a weighted sum over channels
|
# Apply 1x1 convolution: this is a weighted sum over channels
|
||||||
conv_output = np.sum(
|
conv_output = np.sum(
|
||||||
softmax_output * W, axis=1, keepdims=True
|
softmax_output * W, axis=1, keepdims=True
|
||||||
) # shape: (1, 1, 4, 8400)
|
) # shape: (1, 1, 4, 8400)
|
||||||
|
|
||||||
shape2 = np.array([1, 4, num_boxes])
|
shape2 = np.array([1, 4, num_boxes])
|
||||||
reshape_5 = self.onnx_reshape_with_allowzero(
|
reshape_5 = self.onnx_reshape_with_allowzero(
|
||||||
conv_output, shape2, allowzero=0
|
conv_output, shape2, allowzero=0
|
||||||
)
|
)
|
||||||
|
|
||||||
# ONNX Slice — get first 2 channels: [0:2] along axis 1
|
# ONNX Slice — get first 2 channels: [0:2] along axis 1
|
||||||
slice_output1 = reshape_5[:, 0:2, :] # Result: (1, 2, 8400)
|
slice_output1 = reshape_5[:, 0:2, :] # Result: (1, 2, 8400)
|
||||||
|
|
||||||
# Slice channels 2 to 4 → axis = 1
|
# Slice channels 2 to 4 → axis = 1
|
||||||
slice_output2 = reshape_5[:, 2:4, :]
|
slice_output2 = reshape_5[:, 2:4, :]
|
||||||
|
|
||||||
# Perform Subtraction
|
# Perform Subtraction
|
||||||
sub_output = self.const_A - slice_output1 # Equivalent to ONNX Sub
|
sub_output = self.const_A - slice_output1 # Equivalent to ONNX Sub
|
||||||
|
|
||||||
# Perform the ONNX-style Add
|
# Perform the ONNX-style Add
|
||||||
add_output = self.const_B + slice_output2
|
add_output = self.const_B + slice_output2
|
||||||
|
|
||||||
sub1 = add_output - sub_output
|
sub1 = add_output - sub_output
|
||||||
|
|
||||||
add1 = sub_output + add_output
|
add1 = sub_output + add_output
|
||||||
|
|
||||||
div_output = add1 / 2.0
|
div_output = add1 / 2.0
|
||||||
|
|
||||||
concat_5 = self.onnx_concat([div_output, sub1], axis=1)
|
concat_5 = self.onnx_concat([div_output, sub1], axis=1)
|
||||||
|
|
||||||
# Expand B to (1, 1, 8400) so it can broadcast across axis=1 (4 channels)
|
# Expand B to (1, 1, 8400) so it can broadcast across axis=1 (4 channels)
|
||||||
const_C_expanded = self.const_C[:, np.newaxis, :] # Shape: (1, 1, 8400)
|
const_C_expanded = self.const_C[:, np.newaxis, :] # Shape: (1, 1, 8400)
|
||||||
|
|
||||||
# Perform ONNX-style element-wise multiplication
|
# Perform ONNX-style element-wise multiplication
|
||||||
mul_output = concat_5 * const_C_expanded # Result: (1, 4, 8400)
|
mul_output = concat_5 * const_C_expanded # Result: (1, 4, 8400)
|
||||||
|
|
||||||
sigmoid_output = self.sigmoid(split_1)
|
sigmoid_output = self.sigmoid(split_1)
|
||||||
outputs = self.onnx_concat([mul_output, sigmoid_output], axis=1)
|
outputs = self.onnx_concat([mul_output, sigmoid_output], axis=1)
|
||||||
|
|
||||||
final_detections = post_process_yolo(
|
final_detections = post_process_yolo(
|
||||||
outputs, self.memx_model_width, self.memx_model_height
|
outputs, self.memx_model_width, self.memx_model_height
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user