Jetson Xavier NX 下 yolov8 tensorrt模型部署流程记录及问题处理,本文使用的是TensorRT-Alpha封装库,基于tensorrt+cuda,实现模型的gpu加速。
Jetpack5.1.2、CUDA11.4、Tensorrt8.5.2、OpenCV 4.5.4、Ubuntu 20.04
TensorRT-Alpha的代码可以直接从github官网上下载,源码下载地址是https://github.com/FeiYull/TensorRT-Alpha。Linux下代码克隆指令如下
$ git clone https://github.com/FeiYull/tensorrt-alpha
$ cd tensorrt-alpha/cmake
$ vim common.cmake
将文件中的第20行的tensorrt路径更换成自己开发板中的路径,一般默认路径为:/usr/src/tensorrt
路径设置如下:
set (TensorRT_ROOT /usr/src/tensorrt)
在服务器或者主机上将自己训练好的权重best.pt或者下载的官方预训练权重放在ultralytics-main主目录下,进入训练yolov8的conda 环境中。
(如果已安装1.12.0及以上版本的onnx和0.4.8及以上版本的onnx-simplifier,请略过下面的安装)
$ pip install onnx==1.12.0
$ onnx-simplifier==0.4.8
之后导出模型。yolov8官方代码中包含模型导出命令,所以使用以下命令即可导出模型
$ yolo export model=best.pt format=onnx opset=12 dynamic=True simplify=True int8=True
# opset=12 默认值
# dynamic=True 导出维度为dynamic,也就是不确定状态,如不需要,可设为False
# simplify=True 简化模型,建议设为True,开发板性能有限,简化模型很有必要,且能避免后续一些报错发生
# int8=True INT8量化模型,根据需要开启
#将上一步导出的onnx文件放在刚才在开发板上git的tensorrt-alpha/data/yolov8文件夹下
$ cd /tensorrt-alpha/data/yolov8
#声明使用到的tensorrt路径
#(可能不声明也能用,因为我是在Linux服务器上先尝试部署过的,但开发板上没有lib文件夹)
$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/src/tensorrt/lib
$ /usr/src/tensorrt/bin/trtexec --onnx=best.onnx --saveEngine=best.trt --minShapes=images:1x3x640x640 --optShapes=images:4x3x640x640 --maxShapes=images:8x3x640x64
由于开发板性能有限,可能会出现以下警告信息,但最后还是会得到trt文件
如果使用官方权重部署,请跳过这一步
这一步也可以在主机上修改完成后,替换开发板中的对应文件
$ cd tensorrt-alpha/yolov8
$ vim app_yolov8.cpp
#修改第8行的类别数,改成自己训练集的类别数,例如:
initParameters.num_class = 2;
#修改用到的头文件及函数
$ cd tensorrt-alpha/untils
$ vim untils.h
#修改untils.h文件中的第37行,换成自己的类别,如:
const std::vector<std::string> mask2 = {"non-mask", "mask"};
#在untils.h文件的第80行之后,添加自己的类别颜色,如:
const std::vector<cv::Scalar> color2{
cv::Scalar(148, 80, 189),cv::Scalar(105, 52, 238)
};
#修改untils.cpp文件
$ vim untils.cpp
#修改untils.cpp文件中的show函数,在第144行后添加自己类别对应的代码,如:
if (classNames.size() == 2) // mask2
{
color = Colors::color2[box.label];
}
#修改untils.cpp文件中的save函数,在第198行后添加自己类别对应的代码,如:
if (classNames.size() == 2) // mask2
{
color = Colors::color2[box.label];
}
至此源码修改完毕,可以进行编译
$ cd tensorrt-alpha/yolov8
$ mkdir build
$ cd build
$ cmake ..
$ make -j10
cmke后如果报错,可能是找不到cuda文件,可以先进行一下声明后,再进行编译
$ export PATH=/usr/local/cuda-11.4/bin/:$PATH
执行 make -j10 命令后可能会出现以下错误
/usr/bin/ld: libyolov8.so: undefined reference to `sample::splitToStringVec(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, char)'
collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/app_yolov8.dir/build.make:161:app_yolov8] 错误 1
make[1]: *** [CMakeFiles/Makefile2:78:CMakeFiles/app_yolov8.dir/all] 错误 2
make: *** [Makefile:84:all] 错误 2
这是由于tensorrt版本过高导致,tensorrt8.4版本可能不会出现以上错误。
我板子上使用的是tensorrt8.5.2,这个版本tensorrt下的sampleOptions.cpp文件中未定义splitToStringVec函数会出现以上错误。所以需要进行以下修改
首先进入到/usr/src/tensorrt/samples/common文件夹下,打开终端,执行如下命令
$ sudo vim sampleUtils.h
在第77行可以看到关于splitToStringVec函数的一个声明,但并未定义,所以将它注释掉,如下所示:
// std::vector splitToStringVec(std::string const& option, char separator);
之后保存退出(Esc + shift: + wq),打开sampleOptions.cpp文件,将splitToStringVec函数的定义添加在这
$ sudo vim sampleOptions.cpp
#在文件的38行,也就是namespace中添加如下代码
std::vector<std::string> splitToStringVec(const std::string& option, char separator)
{
std::vector<std::string> options;
for (size_t start = 0; start < option.length();)
{
size_t separatorIndex = option.find(separator, start);
if (separatorIndex == std::string::npos)
{
separatorIndex = option.length();
}
options.emplace_back(option.substr(start, separatorIndex - start));
start = separatorIndex + 1;
}
return options;
}
之后保存退出,在tensorrt-alpha/yolov8/build文件下再一次执行make -j10命令,即可编译成功
继续上一步,直接在终端执行如下指令即可
$ ./app_yolov8 --model=../../data/yolov8/best.trt --size=640 --batch_size=1 --img=../../data/bus.jpg --show
$ ./app_yolov8 --model=../../data/yolov8/best.trt --size=640 --batch_size=1 --video=../../data/test.avi --show --savePath=../
其他运行指令在TensorRT-Alpha仓库上都有
本篇博客介绍了关于自己训练的yolov8模型在Jetson Xavier NX嵌入式开发板上的部署工作,并记录了部署过程中自己遇到的问题,感谢各位看到最后。
yolov8
TensorRT-Alpha
linux下 yolov8 tensorrt模型部署