树莓派也可以部署基于YOLO的目标检测

news2024/11/15 4:46:39

5db2331db4380fb78e6d7c9148083f8c.jpeg

YOLO目标检测结果

在本文的第一部分中,我测试了YOLO(You Only Look Once)这一流行的目标检测库的“复古”版本。只使用OpenCV运行深度学习模型,而不使用“沉重”的框架如PyTorch或Keras,对于低功耗设备来说是有前途的,因此我决定深入研究这个主题,看看最新的YOLO v8模型在树莓派上的工作原理。

让我们深入了解。

硬件

在云中运行任何模型通常不是问题,资源几乎是无限的。但对于“在现场”的硬件,有更多的限制。有限的RAM、CPU功率,甚至不同的CPU架构、较旧或不兼容的软件版本、缺乏高速互联网连接等等。云基础设施的另一个重要问题是成本。假设我们正在制作一个智能门铃,并且我们想要向其添加人员检测。我们可以在云中运行一个模型,但每个API调用都要花钱,谁来支付呢?并不是每个客户都愿意为门铃或任何类似的“智能”设备支付月费,因此在本地运行模型可能至关重要,即使结果可能不那么好。

在这个测试中,我将在树莓派上运行YOLO v8模型:

91e194592d7707119f9eee152a494f59.jpeg

树莓派4

树莓派是一款便宜的信用卡大小的单板计算机,运行Raspbian或Ubuntu Linux。我将测试两个不同的版本:

  • 树莓派3 Model B,制造于2015年。它配备了1.2 GHz Cortex-A53 ARM CPU和1 GB RAM。

  • 树莓派4,制造于2019年。它配备了1.8 GHz Cortex-A72 ARM CPU和1、4或8 GB RAM。

树莓派计算机现在广泛用于不仅是爱好和DIY项目,还用于嵌入式工业应用(专为此设计的树莓派计算模块)。因此,看到这些板子如何处理目标检测等计算要求较高的操作是很有趣的。在接下来的所有测试中,我将使用这张图片:

78f2a3c540cab944a03b2dbe3e863fe3.jpeg

测试图片

现在,让我们看看它是如何工作的。

“标准”版本的YOLOv8

作为热身,让我们尝试标准版本,就像它在官方GitHub页面上描述的那样:

from ultralytics import YOLOimport cv2import timemodel = YOLO('yolov8n.pt')img = cv2.imread('test.jpg')# First run to 'warm-up' the modelmodel.predict(source=img, save=False, save_txt=False, conf=0.5, verbose=False)# Second runt_start = time.monotonic()results = model.predict(source=img, save=False, save_txt=False, conf=0.5, verbose=False)dt = time.monotonic() - t_startprint("dT:", dt)# Show resultsboxes = results[0].boxesnames = model.namesconfidence, class_ids = boxes.conf, boxes.cls.int()rects = boxes.xyxy.int()for ind in range(boxes.shape[0]):    print("Rect:", names[class_ids[ind].item()], confidence[ind].item(), rects[ind].tolist())

在“生产”系统中,可以从相机中获取图像;对于我们的测试,我使用了一个名为“test.jpg”的文件,如前所述。我还执行了两次“predict”方法,以使时间估计更加准确(第一次运行通常需要更多时间,因为模型需要“热身”并分配所有所需的内存)。树莓派以“无头”模式工作,没有显示器,因此我使用控制台作为输出;这是大多数嵌入式系统工作的一种更或多或少的标准方式。

在具有32位操作系统的树莓派3上,这个版本不起作用:pip不能安装“ultralytics”模块,因为出现了以下错误:

ERROR: Cannot install ultralyticsThe conflict is caused by:    ultralytics 8.0.124 depends on torch>=1.7.0

结果发现,PyTorch仅适用于ARM 64位操作系统。在具有64位操作系统的树莓派4上,代码确实可以工作,计算时间约为0.9秒。控制台输出如下:

55d12f7c01619ec142a93f1889f617e7.jpeg

我还在台式电脑上进行了相同的实验以可视化结果:

3af23ea29cdfc849baaf0baf68cbc8ed.jpeg

YOLO v8 Nano检测结果

正如我们所看到的,即使对于“nano”大小的模型,结果也相当不错。

Python ONNX版本

ONNX(开放神经网络交换)是一种用于表示机器学习模型的开放格式。它也得到了OpenCV的支持,因此我们可以很容易地以这种方式运行我们的模型。YOLO的开发人员已经提供了一个命令行工具来进行此转换:

yolo export model=yolov8n.pt imgsz=640 format=onnx opset=12

在这里,“yolov8n.pt”是将要转换的PyTorch模型文件。文件名中的最后一个字母“n”表示“nano”。不同的模型可用(“n” — nano,“s” — small,“m” — medium,“l” — large),显然,对于树莓派,我将使用最小和最快的模型。可以在台式电脑上进行转换,然后使用“scp”命令将模型复制到树莓派:

scp yolov8n.onnx pi@raspberrypi:/home/pi/Documents/YOLO

现在我们准备好准备源代码。我使用了Ultralytics存储库中的一个示例,稍作修改以在树莓派上运行:

import cv2
import time




model: cv2.dnn.Net = cv2.dnn.readNetFromONNX("yolov8n.onnx")
names = "person;bicycle;car;motorbike;aeroplane;bus;train;truck;boat;traffic light;fire hydrant;stop sign;parking meter;bench;bird;" \
"cat;dog;horse;sheep;cow;elephant;bear;zebra;giraffe;backpack;umbrella;handbag;tie;suitcase;frisbee;skis;snowboard;sports ball;kite;" \
"baseball bat;baseball glove;skateboard;surfboard;tennis racket;bottle;wine glass;cup;fork;knife;spoon;bowl;banana;apple;sandwich;" \
"orange;broccoli;carrot;hot dog;pizza;donut;cake;chair;sofa;pottedplant;bed;diningtable;toilet;tvmonitor;laptop;mouse;remote;keyboard;" \
"cell phone;microwave;oven;toaster;sink;refrigerator;book;clock;vase;scissors;teddy bear;hair dryer;toothbrush".split(";")


img = cv2.imread('test.jpg')
height, width, _ = img.shape
length = max((height, width))
image = np.zeros((length, length, 3), np.uint8)
image[0:height, 0:width] = img
scale = length / 640


# First run to 'warm-up' the model
blob = cv2.dnn.blobFromImage(image, scalefactor=1 / 255, size=(640, 640), swapRB=True)
model.setInput(blob)
model.forward()


# Second run
t1 = time.monotonic()
blob = cv2.dnn.blobFromImage(image, scalefactor=1 / 255, size=(640, 640), swapRB=True)
model.setInput(blob)
outputs = model.forward()
print("dT:", time.monotonic() - t1)


# Show results
outputs = np.array([cv2.transpose(outputs[0])])
rows = outputs.shape[1]


boxes = []
scores = []
class_ids = []
output = outputs[0]
for i in range(rows):
    classes_scores = output[i][4:]
    minScore, maxScore, minClassLoc, (x, maxClassIndex) = cv2.minMaxLoc(classes_scores)
    if maxScore >= 0.25:
        box = [output[i][0] - 0.5 * output[i][2], output[i][1] - 0.5 * output[i][3],
               output[i][2], output[i][3]]
        boxes.append(box)
        scores.append(maxScore)
        class_ids.append(maxClassIndex)


result_boxes = cv2.dnn.NMSBoxes(boxes, scores, 0.25, 0.45, 0.5)
for index in result_boxes:
    box = boxes[index]
    box_out = [round(box[0]*scale), round(box[1]*scale),
               round((box[0] + box[2])*scale), round((box[1] + box[3])*scale)]
    print("Rect:", names[class_ids[index]], scores[index], box_out)

如我们所见,我们不再使用PyTorch和原始的Ultralytics库,但所需的代码量更大。我们需要将图像转换为一个blob,这是YOLO模型所需的。在打印结果之前,我们还需要将输出矩形转换为原始坐标。但作为优势,这个代码在“纯粹”的OpenCV上运行,没有任何额外的依赖关系。

在树莓派3上,计算时间为28秒。只是为了好玩,我还加载了“medium”模型(这是一个101 MB的ONNX文件!)看看会发生什么。令人惊讶的是,应用程序没有崩溃,但计算时间为224秒(近4分钟)。显然,2015年的硬件不适合运行来自2023年的SOTA模型,但看到它如何工作仍然很有趣。

在树莓派4上,计算时间为1.08秒。

C++ ONNX版本

最后,让我们尝试我们工具集中的“最重”的武器,并在C++中编写相同的代码。但在这之前,我们需要安装用于C++的OpenCV库和头文件。最简单的方法是运行类似“sudo apt install libopencv-dev”的命令。但至少对于Raspbian,它不起作用。通过“apt”可用的最新版本是4.2,而加载YOLO模型所需的OpenCV的最低要求是4.5。因此,我们需要从源代码构建OpenCV。我将使用OpenCV 4.7,与我Python测试中使用的相同的版本:

sudo apt update
sudo apt install g++ cmake libavcodec-dev libavformat-dev libswscale-dev libgstreamer-plugins-base1.0-dev libgstreamer1.0-dev 
sudo apt install libgtk2.0-dev libcanberra-gtk* libgtk-3-dev libpng-dev libjpeg-dev libtiff-dev
sudo apt install libxvidcore-dev libx264-dev libgtk-3-dev libgstreamer1.0-dev gstreamer1.0-gtk3


wget https://github.com/opencv/opencv/archive/refs/tags/4.7.0.tar.gz
tar -xvzf 4.7.0.tar.gz
rm 4.7.0.tar.gz
cd opencv-4.7.0
mkdir build && cd build


cmake -D WITH_QT=OFF -D WITH_VTK=OFF -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -D WITH_FFMPEG=ON -D PYTHON3_PACKAGES_PATH=/usr/lib/python3/dist-packages -D BUILD_EXAMPLES=OFF ..
make -j2 && sudo make install && sudo ldconfig

树莓派不是世界上最快的Linux计算机,编译过程大约需要2小时。对于具有1GB RAM的树莓派3,交换文件大小应至少增加到512MB;否则,编译将失败。

C++代码本身很短:

#include <opencv2/opencv.hpp>
#include <vector>
#include <ctime>
#include "inference.h"


int main(int argc, char **argv) {
Inference inf("yolov8n.onnx", cv::Size(640, 640), "", false);


    cv::Mat frame = cv::imread("test.jpg");


// First run to 'warm-up' the model
    inf.runInference(frame);


// Second run
const clock_t begin_time = clock();


std::vector<Detection> output = inf.runInference(frame);


printf("dT: %f\n",  float(clock() - begin_time)/CLOCKS_PER_SEC);


// Show results
for (auto &detection : output) {
        cv::Rect box = detection.box;


printf("Rect: %s %f: %d %d %d %d\n", detection.className.c_str(), detection.confidence,
                                             box.x, box.y, box.width, box.height);        
    }


return 0;
}

在这个代码中,我使用了Ultralitics GitHub存储库中的“inference.h”和“inference.cpp”文件,这些文件应放置在同一个文件夹中。我还执行了两次“runInference”方法,与之前的测试一样。我们现在可以使用这个命令编译源代码:

c++ yolo1.cpp inference.cpp -I/usr/local/include/opencv4 -L/usr/local/lib -lopencv_core -lopencv_dnn -lopencv_imgcodecs -lopencv_imgproc -O3 -o yolo1

结果令人惊讶。C++版本比之前的版本慢得多!在树莓派3上,执行时间为110秒,比Python版本慢了三倍多。在树莓派4上,计算时间为1.79秒,大约慢了1.5倍。总的来说,很难说为什么。Python的OpenCV库是使用pip安装的,但C++的OpenCV是从源代码构建的,也许一些ARM CPU优化没有启用。如果有读者知道原因,请在下面的评论中写明。无论如何,看到这样的效果发生真的很有趣。

结论

我可以“合理猜测”大多数数据科学家和数据工程师在云中使用他们的模型,或者至少在高端设备上使用模型,并且从未尝试在嵌入式硬件上“现场”运行代码。这篇文章的目标是为读者提供一些关于它是如何工作的见解。在这篇文章中,我们尝试在不同版本的树莓派上运行YOLO v8模型,结果非常有趣。

  • 在低功耗设备上运行深度学习模型可能是一个挑战。即使是树莓派4,也就是撰写本文时基于Raspbian的最佳模型,也只能以约1 FPS的速度提供YOLO v8 Tiny模型。当然,还有改进的空间。可能可以进行一些优化,例如将模型转换为FP16(具有较低精度的浮点格式)或甚至INT8格式。最后,可以使用在特殊的单板计算机上运行的代码,如NVIDIA Jetson Nano,它支持CUDA并且可能更快。

  • 在本文的开头,我写道“只使用OpenCV,而不使用PyTorch或Keras等沉重的框架运行深度学习模型的可能性对于低功耗设备是有前途的”。实际上,PyTorch是一个高效且高度优化的框架。基于PyTorch的原始YOLO版本是最快的,而基于OpenCV的ONNX代码比它慢10-20%。但在我撰写本文时,PyTorch在32位ARM CPU上不可用,因此在某些平台上可能别无选择。

  • C++版本的结果更有趣。正如我们所看到的,要在适当的优化下运行可能是一项挑战,特别是对于嵌入式架构。而且,如果不深入研究这些细节,与由板厂商提供的Python版本相比,自定义构建的OpenCV C++代码甚至可能运行得更慢。

·  END  ·

HAPPY LIFE

563058530ac0525c786a03856b1b4bd3.png

本文仅供学习交流使用,如有侵权请联系作者删除

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1397711.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Python | 六、哈希表 Hash Table(列表、集合、映射)

哈希表基础 哈希表是一类数据结构&#xff08;哈希表包含数组、集合和映射&#xff0c;和前两篇文章叙述的字符串、链表平级&#xff09;哈希表概念&#xff1a;类似于Python里的字典类型&#xff0c;哈希表把关键码key值通过哈希函数来和哈希表上的索引对应起来&#xff0c;之…

DNA序列修正*

题目 import java.util.HashMap; import java.util.Map; import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner sc new Scanner(System.in);int n sc.nextInt();sc.nextLine();char[] sq1 sc.next().toCharArray();sc.nextLine(…

ROS第 10 课 服务数据的自定义与使用

文章目录 第 10 课 服务数据的自定义与使用1.自定义服务数据2.服务数据的使用2.1 创建服务器和客户端代码2.2 运行服务器和客户端节点 第 10 课 服务数据的自定义与使用 1.自定义服务数据 注意&#xff1a;在自定义服务数据之前&#xff0c;需要先创建工作空间和功能包&#x…

【Linux第二课-权限】操作系统、Linux用户、Linux权限、Linux文件类型、粘滞位

目录 操作系统shell外壳为什么有shell外壳shell外壳是什么shell外壳工作原理 Linux用户root用户与非root用户root用户与普通用户的切换普通用户 --> root用户root用户 --> 普通用户普通用户 --> 普通用户对一条指令提升为root权限进行执行 Linux权限Linux中的权限角色…

STM32(--001) Win10、Win11 上的驱动安装说明

一、USB线插到 CMSIS-DAP 接口上&#xff0c;将自动识别到两个设备 ① CMSIS-DAP&#xff1a;用于烧录代码、在线硬件仿真; 在Keil里烧录&#xff0c;无需通过FlyMCU; ② USB转TTL&#xff1a;用于开发板与电脑间串口通信 &#xff0c;即USART1, TX-PA9、RX-PA10; 接口备注&a…

Java 流程控制 - 分支、循环

顺序控制 程序从上到下逐行执行&#xff0c;中间没有任何判断和跳转。 public class Test{//正确形式int a 1;int b a;// 错误形式int c d 1;int d 2; }块作用域 块&#xff08;即复合语句&#xff09;是指由一对大括号括起来的若干条简单的 Java 语句。块确定了变量的…

JVM性能调优-垃圾收集器G1详解

目录 G1收集器(-XX:UseG1GC) G1垃圾收集分类 YoungGC MixedGC Full GC G1收集器参数设置 G1垃圾收集器优化建议 什么场景适合使用G1 G1收集器(-XX:UseG1GC) G1 (Garbage-First)是一款面向服务器的垃圾收集器,主要针对配备多颗处理器及大容量内存的机器. 以极高概率满足…

redis未授权访问全漏洞复现

redis未授权访问全漏洞复现 Redis 有关的漏洞具有明显的时间分段性&#xff0c;在15年11月之前&#xff0c;主要是未授权导致的数据泄露&#xff0c;获得一些账号密码。另外还可以 DoS&#xff08;参考&#xff1a;Sangfor VMP redis unauthorized access vulnerability&#…

UI开发布局-HarmonyOS应用UI开发布局

UI页面的构建不用再像Android开发过程中在.xml文件中书写&#xff0c;可直接在页面上使用声明式UI的方式按照布局进行排列&#xff0c;构建应用的页面。 如下代码使用Row、Column构建一个页面布局&#xff0c;在页面布局中添加组件Text、Button&#xff0c;共同构成页面&#…

Git学习笔记(第5章):Git团队协作机制

目录 5.1 团队内协作 5.2 跨团队协作 Git进行版本控制都是在本地库操作的。若想使用Git进行团队协作&#xff0c;就必须借助代码托管中心。 5.1 团队内协作 问题引入&#xff1a;成员1&#xff08;大佬&#xff09;利用Git在宿主机上初始化本地库&#xff0c;完成代码的整体…

016-Vue-黑马2023:前后端分离开发(在线接口文档),前端工程化、Element、vue编写一个完成页面、Vue路由、vue打包部署到nginx

第三节 前后端分离开发 1、介绍 开发模式 前后端混合开发&#xff1a;传统开发模式 前后端分离开发&#xff1a;当前最为主流的开发模式 页面原型需求案例&#xff1a;分析出接口文档 离线开发文档示例&#xff1a; 2、YAPI&#xff08;官网已停用&#xff09; 202…

服务注册流程解析

本文主要介绍服务注册的基本流程 起手式 接上面的继续说&#xff0c;服务注册是一门至高无上的武学&#xff0c;招式千变万化 &#xff0c;九曲十八弯打得你找不到北。可正所谓这顺藤摸瓜&#xff0c;瓜不好找&#xff0c;可是这藤长得地方特别显眼。那么今天&#xff0c;就让…

【极问系列】springBoot集成elasticsearch出现Unable to parse response body for Response

【极问系列】 springBoot集成elasticsearch出现Unable to parse response body for Response 如何解决&#xff1f; 一.问题 #springboot集成elasticsearch组件,进行增删改操作的时候报异常Unable to parse response body for Response{requestLineDELETE /aurora-20240120/…

HarmonyOS4.0系列——07、自定义组件的生命周期、路由以及路由传参

自定义组件的生命周期 允许在生命周期函数中使用 Promise 和异步回调函数&#xff0c;比如网络资源获取&#xff0c;定时器设置等&#xff1b; 页面生命周期 即被Entry 装饰的组件生命周期&#xff0c;提供以下生命周期接口&#xff1a; onPageShow 页面加载时触发&#xff…

UE5 C++ 学习笔记 UBT UHT 和 一些头文件

总结一些似懂非懂的知识点&#xff0c;从头慢慢梳理。 任何一个项目都有创建这些三个.cs。 这个是蓝图转C 这个是本身就是C项目,应该就是多了一个GameModeBase类 Build.cs包含了每个模块的信息&#xff0c;表明了这个项目用到了哪一些模块。该文件里的using UnrealBuilTool 是…

路由器结构

路由器是连接互联网的设备&#xff0c;本文主要描述路由器的结构组成。 如上所示&#xff0c;OSI&#xff08;Open System Interconnect&#xff09;开放系统互联参考模型是互联网架构的标准协议栈&#xff0c;由ISO标准组织制定。自底向上&#xff0c;互联网架构分为7层&#…

Gitee作为远程仓库保存Vue项目

1.先在gitee上创建仓库 2.本地创建vue项目 3. 将本地项目与远程仓库进行关联 依次执行以下命令 # 进入到项目所在目录 cd vue-rabbit # 将项目变成git项目, 运行命令会在该目录下生成 .git文件 git init# 本地仓库与远程仓库进行关联 git remote add origin 你项目的远程地址…

vue+springboot(前后端分离项目)

目录 JAVA后端项目 一、创建项目 1、使用aliyun的server url 2、初始化项目结构 3、添加依赖 4、创建文件夹 5、把mapper类交给spring容器管理 5.1、方法1 5.2、方法2 6、在yaml文件中配置数据库信息 7、在yaml文件中配置mapper的xml文件的路径 8、配置mapper的xml文…

Django开发_13_静态资源、cookie/session/token

一、在html文件下的操作 &#xff08;一&#xff09;在html中添加{% load static %}标签&#xff0c;加载static模块 &#xff08;二&#xff09;使用{%static "图片地址" %}动态生成静态资源URL 二、csrf跨站请求伪造 在账号登录的html文件中相应位置要加上{% csr…

转转交易猫自带客服多模板全开源完整定制版源码

商品发布&#xff1b; 请在后台商品添加成功后&#xff0c; 再点击该商品管理&#xff0c;可重新编辑当前商品的所有信息及配图以及支付等等相关信息 可点击分享或者跳转&#xff0c;将链接地址进行发布分享 请在手机端打开访问 访问商品主要模板文件路径目录 咸鱼&#…