yolov5训练并生成rknn模型部署在RK3588开发板上,实现NPU加速推理

简介

RK3588是瑞芯微(Rockchip)公司推出的一款高性能、低功耗的集成电路芯片。它采用了先进的28纳米工艺技术,并配备了八核心的ARM Cortex-A76和Cortex-A55处理器,以及ARM Mali-G76 GPU。该芯片支持多种接口和功能,适用于广泛的应用领域。

本篇为yolov5部署在RK3588的教程。

一、yolov5训练数据

请选择v5.0版本:Releases · ultralytics/yolov5 (github.com)

训练方法请按照官方的READEME文件进行。 

转换前将model/yolo.py的 Detect 类下的

    def forward(self, x):
        z = []  # inference output
        for i in range(self.nl):
            if os.getenv('RKNN_model_hack', '0') != '0':
                z.append(torch.sigmoid(self.m[i](x[i])))
                continue
            x[i] = self.m[i](x[i])  # conv
            bs, _, ny, nx = x[i].shape  # x(bs,255,20,20) to x(bs,3,20,20,85)
            x[i] = x[i].view(bs, self.na, self.no, ny, nx).permute(0, 1, 3, 4, 2).contiguous()

            if not self.training:  # inference
                if self.onnx_dynamic or self.grid[i].shape[2:4] != x[i].shape[2:4]:
                    self.grid[i], self.anchor_grid[i] = self._make_grid(nx, ny, i)

                y = x[i].sigmoid()
                if self.inplace:
                    y[..., 0:2] = (y[..., 0:2] * 2 + self.grid[i]) * self.stride[i]  # xy
                    y[..., 2:4] = (y[..., 2:4] * 2) ** 2 * self.anchor_grid[i]  # wh
                else:  # for YOLOv5 on AWS Inferentia https://github.com/ultralytics/yolov5/pull/2953
                    xy, wh, conf = y.split((2, 2, self.nc + 1), 4)  # y.tensor_split((2, 4, 5), 4)  # torch 1.8.0
                    xy = (xy * 2 + self.grid[i]) * self.stride[i]  # xy
                    wh = (wh * 2) ** 2 * self.anchor_grid[i]  # wh
                    y = torch.cat((xy, wh, conf), 4)
                z.append(y.view(bs, -1, self.no))
        if os.getenv('RKNN_model_hack', '0') != '0':
            return z
        return x if self.training else (torch.cat(z, 1),) if self.export else (torch.cat(z, 1), x)

修改为:

    def forward(self, x):
        z = []
        for i in range(self.nl):
            x[i] = self.m[i](x[i])

        return x

出现乱框的现象,可以修改为下面的情况:

    def forward(self, x):
        z = []
        for i in range(self.nl):
            x[i] = torch.sigmoid(self.m[i](x[i]))

        return x

但在训练阶段请勿修改。

接着将训练好的best.pt放在工程文件夹下,使用yolov5工程中的export.py将其转换为onnx模型

7cfa0c6457ae45829d720749b7d32d6b.png

python export.py --weights best.pt

二、下载RKNN-Toolkit2

1、下面的请在 Ubuntu下进行,创建一个Python环境

conda create -n rknn152 python=3.8

激活环境rknn152

conda activate rknn152

拉取rockchip-linux/rknn-toolkit2 at v1.5.2 (github.com)仓库。我是直接下载的1.5.2版本的zip包。

git clone git@github.com:rockchip-linux/rknn-toolkit2.git

2、安装依赖(requirements_cp38-1.5.2.txt,在rknn-toolkit2/doc目录下)

pip install -r /home/yuzhou/rknn15/rknn-toolkit2-1.5.2/doc/requirements_cp38-1.5.2.txt -i https://pypi.tuna.tsinghua.edu.cn/simple

安装rknn-toolkit2,位置在packages文件夹下面,请选择合适的版本。

pip install /home/yuzhou/rknn15/rknn-toolkit2-1.5.2/packages/rknn_toolkit2-1.5.2+b642f30c-cp38-cp38-linux_x86_64.whl

3、开发环境与板子连接

sudo apt-get install adb

使用USB-typeC线连接到板子的TypeC0接口,PC端识别到虚拟机中。
在开发环境中检查是否连接成功

adb devices

如果连接成功会返回板子的设备ID,如下:

List of devices attached
* daemon not running; starting now at tcp:5037
* daemon started successfully
75370ea69f64098d    device

三、onnx转rknn模型

在rknn-toolkit2工程文件夹中浏览至./examples/onnx/yolov5,将我们在yolov5工程中转换得到的best.onnx复制到该文件夹下,需要修改该文件夹下的test.py中的内容。

44c8629bb2b2417b9b1ab81d0fd74cc1.png

 

  • ONNX_MODEL:模型名;
  • RKNN_MODEL:转换后的rknn模型名;
  • IMG_PATH:推理的图片路径;
  • DATASET:需要打开txt文件修改,改为IMG_PATH的图片名
  • CLASSES:修改为自己数据集的类别

306efd6c0d3c4fab9c67a65f286a5280.png

添加target_platform='rk3588'。

进入此目录,运行:

python test.py

 

d393fbc1a3264d189f08c3f7bb625d1c.png

如上图如此,说明没有问题,并且在该目录下会生成一个推理图片,以及转换好的rknn模型。

四、下载NPU工程

git clone https://github.com/rockchip-linux/rknpu2

将rknn_server和rknn库发送到板子上

adb push /home/yuzhou/rknn15/rknpu2-1.5.0/runtime/RK3588/Linux/rknn_server/aarch64/usr/bin/rknn_server /usr/bin/
adb push /home/yuzhou/rknn15/rknpu2-1.5.0/runtime/RK3588/Linux/librknn_api/aarch64/librknnrt.so /usr/bin/
adb push /home/yuzhou/rknn15/rknpu2-1.5.0/runtime/RK3588/Linux/librknn_api/aarch64/librknn_api.so /usr/bin/

 在板子上运行rknn_server服务

adb shell 
root@ok3588:/# chmod +x /usr/bin/rknn_server
root@ok3588:/# rknn_server &
[1] 6932
root@ok3588:/# start rknn server, version:1.5.0 (17e11b1 build: 2023-05-18 21:43:39)
I NPUTransfer: Starting NPU Transfer Server, Transfer version 2.1.0 (b5861e7@2020-11-23T11:50:51)

在开发环境中检测rknn_server是否运行成功

(base) yuzhou@yuzhou-HP:~$ adb shell
root@ok3588:/# pgrep rknn_server
6932

有返回进程id说明运行成功。

git clone https://github.com/rockchip-linux/rknpu2.git

五、部署在rk3588上

在路径 ../rknpu2/examples/rknn_yolov5_demo中

修改include文件中的头文件postprocess.h

#define OBJ_CLASS_NUM     80  #这里的数字修改为数据集的类的个数

修改model目录下的coco_80_labels_list.txt文件,改为自己的类并保存

car

将转换后的rknn文件放在model/RK3588目录下

在model目录下放入需要推理的图片

cd /home/yuzhou/rknn15/rknpu2-1.5.0/examples/rknn_yolov5_demo

编译,运行shell 

bash ./build-linux_RK3588.sh

成功后生成install目录,将文件推到我们的板子上面

adb push /home/yuzhou/rknn15/rknpu2-1.5.0/examples/rknn_yolov5_demo /mydatas/

与rk3588进行交互 

adb shell 

进入我们传入文件的目录下 

cd /mydatas/rknn_yolov5_demo_Linux

使用npu加速推理

./rknn_yolov5_demo ./model/RK3588/best5s.rknn ./model/6.jpg

b51d04b9cacf4a6b973af8a2d90fca6b.png

 将生成的图片拉取到本地来

adb pull /mydatas/rknn_yolov5_demo_Linux/6out.jpg /home/yuzhou/rknn-toolkit2/examples/onnx/yolov5_rk3588_demo/test

六、一些需求修改

假如说,我觉得运行一张的速度太慢了,我想要批量去运行该怎么办,这里我们可以写一个batch_process.sh文件

#!/bin/bash

# 指定图片文件夹路径
IMAGE_DIR="./test"

# 遍历图片文件夹中的所有图片文件
for image_file in "$IMAGE_DIR"/*.jpg; do
    if [ -f "$image_file" ]; then
        echo "Processing $image_file"
        ./rknn_yolov5_demo ./model/RK3588/best5s.rknn "$image_file"
    fi
done

修改权限后: 

chmod +x batch_process.sh

直接运行即可

./batch_process.sh

七、CPU、GPU、NPU推理速度比较

(1)CPU

YOLOv5 Python-3.8.17 torch-1.8.2+cu111 CPU

image 1/164 480x640 1 car, Done. (1.507s)
image 2/164 480x640 1 car, Done. (1.556s)
image 3/164 480x640 1 car, Done. (1.330s)
image 4/164 480x640 1 car, Done. (1.285s)
image 5/164 480x640 1 car, Done. (1.306s)
image 6/164 480x640 1 car, Done. (1.269s)
image 7/164 480x640 1 car, Done. (1.331s)
image 8/164 480x640 1 car, Done. (1.321s)
image 9/164 480x640 1 car, Done. (1.251s)
image 10/164 480x640 1 car, Done. (1.307s)

平均时间为1.3436 s

YOLOv5 Python-3.7.9 torch-1.13.1+cpu CPU

image 1/164 480x640 1 car, Done. (0.597s)
image 2/164 480x640 1 car, Done. (0.625s)
image 3/164 480x640 1 car, Done. (0.614s)
image 4/164 480x640 1 car, Done. (0.607s)
image 5/164 480x640 1 car, Done. (0.541s)
image 6/164 480x640 1 car, Done. (0.498s)
image 7/164 480x640 1 car, Done. (0.497s)
image 8/164 480x640 1 car, Done. (0.481s)
image 9/164 480x640 1 car, Done. (0.512s)
image 10/164 480x640 1 car, Done. (0.502s)

平均时间为0.5475 s

(2)GPU

YOLOv5 Python-3.8.17 torch-1.8.2+cu111 CUDA:0 (NVIDIA GeForce RTX 4060 Laptop GPU, 8188MiB)

image 1/164 480x640 1 car, Done. (0.034s)
image 2/164 480x640 1 car, Done. (0.034s)
image 3/164 480x640 1 car, Done. (0.032s)
image 4/164 480x640 1 car, Done. (0.030s)
image 5/164 480x640 1 car, Done. (0.030s)
image 6/164 480x640 1 car, Done. (0.029s)
image 7/164 480x640 1 car, Done. (0.030s)
image 8/164 480x640 1 car, Done. (0.030s)
image 9/164 480x640 1 car, Done. (0.030s)
image 10/164 480x640 1 car, Done. (0.030s)

平均时间为0.0309 s

(3)NPU

运行十张所分别用到的时间

69.592200 ms,69.781700 ms,69.510100 ms,69.611600 ms,69.823200 ms,69.638200 ms,69.610600 ms,69.563400 ms,69.200500 ms,69.122900 ms

平均时间为69.54544 ms = 0.06954544 s

参考文章

瑞芯微RK3588开发板:虚拟机yolov5模型转化、开发板上python脚本调用npu并部署 全流程_yolov5模型在rk3588-CSDN博客

yolov5训练pt模型并转换为rknn模型,部署在RK3588开发板上——从训练到部署全过程_yolov5 rknn-CSDN博客

瑞芯微rk3588部署yolov5模型实战_在rk3588上部署yolov5-CSDN博客

yolov5训练并生成rknn模型以及3588平台部署_yolov5 在rk3588上的部署-CSDN博客

 

  • 15
    点赞
  • 113
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 15
    评论
【资源说明】 YOLOv8部署瑞芯微RK3588板端c++源码(含使用说明).zipYOLOv8部署瑞芯微RK3588板端c++源码(含使用说明).zip ## 编译和运行 1)编译 ``` cd examples/rknn_yolov8_demo_open bash build-linux_RK3588.sh ``` 2)运行 ``` cd install/rknn_yolov8_demo_Linux ./rknn_yolov8_demo ``` 注意:修改模型、测试图像、保存图像的路径,修改文件为src下的main.cc ``` 测试效果 冒号“:”前的数子是coco的80类对应的类别,后面的浮点数是目标得分。(类别:得分) ![images](test_result.jpg) (注:图片来源coco128) 说明:推理测试预处理没有考虑等比率缩放,激活函数 SiLU 用 Relu 进行了替换。由于使用的是coco128的128张图片数据进行训练的,且迭代的次数不多,效果并不是很好,仅供测试流程用。换其他图片测试检测不到属于正常现象,最好选择coco128中的图像进行测试。 把板端模型推理和后处理时耗也附上,供参考,使用的芯片rk3588。 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载使用,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可直接用于毕设、课设、作业等。 欢迎下载,沟通交流,互相学习,共同进步!
A: 首先,需要安装CUDA和CUDNN的相关库,并下载yolov5的代码仓库。然后,按照以下步骤来编写部署在nvidia开发板上的yolov5模型推理代码。 1. 导入必要的头文件 ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <dirent.h> #include <errno.h> #include <fcntl.h> #include <unistd.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/time.h> #include <cuda_runtime_api.h> #include <cublas_v2.h> #include <curand.h> #include <cudnn.h> #include "darknet.h" ``` 2. 定义模型类和相关参数 ```c typedef struct{ network net; float *output; float *input; cudaStream_t stream; } yolov5; #define BATCH 1 #define DEVICE 0 #define NMS_THRESH 0.45 #define CONF_THRESH 0.25 #define CLASS_NUM 80 #define ANCHOR_NUM 3 #define INPUT_H 640 #define INPUT_W 640 #define CLASS_NAME_FILE "./coco.names" #define WEIGHTS_FILE "./yolov5s.weights" ``` 3. 加载模型 ```c void load_model(yolov5 *model, char *classes_path, char *weights_path){ // 加载类别名 char **names = get_labels(classes_path); // 加载模型 model->net = parse_network_cfg(cfg_path); if(weights_path){ load_weights(&model->net, weights_path); } // 设置输入层 model->input = (float *)calloc(model->net.batch * model->net.inputs, sizeof(float)); cudaMalloc((void **)&model->output, model->net.batch * model->net.outputs * sizeof(float)); cudaStreamCreate(&model->stream); set_batch_network(&model->net, BATCH); model->net.layers[model->net.n - 1].classes = CLASS_NUM; model->net.layers[model->net.n - 1].anchor_num = ANCHOR_NUM; model->net.layers[model->net.n - 1].confidence_thresh = CONF_THRESH; model->net.layers[model->net.n - 1].nms_thresh = NMS_THRESH; model->net.layers[model->net.n - 1].mask = (int *)calloc(ANCHOR_NUM, sizeof(int)); for(int i = 0; i < ANCHOR_NUM; i++) model->net.layers[model->net.n - 1].mask[i] = i; srand(time(NULL)); } ``` 4. 推理函数 ```c void yolov5_inference(yolov5 *model, char *img_path){ // 加载图片 image img = load_image_color(img_path, 0, 0); // 缩放图片 image sized = resize_image(img, INPUT_W, INPUT_H); // 将数据写入输入层 fill_cuda_data(sized.data, INPUT_H * INPUT_W * 3, model->input, INPUT_H * INPUT_W * 3 * BATCH, model->stream); // 进行推理 forward_network(&model->net, model->input); // 获取输出结果 get_network_boxes(&model->net, img.w, img.h, CONF_THRESH, model->net.layers[model->net.n - 1].mask, 0, 1, model->output, 1, &model->net.layers[model->net.n - 1], model->net.classes, model->net.outputs, 1); // 进行非极大值抑制 do_nms_sort(model->net.hold_cpu, model->net.hold_gpu, model->net.batch, model->net.layers[model->net.n - 1].classes, model->net.layers[model->net.n - 1].w, model->net.layers[model->net.n - 1].h, model->output, model->net.layers[model->net.n - 1].nms, CLASS_NUM, NMS_THRESH); // 输出结果 draw_detections(img, model->net.hold_cpu, model->net.darknet_gpu, model->net.layers[model->net.n - 1], CLASS_NUM, names, WINDOW_WIDTH, WINDOW_HEIGHT, 0); } ``` 5. main函数 ```c int main(int argc, char **argv){ yolov5 model; // 加载模型 load_model(&model, CLASS_NAME_FILE, WEIGHTS_FILE); // 进行推理 yolov5_inference(&model, argv[1]); // 释放资源 cudaFree(model.input); cudaFree(model.output); cudaStreamDestroy(model.stream); free_network(model.net); return 0; } ``` 以上就是用C语言编写的在nvidia开发板部署yolov5模型推理代码。
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夏天是冰红茶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值