Ubuntu20.04部署YOLOv5

news2024/12/22 13:44:47

目录

    • 前言
    • 一、环境配置
      • 1 显卡驱动安装
        • 1.1 卸载显卡驱动
        • 1.2 准备工作
        • 1.3 驱动安装
        • 1.4 验证
      • 2 CUDA安装
        • 2.1 准备工作
        • 2.2 CUDA下载
        • 2.3 CUDA安装
        • 2.4 配置环境变量
        • 2.5 验证
        • 2.6 小结
      • 3 cuDNN安装
        • 3.1 cuDNN下载
        • 3.2 cuDNN安装
        • 3.3 小结
      • 4 TensorRT安装
        • 4.1 TensorRT下载
        • 4.2 TensorRT安装
        • 4.3 配置环境变量
        • 4.4 验证
        • 4.5 小结
      • 5 编译OpenCV-4.6.0
        • 5.1 安装依赖项
        • 5.2 下载OpenCV 4.6.0源文件
        • 5.3 Cmake配置和编译OpenCV
        • 5.4 环境配置
        • 5.5 验证
      • 6 编译Protobuf-3.11.4
        • 6.1 安装
        • 6.2 环境变量的配置
    • 二、YOLOv5模型训练
      • 1. 项目的克隆和必要的环境依赖
        • 1.1 项目的克隆
        • 1.2 环境安装
      • 2. 数据集和预训练权重的准备
        • 2.1 数据集
        • 2.2 预训练权重准备
      • 3. 训练模型
      • 4. 测试
    • 三、YOLOv5模型部署
      • 1. 源码下载
      • 2. 环境配置
        • 2.1 配置CMakeLists.txt
        • 2.2 配置Makefile
      • 3. ONNX导出
        • 3.1 静态batch导出
        • 3.2 动态batch导出
        • 3.3 Resize节点解析的问题
        • 3.4 拓展-正确导出ONNX文件
      • 4. 运行
        • 4.1 源码修改
        • 4.2 编译
        • 4.3 模型构建和推理
        • 4.4 拓展-摄像头检测
      • 5. CUDA-Tips
    • 结语
    • 下载链接
    • 参考

前言

最近折腾了下双系统的安装为后续学习做准备,之前都是介绍的关于 Jetson 嵌入式上的模型部署工作,现在来尝试下 Ubuntu20.04 主机的部署工作,本次使用的 repo 是 tensorRT_Pro,部署的模型是 yolov5s.pt,部署流程其实和 Jetson 嵌入式一样(无非是 pytorch 训练 .pt => 转 onnx => tensorRT 生成 engine => 推理部署),难点在于环境的安装和配置,博主使用的软件环境如下:

系统:Ubuntu20.04

软件环境:Diver Version:510.108.03;CUDA Version:11.6;cuDNN Version:8.4.0;tensorRT Version:8.4.1;OpenCV:4.6.0;protobuf:3.11.4

本篇博客主要分享环境配置、YOLOv5模型训练、YOLOv5模型部署三方面的内容。若有问题欢迎各位看官批评指正!!!😘

一、环境配置

环境配置可以查看 Ubuntu20.04软件安装大全

1 显卡驱动安装

参考自:拯救者Y9000K2021H在ubuntu18.04安装显卡驱动、Ubuntu卸载Nvidia驱动和安装最新驱动

描述:显卡驱动安装主要参考文章1,流程按照上面走没有问题,博主显卡为 RTX3060,切记在安装显卡驱动的时候要在 BIOS 中将安全启动关闭

1.1 卸载显卡驱动

进行该步目的是防止系统中已经存在旧版本的驱动,或者存在没有完全安装成功的驱动。

在终端输入如下指令:

sudo apt-get purge nvidia*

1.2 准备工作

点击系统中的设置(Settings),点击最下面的关于(About),点击 Software Updates

  • 在第一栏 Ubuntu Software 页面中,前四个 main,universe,restricted,multiverse 都打上勾,找到 Download from,选择=>Others=>China=>mirrors.aliyun.com,点击确认,输入自己的密码,完成。(该步主要是进行 apt 换源)
  • 在第二栏 Other Software 页面中,将 Canonical Partners 勾选上
  • 在第三栏 Updates 页面中,将 Automatic check for updates 修改为 Never

在这里插入图片描述

换源成功后打开终端,执行如下语句:

cat /etc/apt/sources.list

在终端上会打印 apt 的源,可以看到原始的 Ubuntu 的源会被替换成之前选择的阿里源或者清华源

1.3 驱动安装

本次采用的方式是使用图形驱动程序 PPA 存储库完成 NVIDIA 驱动程序的快捷安装工作。

1.将 ppa 存储库添加到当前系统当中,指令如下:

sudo add-apt-repository ppa:graphics-drivers/ppa

2.更新软件列表,指令如下:

sudo apt-get update

3.查看检测到的驱动程序,指令如下,推荐下载带有 recommended 标志的驱动

sudo ubuntu-drivers devices

4.根据第 3 步检测到的驱动,选择一个合适的版本号(博主选择的是510),安装指令如下:

sudo apt install nvidia-driver-510

执行完成之后执行命令 sudo reboot 重启

1.4 验证

重新启动之后在命令输入 nvidia-smi,如果出现对应的驱动版本和CUDA版本说明安装成功。

同时可以点击设置(Settings),点击最下面的关于(About),查看下 Graphics 这一栏是否已经变为 NVIDIA Corporation,如果是,代表安装全部完成。

2 CUDA安装

参考自linux安装tensorflow,cuda,cudnn安装,pytorch兼容,RTX30系列GPU兼容cuda

描述:本来想体验下 kiwi 一键安装 CUDA+cuDNN+TensorRT 的,但现在还处于内测阶段,还未公测,等 kiwi 公测吧,只能先自己来了。CUDA 的安装按照上面视频的操作来就行,没有问题,下面简单过一遍流程。切记!!!CUDA 的安装依赖于显卡驱动的安装,请务必安装完显卡驱动后再来安装 CUDA

2.1 准备工作

首先确定我们要安装的 CUDA 版本,它是根据你的驱动程序版本来安装的,打开终端输入如下指令:

cat /proc/driver/nvidia/version
# 或者
nvidia-smi

通过上面两种方法都可以获取 nvidia-driver 的版本,如下图所示,博主的驱动程序版本是 510.108.03,记住这个数字,后续会用到

在这里插入图片描述

我们知道了驱动版本后就需要确认 CUDA 下载的版本了,查看 CUDA 版本与驱动版本对应关系见下面的链接(查看表 3 即可):

https://docs.nvidia.com/cuda/cuda-toolkit-release-notes/index.html

下面是表 3 的部分截图,左边一列是 CUDA 版本,后面两列分别对应 Linux 下和 Windows下 驱动版本的要求,GA = General Availability,通用版本,指软件的通用版本(可以理解为稳定版本吧😄),后续我们就安装 GA 版本,那么怎么查看自己要下载的 CUDA 版本呢?看对应的驱动要求就像,比如说在下面的红色框内就是我想要下载的 CUDA 版本,即 CUDA 11.6 GA,驱动版本要求大于等于510.39.01,而我的驱动版本之前提到过是 510.108.03,显然是满足要求的。根据表中来看,我还可以选择 CUDA 11.5GA、CUDA 11.4 等 CUDA 版本,因为我的驱动版本是满足要求的。具体选择那个根据个人情况来就行。

在这里插入图片描述

2.2 CUDA下载

确认了 CUDA 下载的版本后我们就可以去 NVIDIA 官网进行下载了,博主需要下载的是 CUDA 11.6 GA

NVIDIA 官网 CUDA 下载链接:https://developer.nvidia.com/cuda-toolkit-archive

打开上面的链接后,会出现如下的界面,点击你想要下载的 CUDA Toolkit 就行,比如博主想要下载 CUDA 11.6 GA,点击下面红色框中的 CUDA Toolkit 11.6.0 即可。(为什么点击 11.6.0 而不是其它的 11.6 版本呢?其实大家可以从上面的版本对应图可知CUDA 11.6 Update 2对应CUDA Toolkit 11.6.2CUDA 11.6 Update1对应CUDA Toolkit 11.6.1CUDA 11.6 GA对应CUDA Toolkit 11.6.0)

在这里插入图片描述

点进去之后选择目标平台,如下图所示,博主这里选择 Linux 系统、x86_64 架构、Ubuntu、20.04 版本、runfile(local) 安装方式

选择完成后通过 wget 后面的地址就可以下载了,建议将网址复制到浏览器中下载,访问的是外网,下载慢,最好是开代理

在这里插入图片描述

2.3 CUDA安装

首先检查下前面下载的安装包,看下安装包名,博主下载的安装包名为 cuda_11.6.0_510.39.01_linux.run,首先看 11.6.0 是 CUDA 版本没有问题,其次看 510.39.01 是要求的驱动最小版本也没有问题,最后是 linux 即安装的系统也没有问题,检查完毕后下面我们开始安装工作👨‍🏭

首先 cd 到安装包所在目录,执行如下指令:

sudo sh cuda_11.6.0_510.39.01_linux.run

输入密码后等待一段时间,出现下图,键盘按键上下移动,Enter 按键选择确认,我们选择 Continue

在这里插入图片描述

选择完成后跳转到如下界面,在最下面输入 accept

在这里插入图片描述

之后跳转到如下界面,选择你想要安装的选项

在这里插入图片描述

我们只考虑安装 CUDA Toolkit 11.6,其他均取消(空格键取消),最后的界面如下,选择到 Install,确认(等待终端一段时间,这个时候终端没有任何显示,不要关闭!!!)

在这里插入图片描述

最后出现如下界面,表示安装成功

在这里插入图片描述

安装完成之后的路径:

  • /usr/local/cuda-11.6:Toolkit
  • /usr/local/cuda-11.6/include:头文件
  • /usr/local/cuda-11.6/lib64:库文件

2.4 配置环境变量

CUDA 安装完成之后需要添加一下环境变量,输入如下指令打开配置文件:

sudo gedit ~/.bashrc

在最末尾添加如下内容(将 CUDA 版本替换成你自己的)

export PATH=/usr/local/cuda-11.6/bin${PATH:+:${PATH}}
export LD_LIBRARY_PATH=/usr/local/cuda-11.6/lib64${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}

点击保存退出,然后刷新一下

source ~/.bashrc

2.5 验证

环境变量配置完成后,在终端输入如下指令,有对应的输出代表安装成功:

nvcc --version

在这里插入图片描述

2.6 小结

CUDA 的安装流程其实并不复杂,难点在于两个步骤,一是通过你的显卡驱动找到对应的 CUDA 版本,二是能否将外网的 CUDA 安装包顺利下载下来(需要代理)

3 cuDNN安装

参考自linux安装tensorflow,cuda,cudnn安装,pytorch兼容,RTX30系列GPU兼容cuda

描述:cuDNN 的安装按照上面视频的操作来就行,没有问题,下面简单过一遍流程。切记!!!cuDNN 的安装依赖于 CUDA 的安装,请务必安装完 CUDA 后再来安装 cuDNN

3.1 cuDNN下载

cuDNN 的版本选择是根据 CUDA 版本来的,在前面 CUDA 的安装中,我们选择的是 CUDA 11.6.0 版本,依据此我们来安装 cuDNN

NVIDIA 官网 cuDNN 下载链接:https://developer.nvidia.com/rdp/cudnn-archive

打开上面的链接,会出现如下的界面(可能需要登陆,可以先注册一个 NVIDIA 账号,也不麻烦)

在这里插入图片描述

根据你的 CUDA 版本选择对应的 cuDNN 即可,CUDA 11.x 代表 CUDA11 版本的都支持,博主这里选择的是

Download cuDNN v8.4.0 (April 1st, 2022), for CUDA 11.x,如下所示,点击之后选择对应的平台安装包下载就行,如下面红色框所示,选择的是 Linux,Ubuntu,x86_64 的 Tar 安装包

在这里插入图片描述

注意!!!访问的是外网,下载慢,最好是开代理

3.2 cuDNN安装

首先检查下前面下载的安装包,看下安装包名,博主下载的安装包名为 cudnn-linux-x86_64-8.4.0.27_cuda11.6-archive.tar.xz,首先看 linux-x86_64 即安装的系统没有问题,其次看 cuda11.6 是依赖的 cuda 版本也没有问题,检查完毕后下面我们开始安装工作👨‍🏭

首先 cd 到安装包所在目录,进行解压,执行如下指令:

tar -xf cudnn-linux-x86_64-8.4.0.27_cuda11.6-archive.tar.xz

等待解压完成,解压完成之后在目录下有一个 cudnn-linux-x86_64-8.4.0.27_cuda11.6-archive 文件夹,这个文件夹中又包含 includelib 两个文件夹,分别代表 cuDNN 头文件和 cuDNN 库文件。

cuDNN 安装非常简单,就是将这两个文件中的所有内容复制到 CUDA 对应的文件夹中,我们来看下接下来的操作

首先输入如下指令,打开一个超级窗口(直接复制权限不够):

sudo nautilus
  • 在超级窗口中找到之前安装好的 CUDA 路径,在 /usr/local/cuda-11.6
  • 将 cuDNN 解压包中 include 文件全部复制到 /usr/local/cuda-11.6/include
  • 将 cuDNN 解压包中 lib 文件全部复制到 /usr/local/cuda-11.6/lib64

至此,cuDNN 的安装完毕

3.3 小结

cuDNN 的安装流程其实并不复杂,其实都不能称之为安装,就是根据 CUDA 版本找到对应的 cuDNN 版本,下载后把其头文件和库文件复制到对应 CUDA 目录即可。难点在于两个步骤,一是通过你的 CUDA 版本找到对应的 cuDNN 版本,二是能否将外网的 cuDNN 安装包顺利下载下来(需要代理)

4 TensorRT安装

参考自Linux安装TensorRT、Ubuntu20.04安装TensorRT

描述:TensorRT 的安装按照上面视频的操作来就行,没有问题,下面简单过一遍流程。切记!!!TensorRT 安装的版本依赖于 CUDA 和 cuDNN 的版本,请先确认下 CUDA 和 cuDNN 版本

4.1 TensorRT下载

TensorRT 的版本是根据 CUDA 版本和 cuDNN 版本来的,在前面的 CUDA 的安装中,我们选择的是 CUDA 11.6.0 版本,依据此来安装 TensorRT

NVIDIA 官网 TensorRT 下载链接:https://developer.nvidia.com/nvidia-tensorrt-8x-download

打开上面的链接,会出现如下的界面(需要登陆,可以先注册一个 NVIDIA 账号,也不麻烦,可能需要开代理)

在这里插入图片描述

登陆完成之后,可以看到下面的界面,点击 I Agree To the Terms of the ... 即下面的红色框,就可以显示各种 TensorRT 版本(其中 GA 版本=>稳定版本 EA 版本=>测试版本)

在这里插入图片描述

点开之后就是对应 TensorRT 版本的各种形式的安装包(包名有提示适合的对应的 CUDA 版本),比如博主选择的是 TensorRT 8.4 GA,选择的是 x86_64 架构,系统是 Linux 操作系统,下载形式选择压缩包形式(即TAR Package)下载,适用于 CUDA 11.6 版本,即TensorRT 8.4 GA for Linux x86_64 and CUDA 11.0, 11.1, 11.2, 11.3, 11.4, 11.5, 11.6 and 11.7 TAR Package,如下面的红色框所示。

在这里插入图片描述

注意!!!访问的是外网,下载慢,最好是开代理

4.2 TensorRT安装

首先检查下前面下载的安装包,看下安装包名,博主下载的安装包为 TensorRT-8.4.1.5.Linux.x86_64-gnu.cuda-11.6.cudnn8.4.tar.gz,首先看 Linux.x86_64 即安装的系统没有问题,其次看 cuda-11.6 是依赖的 cuda 版本也没有问题,最后看 cudnn8.4 是依赖的 cudnn 版本也没有问题,检查完毕后下面我们开始安装工作👨‍🏭

首先 cd 到安装包所在目录,进行解压,执行如下指令:

tar zxf TensorRT-8.4.1.5.Linux.x86_64-gnu.cuda-11.6.cudnn8.4.tar.gz

等待解压完成。解压完成之后在目录下有一个 TensorRT-8.4.1.5 的文件夹

可以移动该文件夹存放在自己想放的目录下(也可以重命名),如:

mv TensorRT-8.4.1.5 /opt

至此,TensorRT 安装完成

4.3 配置环境变量

TensorRT 安装完成之后需要添加一下环境变量,输入如下指令打开配置文件:

sudo gedit ~/.bashrc

在最末尾添加如下内容(将 TensorRT 版本替换成你自己的)

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/TensorRT-8.4.1.5/lib${LD_LIBRARY_PATH:+:${LD_LIBRARY_PATH}}
export PATH=/opt/TensorRT-8.4.1.5/bin${PATH:+:${PATH}}

点击保存退出,然后刷新一下

source ~/.bashrc

4.4 验证

测试代码:/opt/TensorRT-8.4.1.5/samples/sampleMNIST

在安装的 tensorRT 目录下 samples 文件夹下用 sampleMNIST 示例测试

首先进入该文件夹

cd /opt/TensorRT-8.4.1.5/samples/sampleMNIST

编译

make

如下图所示

在这里插入图片描述

编译成功后执行如下指令会有对应的结果输出:

./../../bin/sample_mnist

在这里插入图片描述

4.5 小结

TensorRT 的安装流程其实并不复杂,其实都不能称之为安装,就是根据 CUDA 版本找到对应的 TensorRT 版本,下载后添加下环境变量即可。难点在于两个步骤,一是通过你的 CUDA 版本找到对应的 TensorRT 版本,二是否能将外网的 TensorRT 安装包顺利下载下来(需要代理)

5 编译OpenCV-4.6.0

参考自Ubuntu 20.04搭建OpenCV 4.5.0 & C++环境、Ubuntu 安装 OpenCV 4.5.5、关于安装opencv编译报错:runtime library * hidden by 等若干问题、cmake编译出错hidden by files

描述:注意!!!如果你在编译 opencv 之前安装了 annaconda,请先看问题解决(与 Anaconda 冲突),除了上述冲突问题之外,没有其他问题,按照上文的操作即可。博主主要参考上文1中的 opencv 安装(即前 3 项)以及上文2中的 opencv 环境配置和验证。下面简单过一遍整个编译流程

5.1 安装依赖项

1.安装 g++,cmake,make,wget,unzip,若已安装,此步跳过

sudo apt install g++
sudo apt install cmake
sudo apt install make
sudo apt install wget unzip

2.安装 opencv 依赖的库

sudo apt-get install build-essential libgtk2.0-dev libgtk-3-dev libavcodec-dev libavformat-dev libjpeg-dev libswscale-dev libtiff5-dev

3.安装一些可选的库

# python3支持(首次安装了python的库,但make报错了,之后删了这两个库,若不使用python,建议不安装)
sudo apt install python3-dev python3-numpy
# streamer支持
sudo apt install libgstreamer-plugins-base1.0-dev libgstreamer1.0-dev
# 可选的依赖
sudo apt install libpng-dev libopenexr-dev libtiff-dev libwebp-dev

5.2 下载OpenCV 4.6.0源文件

可以在官网下载相应版本的 OpenCV,主要有 Source 和 GitHub 两种方式下载

1.Source:https://opencv.org/releases/

点击 Source 进行下载,外网访问慢,可在 Windows 下通过代理下载后传到 Linux;也可通过我提供的下载链接 Baidu Driver[pwd:yolo] 进行下载

2.Github下载方式:

# 安装4.6.0版本
wget -O opencv.zip https://github.com/opencv/opencv/archive/4.6.0.zip
# 安装最新版本
wget -O opencv.zip https://github.com/opencv/opencv/archive/master.zip

下载完成后,解压到主目录,将解压后的文件重命名为 opencv

5.3 Cmake配置和编译OpenCV

1.在主目录下打开终端

2.进入到下载好的 opencv 目录,新建并进入目录 build

cd opencv
mkdir build
cd build

3.使用 cmake 配置 opencv

cmake -D CMAKE_BUILD_TYPE=Release -D OPENCV_GENERATE_PKGCONFIG=YES ..

4.用 make 进行编译

make -j24

5.用 make 安装

sudo make install

默认安装路径如下

  • /usr/local/bin - executable files
  • /usr/local/bin - libraries (.so)
  • /usr/local/cmake/opencv4 - cmake package
  • /usr/local/include/opencv4 - headers
  • /usr/local/share/opencv4 - other files (e.g. trained cascades in XML format)

5.4 环境配置

动态库配置

sudo gedit /etc/ld.so.conf.d/opencv.conf

添加

/usr/local/lib

保存后,终端内执行

sudo ldconfig 

更新PKG_CONFIG_PATH

sudo gedit /etc/bash.bashrc

文末添加

PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig
export PKG_CONFIG_PATH

保存后,终端执行

source /etc/bash.bashrc
sudo updatedb

若出现sudo: updatedb: command not found,执行 sudo apt install mlocate 后再次操作即可。

5.5 验证

pkg-config

在终端输入如下指令,会显示对应的 opencv 版本 4.6.0

pkg-config --modversion opencv4

程序验证,代码如下

test.cpp

#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>

using namespace cv;
using namespace std;

/**
 * 读写与显示
 * @return
 */
int main() {
    cout << CV_VERSION << endl;
    Mat src = cv::imread("test.png", IMREAD_GRAYSCALE);
    if (src.empty()) {
        cout << "Could not load image\n" << endl;
        return -1;
    }
    namedWindow("gray", WINDOW_AUTOSIZE);
    imshow("gray", src);
    waitKey(0);

    return 0;
}

CMakeLists.txt

cmake_minimum_required(VERSION 3.16)
project(test)
find_package(OpenCV REQUIRED)
add_executable(test test.cpp)
target_link_libraries(test ${OpenCV_LIBS})

编译运行

cmake .
make
./test

运行后屏幕会显示目录下 test.png 的灰度图像

6 编译Protobuf-3.11.4

参考自Linux下编译protobuf、Linux下添加protobuf的环境变量

描述:由于要经常使用到 tensorRT_Pro 这个 repo,因此需要编译特定版本的 protobuf-3.11.4,编译流程看我下面的即可

6.1 安装

首先获取压缩包,通过我提供的软件安装包下载链接 Baidu Driver[pwd:yolo],里面就有 protobuf-3.11.4

解压

先 cd 到安装包路径,然后解压,指令如下:

unzip protobuf-3.11.4.zip

编译

cd protobuf-3.11.4/cmake
cmake . -Dprotobuf_BUILD_TESTS=OFF
cmake --build .

耐心等待编译完成(需要一段时间)

创建安装目录

我们先要创建一个文件用于存放安装后的 protobuf 的头文件和库文件,我们选择在 /home 目录下创建一个 protobuf 文件,指令如下:

mkdir protobuf

安装

安装的位置选择上面创建的 protobuf 路径即可,指令如下:

make install DESTDIR=/home/jarvis/protobuf

注意:编译完成后的 protobuf 文件夹下仅仅只有一个 user 一个文件夹,需要将编译好的 protobuf/user/local 下的 bin、include、lib 文件夹复制到 protobuf 当前文件夹下,方便后续 tensorRT_Pro 项目的 CMakeLists.txt 的指定。

6.2 环境变量的配置

首先打开配置文件,指令如下:

sudo vim /etc/profile

添加如下内容保存并退出(注意路径修改为自己的路径)

export PATH=$PATH:/home/jarvis/protobuf/bin
export PKG_CONFIG_PATH=/home/jarvis/probobuf/lib/pkgconfig

source 生效

source /etc/profile

配置动态路径

sudo vim /etc/ld.so.conf

追加如下内容(注意路径修改为自己的路径)

/home/jarvis/protobuf/lib

验证

protoc --version 输出对应版本信息说明安装成功

二、YOLOv5模型训练

1. 项目的克隆和必要的环境依赖

1.1 项目的克隆

yolov5 的代码是开源的可直接从 github 官网上下载,源码下载地址是 https://github.com/ultralytics/yolov5,由于 yolov5 版本较多,本次采用 yolov5-v7.0 分支进行模型的训练和部署工作。Linux 下代码克隆指令如下:

git clone -b v7.0 https://github.com/ultralytics/yolov5.git

1.2 环境安装

关于 Linux 下深度学习的环境安装可参考Ubuntu20.04软件安装大全

2. 数据集和预训练权重的准备

2.1 数据集

训练采用的 VOC 数据集,这里给出下载链接 Baidu Drive[pwd:yolo],本次训练并没有用到所有的数据,博主将 train2007 和 val2007 作为训练集,将 test2007 作为验证集,整个数据集文件夹内容如下图所示:

在这里插入图片描述

其中,images 存放的内容和图片文件,labels 存放的内容是 YOLO 格式的 .txt 标签文件,所有文件都可以从我分享的链接下载,大家可以按照上述方式将数据集进行整合。

2.2 预训练权重准备

yolov5-7.0 预训练权重可以通过下载链接 Baidu Drive[pwd:yolo] 进行下载,将预训练权重放在 yolov5-7.0 主目录下,本次训练 VOC 数据集使用的预训练权重是 yolov5s.pt

3. 训练模型

代码和数据集准备好后就可以进行训练了,训练修改的文件主要是两个即 VOC.yaml 用于指定数据集的相关路径,yolov5s.yaml 用于指定训练的网络结构

VOC.yaml 位于 yolov5-7.0/data 下,其具体内容如下:

  • 首先 path 路径指定为上面整合的数据集的绝对路径,路径中最好不要含有中文
  • train、val、test 的内容就是 VOC 数据集下用于训练、验证以及测试的图片
  • names 不用修改
  • download 内容全部删除即可
# YOLOv5 🚀 by Ultralytics, GPL-3.0 license
# PASCAL VOC dataset http://host.robots.ox.ac.uk/pascal/VOC by University of Oxford
# Example usage: python train.py --data VOC.yaml
# parent
# ├── yolov5
# └── datasets
#     └── VOC  ← downloads here (2.8 GB)


# 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: /home/jarvis/Learn/Datasets
train: # train images (relative to 'path')  16551 images
  - images/train2007
  - images/val2007
val: # val images (relative to 'path')  4952 images
  - images/test2007
test: # test images (optional)
  - images/test2007

# Classes
names:
  0: aeroplane
  1: bicycle
  2: bird
  3: boat
  4: bottle
  5: bus
  6: car
  7: cat
  8: chair
  9: cow
  10: diningtable
  11: dog
  12: horse
  13: motorbike
  14: person
  15: pottedplant
  16: sheep
  17: sofa
  18: train
  19: tvmonitor

yolov5s.yaml 位于 yolov5-7.0/models 下,将 nc:80 修改为 VOC 的 20 个类别,即 nc:20

进入到 yolov5-7.0 目录,在终端执行如下指令即可开始训练:

python train.py --weights=./yolov5s.pt --cfg=./models/yolov5s.yaml --data=./data/VOC.yaml --epochs=100 --batch-size=32

博主训练的模型是 yolov5s.pt 且使用的是单个 GPU 进行训练,显卡为 RTX3060,操作系统为 Ubuntu20.04,pytorch 版本为 1.12.0,训练时长大概 1.7 小时

训练参数的指定简要解释如下:

  • –weights 预训练权重
  • –cfg 模型配置文件路径
  • –data 数据配置文件路径
  • –epochs 训练轮数
  • –batch-size 每次输入到网络的图片数

还有其它参数博主并未设置,如 --workers 最大工作核心数等。大家一定要根据自己的实际情况(如显卡算力)指定不同的参数,如果你之前训练过自己的数据集,那我相信这对你来说应该是小 case😄

训练完成后的模型权重保存在 runs/train/exp/weights 文件夹下,我们选用 best.pt 进行后续模型部署即可,这里提供博主训练好的权重文件下载链接 Baidu Driver[pwd:yolo]

在这里插入图片描述

4. 测试

利用项目中的 detect.py 文件进行测试,将需要推理的图片放入 执行指令如下:

python detect.py --weights=./best.pt

在这里插入图片描述

也可进行视频或者摄像头推理,执行指令如下,0 代表本地摄像头

python detect.py --source=0  --weights=./best.pt

在这里插入图片描述

至此,YOLOv5模型训练已经完毕,下面开始模型部署工作。

三、YOLOv5模型部署

Ubuntu20.04 主机上 yolov5 模型部署流程和 Jetosn 嵌入式基本一致,大家可以参考我之前发的模型部署文章,部署使用的 Github 仓库是 tensorRT_Pro。该 repo 通过 tensorRT 的 ONNX parser 解析 ONNX 文件来完成模型的构建工作。对模型部署有疑问的可以参考 Jetson嵌入式系列模型部署-1,想了解通过 tensorRT 的 Layer API 一层层完成模型的搭建工作可参考 Jetson嵌入式系列模型部署-2,想了解通过 tensorRT 的 trtexec 工具构建模型的可参考 Jetson nano部署YOLOv8。本文主要是针对 tensorRT_Pro 项目中的 yolov5 完成模型部署,本文参考自 tensorRT_Pro的README.md,具体操作流程作者描述非常详细,下面再简单过一遍,本次训练的模型使用 yolov5s.pt,数据集为 VOC,类别数为20.

1. 源码下载

使用如下指令

$ git clone https://github.com/shouxieai/tensorRT_Pro.git

文件较大下载可能比较慢,给出下载好的源码链接 Biadu Driver[pwd:yolo],若有改动请参考最新

2. 环境配置

需要使用的软件环境有 tensorRT、CUDA、cuDNN、OpenCV、Protobuf。之前已经详细介绍了各软件的安装情况,这里不再赘述。编译可采用 CMakeLists.txt 和 Makefile 两种方式,二者选一即可

2.1 配置CMakeLists.txt

主要修改五处

1.修改第 10 行,选择不支持 python (也可选择支持)

set(HAS_PYTHON OFF)

2.修改第 18 行,修改 OpenCV 路径

set(OpenCV_DIR   "/usr/local/include/opencv4/")

3.修改第 20 行,修改 CUDA 路径

set(CUDA_TOOLKIT_ROOT_DIR     "/usr/local/cuda-11.6")

4.修改第 22 行,修改 tensorRT 路径

set(TENSORRT_DIR "/opt/TensorRT-8.4.1.5")

5.修改第 33 行,修改 protobuf 路径

set(PROTOBUF_DIR "/home/jarvis/protobuf")

完整的 CMakeLists.txt 的内容如下:

cmake_minimum_required(VERSION 2.6)
project(pro)

option(CUDA_USE_STATIC_CUDA_RUNTIME OFF)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_BUILD_TYPE Debug)
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/workspace)

# 如果要支持python则设置python路径
set(HAS_PYTHON OFF)                                         # ===== 修改 1 =====
set(PythonRoot "/datav/software/anaconda3")
set(PythonName "python3.9")

# 如果你是不同显卡,请设置为显卡对应的号码参考这里:https://developer.nvidia.com/zh-cn/cuda-gpus#compute
#set(CUDA_GEN_CODE "-gencode=arch=compute_75,code=sm_75")

# 如果你的opencv找不到,可以自己指定目录
set(OpenCV_DIR   "/usr/local/include/opencv4/")             # ===== 修改 2 =====


set(CUDA_TOOLKIT_ROOT_DIR     "/usr/local/cuda-11.6")       # ===== 修改 3 =====
set(CUDNN_DIR    "/datav/lean/cudnn8.2.4.15-cuda11.4")
set(TENSORRT_DIR "/opt/TensorRT-8.4.1.5")                   # ===== 修改 4 =====

# set(CUDA_TOOLKIT_ROOT_DIR     "/data/sxai/lean/cuda-10.2")
# set(CUDNN_DIR    "/data/sxai/lean/cudnn7.6.5.32-cuda10.2")
# set(TENSORRT_DIR "/data/sxai/lean/TensorRT-7.0.0.11")

# set(CUDA_TOOLKIT_ROOT_DIR  "/data/sxai/lean/cuda-11.1")
# set(CUDNN_DIR    "/data/sxai/lean/cudnn8.2.2.26")
# set(TENSORRT_DIR "/data/sxai/lean/TensorRT-7.2.1.6")

# 因为protobuf,需要用特定版本,所以这里指定路径
set(PROTOBUF_DIR "/home/jarvis/protobuf")                   # ===== 修改 5 ======


find_package(CUDA REQUIRED)
find_package(OpenCV)

include_directories(
    ${PROJECT_SOURCE_DIR}/src
    ${PROJECT_SOURCE_DIR}/src/application
    ${PROJECT_SOURCE_DIR}/src/tensorRT
    ${PROJECT_SOURCE_DIR}/src/tensorRT/common
    ${OpenCV_INCLUDE_DIRS}
    ${CUDA_TOOLKIT_ROOT_DIR}/include
    ${PROTOBUF_DIR}/include
    ${TENSORRT_DIR}/include
    ${CUDNN_DIR}/include
)

# 切记,protobuf的lib目录一定要比tensorRT目录前面,因为tensorRTlib下带有protobuf的so文件
# 这可能带来错误
link_directories(
    ${PROTOBUF_DIR}/lib
    ${TENSORRT_DIR}/lib
    ${CUDA_TOOLKIT_ROOT_DIR}/lib64
    ${CUDNN_DIR}/lib
)

if("${HAS_PYTHON}" STREQUAL "ON")
    message("Usage Python ${PythonRoot}")
    include_directories(${PythonRoot}/include/${PythonName})
    link_directories(${PythonRoot}/lib)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DHAS_PYTHON")
endif()

set(CMAKE_CXX_FLAGS  "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -O0 -Wfatal-errors -pthread -w -g")
set(CUDA_NVCC_FLAGS "${CUDA_NVCC_FLAGS} -std=c++11 -O0 -Xcompiler -fPIC -g -w ${CUDA_GEN_CODE}")
file(GLOB_RECURSE cpp_srcs ${PROJECT_SOURCE_DIR}/src/*.cpp)
file(GLOB_RECURSE cuda_srcs ${PROJECT_SOURCE_DIR}/src/*.cu)
cuda_add_library(plugin_list SHARED ${cuda_srcs})
target_link_libraries(plugin_list nvinfer nvinfer_plugin)
target_link_libraries(plugin_list cuda cublas cudart cudnn)
target_link_libraries(plugin_list protobuf pthread)
target_link_libraries(plugin_list ${OpenCV_LIBS})

add_executable(pro ${cpp_srcs})

# 如果提示插件找不到,请使用dlopen(xxx.so, NOW)的方式手动加载可以解决插件找不到问题
target_link_libraries(pro nvinfer nvinfer_plugin)
target_link_libraries(pro cuda cublas cudart cudnn)
target_link_libraries(pro protobuf pthread plugin_list)
target_link_libraries(pro ${OpenCV_LIBS})

if("${HAS_PYTHON}" STREQUAL "ON")
    set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/example-python/pytrt)
    add_library(pytrtc SHARED ${cpp_srcs})
    target_link_libraries(pytrtc nvinfer nvinfer_plugin)
    target_link_libraries(pytrtc cuda cublas cudart cudnn)
    target_link_libraries(pytrtc protobuf pthread plugin_list)
    target_link_libraries(pytrtc ${OpenCV_LIBS})
    target_link_libraries(pytrtc "${PythonName}")
    target_link_libraries(pro "${PythonName}")
endif()

add_custom_target(
    yolo
    DEPENDS pro
    WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/workspace
    COMMAND ./pro yolo
)

add_custom_target(
    yolo_gpuptr
    DEPENDS pro
    WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/workspace
    COMMAND ./pro yolo_gpuptr
)

add_custom_target(
    yolo_fast
    DEPENDS pro
    WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/workspace
    COMMAND ./pro yolo_fast
)

add_custom_target(
    centernet
    DEPENDS pro
    WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/workspace
    COMMAND ./pro centernet
)

add_custom_target(
    alphapose 
    DEPENDS pro
    WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/workspace
    COMMAND ./pro alphapose
)

add_custom_target(
    retinaface
    DEPENDS pro
    WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/workspace
    COMMAND ./pro retinaface
)

add_custom_target(
    dbface
    DEPENDS pro
    WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/workspace
    COMMAND ./pro dbface
)

add_custom_target(
    arcface 
    DEPENDS pro
    WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/workspace
    COMMAND ./pro arcface
)

add_custom_target(
    bert 
    DEPENDS pro
    WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/workspace
    COMMAND ./pro bert
)

add_custom_target(
    fall
    DEPENDS pro
    WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/workspace
    COMMAND ./pro fall_recognize
)

add_custom_target(
    scrfd
    DEPENDS pro
    WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/workspace
    COMMAND ./pro scrfd
)

add_custom_target(
    lesson
    DEPENDS pro
    WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/workspace
    COMMAND ./pro lesson
)

add_custom_target(
    pyscrfd
    DEPENDS pytrtc
    WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/example-python
    COMMAND python test_scrfd.py
)

add_custom_target(
    pyinstall
    DEPENDS pytrtc
    WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/example-python
    COMMAND python setup.py install
)

add_custom_target(
    pytorch
    DEPENDS pytrtc
    WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/example-python
    COMMAND python test_torch.py
)

add_custom_target(
    pyyolov5
    DEPENDS pytrtc
    WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/example-python
    COMMAND python test_yolov5.py
)

add_custom_target(
    pycenternet
    DEPENDS pytrtc
    WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/example-python
    COMMAND python test_centernet.py
)

2.2 配置Makefile

主要修改五处

1.修改第 4 行,修改 protobuf 路径

lean_protobuf  := /home/jarvis/protobuf

2.修改第 5 行,修改 tensorRT 路径

lean_tensor_rt := /opt/TensorRT-8.4.1.5

3.修改第 7 行,修改 OpenCV 路径

lean_opencv    := /usr/local

4.修改第 8 行,修改 CUDA 路径

lean_cuda      := /usr/local/cuda-11.6

5.修改第 9 行,选择不支持 python (也可选择支持)

use_python     := false

完整的 Makefile 的内容如下:

cc        := g++
nvcc      = ${lean_cuda}/bin/nvcc

lean_protobuf  := /home/jarvis/protobuf		# ===== 修改 1 =====
lean_tensor_rt := /opt/TensorRT-8.4.1.5		# ===== 修改 2 =====
lean_cudnn     := /datav/lean/cudnn8.2.4.15-cuda11.4
lean_opencv    := /usr/local				# ===== 修改 3 =====
lean_cuda      := /usr/local/cuda-11.6		# ===== 修改 4 =====
use_python     := false						# ===== 修改 5 =====
python_root    := /datav/software/anaconda3

# python_root指向的lib目录下有个libpython3.9.so,因此这里写python3.9
# 对于有些版本,so名字是libpython3.7m.so,你需要填写python3.7m
# /datav/software/anaconda3/lib/libpython3.9.so
python_name    := python3.9

# 如果是其他显卡,请修改-gencode=arch=compute_75,code=sm_75为对应显卡的能力
# 显卡对应的号码参考这里:https://developer.nvidia.com/zh-cn/cuda-gpus#compute
cuda_arch := # -gencode=arch=compute_75,code=sm_75

cpp_srcs  := $(shell find src -name "*.cpp")
cpp_objs  := $(cpp_srcs:.cpp=.cpp.o)
cpp_objs  := $(cpp_objs:src/%=objs/%)
cpp_mk    := $(cpp_objs:.cpp.o=.cpp.mk)

cu_srcs  := $(shell find src -name "*.cu")
cu_objs  := $(cu_srcs:.cu=.cu.o)
cu_objs  := $(cu_objs:src/%=objs/%)
cu_mk    := $(cu_objs:.cu.o=.cu.mk)

include_paths := src        \
			src/application \
			src/tensorRT	\
			src/tensorRT/common  \
			$(lean_protobuf)/include \
			$(lean_opencv)/include/opencv4 \
			$(lean_tensor_rt)/include \
			$(lean_cuda)/include  \
			$(lean_cudnn)/include 

library_paths := $(lean_protobuf)/lib \
			$(lean_opencv)/lib    \
			$(lean_tensor_rt)/lib \
			$(lean_cuda)/lib64  \
			$(lean_cudnn)/lib

link_librarys := opencv_core opencv_imgproc opencv_videoio opencv_imgcodecs \
			nvinfer nvinfer_plugin \
			cuda cublas cudart cudnn \
			stdc++ protobuf dl


# HAS_PYTHON表示是否编译python支持
support_define    := 

ifeq ($(use_python), true) 
include_paths  += $(python_root)/include/$(python_name)
library_paths  += $(python_root)/lib
link_librarys  += $(python_name)
support_define += -DHAS_PYTHON
endif

empty         :=
export_path   := $(subst $(empty) $(empty),:,$(library_paths))

run_paths     := $(foreach item,$(library_paths),-Wl,-rpath=$(item))
include_paths := $(foreach item,$(include_paths),-I$(item))
library_paths := $(foreach item,$(library_paths),-L$(item))
link_librarys := $(foreach item,$(link_librarys),-l$(item))

cpp_compile_flags := -std=c++11 -g -w -O0 -fPIC -pthread -fopenmp $(support_define)
cu_compile_flags  := -std=c++11 -g -w -O0 -Xcompiler "$(cpp_compile_flags)" $(cuda_arch) $(support_define)
link_flags        := -pthread -fopenmp -Wl,-rpath='$$ORIGIN'

cpp_compile_flags += $(include_paths)
cu_compile_flags  += $(include_paths)
link_flags        += $(library_paths) $(link_librarys) $(run_paths)

ifneq ($(MAKECMDGOALS), clean)
-include $(cpp_mk) $(cu_mk)
endif

pro    : workspace/pro
pytrtc : example-python/pytrt/libpytrtc.so
expath : library_path.txt

library_path.txt : 
	@echo LD_LIBRARY_PATH=$(export_path):"$$"LD_LIBRARY_PATH > $@

workspace/pro : $(cpp_objs) $(cu_objs)
	@echo Link $@
	@mkdir -p $(dir $@)
	@$(cc) $^ -o $@ $(link_flags)

example-python/pytrt/libpytrtc.so : $(cpp_objs) $(cu_objs)
	@echo Link $@
	@mkdir -p $(dir $@)
	@$(cc) -shared $^ -o $@ $(link_flags)

objs/%.cpp.o : src/%.cpp
	@echo Compile CXX $<
	@mkdir -p $(dir $@)
	@$(cc) -c $< -o $@ $(cpp_compile_flags)

objs/%.cu.o : src/%.cu
	@echo Compile CUDA $<
	@mkdir -p $(dir $@)
	@$(nvcc) -c $< -o $@ $(cu_compile_flags)

objs/%.cpp.mk : src/%.cpp
	@echo Compile depends CXX $<
	@mkdir -p $(dir $@)
	@$(cc) -M $< -MF $@ -MT $(@:.cpp.mk=.cpp.o) $(cpp_compile_flags)
	
objs/%.cu.mk : src/%.cu
	@echo Compile depends CUDA $<
	@mkdir -p $(dir $@)
	@$(nvcc) -M $< -MF $@ -MT $(@:.cu.mk=.cu.o) $(cu_compile_flags)

yolo : workspace/pro
	@cd workspace && ./pro yolo

yolo_gpuptr : workspace/pro
	@cd workspace && ./pro yolo_gpuptr

dyolo : workspace/pro
	@cd workspace && ./pro dyolo

dunet : workspace/pro
	@cd workspace && ./pro dunet

dmae : workspace/pro
	@cd workspace && ./pro dmae

dclassifier : workspace/pro
	@cd workspace && ./pro dclassifier

yolo_fast : workspace/pro
	@cd workspace && ./pro yolo_fast

bert : workspace/pro
	@cd workspace && ./pro bert

alphapose : workspace/pro
	@cd workspace && ./pro alphapose

fall : workspace/pro
	@cd workspace && ./pro fall_recognize

retinaface : workspace/pro
	@cd workspace && ./pro retinaface

arcface    : workspace/pro
	@cd workspace && ./pro arcface

test_warpaffine    : workspace/pro
	@cd workspace && ./pro test_warpaffine

test_yolo_map    : workspace/pro
	@cd workspace && ./pro test_yolo_map

arcface_video    : workspace/pro
	@cd workspace && ./pro arcface_video

arcface_tracker    : workspace/pro
	@cd workspace && ./pro arcface_tracker

test_all : workspace/pro
	@cd workspace && ./pro test_all

scrfd : workspace/pro
	@cd workspace && ./pro scrfd

centernet : workspace/pro
	@cd workspace && ./pro centernet

dbface : workspace/pro
	@cd workspace && ./pro dbface

high_perf : workspace/pro
	@cd workspace && ./pro high_perf

lesson : workspace/pro
	@cd workspace && ./pro lesson

plugin : workspace/pro
	@cd workspace && ./pro plugin

pytorch : pytrtc
	@cd example-python && python test_torch.py

pyscrfd : pytrtc
	@cd example-python && python test_scrfd.py

pyretinaface : pytrtc
	@cd example-python && python test_retinaface.py

pycenternet : pytrtc
	@cd example-python && python test_centernet.py

pyyolov5 : pytrtc
	@cd example-python && python test_yolov5.py

pyyolov7 : pytrtc
	@cd example-python && python test_yolov7.py

pyyolox : pytrtc
	@cd example-python && python test_yolox.py

pyarcface : pytrtc
	@cd example-python && python test_arcface.py

pyinstall : pytrtc
	@cd example-python && python setup.py install

clean :
	@rm -rf objs workspace/pro example-python/pytrt/libpytrtc.so example-python/build example-python/dist example-python/pytrt.egg-info example-python/pytrt/__pycache__
	@rm -rf workspace/single_inference
	@rm -rf workspace/scrfd_result workspace/retinaface_result
	@rm -rf workspace/YoloV5_result workspace/YoloX_result
	@rm -rf workspace/face/library_draw workspace/face/result
	@rm -rf build
	@rm -rf example-python/pytrt/libplugin_list.so
	@rm -rf library_path.txt

.PHONY : clean yolo alphapose fall debug

# 导出符号,使得运行时能够链接上
export LD_LIBRARY_PATH:=$(export_path):$(LD_LIBRARY_PATH)

3. ONNX导出

  • 训练的模型使用 yolov8s.pt,torch 版本1.12.0,onnx 版本1.13.1

  • ONNX 导出参考自 YoloV5案例第一部分,导出ONNX

关于静态 batch 和动态 batch 有以下几点说明,更多细节请查看视频

静态batch

  • 导出的 onnx 指定所有维度均为明确的数字,是静态 shape 模型
  • 在推理的时候,它永远都是同样的 batch 推理,即使你目前只有一个图推理,它也需要 n 和 batch 的耗时
  • 适用于大部分场景,整个代码逻辑非常简单

动态batch

  • 导出的时候指定特定维度为 dynamic,也就是不确定状态
  • 模型推理时才决定所需推理的 batch 大小,耗时最优,但 onnx 复杂度提高了
  • 适用于如 server 有大量不均匀的请求时的场景

3.1 静态batch导出

静态 batch 的 ONNX 模型导出指令如下

cd yolov5-7.0
python export.py --weights=./best.pt --include=onnx --opset=11

3.2 动态batch导出

修改代码,保证动态 batchsize,主要修改两个文件的内容

  • yolov5-7.0/models/yolo.py
  • yolov5-7.0/export.py
# yolov5-7.0/models/yolo.py第60行,forward函数
# 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()
# 修改为:

bs, _, ny, nx = x[i].shape  # x(bs,255,20,20) to x(bs,3,20,20,85)
bs = -1
ny = int(ny)
nx = int(nx)
x[i] = x[i].view(bs, self.na, self.no, ny, nx).permute(0, 1, 3, 4, 2).contiguous()

# yolov5-7.0/export.py第141行
# output_names = ['output0', 'output1'] if isinstance(model, SegmentationModel) else ['output0']
# if dynamic:
#     dynamic = {'images': {0: 'batch', 2: 'height', 3: 'width'}}  # shape(1,3,640,640)
#     if isinstance(model, SegmentationModel):
#         dynamic['output0'] = {0: 'batch', 1: 'anchors'}  # shape(1,25200,85)
#         dynamic['output1'] = {0: 'batch', 2: 'mask_height', 3: 'mask_width'}  # shape(1,32,160,160)
#         elif isinstance(model, DetectionModel):
#             dynamic['output0'] = {0: 'batch', 1: 'anchors'}  # shape(1,25200,85)
output_names = ['output0', 'output1'] if isinstance(model, SegmentationModel) else ['output']            
if dynamic:
    dynamic = {'images': {0: 'batch'}}  # shape(1,3,640,640)
    if isinstance(model, SegmentationModel):
        dynamic['output0'] = {0: 'batch', 1: 'anchors'}  # shape(1,25200,85)
        dynamic['output1'] = {0: 'batch', 2: 'mask_height', 3: 'mask_width'}  # shape(1,32,160,160)
        elif isinstance(model, DetectionModel):
            dynamic['output'] = {0: 'batch'}  # shape(1,25200,85)

动态 batch 的 ONNX 模型导出指令如下

cd yolov5-7.0
python export.py --weights=./best.pt --dynamic --include=onnx --opset=11

3.3 Resize节点解析的问题

先剧透下,当构建 engine 时会出现错误,我们一并解决,到时候可直接生成 engine,错误信息如下图所示,大概意思就是说 Resize_143 这个节点的 scales 没有初始化(应该是这样理解的吧🤔)

在这里插入图片描述

更多细节的描述可查看Jetson nano部署YOLOv8,这里只提供解决方案即通过 onnxsim 来进行优化。新建一个 v5onnxsim.py 文件,用于优化 onnx 文件,具体内容如下:

import onnx
from onnxsim import simplify

onnx_model = onnx.load("best.onnx")
model_simp, check = simplify(onnx_model)
assert check, "Simplified ONNX model could not be Validated"
onnx.save(model_simp, "best.sim.onnx")

运行后会在当前文件夹生成一个 best.sim.onnx 模型,现在可以查看对应的 Resize_143 节点发生了变化。

3.4 拓展-正确导出ONNX文件

如何正确导出 ONNX 文件?主要包含以下几条:

  1. 对于任何用到 shape、size 返回值的参数时,例如:tensor.view(tensor.size(0),-1)这类操作,避免直接使用 tensor.size 的返回值,而是加上 int 转换如tensor.view(int(tensor(0)),-1),断开跟踪

  2. 对于 nn.Unsample 或 nn.functional.interpolate 函数,使用 scale_factor 指定倍率,而不是使用 size 参数指定大小

  3. 对于 reshape、view 操作时,-1的指定需放到 batch 维度。其他维度计算出来即可。batch 维度禁止指定为大于-1的明确数字

  4. torch.onnx.export 指定 dynamic_axes 参数,并且只指定 batch 维度,禁止其他动态

  5. 使用 opset_version=11,不要低于11

  6. 避免使用 inplace 操作,如y[...,0:2] = y[..., 0:2] * 2 - 0.5

  7. 尽量少的出现 5 个维度,例如 ShuffleNet Module,可用考虑合并 wh 避免出现 5 维

  8. 尽量将后处理部分在 onnx 模型中实现,降低后处理复杂度

:参考自手写AI的详解TensorRT高性能部署视频,这些做法的必要性体现在,简化过程的复杂度,去掉 Gather,Shape 类节点,很多时候不这么改看似也可以成功,但是需求复杂后,依旧存在各类问题。按照上述要求修改后,基本总能成,就不需要使用 onnx-simplifer 了,具体更多细节描述请观看视频。

4. 运行

4.1 源码修改

YOLO模型的推理代码主要在 src/application/app_yolo.cpp 文件中,需要推理的图片放在 workspace/inference 文件夹中,将上述修改后导出的 ONNX 文件放在 workspace 文件夹下。源码修改较简单主要有以下几点:

  • 1.app_yolo.cpp 177行注释,测试 yolov5 而非 yolov7
  • 2.app_yolo.cpp 178行取消注释,测试 yolov5,修改 yolov5s 为 best.sim,构建的模型为 best.sim.onnx
  • 3.app_yolo.cpp 100行 cocolabels 修改为 voclabels
  • 4.app_yolo.cpp 25行 新增 voclabels 数组,添加 VOC 的类别名称

具体修改如下:

//test(Yolo::Type::V7, TRT::Mode::FP32, "yolov7");   //修改1 注释177行
test(Yolo::Type::V5, TRT::Mode::FP32, "best.sim");    //修改2 取消注释178行

for(auto& obj : boxes){
     ...
     auto name    = cocolabels[obj.class_label];	 //修改3 101行cocolabels修改为voclabels
	 ...
}

static const char *voclabels[] = {"aeroplane",   "bicycle", "bird",   "boat",       "bottle",
                                  "bus",         "car",     "cat",    "chair",      "cow",
                                  "diningtable", "dog",     "horse",  "motorbike",  "person",
                                  "pottedplant",  "sheep",  "sofa",   "train",      "tvmonitor"};		 //修改4 25行新增代码,为自训练模型的类别名称

4.2 编译

OK!源码修改好了,编译文件也搞定了,可以编译运行了,编译方式有两种,根据自己喜好更改即可

1.采用 CMakeLists.txt 文件编译,指令如下:

cd tensorRT_Pro-main
mkdir build && cd build
cmake .. && make -j24

耐心等待编译完成(PS:需要一段时间),make -j 参数的选取一般是以 CPU 核心数两倍为宜,参考自make -j参数简介,Linux 下 CPU 核心数可以通过 lscpu 指令查看,博主的 CPU 核心数为 12

2.采用 Makefile 文件编译,指令如下:

cd tensorRT_Pro-main
make pro

4.3 模型构建和推理

编译完成后的可执行文件 .pro 存放在 workspace 文件夹下,模型推理指令如下:

cd workspace  // 进入可执行文件目录下
./pro yolo	  // 构建模型并推理 

推理完成后在 workspace 文件夹下会生成 best.sim.FP32.trtmodel 引擎文件用于模型推理,会生成 best.sim_Yolov5_FP32_result 文件夹,该文件夹下保存了推理的图片。模型构建和推理图解如下所示:

在这里插入图片描述

模型推理效果如下图所示:

在这里插入图片描述

4.4 拓展-摄像头检测

简单写了一个摄像头检测的 demo,默认打开的是 USB 摄像头,如果有其它需求如 CSI 摄像头或者网络摄像头,大家自行修改即可,主要修改以下几点:

  • 1.app_yolo.cpp 新增 app_yolo_video_demo() 函数,具体内容参考下面
  • 2.app_yolo.cpp 177行注释
  • 3.app_yolo.cpp 176行 新增调用 app_yolo_video_demo() 函数代码,具体内容参考下面
static void app_yolo_video_demo(const string& engine_file, TRT::Mode mode){  // 修改1
    auto yolo = Yolo::create_infer(
        engine_file,                    // engine file
        Yolo::Type::V5,                 // yolo type, Yolo::Type::V5 / Yolo::Type::X
        0,                              // gpu_id
        0.5f,                           // confidence threshold
        0.5f,                           // nms threshold
        Yolo::NMSMethod::FastGPU,       // NMS method, fast GPU / CPU
        1024,                           // max objects
        false                           // preprocess use multi stream
        );      
    if (yolo == nullptr){
        INFO("Engine is nullptr");
        return;
    }

    cv::Mat frame;
    cv::VideoCapture cap(0);
    if (!cap.isOpened()){
        INFO("Engine is nullptr");
        return;
    }
    
    while (true){
        cap.read(frame);
        auto t0 = iLogger::timestamp_now_float();
        time_t now = time(0);
        auto boxes = yolo->commit(frame).get();
        for (auto &obj : boxes){
            uint8_t b, g, r;
            tie(r, g, b) = iLogger::random_color(obj.class_label);
            cv::rectangle(frame, cv::Point(obj.left, obj.top), cv::Point(obj.right, obj.bottom), cv::Scalar(b, g, r), 5);

            auto name = voclabels[obj.class_label];
            auto caption = iLogger::format("%s %.2f", name, obj.confidence);

            int width = cv::getTextSize(caption, 0, 1, 2, nullptr).width + 10;
            cv::rectangle(frame, cv::Point(obj.left - 3, obj.top - 33), cv::Point(obj.left + width, obj.top), cv::Scalar(b, g, r), -1);
            cv::putText(frame, caption, cv::Point(obj.left, obj.top - 5), 0, 1, cv::Scalar::all(0), 2, 16);
        }
        imshow("frame", frame);
        auto fee = iLogger::timestamp_now_float() - t0;
        INFO("fee %.2f ms, fps = %.2f", fee, 1 / fee * 1000);
        int key = cv::waitKey(1);
        if (key == 27)
            break;
    }
    cap.release();
    cv::destroyAllWindows();
    INFO("Done");
    yolo.reset();
    return;
}

int app_yolo(){
    app_yolo_video_demo("best.sim.FP32.trtmodel", TRT::Mode::FP32);		// 修改3
    // test(Yolo::Type::V7, TRT::Mode::FP32, "yolov7");					// 修改2
    // test(Yolo::Type::V5, TRT::Mode::FP32, "yolov5s");
    // test(Yolo::Type::V3, TRT::Mode::FP32, "yolov3");
}

进入 build 文件夹下重新编译,然后进入 workspace 文件夹下运行即可调用摄像头进行检测,指令如下(以 CMakeLists.txt 编译为例):

cd build
make -j24
cd ../workspace
./pro yolo

图解如下所示:

在这里插入图片描述

5. CUDA-Tips

在 VSCode 中,要让编辑器正确识别 CUDA 代码并进行语法高亮等操作,需要安装相应的插件。可以在 VSCode 的插件商店中搜索 CUDA,安装名为 vscode-cudacpp 的插件,即可以在编辑器中获得对 CUDA 代码的支持。(from chatGPT)

安装完成后,如果打开的 CUDA 文件仍然存在语法高亮等问题,可以尝试执行以下操作:

  1. 点击 VSCode 编辑器底部的选择语言模式按钮,选择CUDA C/C++作为语言模式

  2. ctrl+shift+p快捷键选择Open Workspace Settings(JSON)/打开工作区设置(JSON)

  3. 在打开的设置页面中,搜索files.associations设置,找到以 .cu 为键的配置项,确保其值为cuda-cpp(即将 .cu 文件与 CUDA C++ 关联)。如果该配置项不存在,可以手动添加以下配置:

    "files.associations": {
        "*.cu": "cuda-cpp"
    }
    
  4. 修改完成后,保存配置文件,关闭并重新打开 VSCode,再次打开 CUDA 文件时就可以看到语法高亮等功能生效了。

结语

本篇博客介绍了 Ubuntu20.04 主机部署 YOLOv5 模型,其难点在于环境的安装和配置,部署流程和我之前介绍的 Jetson 嵌入式模型部署如出一辙,本篇博客从环境配置、模型训练、模型部署三方面进行了介绍,让大家对整体流程有一个基本的把握。博主对于 tensorRT_Pro 只做了最基础的演示,如果有更多的需求需要各位看官自己去挖掘啦😄。感谢各位看到最后,创作不易,读后有收获的看官请帮忙👍⭐️

下载链接

  • 软件安装包[pwd:yolo]
  • VOC数据集[pwd:yolo]
  • yolov5-7.0预训练权重[pwd:yolo]
  • 训练好的权重[pwd:yolo]
  • tensorRT_Pro源文件[pwd:yolo]

参考

  • tensorRT_Pro

  • YOLOv5

  • Ubuntu20.04软件安装大全

  • 拯救者Y9000K2021H在ubuntu18.04安装显卡驱动

  • Ubuntu卸载Nvidia驱动和安装最新驱动

  • linux安装tensorflow,cuda,cudnn安装,pytorch兼容,RTX30系列GPU兼容cuda

  • Linux安装TensorRT

  • Ubuntu20.04安装TensorRT

  • Ubuntu 20.04搭建OpenCV 4.5.0 & C++环境

  • Ubuntu 安装 OpenCV 4.5.5

  • 关于安装opencv编译报错:runtime library * hidden by 等若干问题

  • cmake编译出错hidden by files

  • Linux下编译protobuf

  • Linux下添加protobuf的环境变量

  • YoloV5案例第一部分,导出ONNX

  • YoloV8的动态静态batch如何理解和使用

  • Jetson nano部署YOLOv8

  • 手写AI的详解TensorRT高性能部署视频

  • make -j参数简介

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

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

相关文章

UOS-----本地YUM源配置

1. cd /etc/apt/sources.list.d/ 将文件中的两个list配置文件内容注释掉&#xff0c;并保存 2. cd /etc/apt/ vi sources.list 将配置文件内容注释 3. cd /etc/apt/sources.list.d/ vi local.list (创建一个新的list文件&#xff0c;作为本地yum配置文件) 添…

电脑怎么压缩图片大小,4个通用方法分享

电脑怎么压缩图片大小&#xff1f;我相信这个问题很多小伙伴都遇到过的。我们压缩图片大小的主要原因是为了优化网站、应用程序或移动设备的性能。大尺寸的图片文件需要更多的存储空间和带宽&#xff0c;这将导致网页加载速度变慢&#xff0c;浪费用户时间并影响用户体验。此外…

香港科技大学有什么好的专业?

香港科技大学创办于1991年10月&#xff0c;是一所坐落于香港清水湾半岛的公立研究型大学。大学设有4个学院&#xff1a;工学院、理学院、人文社会科学学院和工商管理学院&#xff0c;还设有2个研究院&#xff1a;香港科技大学公共政策和行政研究生院和香港科技大学霍英东研究院…

nginx 配置代理ip访问https的域名配置

目录 问题背景 解决方式 正向代理&#xff1a; 反向代理&#xff1a; 通俗点儿一句话&#xff0c;正向与反向的区别&#xff1a; 问题背景 在某些单位或机构内部&#xff0c;访问互联网接口需要通过指定的服务器去访问&#xff0c;那我们就需要通过代理 ip 和 端口去访问外…

云计算基础——虚拟化

虚拟化技术简介 虚拟化是一个广义的术语&#xff0c;在计算机方面通常是指计算元件在虚拟的基础上而不是真实的基础上运行 虚拟化是一种经过验证的软件技术&#xff0c;它正迅速改变着IT的面貌&#xff0c;并从根本上改变着人们的计算方式 虚拟化是一个抽象层&#xff0c;它…

【C++学习】类和对象--运算符重载

运算符重载概念&#xff1a;对已有运算符重新定义&#xff0c;赋予其另一种功能&#xff0c;以适应不同的数据类型。 作用&#xff1a;实现两个自定义数据类型相加的运算。 目录 加号运算符重载 1.成员函数重载 2.全局函数重载 左移运算符重载<< 递增运算符重载 赋值…

java堆排序

堆排序是最基本的排序算法&#xff0c;简单来说就是把一堆数据&#xff08;数组&#xff09;分成两个相等的部分&#xff0c;其中一个部分作为数组的开头&#xff0c;另一个部分作为数组的结尾。之后在对这两个相等的部分进行比较&#xff0c;如果在比较之后发现这个数组中有一…

读懂什么是RDMA

一.什么是RDMA 1.RDMA主要体现 2.如何理解RDMA和TCP技术的区别&#xff1f; 3.使用RDMA的好处包括&#xff1a; 二.什么是RoCE&#xff1f; 1. RDMA协议包含: Infiniband&#xff08;IB&#xff09; 2. 为什么RoCE是目前主流的RDMA协议&#xff1f; …

GhostNet

文章目录 相关文章一、轻量化网络结构1. 分组卷积2. 深度可分离卷积 二、GhostNet1. 动机2. Ghost Module 相关文章 https://blog.csdn.net/search_129_hr/article/details/130280697 https://blog.csdn.net/c2250645962/article/details/104601305 一、轻量化网络结构 目的…

信息收集(一)域名信息收集

前言 信息收集也叫做资产收集。信息收集是渗透测试的前期主要工作&#xff0c;是非常重要的环节&#xff0c;收集足够多的信息才能方便接下来的测试&#xff0c;信息收集主要是收集网站的域名信息、子域名信息、目标网站信息、目标网站真实IP、敏感/目录文件、开放端口和中间件…

052:cesium加载网格地图

第052个 点击查看专栏目录 本示例的目的是介绍如何在vue+cesium中加载grid地图。一个 ImageryProvider,它在每个具有可控背景和发光的图块上绘制线框网格。 可能对自定义渲染效果或调试地形很有用。 直接复制下面的 vue+cesium源代码,操作2分钟即可运行实现效果. 文章目录 …

redis 教程 6(Redis 的Pipeline , Lua)

Redis 的Pipeline, Lua PipelinePipeline简介为什么需要PipelinePipeline 性能测试与原生批量命令对比 LuaLua 与事物Lua 的用法Redis 如何管理Lua脚本 Pipeline Pipeline简介 Pipeline&#xff08;流水线&#xff09; 能够将一组redis命令进行组装&#xff0c; 通过一次RTT&…

fmriprep2

一. sub-subXXX文件夹 sub-subXXX.html 二. sub-subXXX文件夹 sub-sub097 / anat / figures / func / log / anat / anat文件夹内文件比较多&#xff0c;文件命名规则遵守BIDS要求( https://bids-specification.readthedocs.io/en/stable/05-derivatives/01-introduction.ht…

【国内chatgpt使用方法合集】

写在前面 Hello大家好&#xff0c; 我是【麟-小白】&#xff0c;一位软件工程专业的学生&#xff0c;喜好计算机知识。希望大家能够一起学习进步呀&#xff01;本人是一名在读大学生&#xff0c;专业水平有限&#xff0c;如发现错误或不足之处&#xff0c;请多多指正&#xff0…

2023_4_23_VS下Release怎么打断点进行debug

&#x1f37f;*★,*:.☆(&#xffe3;▽&#xffe3;)/$:*.★* &#x1f37f; &#x1f4a5;&#x1f4a5;&#x1f4a5;欢迎来到&#x1f91e;汤姆&#x1f91e;的csdn博文&#x1f4a5;&#x1f4a5;&#x1f4a5; &#x1f49f;&#x1f49f;喜欢的朋友可以关注一下&#xf…

MySQL——流程控制函数

在 MySQL 中&#xff0c;流程控制函数是指可以控制存储过程&#xff08;stored procedure&#xff09;或函数&#xff08;function&#xff09;中执行流程的语句。以下是几个常用的流程控制函数&#xff1a; 1. IF函数 实现IF……ELSE……的效果。 # 如果expr1为true&#x…

深入探究java中的 xxxable和xxxator

前言 相信有一定工作经验的朋友,都见过或者用过xxxable和xxxator ,比如常见的Comparable和Comparator, 还有还有常见并且容易迷糊的Iterable和Iterator, 看这名字,前两个是和比较相关的, 后两个是和迭代相关. 但是命名如此相似的接口, 又有何区别呢?各自的用途又是什么呢? 今…

详解车载设备FOTA测试

作者 | 李伟 上海控安安全测评部总监 来源 | 鉴源实验室 引言&#xff1a;上一篇文章我们以车载Tbox为例介绍了相关的性能测试&#xff08;车载TBOX嵌入式设备软件的性能测试&#xff09;&#xff0c;本篇我们介绍另外一个重要功能的专项测试&#xff1a;OTA&#xff08;Over…

MySQL安装及卸载

安装 mysql现在安装的是5.7.mysql的安装方式有两种: 一种是exe方式 另外一种解压版 这次就使用解压版安装 解压缩到非中文目录 编写配置文件 1) 在安装目录下新建my.ini的配置文件 打开文件后缀和隐藏文件显示 2) 新建文件内编写内容 [Client] port 3306 [mysqld] #设置330…

【移植Ardupilot的日志记录方法到linux上】

移植Ardupilot的日志记录方法到linux上 说明日志结构组成日志写入操作预定义日志项运行时添加日志项的方法 单例测试编译方法查看数据其他 说明 采用二进制文件记录&#xff0c;可在mission planer查看 支持所有数据类型记录精巧移植方便可直接在地面站绘制曲线查看可导出生成…