打包YOLO+TensorRT+Cuda为SO库,并通过Python调用

一. 项目简介

1.1 项目目标

  • TensorRT C++ api推理 YOLOv5的代码,打包成动态链接库,并通过 Python 调用。

这样做的原因

  1. 使用 TensorRTC++ api优化 YOLO 模型,可以显著提升目标检测的速度,但 C++ 代码不方便扩展为网络通信协议接口;

  2. Python 作为最流行的胶水语言,拥有很多成熟的通信协议库,可以方便的进行各种网络协议通信,赋能于各种各样的服务;

因此,若将C++的模型推理代码编译为动态链接库,再使用Python封装,那就既有推理速度的优势,又具备可扩展性的便利

​ 可能有人问为什么不直接使用 TensorRT Python Api,看似可以达到相同的效果,博主认为本项目有以下优势,比直接使用TensorRT Python Api 更好:

  1. 使用 TensorRT Python Api 时,前处理和后处理是使用 Python 完成的,不过也是通过numpy实现的,速度方面没有太大差距;
  2. 博主使用 Cuda 编程加速预处理,提升预处理速度,之后一同打包到动态链接库,推理速度更快。

1.2 项目概述

  • 使用 TensorRT-v8.2C++ api,加速YOLOv5-v5.0 目标检测;
  • Linux x86_64 上进行部署;
  • Jetson系列嵌入式设备上也是可行的,把本项目中的 CMakeLists.txt 文件中头文件、库文件相关目录更换即可;

大致实现过程如下:

  1. 博主把 YOLOv5TensorRT 推理封装成 C++ 的类,关键代码如下:
class YoloDetecter
{
public:
    YoloDetecter(const std::string trtFile, const int gpuId);
    ~YoloDetecter();
    float* inference(cv::Mat& img);
};
  1. 接着博主使用 C 类型的函数再次封装上面的类,关键代码如下:
#ifdef __cplusplus
extern "C" {
#endif

YoloDetecter* YoloDetecter_new(char* trtFile, int gpuId){
    return new YoloDetecter(std::string(trtFile), gpuId);
}

float* inference_one(YoloDetecter* instance, const uchar* srcImgData, const int srcH, const int srcW){
    cv::Mat srcImg(srcH, srcW, CV_8UC3);
    memcpy(srcImg.data, srcImgData, srcH * srcW * 3 * sizeof(uchar));
    return instance->inference(srcImg);
}

void destroy(YoloDetecter* instance) { delete instance; }

#ifdef __cplusplus
}
#endif
  1. 把封装后的代码生成动态链接库CMakeLists.txt 中的关键部分如下
# ====== yolo infer shared lib ======
cuda_add_library(yolo_infer SHARED 
    ${PROJECT_SOURCE_DIR}/src/preprocess.cu 
    ${PROJECT_SOURCE_DIR}/src/yololayer.cu 
    ${PROJECT_SOURCE_DIR}/src/yolo_infer.cpp
    ${PROJECT_SOURCE_DIR}/main.cpp
)
target_link_libraries(yolo_infer nvinfer cudart ${OpenCV_LIBS})
  1. 再接着博主使用 Python 封装一个检测类,类当中调用的是上述 C/C++ 代码,关键部分代码如下:
class YoloDetector:
    def __init__(self, trt_file, gpu_id=0):
        self.yolo_infer_lib = ctypes.cdll.LoadLibrary("./lib/libyolo_infer.so")
        self.cpp_yolo_detector = self.yolo_infer_lib.YoloDetecter_new(trt_file.encode('utf-8'), gpu_id)

    def release(self):
        self.yolo_infer_lib.destroy(self.cpp_yolo_detector)

    def infer(self, image):
        out_data = self.yolo_infer_lib.inference_one(self.cpp_yolo_detector, image, height, width)
        out_data = as_array(out_data).copy().reshape(-1)
  1. 最后,使用者不必关心具体的实现,仅仅使用下面的 2 行代码,即可实现 PythonYOLOv5+TensorRT C++ 代码的调用
# 实例化目标检测类
yolo_infer = YoloDetector(trt_file=plan_path, gpu_id=0)
# 使用目标检测实例推理
detect_res = yolo_infer.infer(img)

二. 代码地址

  • 完整的项目代码链接:YOLOv5-TensorRT-lib-Python
  • 代码绝大多数为博主手打,编码不易,若有帮助,望不吝 Star

三. 项目效果

在这里插入图片描述
在这里插入图片描述
推理速度:

Model load cost: 1.2174 s
Infer 001.jpg cost: 0.0077 s
Infer 002.jpg cost: 0.0054 s
Infer 003.jpg cost: 0.0043 s

四. 环境要求

  • 博主自己所使用的基本环境如下:
UbuntuCUDAcuDNNTensorRTOpenCV
20.0411.68.48.2.44.5.0

想要方便点的话,可以直接拉取一个 docker 镜像:

docker pull nvcr.io/nvidia/tensorrt:22.04-py3

然后在镜像中编译安装 OpenCV,具体可参考下面链接中的环境构建部分:

https://github.com/emptysoal/TensorRT-v8-YOLOv5-v5.0

  • python 第三方库环境
pip install numpy==1.22.3
pip install opencv-python==3.4.16.59

五. 模型转换

YOLO检测模型,转换成TensorRT的序列化文件,后缀 .plan(博主的习惯,也可以是.engine或其他)

5.1 原模型下载

  • 链接:https://pan.baidu.com/s/1YG-A8dXL4zWvecsD6mW2ug
  • 提取码:y2oz

下载并解压后,模型文件说明:

模型文件目录
    └── YOLOv5-v5.0  # 该目录中存放的是 YOLOv5 目标检测网络的模型
        ├── yolov5s.pt  # 官方 PyTorch 格式的模型文件
        └── para.wts  # 根据 yolov5s.pt 导出的 wts 格式模型文件

也可以直接从官方YOLOv5-v5.0处下载 yolov5s.pt,然后直接进入到下面的模型转换

5.2 YOLO模型转换

  • 将上述 yolov5s.pt 转为 model.plan,或 para.wts转为 model.plan

  • 具体转换方法参考下面链接,也是博主自己发布的一个项目

  • https://github.com/emptysoal/TensorRT-v8-YOLOv5-v5.0/tree/main

完成之后便可得到 model.plan ,为检测网络的 TensorRT 序列化模型文件。

六. 运行项目

  • 开始编译并运行
  • 按如下步骤
# 创建用于存储 TensoRT 模型的目录
mkdir resources
# 把上面转换得到的 plan 文件复制到目录 resources 中
cp {TensorRT-v8-YOLOv5-v5.0}/model.plan ./resources

mkdir images  # 向其中放入用于推理的图片文件

mkdir build
cd build
cmake ..
make
# 以上执行完成后,会生成 lib 目录,其中存放着 C++ 代码所生成的动态链接库

# 运行 python 推理代码,即可调用动态链接库完成快速推理
python main.py
# 检测结果会保存到output目录下
  • 运行后可以看到如下日志:
Succeeded getting serialized engine!
Succeeded loading engine!
Model load cost: 1.2174 s
Infer 001.jpg cost: 0.0077 s
Infer 002.jpg cost: 0.0054 s
Infer 003.jpg cost: 0.0043 s

七. 项目参考

Python如何调用C++代码部分,主要参考了下面的链接:

  • https://geek-docs.com/python/python-ask-answer/601_python_how_can_i_use_c_class_in_python.html
  • https://blog.csdn.net/qq_41554005/article/details/128292116

八. 其他项目

博主的其他一些链接,若感兴趣,欢迎交流

基于TensorRT v8部署加速YOLOv5-v5.0

Deepsort+YOLOv5的TensorRT加速部署

CUDA编程加速图像预处理

TensorRT各种API对模型加速效果的对比实验

感谢阅毕,若有帮助,欢迎点赞收藏

============================= END =============================

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
将Paddle训练好的YOLO模型进行TensorRT推理加速,可以大幅提高模型的推理速度。 以下是大致的步骤: 1. 转换模型格式:将Paddle训练好的YOLO模型转换为TensorRT可读取的格式,比如ONNX或TensorRT格式。 2. 构建TensorRT引擎:使用TensorRT API构建推理引擎,其中包括模型的输入输出设置、推理精度设置、推理策略设置等。 3. 加载数据:将需要推理的数据加载进TensorRT引擎。 4. 执行推理:调用TensorRT引擎的推理接口进行推理,得到结果。 具体步骤如下: 1. 安装Paddle和TensorRT,并确认两者版本兼容。 2. 将Paddle训练好的YOLO模型转换为ONNX格式或TensorRT格式。其中,转换为ONNX格式可以使用Paddle的 `paddle2onnx` 工具,转换为TensorRT格式可以使用TensorRT自带的 `uff-converter-tf` 工具。 3. 使用TensorRT API构建推理引擎。具体的代码实现可以参考TensorRT官方文档和示例代码。 4. 加载数据。对于YOLO模型,需要将输入数据进行预处理,包括图像的缩放、填充和通道的交换等操作。 5. 执行推理。调用TensorRT引擎的推理接口进行推理,得到结果。对于YOLO模型,需要对输出结果进行后处理,包括解码、非极大值抑制和类别置信度筛选等操作。 参考代码: ```python import pycuda.driver as cuda import pycuda.autoinit import tensorrt as trt import numpy as np # Load the serialized ONNX model with open('yolov3.onnx', 'rb') as f: engine_bytes = f.read() # Create a TensorRT engine trt_logger = trt.Logger(trt.Logger.WARNING) trt_engine = trt.Runtime(trt_logger).deserialize_cuda_engine(engine_bytes) # Allocate memory for the input and output buffers host_input = cuda.pagelocked_empty(trt.volume(trt_engine.get_binding_shape(0)), dtype=np.float32) host_output = cuda.pagelocked_empty(trt.volume(trt_engine.get_binding_shape(1)), dtype=np.float32) cuda.memcpy_htod_async(input_buffer, host_input, stream) cuda.memcpy_htod_async(output_buffer, host_output, stream) # Load the input data with open('input.bin', 'rb') as f: input_data = np.fromfile(f, dtype=np.float32) np.copyto(host_input, input_data) # Execute the inference context = trt_engine.create_execution_context() context.execute(batch_size=1, bindings=[int(input_buffer), int(output_buffer)]) cuda.memcpy_dtoh_async(host_output, output_buffer, stream) # Post-process the output with open('output.bin', 'wb') as f: host_output.tofile(f) ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值