yolov8 瑞芯微RKNN和地平线Horizon芯片仿真测试部署_yolov8 rknn-程序员宅基地

技术标签: YOLO  深度学习  瑞芯微  人工智能  地平线  

特别说明:参考官方开源的yolov8代码、瑞芯微官方文档、地平线的官方文档,如有侵权告知删,谢谢。

模型和完整仿真测试代码,放在github上参考链接 模型和代码

跟上技术的步伐,yolov8 首个板端芯片部署。

#2024年更新了更简单、更高效的部署博客(推荐使用)#

更简单、更高效的方式参考最新部署版本(推荐使用):【yolov8n 瑞芯微RKNN、地平线Horizon芯片部署、TensorRT部署,部署工程难度小、模型推理速度快】

1 模型和训练

  训练代码参考官方开源的yolov8训练代码,由于SiLU在有些板端芯片上还不支持,因此将其改为ReLU。

2 导出 yolov8 onnx

   后处理中有些算在板端芯片上效率低或者不支持,导出 onnx 需要将板端芯片不友好或不支持算子规避掉。导出onnx修改的部分。(注意以下步骤顺序不能乱,且有些步骤会运行保存,但只要能生成对应的文件就可以,报错不用管。)

第一步:
将pt只保存权重值,增加代码如下图。
![在这里插入图片描述](https://img-blog.csdnimg.cn/34f9ca7f164a446aa31330bc09113e36.png

        # 保存权重值
        import torch
        self.model.fuse()
        self.model.eval()
        torch.save(self.model.state_dict(), './weights/Yolov8_dict.pt')
        # self.model.load_state_dict(torch.load('./weights/Yolov8_dict.pt', map_location='cpu'))

修改后运行以下代码:

from ultralytics import YOLO
model = YOLO('./weights/yolov8n_coco128.pt')
results = model(task='detect', mode='predict', source='./images/test.jpg', line_thickness=3, show=True, save=True, device='cpu')

第二步:
导出onnx,去除不需要的算子。修改代码如下。
在这里插入图片描述

# heads
class Detect(nn.Module):
    # YOLOv8 Detect head for detection models
    dynamic = False  # force grid reconstruction
    export = False  # export mode
    shape = None
    anchors = torch.empty(0)  # init
    strides = torch.empty(0)  # init

    def __init__(self, nc=80, ch=()):  # detection layer
        super().__init__()
        self.nc = nc  # number of classes
        self.nl = len(ch)  # number of detection layers
        self.reg_max = 16  # DFL channels (ch[0] // 16 to scale 4/8/12/16/20 for n/s/m/l/x)
        self.no = nc + self.reg_max * 4  # number of outputs per anchor
        self.stride = torch.zeros(self.nl)  # strides computed during build

        c2, c3 = max((16, ch[0] // 4, self.reg_max * 4)), max(ch[0], self.nc)  # channels
        self.cv2 = nn.ModuleList(
            nn.Sequential(Conv(x, c2, 3), Conv(c2, c2, 3), nn.Conv2d(c2, 4 * self.reg_max, 1)) for x in ch)
        self.cv3 = nn.ModuleList(nn.Sequential(Conv(x, c3, 3), Conv(c3, c3, 3), nn.Conv2d(c3, self.nc, 1)) for x in ch)
        self.dfl = DFL(self.reg_max) if self.reg_max > 1 else nn.Identity()

        # 导出 onnx 增加
        self.conv1x1 = nn.Conv2d(16, 1, 1, bias=False).requires_grad_(False)
        x = torch.arange(16, dtype=torch.float)
        self.conv1x1.weight.data[:] = nn.Parameter(x.view(1, 16, 1, 1))

    def forward(self, x):
        shape = x[0].shape  # BCHW

        y = []
        for i in range(self.nl):
            t1 = self.cv2[i](x[i])
            t2 = self.cv3[i](x[i])
            y.append(self.conv1x1(t1.view(t1.shape[0], 4, 16, -1).transpose(2, 1).softmax(1)))
            # y.append(t2.sigmoid())
            y.append(t2)
        return y

        for i in range(self.nl):
            x[i] = torch.cat((self.cv2[i](x[i]), self.cv3[i](x[i])), 1)
        if self.training:
            return x
        elif self.dynamic or self.shape != shape:
            self.anchors, self.strides = (x.transpose(0, 1) for x in make_anchors(x, self.stride, 0.5))
            self.shape = shape

        box, cls = torch.cat([xi.view(shape[0], self.no, -1) for xi in x], 2).split((self.reg_max * 4, self.nc), 1)
        dbox = dist2bbox(self.dfl(box), self.anchors.unsqueeze(0), xywh=True, dim=1) * self.strides
        y = torch.cat((dbox, cls.sigmoid()), 1)
        return y if self.export else (y, x)

    def bias_init(self):
        # Initialize Detect() biases, WARNING: requires stride availability
        m = self  # self.model[-1]  # Detect() module
        # cf = torch.bincount(torch.tensor(np.concatenate(dataset.labels, 0)[:, 0]).long(), minlength=nc) + 1
        # ncf = math.log(0.6 / (m.nc - 0.999999)) if cf is None else torch.log(cf / cf.sum())  # nominal class frequency
        for a, b, s in zip(m.cv2, m.cv3, m.stride):  # from
            a[-1].bias.data[:] = 1.0  # box
            b[-1].bias.data[:m.nc] = math.log(5 / m.nc / (640 / s) ** 2)  # cls (.01 objects, 80 classes, 640 img)

增加保存onnx模型代码,如下:
在这里插入图片描述

        # 导出 onnx 增加
        import torch
        self.model.fuse()
        self.model.eval()
        self.model.load_state_dict(torch.load('./weights/Yolov8_dict.pt', map_location='cpu'), strict=False)

        print("===========  onnx =========== ")
        dummy_input = torch.randn(1, 3, 640, 640)
        input_names = ["data"]
        output_names = ["cls1", "reg1", "cls2", "reg2", "cls3", "reg3"]
        torch.onnx.export(self.model, dummy_input, "./weights/yolov8n_ZQ.onnx", verbose=False, input_names=input_names, output_names=output_names, opset_version=11)
        print("======================== convert onnx Finished! .... ")

以上修改后完运行以下代码(注意和第一次运行的不一样,这次加载的是yaml):

from ultralytics import YOLO

model = YOLO('./ultralytics/models/v8/yolov8n.yaml')
results = model(task='detect', mode='predict', source='./images/test3.jpg', line_thickness=3, show=False, save=True, device='cpu')

3 yolov8 onnx 测试效果

onnx模型和测试完整代码,放在github上代码
图片来源coco128
注:图片来源coco128

4 yolov8导出瑞芯微rknn和地平线horizon仿真测试

4.1 瑞芯微 rknn 仿真

  瑞芯微环境搭建和详细步骤参考上一篇 【瑞芯微RKNN模型转换和PC端仿真】
  yolov8导出rknn模型代码和后处理参考 yolov8_rknn

4.2 地平线仿真

  地平线环境搭建和详细步骤参考上一篇 【地平线Horizon模型转换和PC端仿真测试】
  yolov8导出地平线模型代码和后处理参考 yolov8_horizon

5 官方导出onnx方式进行瑞芯微rknn和地平线horizon仿真测试

yolov8 官方模型进行瑞芯微RKNN和地平线Horizon芯片仿真测试部署

6 rknn 板端C++部署

C++完整部署代码和模型示例

把板端C++代码的模型和时耗也给贴出来供大家参考,使用芯片rk3588。
在这里插入图片描述

7 yolov8seg 部署

想尝试yolov8seg的小伙伴看过来,参考链接yolov8seg完整部署代码和模型示例

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/zhangqian_1/article/details/128918268

智能推荐

你时间总不够用?请收下这套最佳的分配时间的方法-程序员宅基地

文章浏览阅读399次。有谁要是为了赚得更多的钱而加班加点、 更加卖力地去工作, 他就不会真正变得更加富有。 被牺牲掉的业余时间的价值必须从其更高收入中扣除, 而且被牺牲掉的这部分的价值通常比财务上得到的要高很多。为了赚更多的钱而牺牲掉您的业余时间, 靠这种方法您不可能实现真正的富有。 真正的富有是指具有由少变多的本事, 而并非必须为此做出同样程度的牺牲。真正的成功意味着: 您能够获得更高的收入, 但您的...

错误处理:MySQL报错解决:插入数据时发生错误-程序员宅基地

文章浏览阅读2.2k次。大家好,今天我来分享一下在Linux上运行MySQL服务时遇到的一个插入数据时的报错以及其解决方法。这个报错信息非常具体,相信很多开发者和运维人员都曾经遇到过。记得关注我的公众号“运维家”,获取更多实用技巧和经验分享。一、问题描述当你尝试向MySQL数据库中插入数据时,可能会遇到以下报错信息:“无法插入数据,因为字段不匹配”。这时候,你可能会感到困惑,因为你明明已经按照正确的格式提供了数据,为什么..._mysql数据添加数据报错

idea插件 监听编辑板块切换_ideaeditor编辑监听-程序员宅基地

文章浏览阅读1.8k次。监听编辑板块切换开发工具:IntellJ Idea 开发语言:Kotlin功能描述:实现监听编辑板块切换效果图: 打印日志: 下面是实现该功能的代码: com.your.company.unique.plugin.id Djy 1.0

MAC下配置SSH免密登录及相关报错_mac ssh-rsa-程序员宅基地

文章浏览阅读418次。MAC下配置SSH免密登录及相关报错_mac ssh-rsa

excel统计分析——S-N-K法多重比较_snk检验 excel-程序员宅基地

文章浏览阅读779次,点赞22次,收藏8次。S-N-K法全称Newman-Keuls或Student-Newman-Keuls法,又称复极差检验法或q检验法。最小显著极差的计算与Tukey法相同,只是将第一自由度换成了秩次距m,即计算。是指当平均数由大到小排序后,相比较的两个平均数之间(含这两个平均数)包含的平均数个数。1、利用数据分析工具获取方差分析结果:步骤参照。其中,m为秩次距,df为误差项自由度,2.1计算需要用到的最小显著极差LSR。2、利用公式进行多重比较。2.2平均数间的多重比较。参考资料:生物统计学。_snk检验 excel

产品入库的PV操作-程序员宅基地

文章浏览阅读3k次,点赞4次,收藏19次。在一个仓库中可以存放A和B两种产品,要求: 1)每次只能存入一种–互斥访问 2)A产品数量 - B产品数量 < M 3)B产品数量 - A产品数量 < N其中,M,N是正整数,使用PV操作描述A和B的入库过程。semaphore mutex = 1;int countA = 0,countB = 0;PA:while(1){ if(countA - countB < M -

随便推点

【张朝阳的物理课笔记】 3. 光的散射,天空的蓝色,早晚太阳是红色的原因_光线散射 公式-程序员宅基地

文章浏览阅读997次。散射光能量和入射光频率的4次方成正比,所以蓝光紫光比红光更容易被散射_光线散射 公式

HDU 2108 Shape of HDU-程序员宅基地

文章浏览阅读541次。Shape of HDUTime Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 7061 Accepted Submission(s): 3200Problem Description话说上回讲到海东集团推选老总的_hdu 2108 shape of hdu

浅谈现代建筑照明中的智能照明控制系统-程序员宅基地

文章浏览阅读133次。但是,智能照明在我国一直没有引起足够的重视,大部分建筑物采用的照明依然是传统的照明控制方式,因此,本文就智能照明系统在现代建筑中的应用进行分析, 继而使人们认识智能照明系统的优点,为其发展提供一些推动作用。智能化已经成为全球建筑发展的主流技术,其涵盖多个方面。在现代建筑中, 智能照明系统的设备不但多而且比较分散,待实现的控制功能较多,因而如何构建经济 合理、实用的智能照明系统,如何确定智能照明系统在现代建筑照明中的控制策略 是亟待解决的问题,只有把这些问题解决了,智能照明系统才能够在现代建筑中广泛的应用。

CMake buildsystem_install_interface-程序员宅基地

文章浏览阅读683次。基于CMake的构建系统(buildsystem),其组织形式是一组高级逻辑目标(high-level logical targets)。每个目标(target)对应于一个可执行文件或库,或者一个包含自定义命令的自定义目标。构建系统说明了目标之间的依赖关系,从而确定构建顺序和响应更改时的重生成规则。_install_interface

Nginx网络服务-程序员宅基地

文章浏览阅读788次,点赞9次,收藏28次。先使用命令/usr/local/nginx/sbin/nginx -V 查看已安装的 Nginx 是否包HTTP_STUB_STATUS 模块,cat /opt/nginx-1.12.0/auto/options | grep YES #查看nginx已安装的所有模块。在Linux平台.上,在进行高并发TCP连接处理时,最高的并发数量都要受到系统对用户单一进程同时可打开文件数量的限制(这是因为系统为每个TCP连接都要创建一个socket句柄,每个socket句柄同时也是一个文件句柄)。

数据流图——从软考真题中学画数据流图DFD_招聘考试成绩管理数据流程图-程序员宅基地

文章浏览阅读2.7w次,点赞211次,收藏852次。某高校欲开发一个成绩管理系统,记录并管理所有选修课程的学生的平时成绩和考试成绩,其主要功能描述如下:  1. 每门课程都有3到6个单元构成,每个单元结束后会进行一次测试,其成绩作为这门课程的平时成绩。课程结束后进行期末考试,其成绩作为这门课程的考试成绩。  2. 学生的平时成绩和考试成绩均由每门课程的主讲教师上传给成绩管理系统。  3. 在记录学生成绩之前,系统需要验证这些成绩是否有效。首先..._招聘考试成绩管理数据流程图