RK3588/RK3588s运行yolov8达到27ms

前言

        Hello,小伙伴们~~我最近做了一个比较有意思的东西,想起来也好久没有写博客了,就记录一下吧。希望和大家一起学习,一起进步!

        我简单介绍一下我最近做的这个东西的经过哈~上个月在B站上看到了一个博主发了一条视频关于边缘计算相关的,他仅仅用了一块巴掌不到的开发板完成了yolo的目标检测功能,而且延时还比较低,成本也仅有100元不到!倍感神奇哇!然后我就去学习了一下,关于NPU计算相关的知识,刚好有小伙伴手里有一块类似的开发板,于是就有了这篇博客。

 PS:我用的这块开发板的NPU芯片的算力达到了6TOPS,而上述博主的开发板芯片只有0.5TOPS。但是我尽力啦~~

设备

板卡

        为了避免打广告,我这里就简单放一下板卡的基本信息的介绍吧。

  然后,板卡长这样:

 这个板卡是自带系统的,我使用的是Ubuntu20.04的操作系统。

电脑

        这个电脑需要有Ubuntu操作系统。我使用的是windows10,然后安装了Ubuntu20.04虚拟机。这台电脑主要是将pytorch生成的.pt文件转换成.onnx文件,最后转成.rknn文件。

权重转换

yolov8训练

        在权重转换前,需要创建自己训练集,然后使用yolov8训练出自己训练集的权重。这里就不做过多的解释了,简单贴一下训练集中的标注文件和训练用的比较重要的两个配置文件。

标注文件解释

训练集配置(myDetData.yaml)

# Train/val/test sets as 1) dir: path/to/imgs, 2) file: path/to/imgs.txt, or 3) list: [path/to/imgs1, path/to/imgs2, ..]
path: 训练集路径  # dataset root dir
train: images/train  # train images (relative to 'path') 118287 images
val: images/val  # val images (relative to 'path') 5000 images
#test: test-dev2017.txt  # 20288 of 40670 images, submit to https://competitions.codalab.org/competitions/20794# Classes
names:0: hole    #种类索引和具体类别名称
nc: 1        #种类数量

网络配置(yolov8s.yaml)

# Ultralytics YOLO 🚀, AGPL-3.0 license
# YOLOv8 object detection model with P3-P5 outputs. For Usage examples see https://docs.ultralytics.com/tasks/detect# Parameters
nc: 1  # number of classes
scales: # model compound scaling constants, i.e. 'model=yolov8n.yaml' will call yolov8.yaml with scale 'n'# [depth, width, max_channels]
#  n: [0.33, 0.25, 1024]  # YOLOv8n summary: 225 layers,  3157200 parameters,  3157184 gradients,   8.9 GFLOPss: [0.33, 0.50, 1024]  # YOLOv8s summary: 225 layers, 11166560 parameters, 11166544 gradients,  28.8 GFLOPs
#  m: [0.67, 0.75, 768]   # YOLOv8m summary: 295 layers, 25902640 parameters, 25902624 gradients,  79.3 GFLOPs
#  l: [1.00, 1.00, 512]   # YOLOv8l summary: 365 layers, 43691520 parameters, 43691504 gradients, 165.7 GFLOPs
#  x: [1.00, 1.25, 512]   # YOLOv8x summary: 365 layers, 68229648 parameters, 68229632 gradients, 258.5 GFLOPs# YOLOv8.0n backbone
backbone:# [from, repeats, module, args]- [-1, 1, Conv, [64, 3, 2]]  # 0-P1/2- [-1, 1, Conv, [128, 3, 2]]  # 1-P2/4- [-1, 3, C2f, [128, True]]- [-1, 1, Conv, [256, 3, 2]]  # 3-P3/8- [-1, 6, C2f, [256, True]]- [-1, 1, Conv, [512, 3, 2]]  # 5-P4/16- [-1, 6, C2f, [512, True]]- [-1, 1, Conv, [1024, 3, 2]]  # 7-P5/32- [-1, 3, C2f, [1024, True]]- [-1, 1, SPPF, [1024, 5]]  # 9# YOLOv8.0n head
head:- [-1, 1, nn.Upsample, [None, 2, 'nearest']]- [[-1, 6], 1, Concat, [1]]  # cat backbone P4- [-1, 3, C2f, [512]]  # 12- [-1, 1, nn.Upsample, [None, 2, 'nearest']]- [[-1, 4], 1, Concat, [1]]  # cat backbone P3- [-1, 3, C2f, [256]]  # 15 (P3/8-small)- [-1, 1, Conv, [256, 3, 2]]- [[-1, 12], 1, Concat, [1]]  # cat head P4- [-1, 3, C2f, [512]]  # 18 (P4/16-medium)- [-1, 1, Conv, [512, 3, 2]]- [[-1, 9], 1, Concat, [1]]  # cat head P5- [-1, 3, C2f, [1024]]  # 21 (P5/32-large)- [[15, 18, 21], 1, Detect, [nc]]  # Detect(P3, P4, P5)

训练配置(train.py)

from ultralytics import YOLOif __name__ == '__main__':# 加载模型model = YOLO(r'yolov8s.yaml').load("yolov8s.pt")  # 使用预训练权重训练# 训练参数 ----------------------------------------------------------------------------------------------model.train(data=r'myDetectData.yaml',epochs=300,  # (int) 训练的周期数patience=50,  # (int) 等待无明显改善以进行早期停止的周期数batch=32,  # (int) 每批次的图像数量(-1 为自动批处理)imgsz=640,  # (int) 输入图像的大小,整数或w,hsave=True,  # (bool) 保存训练检查点和预测结果save_period=-1,  # (int) 每x周期保存检查点(如果小于1则禁用)cache=False,  # (bool) True/ram、磁盘或False。使用缓存加载数据device=0,  # (int | str | list, optional) 运行的设备,例如 cuda device=0 或 device=0,1,2,3 或 device=cpuworkers=8,  # (int) 数据加载的工作线程数(每个DDP进程)project='runs/train',  # (str, optional) 项目名称name='exp',  # (str, optional) 实验名称,结果保存在'project/name'目录下exist_ok=False,  # (bool) 是否覆盖现有实验pretrained=True,  # (bool | str) 是否使用预训练模型(bool),或从中加载权重的模型(str)optimizer='SGD',  # (str) 要使用的优化器,选择=[SGD,Adam,Adamax,AdamW,NAdam,RAdam,RMSProp,auto]verbose=True,  # (bool) 是否打印详细输出seed=0,  # (int) 用于可重复性的随机种子deterministic=True,  # (bool) 是否启用确定性模式single_cls=False,  # (bool) 将多类数据训练为单类rect=False,  # (bool) 如果mode='train',则进行矩形训练,如果mode='val',则进行矩形验证cos_lr=False,  # (bool) 使用余弦学习率调度器close_mosaic=0,  # (int) 在最后几个周期禁用马赛克增强resume=False,  # (bool) 从上一个检查点恢复训练amp=True,  # (bool) 自动混合精度(AMP)训练,选择=[True, False],True运行AMP检查fraction=1.0,  # (float) 要训练的数据集分数(默认为1.0,训练集中的所有图像)profile=False,  # (bool) 在训练期间为记录器启用ONNX和TensorRT速度# freeze= None,  # (int | list, 可选) 在训练期间冻结前 n 层,或冻结层索引列表。# 分割overlap_mask=True,  # (bool) 训练期间是否应重叠掩码(仅适用于分割训练)mask_ratio=4,  # (int) 掩码降采样比例(仅适用于分割训练)# 分类dropout=0.0,  # (float) 使用丢弃正则化(仅适用于分类训练)# 超参数 ----------------------------------------------------------------------------------------------lr0=0.01,  # (float) 初始学习率(例如,SGD=1E-2,Adam=1E-3)lrf=0.01,  # (float) 最终学习率(lr0 * lrf)momentum=0.937,  # (float) SGD动量/Adam beta1weight_decay=0.0005,  # (float) 优化器权重衰减 5e-4warmup_epochs=3.0,  # (float) 预热周期(分数可用)warmup_momentum=0.8,  # (float) 预热初始动量warmup_bias_lr=0.1,  # (float) 预热初始偏置学习率box=7.5,  # (float) 盒损失增益cls=0.5,  # (float) 类别损失增益(与像素比例)dfl=1.5,  # (float) dfl损失增益pose=12.0,  # (float) 姿势损失增益kobj=1.0,  # (float) 关键点对象损失增益label_smoothing=0.0,  # (float) 标签平滑(分数)nbs=64,  # (int) 名义批量大小hsv_h=0.015,  # (float) 图像HSV-Hue增强(分数)hsv_s=0.7,  # (float) 图像HSV-Saturation增强(分数)hsv_v=0.4,  # (float) 图像HSV-Value增强(分数)degrees=0.0,  # (float) 图像旋转(+/- deg)translate=0.1,  # (float) 图像平移(+/- 分数)scale=0.5,  # (float) 图像缩放(+/- 增益)shear=0.0,  # (float) 图像剪切(+/- deg)perspective=0.0,  # (float) 图像透视(+/- 分数),范围为0-0.001flipud=0.0,  # (float) 图像上下翻转(概率)fliplr=0.5,  # (float) 图像左右翻转(概率)mosaic=1.0,  # (float) 图像马赛克(概率)mixup=0.0,  # (float) 图像混合(概率)copy_paste=0.0,  # (float) 分割复制-粘贴(概率))

注意事项

        在后续导出onnx权重时,有一点要特别注意,就是yolov8的版本问题,使用最新版的yolov8版本可能会报错,AttributeError: 'Segment' object has no attribute 'detect'。我使用的是yolov8的8.0.151版本。(注意:该文件最好仅用于yolov8训练)

pt转onnx

        这个地方我使用的是这个代码:”pt转onnx“。这个里面对应的yolov8版本就是8.0.151的,如果用的版本对不上很有可能会报 AttributeError: 'Segment' object has no attribute 'detect'的错误。另外,这个链接里面的代码还有一部分需要修改。(注意:该链接代码最好仅用于pt转onnx)

在./ultralytics/nn/modules/head.py中需要修改为:

        # 导出 onnx 增加y = []for i in range(self.nl):sigmoid = nn.Sigmoid()t1 = self.cv2[i](x[i])# 这里没有加sigmoid会出现置信度大于1的情况t2 = sigmoid(self.cv3[i](x[i]))y.append(t1)y.append(t2)a = torch.sum(t2, dim=(1, ), keepdim=True).clip(min=0, max=1)y.append(a)return y

 如果要导出yolov8s-seg对应的onnx文件的小伙伴还需要改一个地方:

        p = self.proto(x[0])  # mask protosbs = p.shape[0]  # batch size# 导出 onnx 增加(修改)# mc = torch.cat([self.cv4[i](x[i]).view(bs, self.nm, -1) for i in range(self.nl)], 2)  # mask coefficientsmc = [self.cv4[i](x[i]) for i in range(self.nl)]x = self.detect(self, x)return x[0], x[1], x[2], mc[0], x[3], x[4], x[5], mc[1], x[6], x[7], x[8], mc[2], p

另外,就是导出部分需要再改一下代码。

在./ultralytics/engine/model.py文件中

        if self.task == "detect":print("===========  onnx =========== ")import torchdummy_input = torch.randn(1, 3, 640, 640)input_names = ["data"]output_names = ["reg1", "cls1", "scc1", "reg2", "cls2", "scc2", "reg3", "cls3", "scc3"]torch.onnx.export(self.model, dummy_input, "./yolov8s_rknn.onnx", verbose=False, input_names=input_names, output_names=output_names, opset_version=11)print("======================== convert onnx Finished! .... ")returnif self.task == "segment":print("===========  onnx =========== ")import torchdummy_input = torch.randn(1, 3, 640, 640)input_names = ["data"]output_names = ["cls1", "reg1", "scc1", "mc1", "cls2", "reg2", "scc2", "mc2", "cls3", "reg3", "scc3", "mc3", "seg"]torch.onnx.export(self.model, dummy_input, "./yolov8s_seg_rknn.onnx", verbose=False, input_names=input_names, output_names=output_names, opset_version=12)print("======================== convert onnx Finished! .... ")return

修改完上述代码后,就可以新建一个文件(export.py)了。文件内容如下:

from ultralytics import YOLO
# 推理
model = YOLO('./best.pt')
results = model(task='detect', mode='predict', source='./20240823092916.png', line_width=3, show=True, save=True, device='0')# results = model(task='segment', mode='predict', source='./20240823092916.png', line_width=3, show=True, save=True, device='0')

运行上面的文件就会出现下面的报错,如果报错和下方图片一样,则表明转换成功。

这里我按照官方给的文件进行修改的。

使用netron查看之后可以发现经过上述修改之后导出的文件结果和官方给出的结果是一模一样的。

detect

 segment

         到这,基本上就完成一半的工作了。后面就是onnx转rknn了,这一部分需要在Ubuntu下完成。

onnx转rknn

         完成这一步需要先配置一下python的环境,然后下载rknn-toolkit2文件。这个文件有点大,小伙伴也可以直接下载对应的requirements_cp38-1.6.0.txt和rknn_toolkit2-1.6.0+81f21f4d-cp38-cp38-linux_x86_64.whl,这样会小很多。然后使用下面命令

cd 到requirements_cp38-1.6.0.txt路径下
pip install -r requirements_cp38-1.6.0.txt -i https://pypi.tuna.tsinghua.edu.cn/simple/等到上述指令安装完成后
cd 到rknn_toolkit2-1.6.0+81f21f4d-cp38-cp38-linux_x86_64.whl路径下
pip install rknn_toolkit2-1.6.0+81f21f4d-cp38-cp38-linux_x86_64.whl -i https://pypi.tuna.tsinghua.edu.cn/simple/

 到这一步,基本环境就配置完成了,如果后面还需要其他的包,再继续安装就好了。

        下面再下载rknn_model_zoo,就可以进行onnx转rknn的模型转换了。

        下载完成后,先进入到./rknn_model_zoo/examples/yolov8/python目录下,将上一步生成的onnx文件复制到该路径下。

先运行下面的指令,验证导出模型的是否正确。

python3 yolov8.py --model_path yolov8s_rknn.onnx --img_show

         这里如果是使用自己的训练集的话,需要改一下yolov8.py中的CLASSES的种类。上面这种情况就表明onnx权重导出没问题。

python3 convert.py yolov8s_rknn.onnx rk3588s(或者rk3588)

 出现--> Export rknn model        done则表明导出成功。

rknn模型在./rknn_model_zoo/examples/yolov8/model中

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

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

相关文章

TomCat乱码问题

TomCat控制台乱码问题 乱码问题解决: 响应乱码问题 向客户端响应数据: package Servlet;import jakarta.servlet.ServletException; import jakarta.servlet.annotation.WebServlet; import jakarta.servlet.http.HttpServlet; import jakarta.servl…

对 Python 中 GIL 的理解

一.Python 中的 GIL Python 中的全局解释器锁(Global Interpreter Lock,GIL)是 CPython 解释器的一个机制,用来确保在多线程环境下,只有一个线程可以执行 Python 字节码,任何时刻只能有一个线程在执行 Pyt…

低代码可视化工具-uniapp页面跳转传参-代码生成器

uniapp页面跳转传参 在uni-app中,页面间的跳转和传参是一个常见的需求。uni-app提供了多种页面跳转方式,如uni.navigateTo、uni.redirectTo、uni.reLaunch、uni.switchTab、uni.navigateBack等,每种方式适用于不同的场景。以 页面跳转并传参…

win7自带壁纸丢失主题丢失

有时候盗版破解或者其他美化工具会导致win7自带的壁纸丢失,从个性化管理里面无法恢复原始的壁纸(如下图),但是由于工作原因公司的电脑又不方便设置第三方的壁纸,所以找了一下解决方案。 经典问题,百度找到的…

软考中级软设背诵内容

冯诺依曼结构、哈佛结构 冯诺依曼结构: 程序指令和数据都采用二进制表示 程序指令和数据在同一个存储器中混合 程序的功能都由中央处理器(CPU)执行指令来实现 程序的执行工作由指令进行自动控制 SRAM、DRAM 与DRAM相比,SRAM集成率低、功…

详细剖析RocketMQ消息消费原理

本文参考转载至《RocketMQ技术内幕 第2版》 一. 消息消费概述 消息消费以组的模式开展,一个消费组可以包含多个消费者,每个消费组可以订阅多个主题,消费组之间有集群模式和广播模式两种消费模式。集群模式是当前主题下的同一条消息只允许被其…

hutool 解压缩读取源文件和压缩文件大小失败导致报错

前言 最近处理老项目中的问题,升级安全jar,发现hutool的jar在解压缩的时候报错了,实际上是很简单的防御zip炸弹攻击的手段,但是却因为hutool的工具包取文件大小有bug,造成了解压缩不能用,报错:…

2024年华为杯数学建模研赛(F题) 建模解析| 卫星轨道 | 小鹿学长带队指引全代码文章与思路

我是鹿鹿学长,就读于上海交通大学,截至目前已经帮2000人完成了建模与思路的构建的处理了~ 本篇文章是鹿鹿学长经过深度思考,独辟蹊径,实现综合建模。独创复杂系统视角,帮助你解决研赛的难关呀。 完整内容可…

代码随想录Day 51|题目:99.岛屿数量、100.岛屿的最大面积

提示:DDU,供自己复习使用。欢迎大家前来讨论~ 文章目录 题目一:99. 岛屿数量思路深度优先搜索DFS广度优先搜索BFS 题目二:100. 岛屿的最大面积DFSBFS 总结 题目一:99. 岛屿数量 99. 岛屿数量 (kamacoder.com) 思路 …

Java高级Day48-JDBC-API和JDBC-Utils

127.JDBC API 128.JDBC-Utils public class JDBCUtils {//这是一个工具类,完成mysql的连接和关闭资源//顶柜相关的属性(4个),因为只需要一份,因此做成staticprivate static String user;//用户名private static Stri…

Vision Transformer (ViT)、Swin Transformer 和 Focal Transformer

1. Vision Transformer (ViT) Vision Transformer详解-CSDN博客https://blog.csdn.net/qq_37541097/article/details/118242600?ops_request_misc%257B%2522request%255Fid%2522%253A%2522F8BBAFBF-A4A1-4D38-9C0F-9A43B56AF6DB%2522%252C%2522scm%2522%253A%252220140713.13…

如何把python(.py或.ipynb)文件打包成可运行的.exe文件?

将 Python 程序打包成可执行的 .exe 文件,通常使用工具如 PyInstaller。这是一个常用的 Python 打包工具,可以将 Python 程序打包成独立的可执行文件,即使没有安装 Python 也能运行。 步骤: 1. 安装 PyInstaller 使用 conda 安…

如何在Linux Centos7系统中挂载群晖共享文件夹

前景:企业信息化各种系统需要上传很多的图片或者是文件,文件如何在群晖中显示,当文件或者图片上传到linux指定文件夹内,而文件夹又与群晖共享文件夹进行挂载,就能保证上传的文件或者图片出现在群晖并在群晖里进行管理。…

Java之继承1

1. 继承 1.1 为什么要继承 在Java中我们定义猫类和狗类,如下 public class Cat {public String name;public int age;public String color;public void eat(){System.out.println(name "正在吃饭");}public void sleep(){System.out.println(name &qu…

网页聊天——测试报告——Selenium自动化测试

一,项目概括 1.1 项目名称 网页聊天 1.2 测试时间 2024.9 1.3 编写目的 对编写的网页聊天项目进行软件测试活动,揭示潜在问题,总结测试经验 二,测试计划 2.1 测试环境与配置 服务器:云服务器 ubuntu_22 PC机&am…

国庆电影扎堆来袭,AI智能体帮你推荐必看佳片!(附制作教程)

大家好,我是凡人。 今天看到新闻,发现国庆有10部影片要扎堆儿上映,对于选择困难症的我属实有点难选,同时也想避开一些坑省的浪费金钱和时间。 本着不知道就问AI的习惯,想问问大模型怎么看,但做了简单的交…

Go语言基础学习02-命令源码文件;库源码文件;类型推断;变量重声明

命令源码文件 GOPATH指向的一个或者多个工作区,每个工作区都会有以代码包为基本组织形式的源码文件。 Go语言中源码文件可以分为三类:命令源码文件、库源码文件、测试源码文件。 命令源码文件: 命令源码文件是程序的运行入口,是每…

descrTable常用方法

descrTable 为 R 包 compareGroups 的重要函数,有关该函数以及 compareGroups 包的详细内容见:R包compareGroups详细用法 加载包和数据 library(compareGroups)# 加载 REGICOR 数据(横断面,从不同年份纳入,每个变量有…

十五、差分输入运算放大电路

差分输入运算放大电路 1、差分输入运算放大电路的特点、用途, 2、输出信号电压与输入信号电压的关系。

Python | Leetcode Python题解之第420题强密码检验器

题目: 题解: class Solution:def strongPasswordChecker(self, password: str) -> int:n len(password)has_lower has_upper has_digit Falsefor ch in password:if ch.islower():has_lower Trueelif ch.isupper():has_upper Trueelif ch.isdi…