一、前言

        最近接触到了hailo边缘计算加速芯片。我目前调试的这一款型号为hailo8,具有26Tops的算力,已经相当于3个3588的算力了。整体用下来感觉算力方面没得说,但是生态还差点意思,对于这个系列的芯片国内资料非常少,官方也只发布了针对某些开发板的demo程序,这也就间接导致了我们调试这款芯片非常困难,常常因为找不到demo程序,我们需要自己去翻官方文档。hailo融合的概念非常多,比如hailoRT,hailo_model_zoo,pyhailort等等。概念太复杂了,非常不适合新手。调试hailo在感觉上比我调试RK芯片更为困难。所以现在有了这篇文章,我会将我调试hailo的经历分享出来,当然,也只是作为一个参考,对于不同的开发板,不同的内核,以至于不同的hailo计算卡,不同的pcie驱动版本,这些步骤都不可能完全一样。如果你准备好了,就让我们开始吧!

二、谁适合本次教程

        在本次教程中,涉及到了YOLO,Linux,python等诸多概念,已经不是面向纯小白的了,所以,在开始之前,请你一定要确保自己具备上述基础。在教程中,一些简单,通用的概念我可能只会简单提及甚至一笔带过,所以,在开始之前,请确保你自己一定有基础。

三、整体流程

        现在我们先来梳理一下使用hailo计算卡推理YOLO的整体流程。首先我们需要使用YOLO训练一个自己的模型,这里我使用的是YOLOv8,然后使用onnx库将我们训练出来的pt格式的模型转换为onnx格式。然后需要在Linux中搭建hailo_model_zoo的环境,我们需要使用hailo_model_zoo环境将一开始得到的onnx格式模型转换为hef格式,至此我们模型转换就完成了。然后我们需要在板端安装好hailo的pcie驱动(一般卖家提供,如果没有提供或者是自己搭配的板子与计算卡,那么极有可能你需要自己编译驱动,编译驱动需要借助你板子的内核源码进行编译,这是一个非常麻烦的过程)。当我们hailo计算卡的pcie驱动正确以后,就可以在板端安装hailoRT了,这里hailoRT的版本需要和我们的pcie驱动对应(hailoRT的运行依赖了hailo-pcie,不要存在侥幸心理,版本差0.1你的hailoRT都装不上去)。然后就是需要在板端安装python,我们利用python创建一个虚拟环境,在这个python虚拟环境中我们安装hailoRT的python包,这里被俗称pyhailoRT(这里需要注意,pyhailoRT依赖了我们上面安装的hailoRT,所以这里需要先装hailoRT),完成上面的步骤以后,环境配置就差不多了,我们需要用python代码来运行我们的模型,到了代码这一步就来到了最困难的一步,如果你使用的是树莓派搭配hailo,那么恭喜你,hailo官方提供了现成了demo代码。如果你使用hailoRT,hailo-pcie,pyhailoRT版本都在4.22以上,那么同样恭喜你,官方提供了现成的demo代码。如果你不属于上面的情况,那就非常麻烦了,hailo4.22以下的版本官方几乎没提供任何demo代码,只有API文档,你需要参考这个文档进行编程。当然,如果你处于第三种情况也不用担心,因为我也正处于这种情况,后续会教大家如何解决。 

        上面就是使用hailo推理YOLO的基本流程,现在让我们开始吧!

四、YOLO的训练与ONNX模型转换

        这里我会使用YOLOv8进行展示,如果你对YOLO的环境搭建与训练不是很了解,可以看下面的教程:

YOLO环境搭建:[AI]小白向的YOLO安装教程-CSDN博客

YOLO的训练:[AI]YOLO如何训练对象检测模型(详细)_yolo模型训练-CSDN博客

这里YOLO的环境搭建与训练都比较简单,我也就不多说了,我下面的操作会默认大家已经搭建好了YOLO的训练环境。

我们需要hailo推理YOLO模型,所以首先我们就需要训练一个YOLO模型,这里我从网络上下载了一个开源的识别杯子的数据集:

这里我们将其放到YOLOv8目录下的datasets如图所示,这里默认大家都会训练,就不多说了:

我的data.yaml内容如下:

train.py文件如下:

因为我这里的数据集有好几千张,所以就只训练三步,大家根据自己的情况调整训练步数即可。

训练完成后的文件夹如图所示:

pt模型在weights文件夹中:

这里我们训练得到pt文件以后,需要将其转换为onnx格式,在转换之前需要安装一下相关的库,直接使用下面的命令安装onnx库即可:

pip install --no-cache-dir "onnx>=1.12.0"

安装完相关onnx库以后,我们就可以来转换模型了,这里我们进入有pt文件的文件夹,执行下面的命令:

yolo export model=./best.pt imgsz=640 format=onnx opset=11

这里的参数很好理解,就不多说了。

执行以后,就可以看到下面的内容了:

我们的模型输出为了一个与pt文件同名的onnx文件。至此,我们YOLO的训练与模型转换就完成了。

五、VM虚拟机配置及HEF模型转换

        当我们得到onnx文件以后,就可以来转换hef文件了。这里我们需要在Linux环境中进行,这里我使用的是VM虚拟机,大家根据自己的情况进行操作即可。如果你还不会创建虚拟机,可以看下面的文章:

VM安装及虚拟机创建:[Linux]如何在虚拟机安装Ubuntu?(小白向)_虚拟机 ubuntu-CSDN博客

这里我使用的是Ubuntu22.04的系统,为了完整还原整个过程,我将新建了一个虚拟机,新建完成如图所示:

为了方便我们后面命令操作的方便,这里先来安装一下ssh相关的库,直接使用下面的命令:

sudo apt install openssh-server net-tools

安装完成以后,我们就可以查询到我们虚拟机的IP地址了:

这里我们直接在windows中使用powershell远程即可:

这样我们后续复制命令就会方便很多。

这里我们首先要把hailo_model_zoo的项目克隆下来,hailo_model_zoo主要用于模型转换与训练,我们这里只讲模型转换。

要克隆项目我们就需要git,这里我们直接使用下面的命令安装一下git:

sudo apt install git

git安装完成以后,使用下面的命令克隆hailo_model_zoo:

git clone https://github.com/hailo-ai/hailo_model_zoo.git

如果你在克隆时遇到问题,可以使用下面的命令配置一下git的代理,这里大家将代理的地址和端口号修改为自己的即可:

git config --global http.proxy http://192.168.61.22:7897
git config --global https.proxy http://192.168.61.22:7897

克隆完成以后,得到以下文件夹:

hailo的运行依赖了python环境,这里我们需要安装conda来实现python的虚拟环境,我们可以直接在浏览器中搜索“miniconda”:

一般搜出来的第一个就是miniconda的官网,当然也可以点击下方的链接前往:

miniconda:Miniconda - Anaconda

进入以后,就可以看到如下界面了:

随后点击左边选框的“Installing Miniconda”来到以下界面:

然后这里我们选择“Basic install instructions”下的“macOS/Linux installation”:

然后我们点击“Linux terminal installer”下的“Linux x86”:

我们这里将miniconda的安装脚本的下载链接复制下来:

我们直接把下载命令粘贴到终端下载即可:

如果你在下载时出现了卡住的情况,可以使用下面的命令配置一下代理:

export http_proxy="http://192.168.61.22:7897"
export https_proxy="http://192.168.61.22:7897"

下载完以后,使用下面的命令取消代理,这里的代理尽量取消掉,不然Ubuntu的任何流量都会走代理。

unset http_proxy
unset https_proxy

下载完成以后,得到下面的shell脚本文件:

我们直接使用下面的命令运行这个脚本文件即可:

bash Miniconda3-latest-Linux-x86_64.sh

运行以后,这里让我们看协议,我们直接回车即可:

然后问我们要不要同意,我们直接输入yes回车即可:

下面问我们Miniconda的安装位置,这里安装位置默认为用户目录下,我们直接回车即可:

回车以后,就进入了安装步骤:

这里在问我们是否希望修改你的 Shell 启动配置文件,以便让 Conda 在每次打开终端时自动启动?,我们输入yes回车即可:

这一步完了以后,我们的conda就安装完成了:

安装完成以后,我们使用下面的命令刷新一下环境变量,这样我们的conda就被正常加载了:

source ~/.bashrc

conda安装完成以后,我们使用下面的命令来创建一个针对与hailo_model_zoo的虚拟环境:

conda create -n hailo_model_zoo python=3.10

这里在我们是否接收conda仓库的条款,我们输入“a”回车即可:

如果你出现了下面这样的情况,可以尝试把代理配回去,我实际测试下来,配置了代理后,环境可以正常创建了:

当然,也可以考虑换源,下面我来演示一下,直接用下面的命令,在用户目录新建一个名为“.condarc”的文件:

touch ~/.condarc

然后用你熟悉的编辑器打开这个文件,将下面的内容粘贴到文件中:

channels:
  - defaults
show_channel_urls: true
default_channels:
  - https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main
  - https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/r
  - https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/msys2
custom_channels:
  conda-forge: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud
  pytorch: https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud

这样就换镜像源完成了。

新建完conda虚拟环境后,我们使用下面的命令进入虚拟环境:

conda activate hailo_model_zoo

进入虚拟环境以后,我们先不着急去安装hailo_model_zoo的环境,我们预先安装一些库,防止在安装hailo_model_zoo的环境时报错,直接执行下面两条命令即可:

sudo apt install -y graphviz graphviz-dev pkg-config gcc g++ make
conda install -c conda-forge lap

这几个库安装完成以后,我们就可以开始配置hailo_model_zoo的环境了,我们直接使用下面的命令进入hailo_model_zoo的项目目录:

cd hailo_model_zoo

然后执行下面的命令来安装相关库:

pip install -e . -i https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple some-package

输入命令回车以后,可以发现,报错了,这里告诉我们缺少hailo相关的依赖包:

这些与hailo相关的包在pip源中没有,只能去hailo官网下载,下面教大家如何下载。

我们首先使用下面的链接前往hailo的官网:

hailo:Hailo AI on the Edge Processors | Edge AI Chip Solutions

进入以后,可以看到下面的界面:

这里我们需要点击右上角的头像注册并且登录我们的hailo账号:

登录完成以后,如图所示:

然后我们点击右上角的“Developer Zone”进入开发者社区:

进入以后,可以看到以下界面:

我们点击界面中的“SW Download”来到软件下载界面:

软件下载界面如图所示:

这里我们需要下载“Dataflow Compiler”的whl包。下面我来演示如何下载,首先我们需要选择我们hailo计算卡,这里我的计算卡是hailo8所以就选择了第一个:

我们首先来下载“Dataflow Compiler”,首先在下方的选框中,选择“Dataflow Compiler”,架构选择X86,系统选择Linux,python版本就是我们一开始创建虚拟环境时的python版本,即3.10:

选择完成以后,我们往下拉就可以看到,它已经列举出了与我们选项符合并且最新的“Dataflow Compiler”的whl包:

下载完成以后,得到以下文件:

我们将我们下载完成的“Dataflow Compiler”whl文件传到Ubuntu中,完成以后如图所示:

我们直接在虚拟环境中,使用pip安装这两个包即可:

pip install hailo_dataflow_compiler-3.32.0-py3-none-linux_x86_64.whl

如果觉得中途下载库太慢了,可以在命令后面加上下面的镜像源:

-i https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple some-package

安装完上面两个依赖库以后,我们再次到hailo_model_zoo目录执行下面的环境安装命令:

pip install -e . -i https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple some-package

可以看到,这次已经不报错了:

至此,我们hailo_model_zoo的环境就安装完成了。

我们可以直接在虚拟环境中输出hailo来看看效果:

当我们安装好hailo_model_zoo的模型以后,就可以来进行模型转换了,我们将我们之前转换得到的onnx模型复制到hailo_model_zoo的项目目录中,如图所示:

这里我们使用还需要将我们训练时用到的数据集拿过来一些,这里拿500~1000张就行,我们在hailo_model_zoo的项目目录下新建一个名为“images”的文件夹,将我们的数据集放进去,如图:

这里只需要图片即可,即images文件夹下只包含我们训练时用的数据集的图片。

完成以后,我们使用下面的命令来转换模型:

hailomz compile --ckpt best.onnx --calib-path ./images  --yaml  ./hailo_model_zoo/cfg/networks/yolov8n.yaml  --classes 9

下面我来简单解释一下这些参数,

--ckpt 表示我们要转换的模型的路径,这里需要指向我们的onnx文件。

--calib-path 表示我们数据集的路径,这里就指向我们刚刚复制过来的数据集。

--yaml 表示模型转换时配置文件的位置,这里我们直接使用官方的配置文件。大家根据自己底模选配置文件。

--classes 表示我们模型中包含物品的数量,这里一定要和训练时对上。这关系到后面的推理代码。

如果想要了解更详细的参数,以及yaml配置文件的格式,可以看hailo_model_zoo的文档:

hailo_model_zoo文档:文档 |海洛

这里没办法直接把文档网址复制过来,大家自己进去选Model_zoo即可。

输入命令回车以后,模型转换就开始了,但是我们会发现,出现了错误:

是哪个环节出了问题?

因为我们克隆了最新的hailo_model_zoo源码版本为5.0,我们使用pip list就可看到:

这个版本是不支持hailo8芯片的,即使我们转换模型时指定芯片,也会被提示不支持:

我们使用下面的命令将我们hailo_model_zoo的版本切换到2.16:

git checkout tags/v2.16 -b version-v2.16

可以看到,我们已经切换过来了:

然后我们再次执行依赖库安装命令:

pip install -e . -i https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple some-package

这次安装完以后,就可以看到,我们hailo_model_zoo的版本就是2.16了:

我们再次使用模型转换命令:

hailomz compile --ckpt best.onnx --calib-path ./images  --yaml  ./hailo_model_zoo/cfg/networks/yolov8n.yaml  --classes 9 --hw-arch hailo8

这里新增了一个--hw-arc参数来指定我们的芯片。

过一会儿就可以看到我们的模型转换已经开始了:

这里模型转换需要一阵子,大家耐心等待。

当出现这样的提示以后,表示我们的模型已经转换完成了:

可以看到,我们的模型输出为了一个名为“yolov8n.hef”的文件。在hailo_model_zoo的项目目录中就能看到:

这就是我们转换出来的模型文件了。至此,hef模型转换就完成了。

六、板端配置及hailo模型推理

        当我们转换完模型以后,就可以来配置开发板一侧了,这里开发板一侧首先需要我们将网络远程配通,我们可以通过ssh远程到开发板:

这里我使用的是鲁班猫3588开发板,大家根据自己的开发板配置即可。然后我们还需要将开发板的外部网络配通,我们的开发板需要能上网:

然后我们还需要配置hailo的pcie驱动,这一部分是非常麻烦的,我们需要得到当前开发板的内核源码,然后使用与编译内核时相同的交叉编译工具编译hailo的pcie驱动程序,最后得到ko,bin等二进制文件。具体的编译步骤可以查看hailort的相关文档:

hailoRT文档:v4.20.0 | Hailo

我现在拿到的板子,卖家已经帮我编译好了驱动,我只需要安装。但是这也引发了一些另外的问题,现在卖家编译的pcie驱动版本为4.20,这就意味着,我hailoRT也需要安装4.20版本,后面再python环境中安装的pyhailoRT也需要4.20版本。这里版本必须一样,我已经尝试过了,就算相差0.1都不行。但是目前,官方公开的demo代码的hailoRT版本为4.22,这就意味着,我们用不了官方的demo代码来推理,更糟糕的是,我们无法模仿demo来编写我们的代码,因为每个hailoRT版本之间的接口不完全通用。当然,针对4.20版本我已经摸索出来了一套能够运行代码,下面我将继续使用4.20版本进行演示。

当我们安装好板子的pcie驱动以后,我们就可以来安装hailoRT,这里我们同样来到刚刚下载“Dataflow Compiler”的地方,我们选择HailoRT:

这里因为是给板子安装的,架构我们选择ARM64,系统选择Linux,python选择3.11然后右边同样选择“Archive”,往下滑,就可以看到被筛选出来的文件了:

我们往下滑找到4.20版本:

这里我们需要下载两个东西,一个是hailoRT的deb包,另一个是hailoRT的whl包,whl包也被被我们叫做pyhailoRT,下次我提及这个概念的时候大家要知道。要下载的东西,就是被我框出来的这两个,当然,我这里因为pcie驱动是4.20,所以选择4.20,大家根据自己的情况选择即可:

下载完成以后,得到以下文件:

我们将其传到板子上,如图所示:

这里我们首先使用下下面的命令来安装hailoRT的deb包:

sudo dpkg -i hailort_4.20.0_arm64.deb

安装完hailoRT并且hailo的pcie驱动没问题的话,我们就可以输入下面的命令来查看以下我们的hailo设备:

可以看到,我们的设备被正常识别。

下面我们来安装python,直接使用下面的命令为开发板安装python3.11:

sudo apt install python3.11-venv python3.11-distutils python3.11-dev -y

安装完成以后,我们使用下面的命令来创建一个python的虚拟环境:

python3.11 -m venv hailo_test

创建好以后,使用下面的命令进入这个虚拟环境:

source hailo_test/bin/activate

下面我们在虚拟环境中来安装pyhailoRT,直接使用下面的命令来安装我们刚刚下载whl包:

pip install hailort-4.20.0-cp311-cp311-linux_aarch64.whl

安装完成以后,如图所示:

现在就来到最后一步了,我们需要写代码来推理我们hailo模型。如果你和我一样使用的是hailoRT4.20版本,那么我的代码你可以完美的运行起来。如果不是,那就需要看官方文档了,文档地址如下:

hailoRT文档:

可以在上方的版本这里选你自己hailo的版本:

目录往下滑,就能看看各个语言接口的参考了:

这些接口文档都是没有中文的,大家可以借助翻译与AI来阅读文档,从而编写推理代码。

好了,现在下面是我针对hailoRT4.20写的代码,不一定是最好的,但是起码能够推理图片:

import cv2
import numpy as np
from PIL import Image
import time
from hailo_platform.pyhailort.pyhailort import VDevice, HEF, InputVStreamParams, OutputVStreamParams, InferVStreams

# ---------- 初始化设备和模型 ----------
vdevice = VDevice()
hef = HEF("yolov8n.hef")
net_groups = vdevice.configure(hef)
net_group = net_groups[0]

input_info = net_group.get_input_vstream_infos()[0]
output_info = net_group.get_output_vstream_infos()[0]

# ---------- 类别列表 ----------
names = ['bird']

# ---------- 加载图片 ----------
image_path = "001.jpg"
image = Image.open(image_path).convert('RGB')
image_resized = image.resize((input_info.shape[0], input_info.shape[1]))  # width, height
input_data = np.array(image_resized)

# ---------- 数据类型 ----------
input_dtype = np.uint8 if hasattr(input_info, "quant_info") else np.float32
if input_dtype == np.float32:
    input_data = input_data.astype(np.float32) / 255.0
else:
    input_data = input_data.astype(np.uint8)

input_data = np.expand_dims(input_data, axis=0)  # batch维度

# ---------- 推理 ----------
input_params = InputVStreamParams.make(net_group)
output_params = OutputVStreamParams.make(net_group)

with net_group.activate():
    with InferVStreams(net_group, input_params, output_params) as inferer:
        start_time = time.time()
        results = inferer.infer({input_info.name: input_data})
        end_time = time.time()
        infer_time = (end_time - start_time) * 1000  # 转换成毫秒
        print(f"Inference time: {infer_time:.2f} ms")

# ---------- 合并输出,添加 class_id ----------
output_list = results[output_info.name]
all_detections = []

for batch_outputs in output_list:  # 遍历 batch
    for class_id, out_arr in enumerate(batch_outputs):  # 每个 buffer 对应一个类别
        if out_arr.size > 0:
            class_col = np.full((out_arr.shape[0], 1), class_id, dtype=np.int32)
            out_with_class = np.hstack([out_arr, class_col])  # shape=(N,6)
            all_detections.append(out_with_class)

if len(all_detections) > 0:
    all_detections = np.vstack(all_detections)  # shape=(N,6)
else:
    all_detections = np.empty((0,6))

# ---------- 画框 ----------
img_cv = cv2.imread(image_path)
h, w = img_cv.shape[:2]

for det in all_detections:
    y1, x1, y2, x2, score, cls_id = det
    score = float(score)
    cls_id = int(cls_id)
    if score < 0.5:
        continue

    # 归一化坐标 -> 像素
    x1 = int(x1 * w)
    x2 = int(x2 * w)
    y1 = int(y1 * h)
    y2 = int(y2 * h)

    x1, x2 = sorted((max(0, x1), min(w - 1, x2)))
    y1, y2 = sorted((max(0, y1), min(h - 1, y2)))

    class_name = names[cls_id]
    print(f"Box: ({x1},{y1},{x2},{y2}), score={score:.2f}, class_id={cls_id}, class_name={class_name}")

    label = f"{class_name} {score:.2f}"
    cv2.rectangle(img_cv, (x1, y1), (x2, y2), (0, 255, 0), 2)
    cv2.putText(img_cv, label, (x1, max(0, y1 - 5)),
                cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1)

cv2.imwrite("001_result.jpg", img_cv)
print("Result saved as 001_result.jpg")

这里代码中有几处大家需要自己改以下,首先就是“hef = HEF("yolov8n.hef")”这里大家需要将其修改为自己的模型路径。

然后是下面的类别列表中,这里的列表要与你训练时yaml文件的列表对应,下面是我训练模型时yaml的列表:

那我写到这边来就是这样的:

然后就是下面的“image_path = "001.jpg"”大家修改为自己要推理的图片的路径。

完成上面的步骤以后,我们使用下面的命令安装以下代码运行的依赖:

sudo apt install -y libopencv-dev libglib2.0-0 libsm6 libxext6 libxrender-dev
pip install opencv-python numpy Pillow -i https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple some-package

安装完成以后,大家别忘了把我们转换完成的hef模型文件拿过来:

准备好以后,我们直接运行这个py文件:

可以看到,这次运行使用了13.52ms,模型检测到了四个对象,并且将检测画框后的图像输出到了“001_result.jpg”。我们看看这个输出的图像:

可以看到,模型正常的框出了每一个杯子,并且类型也没问题。至此,我们使用hailo推理YOLO模型就完成了。

七、结语

        总算是完成了,完成这篇文章可以说是非常不容易,中间出现了太多没有解决办法的错误。在配置过程中,我反复强调版本问题,就是因为这是我折腾最久的地方,当你在某个步骤出错,不知道怎么办时,可以尝试看看官方文档。那么最后,感谢大家的观看!

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐