- 在此记录yolov5-5.0模型部署的完整步骤,做好笔记,便于后续重复使用和学习,肝了一个多星期才完成
- 如果想使用 ONNX Runtime 进行部署,请参考文章:
详细介绍 Yolov5 转 ONNX模型 + 使用ONNX Runtime 的 Python 部署
详细介绍 Yolov5 转 ONNX模型 + 使用 ONNX Runtime 的 C++ 部署 - 也可以直接用 QT 或者直接 C++ 调用 Python ,网上资料很多,可以自己找,注意 如果要多次调用Pyhon脚本,需要开启全局锁。
前置条件
确保已经完成了yolov5的环境配置并实现了训练自己的数据集,得到权重文件
本文整体结构和流程参考:Yolov5训练自己的数据集+TensorRT加速+Qt部署
完善知识体系的知识:win32和x86以及x64的区别
本人使用的环境记录:TensorRT版本不同,对应的lib库会有不同
Win10
cuda 11.1
cudnn 8.5.0
TensorRT 8.2.1.8
Visual Studio 2019
Opencv 4.5.5
Qt 5.14.2
- 为自己的电脑配置可能需要的环境变量做的笔记,便于复制
头文件包含目录:
D:\Program Files\TensorRT-8.2.1.8\include
D:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.1\include
D:\OpenCV\v455\opencv\build\include
D:\OpenCV\v455\opencv\build\include\opencv2
lib 库目录:TensorRT的lib文件夹不分x64和Win32,Ohttps://blog.csdn.net/qq_22487889/article/details/127040950penCV只有x64,CUDA分x64和Win32
D:\Program Files\TensorRT-8.2.1.8\lib
D:\OpenCV\v455\opencv\build\x64\vc15\lib
D:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.1\lib\x64
D:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.1\lib\Win32
//一般不用最后一行的Win32
附加依赖项:根据环境的不同,需要依赖的lib文件可能不同(注意注意:不要在附加依赖项中添加成了dll文件!!!!)
//前5个(一般不用)是CUDA/vxx.x/lib/Win32拥有的,5-8是x64所拥有的
//再后面除了opencv以外都是TensorRT拥有的,但是我用的
cuda.lib
cudadevrt.lib
cudart_static.lib
OpenCL.lib
cudart.lib
cublas.lib
cudnn.lib
cudnn64_8.lib
myelin64_1.lib
nvinfer.lib
nvinfer_plugin.lib
nvonnxparser.lib
nvparsers.lib
opencv_world455.lib //opencv版本不同就不一样
由于TensorRT8.2.18没有myelin64_1.lib,会报错:无法打开输入文件“myelin64_1.lib“,如果是没有该库文件的,删除myelin64_1.lib这一行
一、 利用TenbsorRT进行模型的加速
.pt文件→.wts文件→.engine文件
1.1 生成 .wts 文件
此处参考Yolov5训练自己的数据集+TensorRT加速+Qt部署的 3.1 节即可
1.2 生成 .engine 文件
1.2.1 下载电脑支持的CUDA版本以及对应的cuDNN和TensorRT
- 我下载的是CUDA 11.1.1版本,具体查看自己电脑支持的CUD【A版本可以上网搜资料。记得使用VS2019及以下版本比较好。
Pytorch,查看Pytorch版本,查看CUDA版本,查看cudnn版本,查看pytorch可用性,查看cuda可用性,查看cudnn可用性
Cuda和cuDNN安装教程(超级详细)
如果在没有显卡的电脑上安装,只有intel核显,没有出现第二行
还出现了如下问题:Win10系统安装CUDA10.0和cuDNN
卸载了VS2022,然后安装VS2019,问题得到了解决。
- 然后是安装TensorRT:
TensorRT下载网站
windows上安装TensorRT
在sample_mnist.sln下,重新生成解决方案,再执行
一些问题的解决:
- 无法找到 v143 的生成工具
- 无法打开输入文件“cudnn.lib” :
cudnn中的 lib 中的文件,直接放入CUDA的 lib 中的x64文件夹,而不是上图直接放入lib文件夹,就可以正常运行了 - 问题:Could not locate zlibwapi.dll. Please make sure it is in your library path!
解决:Could not locate zlibwapi.dll. Please make sure it is in your library path - 大功告成:
1.2.2 根据自己使用的VS版本下载对应版本的OpenCV
- VS2022下安装和配置OpenCV环境参数
注意:创建新项目的时候,不要勾选解决方案放在同一目录
在“通用属性-链接器-输入-附加依赖项”中添加,注意一定要是****d.lib,因为只有d.lib才对应的是dubug版本
测试代码:Visual Studio 2022下载及配置OpenCV4.5.5的详细过程
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc.hpp>
#include<iostream>
using namespace cv;
using namespace std;
int main() {
Mat image = Mat::zeros(300, 600, CV_8UC3);
circle(image, Point(300, 200), 100, Scalar(0, 255, 120), -100);
circle(image, Point(400, 200), 100, Scalar(255, 255, 255), -100);
imshow("show window", image);
waitKey(0);
return 0;
}
结果:
- 配置Release模式:刚刚我们配置的只能在DeBug|x64中运行,下面我们配置Release|x64的属性表,可以在Release|x64中运行。
在visual studio中找到属性管理器
VS2022永久配置OpenCV开发环境
注意配置release版本,在“通用属性-链接器-输入-附加依赖项”中添加一定要是****.lib,而不是debug版本中的****d.lib,因为只有.lib才对应的是Release版本
1.2.3 编译生成可执行文件
参考:
BiliBili:win10 使用TensorRT部署 yolov5-v4.0(C++)(二)
CSDN:win10 使用TensorRT部署 yolov5-v4.0(C++)
如果使用的是自己的数据集,记得修改 yololayer.h 头文件,主要是修改分类和识别框
错误记录:直接使用参考博客的 CMakeLists 会出现错误,需要添加tensorrtx/yolov5/CMakeLists.txt的
add_definitions(-DAPI_EXPORTS)
注意是 yolov5-5.0 版本,最后我的 CMakeLists 如下:文件目录要和自己的对应
cmake_minimum_required(VERSION 2.8)
#=========================================================
project(yolov5) #1 工程名
set(OpenCV_DIR "D:\\OpenCV\\v455\\opencv\\build") #2 opencv目录
set(OpenCV_INCLUDE_DIRS ${OpenCV_DIR}\\include) #3
set(OpenCV_LIB_DIRS ${OpenCV_DIR}\\x64\\vc15\\lib) #4
set(OpenCV_Debug_LIBS "opencv_world455d.lib") #5
set(OpenCV_Release_LIBS "opencv_world455.lib") #6
set(TRT_DIR "D:\\Program Files\\TensorRT-8.2.1.8") #7
set(TRT_INCLUDE_DIRS ${TRT_DIR}\\include) #8
set(TRT_LIB_DIRS ${TRT_DIR}\\lib) #9
set(Dirent_INCLUDE_DIRS "D:\\DeepLearning\\tensorrtx-yolov5-v5.0\\yolov5") #10
#=========================================================
add_definitions(-std=c++11)
add_definitions(-DAPI_EXPORTS)
option(CUDA_USE_STATIC_CUDA_RUNTIME OFF)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_BUILD_TYPE Debug)
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads)
# setup CUDA
find_package(CUDA REQUIRED)
message(STATUS " libraries: ${CUDA_LIBRARIES}")
message(STATUS " include path: ${CUDA_INCLUDE_DIRS}")
include_directories(${CUDA_INCLUDE_DIRS})
####
enable_language(CUDA) # add this line, then no need to setup cuda path in vs
####
include_directories(${PROJECT_SOURCE_DIR}/include) #11
include_directories(${TRT_INCLUDE_DIRS}) #12
link_directories(${TRT_LIB_DIRS}) #13
include_directories(${OpenCV_INCLUDE_DIRS}) #14
link_directories(${OpenCV_LIB_DIRS}) #15
include_directories(${Dirent_INCLUDE_DIRS}) #16
# -D_MWAITXINTRIN_H_INCLUDED for solving error: identifier "__builtin_ia32_mwaitx" is undefined
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -Ofast -D_MWAITXINTRIN_H_INCLUDED")
# setup opencv
find_package(OpenCV QUIET
NO_MODULE
NO_DEFAULT_PATH
NO_CMAKE_PATH
NO_CMAKE_ENVIRONMENT_PATH
NO_SYSTEM_ENVIRONMENT_PATH
NO_CMAKE_PACKAGE_REGISTRY
NO_CMAKE_BUILDS_PATH
NO_CMAKE_SYSTEM_PATH
NO_CMAKE_SYSTEM_PACKAGE_REGISTRY
)
message(STATUS "OpenCV library status:")
message(STATUS " version: ${OpenCV_VERSION}")
message(STATUS " lib path: ${OpenCV_LIB_DIRS}")
message(STATUS " Debug libraries: ${OpenCV_Debug_LIBS}")
message(STATUS " Release libraries: ${OpenCV_Release_LIBS}")
message(STATUS " include path: ${OpenCV_INCLUDE_DIRS}")
add_executable(yolov5 ${PROJECT_SOURCE_DIR}/yolov5.cpp ${PROJECT_SOURCE_DIR}/common.hpp ${PROJECT_SOURCE_DIR}/yololayer.cu ${PROJECT_SOURCE_DIR}/yololayer.h) #17
target_link_libraries(yolov5 "nvinfer" "nvinfer_plugin") #18
target_link_libraries(yolov5 debug ${OpenCV_Debug_LIBS}) #19
target_link_libraries(yolov5 optimized ${OpenCV_Release_LIBS}) #20
target_link_libraries(yolov5 ${CUDA_LIBRARIES}) #21
target_link_libraries(yolov5 Threads::Threads)
- 最终的项目结构如下:
- Debug和Release模式的区别:编译工具条内的Debug与Release选项有什么含义
Debug 通常称为调试版本,它包含调试信息,并且不作任何优化,便于程序员调试程序。Release 称为发布版本,它往往是进行了各种优化,使得程序在代码大小和运行速度上都是最优的,以便用户很好地使用。Debug带有大量的调试代码,运行时需要相应的运行库,发布模式程序紧凑不含有调试代码和信息,直接可以运行(如果不需要运行库)。
顺便补充一下 gcc 和 g++ 的知识
GCC的DEBUG和release版本编译方法
1.2.4 wts文件生成engine文件
- 对之前生成的.wts文件使用命令:exe 文件和 wts 具体名称以及文件夹自己修改
也可以直接将权重文件复制到生成的目录(Debug或者Release)下进行如下执行
yolov5.exe -s best20220918.wts best20220918.engine s
生成成功:
- 测试:模型预测
在刚刚的地方直接新建一个文件夹用来存放预测图象
然后输入命令:处理image_dir文件夹内的图片,可以看到处理速度,处理后的图片会显示识别框以及标签的 id
yolov5.exe -d best20220918.engine ./image_dir
二、 模型的封装
将模型封装成动态链接库(.dll)的形式,从而在Qt中调用。
用于完善自己知识体系的知识:
VS中空项目、win32项目、控制台程序的区别
2.1 VS2019创建 dll 并调用动态库的方法
该节的内容比较长,新写了一个文章,内容请看:VS2019 - 动态库的编写和调用
本节参考:
CSDN:VS2019环境下C++动态链接库(DLL)的创建与调用
BIliBili:Visual Studio 2019-编写C++动态链接库
BiliBili:Visual Studio 2019-显式调用C++动态库
2.2 将yolov5封装成一个导出类,生成动态链接库 dll
该节的内容请看:(win10) yolov5-v5.0导出动态链接库-TensorRT+VS2019+CMake
本节新增参考参考:CSDN:yolov5动态链接库DLL导出(TensorRT)
BiliBili:win10 使用TensorRT部署 yolov5-v4.0(C++)(三)
上述采用的是yolov5-v4.0,而我的是yolov5-v5.0,因此代码是需要根据自己的版本进行更改的
2.3 在VS中进行检测封装好的模型是否能够运行
- 创建空项目
- 将需要的文件放入项目中,文件在属性中的包含了的文件夹内其实也可以不放
- 需要的文件
- 项目内容如下: main.cpp 是自己写的,参考:三.测试
- 项目结构及代码如下:注意属性要与 dll 的导出属性相同,我的均在Release | x64 下实现
//main.cpp
#pragma once
#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/dnn.hpp>
#include "Detection.h"
#include "dirent.h"
#include "yololayer.h"
using namespace std;
int main()
{
Connect connect;
YOLOV5* yolo_dll = connect.Create_YOLOV5_Object();
cv::VideoCapture capture(0);
if (!capture.isOpened()) {
std::cout << "Error opening video stream or file" << std::endl;
return -1;
}
yolo_dll->Initialize("./best20220918.engine", 0);
while (1)
{
cv::Mat frame;
capture >> frame;
vector<cv::Rect> Boxes;
vector<const char*> ClassLables;
yolo_dll->Detecting(frame, Boxes, ClassLables);
cv::imshow("output", frame);
cv::waitKey(1);
}
connect.Delete_YOLOV5_Object(yolo_dll);
return 0;
}
- 配置环境需要配置,不一定每一行都需要,我是一刀切了
#将此路径加入项目属性包含目录中
D:\DeepLearning\tensorrtx-yolov5-v5.0_dll\yolov5
D:\Program Files\TensorRT-8.2.1.8\include
D:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.1\include
D:\OpenCV\v455\opencv\build\include
D:\OpenCV\v455\opencv\build\include\opencv2
#将此路径加入项目属性的库目录中,也就是我们刚刚生成dll的文件目录
#TensorRT的lib文件夹不分x64和Win32,OpenCV只有x64,CUDA分x64和Win32
D:\DeepLearning\tensorrtx-yolov5-v5.0_dll\yolov5\build_dll\Release
D:\Program Files\TensorRT-8.2.1.8\lib
D:\OpenCV\v455\opencv\build\x64\vc15\lib
D:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.1\lib\x64
D:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.1\lib\Win32
#在输入链接器添加依赖库
yolov5.lib
#前5个(一般不用)是CUDA/vxx.x/lib/Win32拥有的,5-8是x64所拥有的
#再后面除了opencv以外都是TensorRT拥有的
cuda.lib
cudadevrt.lib
cudart_static.lib
OpenCL.lib
cudart.lib
cublas.lib
cudnn.lcucuda
cudnn64_8.lib
nvinfer.lib
nvinfer_plugin.lib
nvonnxparser.lib
nvparsers.lib
opencv_world455.lib
opencv_world455d.lib //opencv版本不同就不一样
- 报错解决
1.‘localtime’: This function or variable may be unsafe. Consider using localtime_s instead.
2.运行成功,但是仍然有问题:
问题出在:Detection.cpp,根据自己的大小进行调整即可,我改成了if (img.rows < 320 || img.cols < 320)
- 运行成功:
三、 利用QT部署
方法1(我没有使用):Visual Studio 2019 配置 Qt5.14.2 开发环境并部署,参考:该博客的五、利用Qt进行部署
该方法要注意:Qt中使用的编译器(MinGW or MSVC)必须和编译库使用的编译器相同!!!
- 环境配置参考,对照着看:VS2019 Qt开发环境搭建与配置
QT从入门到入土(一)——Qt5.14.2安装教程和VS2019环境配置
Visual Studio 2019配置qt开发环境
如果需要更新Qt组件,请参考:QT组件添加、更新、移除
其中VS种配置插件时候的位置如下:
其中QT所需的头文件和库目录参考:VS2017如何添加QT的头文件和库目录 和 如何设置vs包含目录的相对路径
移植到到qt creator上使用,参考:visual studio 2019配置qt开发,并移植到到qt creator上使用 - 我的方法:将 2.3 节中测试 dll 文件的项目进行打包,然后用QT调用并读取参数。步骤如下:
3.1 Visual Studio 2019 的项目进行打包并与Qt互相传递参数
3.1.1 修改main.cpp文件,从而获取参数
参考:OpenCV中Rect()函数常用操作和使用详解(含绘图示例)+Rectangle()函数用法 按照自己需要选取参数。
我增加的代码如下:
for (auto r : Boxes) {
cout << "Boxes:" << r << endl;
cout << "左上:" << r.tl() << "右下" << r.br() << "\t";
}
输出如图:可以看出Boxes的参数是【宽 × 长 from 左上角】
3.1.2 对VS项目进行打包
- 首先对项目的属性进行修改:
vs2019 生成包含dll的exe
https://blog.csdn.net/love521963/article/details/107326320
然后生成解决方案因为我测试 dll 的环境是Release | x64 的环境,就改成多线程(/MT),点击生成解决方案,根据下方项目路径找到exe文件:
- 然后进入文件夹中添加文件,最后文件夹所需的所有内容如下:
- 在别人的电脑上会出现以下问题:这是因为运行的电脑要有和配置环境的电脑拥有相同的环境