RK3588/RK3588s运行yolov8达到27ms

news2024/9/22 0:29:01

前言

        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 GFLOPs
  s: [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 YOLO

if __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,h
        save=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=cpu
        workers=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 beta1
        weight_decay=0.0005,  # (float) 优化器权重衰减 5e-4
        warmup_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.001
        flipud=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 protos
        bs = 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 coefficients
        mc = [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 torch
            dummy_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! .... ")
            return

        if self.task == "segment":
            print("===========  onnx =========== ")
            import torch
            dummy_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.coloradmin.cn/o/2153718.html

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

相关文章

DataGrip远程连接Hive

学会用datagrip远程操作hive 连接前提条件: 注意:mysql是否是开启状态 启动hadoop集群 start-all.sh 1、启动hiveserver2服务 nohup hiveserver2 >> /usr/local/soft/hive-3.1.3/hiveserver2.log 2>&1 & 2、beeline连接 beelin…

上海市高等学校信息技术水平考试 C程序设计(2021A场)全解

2e-1 为 1.0^(-1)*2 在顺序查找法中,如果要从n个学生中找到某个特定的学生信息,最坏的情况是这个学生是最后一个被比较的,这时需要比较n次。但是,如果学生是均匀分布的,那么平均来说,你会在列表的中间找到这…

stm32单片机个人学习笔记5(OLED调试工具)

前言 本篇文章属于stm32单片机(以下简称单片机)的学习笔记,来源于B站教学视频。下面是这位up主的视频链接。本文为个人学习笔记,只能做参考,细节方面建议观看视频,肯定受益匪浅。 STM32入门教程-2023版 细…

校园场景物体检测系统源码分享

校园场景物体检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer…

【RabbitMQ】⾼级特性

RabbitMQ ⾼级特性 1. 消息确认1.1 消息确认机制1.2 代码示例 2. 持久化2.1 交换机持久化2.2 队列持久化2.3 消息持久化 3. 发送⽅确认3.1 confirm确认模式3.2 return退回模式3.3 问题: 如何保证RabbitMQ消息的可靠传输? 4. 重试机制5. TTL5.1 设置消息的TTL5.2 设置队列的TTL…

华为HarmonyOS地图服务 10 - 如何在地图上绘制圆?

场景介绍 本章节将向您介绍如何在地图上绘制圆形。 接口说明 添加圆形功能主要由MapCircleOptions、addCircle和MapCircle提供,更多接口及使用方法请参见

gbase8s数据库常见的索引扫描方式

1 顺序扫描(Sequential scan):数据库服务器按照物理顺序读取表中的所有记录。 常发生在表上无索引或者数据量很少或者一些无法使用索引的sql语句中 2 索引扫描(Index scan):数据库服务器读取索引页&#…

Leetcode—1184. 公交站间的距离【简单】

2024每日刷题&#xff08;161&#xff09; Leetcode—1184. 公交站间的距离 实现代码 class Solution { public:int distanceBetweenBusStops(vector<int>& distance, int start, int destination) {int clockwise 0;int counterclockwise 0;if(start > desti…

CompletableFuture的allOf一定不要乱用!血泪史复盘

文章目录 1. 到底遇到了什么问题&#xff1f;2. CountDownLatch搞起&#xff1f;3. allOf里面的坑4. 优化建议&#xff1a; 1. 到底遇到了什么问题&#xff1f; 最近看到组里面的同学遇到了这样的业务场景&#xff1a; 主线程需要异步并发调用多个接口&#xff0c;并且主线程…

大模型终极指南:零基础到精通,一文搞定!

随着 ChatGPT 的到来&#xff0c;大模型[1]&#xff08;Large Language Model&#xff0c;简称 LLM&#xff09;成了新时代的 buzzword&#xff0c;各种 GPT 产品百花齐放。 大多数人直接用现有产品就可以了&#xff0c;但对于喜欢刨根问底的程序员来说&#xff0c;能够在本地…

python-SZ斐波那契数列/更相减损数

一&#xff1a;SZ斐波那契数列题目描述 你应该很熟悉斐波那契数列&#xff0c;不是吗&#xff1f;现在小理不知在哪里搞了个山寨版斐波拉契数列&#xff0c;如下公式&#xff1a; F(n) { $\ \ \ \ \ \ \ \ \ \ \ \ $ a,( n1) $\ \ \ \ \ \ \ \ \ \ \ \ $ b,( n2) $\ \ \ \ \ \ …

回归预测 | Matlab实现ReliefF-XGBoost多变量回归预测

回归预测 | Matlab实现ReliefF-XGBoost多变量回归预测 目录 回归预测 | Matlab实现ReliefF-XGBoost多变量回归预测效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.ReliefF-xgboost回归预测代码&#xff0c;对序列数据预测性能相对较高。首先通过ReleifF对输入特征计算权…

Spring中的Web Service消费者集成(应该被淘汰的技术)

问题 最近需要对接一个老系统的web service接口&#xff0c;我已经有7&#xff0c;8年没有遇到过这种接口了。 思路 先用Spring空项目中的jaxws-maven-plugin插件生成一波web service客户端&#xff0c;然后&#xff0c;集成到现有的SpringBoot3项目中使用就可以了。 生成w…

人才有约,职为你:颐年集团携手粤荣学校共绘养老行业的美好未来

摘要&#xff1a;广州市白云区粤荣职业培训学校成功举办“人才有约&#xff0c;职为你”颐年集团养老机构线下招聘会 2024年9月19日下午2点30分&#xff0c;广州市白云区金骊城二楼热闹非凡。粤荣职业培训学校携手颐年集团&#xff0c;共同举办了主题为“人才有约&#xff0c;…

做短剧申请微信小程序备案整体的操作流程!

做国内短剧对接微信小程序&#xff0c;小程序备案是必不可少的&#xff0c;需要准备哪些资料&#xff0c;以及需要注意的事项&#xff0c;所需材料全部整理出来了&#xff0c;小程序从注册到类目和备案分为五个步骤来讲解&#xff0c;下面就由我来向大家介绍所有的操作流程。 …

【RabbitMQ】消息分发、事务

消息分发 概念 RabbitMQ队列拥有多个消费者时&#xff0c;队列会把收到的消息分派给不同的消费者。每条消息只会发送给订阅该队列订阅列表里的一个消费者。这种方式非常适合扩展&#xff0c;如果现在负载加重&#xff0c;那么只需要创建更多的消费者来消费处理消息即可。 默…

docker desktop windows stop

服务docker改为启动 cmd下查看docker版本 {"builder": {"gc": {"defaultKeepStorage": "20GB","enabled": true}},"experimental": false,"registry-mirrors": ["https://hub.atomgit.com/"]…

详解c++:new和delete

文章目录 前言一、new和mallocnew的用法&#xff08;爽点&#xff09;自动构造 delete和freedelete的用法&#xff08;爽点&#xff09; 提醒 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 在C中&#xff0c;new 和 delete 是两个非常重要的操作符&am…

Python面相对象案例熟悉对MySQL的操作(案例一、学生管理系统,案例二、模拟注册与用户登录)有源码

Python面相对象案例熟悉对MySQL的操作 案例一&#xff0c;学生管理系统 对数据表的要求&#xff1a; 在mysql中创建数据库gamedb,创建用户表userinfo,字段如下&#xff1a; 用户编号uid(int,主键&#xff0c;自动增长) 用户姓名uname(varchar(20),非空) 用户昵称nickname(…

【Delphi】Delphi 中的 LiveBindings 使用场景与概念

LiveBindings 是 Delphi 提供的一种数据绑定机制&#xff0c;用于将 UI 控件与数据源&#xff08;如数据库字段、对象属性等&#xff09;进行动态连接。LiveBindings 允许开发人员通过可视化的方式绑定数据&#xff0c;省去了大量的手动编写代码&#xff0c;使 UI 更新和数据同…