Skip to content

Commit 4a35573

Browse files
spanner3003NickM-27hawkeye217
committed
Initial support for Hailo-8L (blakeblackshear#12431)
* Initial support for Hailo-8L Added file for Hailo-8L detector including dockerfile, h8l.mk, h8l.hcl, hailo8l.py, ci.yml and ssd_mobilenat_v1.hef as the inference network. Added files to help with the installation of Hailo-8L dependences like generate_wheel_conf.py, requirements-wheel-h8l.txt and modified setup.py to try and work with any hardware. Updated docs to reflect Initial Hailo-8L support including oject_detectors.md, hardware.md and installation.md. * Update .github/workflows/ci.yml typo h8l not arm64 Co-authored-by: Nicolas Mowen <[email protected]> * Update docs/docs/configuration/object_detectors.md Clarity for the end user and correct uses of words Co-authored-by: Nicolas Mowen <[email protected]> * Update docs/docs/frigate/installation.md typo Co-authored-by: Nicolas Mowen <[email protected]> * update Installation.md to clarify Hailo-8L installation process. * Update docs/docs/frigate/hardware.md Co-authored-by: Josh Hawkins <[email protected]> * Update hardware.md add Inference time. * Oops no new line at the end of the file. * Update docs/docs/frigate/hardware.md typo Co-authored-by: Josh Hawkins <[email protected]> * Update dockerfile to download the ssd_modilenet_v1 model instead of having it in the repo. * Updated dockerfile so it dose not download the model file. add function to download it at runtime. update model path. * fix formatting according to ruff and removed unnecessary functions. --------- Co-authored-by: Nicolas Mowen <[email protected]> Co-authored-by: Josh Hawkins <[email protected]>
1 parent e7fabce commit 4a35573

File tree

12 files changed

+689
-1
lines changed

12 files changed

+689
-1
lines changed

.github/workflows/ci.yml

+10
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,16 @@ jobs:
7878
set: |
7979
rk.tags=${{ steps.setup.outputs.image-name }}-rk
8080
*.cache-from=type=gha
81+
- name: Build and push Hailo-8l build
82+
uses: docker/bake-action@v4
83+
with:
84+
push: true
85+
targets: h8l
86+
files: docker/hailo8l/h8l.hcl
87+
set: |
88+
h8l.tags=${{ steps.setup.outputs.image-name }}-h8l
89+
*.cache-from=type=registry,ref=${{ steps.setup.outputs.cache-name }}-h8l
90+
*.cache-to=type=registry,ref=${{ steps.setup.outputs.cache-name }}-h8l,mode=max
8191
jetson_jp4_build:
8292
runs-on: ubuntu-latest
8393
name: Jetson Jetpack 4

CODEOWNERS

+1
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@
44
/docker/tensorrt/*jetson* @madsciencetist
55
/docker/rockchip/ @MarcA711
66
/docker/rocm/ @harakas
7+
/docker/hailo8l/ @spanner3003

docker/hailo8l/Dockerfile

+100
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
# syntax=docker/dockerfile:1.6
2+
3+
ARG DEBIAN_FRONTEND=noninteractive
4+
5+
# Build Python wheels
6+
FROM wheels AS h8l-wheels
7+
8+
COPY docker/main/requirements-wheels.txt /requirements-wheels.txt
9+
COPY docker/hailo8l/requirements-wheels-h8l.txt /requirements-wheels-h8l.txt
10+
11+
RUN sed -i "/https:\/\//d" /requirements-wheels.txt
12+
13+
# Create a directory to store the built wheels
14+
RUN mkdir /h8l-wheels
15+
16+
# Build the wheels
17+
RUN pip3 wheel --wheel-dir=/h8l-wheels -c /requirements-wheels.txt -r /requirements-wheels-h8l.txt
18+
19+
# Build HailoRT and create wheel
20+
FROM deps AS build-hailort
21+
22+
# Install necessary APT packages
23+
RUN apt-get update && apt-get install -y \
24+
build-essential \
25+
cmake \
26+
git \
27+
wget \
28+
python3-dev \
29+
gcc-9 \
30+
g++-9 \
31+
libzmq3-dev \
32+
pciutils \
33+
rsync \
34+
&& rm -rf /var/lib/apt/lists/*
35+
36+
# Extract Python version and set environment variables
37+
RUN PYTHON_VERSION=$(python3 --version 2>&1 | awk '{print $2}' | cut -d. -f1,2) && \
38+
PYTHON_VERSION_NO_DOT=$(echo $PYTHON_VERSION | sed 's/\.//') && \
39+
echo "PYTHON_VERSION=$PYTHON_VERSION" > /etc/environment && \
40+
echo "PYTHON_VERSION_NO_DOT=$PYTHON_VERSION_NO_DOT" >> /etc/environment
41+
42+
#ENV PYTHON_VER=$PYTHON_VERSION
43+
#ENV PYTHON_VER_NO_DOT=$PYTHON_VERSION_NO_DOT
44+
45+
# Clone and build HailoRT
46+
RUN . /etc/environment && \
47+
git clone https://github.com/hailo-ai/hailort.git /opt/hailort && \
48+
cd /opt/hailort && \
49+
git checkout v4.17.0 && \
50+
cmake -H. -Bbuild -DCMAKE_BUILD_TYPE=Release -DHAILO_BUILD_PYBIND=1 -DPYBIND11_PYTHON_VERSION=${PYTHON_VERSION} && \
51+
cmake --build build --config release --target libhailort && \
52+
cmake --build build --config release --target _pyhailort && \
53+
cp build/hailort/libhailort/bindings/python/src/_pyhailort.cpython-${PYTHON_VERSION_NO_DOT}-aarch64-linux-gnu.so hailort/libhailort/bindings/python/platform/hailo_platform/pyhailort/ && \
54+
cp build/hailort/libhailort/src/libhailort.so hailort/libhailort/bindings/python/platform/hailo_platform/pyhailort/
55+
56+
RUN ls -ahl /opt/hailort/build/hailort/libhailort/src/
57+
RUN ls -ahl /opt/hailort/hailort/libhailort/bindings/python/platform/hailo_platform/pyhailort/
58+
59+
# Remove the existing setup.py if it exists in the target directory
60+
RUN rm -f /opt/hailort/hailort/libhailort/bindings/python/platform/setup.py
61+
62+
# Copy generate_wheel_conf.py and setup.py
63+
COPY docker/hailo8l/pyhailort_build_scripts/generate_wheel_conf.py /opt/hailort/hailort/libhailort/bindings/python/platform/generate_wheel_conf.py
64+
COPY docker/hailo8l/pyhailort_build_scripts/setup.py /opt/hailort/hailort/libhailort/bindings/python/platform/setup.py
65+
66+
# Run the generate_wheel_conf.py script
67+
RUN python3 /opt/hailort/hailort/libhailort/bindings/python/platform/generate_wheel_conf.py
68+
69+
# Create a wheel file using pip3 wheel
70+
RUN cd /opt/hailort/hailort/libhailort/bindings/python/platform && \
71+
python3 setup.py bdist_wheel --dist-dir /hailo-wheels
72+
73+
# Use deps as the base image
74+
FROM deps AS h8l-frigate
75+
76+
# Copy the wheels from the wheels stage
77+
COPY --from=h8l-wheels /h8l-wheels /deps/h8l-wheels
78+
COPY --from=build-hailort /hailo-wheels /deps/hailo-wheels
79+
COPY --from=build-hailort /etc/environment /etc/environment
80+
RUN CC=$(python3 -c "import sysconfig; import shlex; cc = sysconfig.get_config_var('CC'); cc_cmd = shlex.split(cc)[0]; print(cc_cmd[:-4] if cc_cmd.endswith('-gcc') else cc_cmd)") && \
81+
echo "CC=$CC" >> /etc/environment
82+
83+
# Install the wheels
84+
RUN pip3 install -U /deps/h8l-wheels/*.whl
85+
RUN pip3 install -U /deps/hailo-wheels/*.whl
86+
87+
RUN . /etc/environment && \
88+
mv /usr/local/lib/python${PYTHON_VERSION}/dist-packages/hailo_platform/pyhailort/libhailort.so /usr/lib/${CC} && \
89+
cd /usr/lib/${CC}/ && \
90+
ln -s libhailort.so libhailort.so.4.17.0
91+
92+
# Copy base files from the rootfs stage
93+
COPY --from=rootfs / /
94+
95+
# Set environment variables for Hailo SDK
96+
ENV PATH="/opt/hailort/bin:${PATH}"
97+
ENV LD_LIBRARY_PATH="/usr/lib/aarch64-linux-gnu:${LD_LIBRARY_PATH}"
98+
99+
# Set workdir
100+
WORKDIR /opt/frigate/

docker/hailo8l/h8l.hcl

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
target wheels {
2+
dockerfile = "docker/main/Dockerfile"
3+
platforms = ["linux/arm64"]
4+
target = "wheels"
5+
}
6+
7+
target deps {
8+
dockerfile = "docker/main/Dockerfile"
9+
platforms = ["linux/arm64"]
10+
target = "deps"
11+
}
12+
13+
target rootfs {
14+
dockerfile = "docker/main/Dockerfile"
15+
platforms = ["linux/arm64"]
16+
target = "rootfs"
17+
}
18+
19+
target h8l {
20+
dockerfile = "docker/hailo8l/Dockerfile"
21+
contexts = {
22+
wheels = "target:wheels"
23+
deps = "target:deps"
24+
rootfs = "target:rootfs"
25+
}
26+
platforms = ["linux/arm64"]
27+
}

docker/hailo8l/h8l.mk

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
BOARDS += h8l
2+
3+
local-h8l: version
4+
docker buildx bake --load --file=docker/hailo8l/h8l.hcl --set h8l.tags=frigate:latest-h8l h8l
5+
6+
build-h8l: version
7+
docker buildx bake --file=docker/hailo8l/h8l.hcl --set h8l.tags=$(IMAGE_REPO):${GITHUB_REF_NAME}-$(COMMIT_HASH)-h8l h8l
8+
9+
push-h8l: build-h8l
10+
docker buildx bake --push --file=docker/hailo8l/h8l.hcl --set h8l.tags=$(IMAGE_REPO):${GITHUB_REF_NAME}-$(COMMIT_HASH)-h8l h8l
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import json
2+
import os
3+
import platform
4+
import sys
5+
import sysconfig
6+
7+
8+
def extract_toolchain_info(compiler):
9+
# Remove the "-gcc" or "-g++" suffix if present
10+
if compiler.endswith("-gcc") or compiler.endswith("-g++"):
11+
compiler = compiler.rsplit("-", 1)[0]
12+
13+
# Extract the toolchain and ABI part (e.g., "gnu")
14+
toolchain_parts = compiler.split("-")
15+
abi_conventions = next(
16+
(part for part in toolchain_parts if part in ["gnu", "musl", "eabi", "uclibc"]),
17+
"",
18+
)
19+
20+
return abi_conventions
21+
22+
23+
def generate_wheel_conf():
24+
conf_file_path = os.path.join(
25+
os.path.abspath(os.path.dirname(__file__)), "wheel_conf.json"
26+
)
27+
28+
# Extract current system and Python version information
29+
py_version = f"cp{sys.version_info.major}{sys.version_info.minor}"
30+
arch = platform.machine()
31+
system = platform.system().lower()
32+
libc_version = platform.libc_ver()[1]
33+
34+
# Get the compiler information
35+
compiler = sysconfig.get_config_var("CC")
36+
abi_conventions = extract_toolchain_info(compiler)
37+
38+
# Create the new configuration data
39+
new_conf_data = {
40+
"py_version": py_version,
41+
"arch": arch,
42+
"system": system,
43+
"libc_version": libc_version,
44+
"abi": abi_conventions,
45+
"extension": {
46+
"posix": "so",
47+
"nt": "pyd", # Windows
48+
}[os.name],
49+
}
50+
51+
# If the file exists, load the existing data
52+
if os.path.isfile(conf_file_path):
53+
with open(conf_file_path, "r") as conf_file:
54+
conf_data = json.load(conf_file)
55+
# Update the existing data with the new data
56+
conf_data.update(new_conf_data)
57+
else:
58+
# If the file does not exist, use the new data
59+
conf_data = new_conf_data
60+
61+
# Write the updated data to the file
62+
with open(conf_file_path, "w") as conf_file:
63+
json.dump(conf_data, conf_file, indent=4)
64+
65+
66+
if __name__ == "__main__":
67+
generate_wheel_conf()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
import json
2+
import os
3+
4+
from setuptools import find_packages, setup
5+
from wheel.bdist_wheel import bdist_wheel as orig_bdist_wheel
6+
7+
8+
class NonPurePythonBDistWheel(orig_bdist_wheel):
9+
"""Makes the wheel platform-dependent so it can be based on the _pyhailort architecture"""
10+
11+
def finalize_options(self):
12+
orig_bdist_wheel.finalize_options(self)
13+
self.root_is_pure = False
14+
15+
16+
def _get_hailort_lib_path():
17+
lib_filename = "libhailort.so"
18+
lib_path = os.path.join(
19+
os.path.abspath(os.path.dirname(__file__)),
20+
f"hailo_platform/pyhailort/{lib_filename}",
21+
)
22+
if os.path.exists(lib_path):
23+
print(f"Found libhailort shared library at: {lib_path}")
24+
else:
25+
print(f"Error: libhailort shared library not found at: {lib_path}")
26+
raise FileNotFoundError(f"libhailort shared library not found at: {lib_path}")
27+
return lib_path
28+
29+
30+
def _get_pyhailort_lib_path():
31+
conf_file_path = os.path.join(
32+
os.path.abspath(os.path.dirname(__file__)), "wheel_conf.json"
33+
)
34+
if not os.path.isfile(conf_file_path):
35+
raise FileNotFoundError(f"Configuration file not found: {conf_file_path}")
36+
37+
with open(conf_file_path, "r") as conf_file:
38+
content = json.load(conf_file)
39+
py_version = content["py_version"]
40+
arch = content["arch"]
41+
system = content["system"]
42+
extension = content["extension"]
43+
abi = content["abi"]
44+
45+
# Construct the filename directly
46+
lib_filename = f"_pyhailort.cpython-{py_version.split('cp')[1]}-{arch}-{system}-{abi}.{extension}"
47+
lib_path = os.path.join(
48+
os.path.abspath(os.path.dirname(__file__)),
49+
f"hailo_platform/pyhailort/{lib_filename}",
50+
)
51+
52+
if os.path.exists(lib_path):
53+
print(f"Found _pyhailort shared library at: {lib_path}")
54+
else:
55+
print(f"Error: _pyhailort shared library not found at: {lib_path}")
56+
raise FileNotFoundError(
57+
f"_pyhailort shared library not found at: {lib_path}"
58+
)
59+
60+
return lib_path
61+
62+
63+
def _get_package_paths():
64+
packages = []
65+
pyhailort_lib = _get_pyhailort_lib_path()
66+
hailort_lib = _get_hailort_lib_path()
67+
if pyhailort_lib:
68+
packages.append(pyhailort_lib)
69+
if hailort_lib:
70+
packages.append(hailort_lib)
71+
packages.append(os.path.abspath("hailo_tutorials/notebooks/*"))
72+
packages.append(os.path.abspath("hailo_tutorials/hefs/*"))
73+
return packages
74+
75+
76+
if __name__ == "__main__":
77+
setup(
78+
author="Hailo team",
79+
author_email="[email protected]",
80+
cmdclass={
81+
"bdist_wheel": NonPurePythonBDistWheel,
82+
},
83+
description="HailoRT",
84+
entry_points={
85+
"console_scripts": [
86+
"hailo=hailo_platform.tools.hailocli.main:main",
87+
]
88+
},
89+
install_requires=[
90+
"argcomplete",
91+
"contextlib2",
92+
"future",
93+
"netaddr",
94+
"netifaces",
95+
"verboselogs",
96+
"numpy==1.23.3",
97+
],
98+
name="hailort",
99+
package_data={
100+
"hailo_platform": _get_package_paths(),
101+
},
102+
packages=find_packages(),
103+
platforms=[
104+
"linux_x86_64",
105+
"linux_aarch64",
106+
"win_amd64",
107+
],
108+
url="https://hailo.ai/",
109+
version="4.17.0",
110+
zip_safe=False,
111+
)
+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
appdirs==1.4.4
2+
argcomplete==2.0.0
3+
contextlib2==0.6.0.post1
4+
distlib==0.3.6
5+
filelock==3.8.0
6+
future==0.18.2
7+
importlib-metadata==5.1.0
8+
importlib-resources==5.1.2
9+
netaddr==0.8.0
10+
netifaces==0.10.9
11+
verboselogs==1.7
12+
virtualenv==20.17.0

docs/docs/configuration/object_detectors.md

+23-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ title: Object Detectors
55

66
# Officially Supported Detectors
77

8-
Frigate provides the following builtin detector types: `cpu`, `edgetpu`, `openvino`, `tensorrt`, and `rknn`. By default, Frigate will use a single CPU detector. Other detectors may require additional configuration as described below. When using multiple detectors they will run in dedicated processes, but pull from a common queue of detection requests from across all cameras.
8+
Frigate provides the following builtin detector types: `cpu`, `edgetpu`, `openvino`, `tensorrt`, `rknn`, and `hailo8l`. By default, Frigate will use a single CPU detector. Other detectors may require additional configuration as described below. When using multiple detectors they will run in dedicated processes, but pull from a common queue of detection requests from across all cameras.
99

1010
## CPU Detector (not recommended)
1111

@@ -386,3 +386,25 @@ $ cat /sys/kernel/debug/rknpu/load
386386

387387
- All models are automatically downloaded and stored in the folder `config/model_cache/rknn_cache`. After upgrading Frigate, you should remove older models to free up space.
388388
- You can also provide your own `.rknn` model. You should not save your own models in the `rknn_cache` folder, store them directly in the `model_cache` folder or another subfolder. To convert a model to `.rknn` format see the `rknn-toolkit2` (requires a x86 machine). Note, that there is only post-processing for the supported models.
389+
390+
## Hailo-8l
391+
392+
This detector is available if you are using the Raspberry Pi 5 with Hailo-8L AI Kit. This has not been tested using the Hailo-8L with other hardware.
393+
394+
### Configuration
395+
396+
```yaml
397+
detectors:
398+
hailo8l:
399+
type: hailo8l
400+
device: PCIe
401+
model:
402+
path: /config/model_cache/h8l_cache/ssd_mobilenet_v1.hef
403+
404+
model:
405+
width: 300
406+
height: 300
407+
input_tensor: nhwc
408+
input_pixel_format: bgr
409+
model_type: ssd
410+
```

0 commit comments

Comments
 (0)