今天是20240329,我见有人问我,我看了下现在的YOLOv5_6.1——7.0的版本是支持未改网络结构的.pt在export.py直接转.engine的,6.1以前的版本不可以直接转,至于master大家可以去试试

————————————————————————————————————————————————————————————————————————————————————————————————

说在前面,之前做项目遇到了需要对yolov5进行tensorrt加速,然后部署在边缘设备上,写本篇主要是为了记住加速的步骤,见别的很多大佬先转换的.wts,现在已经不用那么复杂了,有更简洁的方法,如果能对大家有帮助,我也很开心。

一、首先yolov5的环境配置就不说了,网上资料已经很多了。

二、再者,CUDA和CUDNN安装以及完整训练步骤,也不说了网上资料依然已经很多了。

三、主要记录下tensorrt,tensorrt的安装,截止到我写这篇文章的时候,大家普遍用的tensorrt8.x的版本,TensorRT 同时支持 C++ 和 Python。因为yolov5是python写的,所以我也主要用python的。

   转换网络权重文件主要分为未修改网络的权重文件,和自行修改网络后的权重文件。

    其中未修改网络的权重文件可以直接把yolov5源码训练得到的.pt转换为tensorrt支持的.engine文件,这个.engine在yolov5的detect.py里可以直接调用,当然也可以自己写推理代码

    自行修改网络后的权重文件是先将yolov5源码训练得到的.pt文件转换成.onnx,再把.onnx转化为优化后的.onnx,最后再把优化后的.onnx转换为tensorrt支持的.engine,这个.engine在yolov5的detect.py里可以直接调用,当然也可以自己写推理代码。

    首先.pt文件可以通过yolov5自带的export.py这个程序去直接转化,如果是未修改网络的权重文件,可以在export.py程序里,最下面的parse_opt函数里修改参数如下:

onnxruntime_gpu加载onnx模型_YOLO

然后右击运行,如果环境配好的话,等几分钟就可以转换好了,我的这个yolov5版本是随时更新的yolov5_master版本,不同的版本可能不太一样,不过大同小异。(有些比较老的版本不能直接转.engine,如果不能转,就看我下面的自行修改网络后的权重文件转.engine,步骤是一样的。)转换.engine后,可以在yolov5的detect.py里可以直接调用,当然也可以自己写推理代码。

自行修改网络后的权重文件,首先在yolov5自带的export.py里,修改

onnxruntime_gpu加载onnx模型_YOLO_02

然后右击运行,如果环境配好的话,等几秒钟就可以转换好了,转换好后会得到一个.onnx的文件,这个.onnx是未优化后的,得在一键转换 Caffe, ONNX, TensorFlow 到 NCNN, MNN, Tengine这里进行优化(感谢这位大佬)。主要是onnx转onnx,得到优化后的.onnx后,通过下面的代码去转换成.engine。
 

import tensorrt as trt
import os

EXPLICIT_BATCH = 1 << (int)(trt.NetworkDefinitionCreationFlag.EXPLICIT_BATCH)
TRT_LOGGER = trt.Logger()


def get_engine(onnx_file_path, engine_file_path=""):
    """Attempts to load a serialized engine if available, otherwise builds a new TensorRT engine and saves it."""

    def build_engine():
        """Takes an ONNX file and creates a TensorRT engine to run inference with"""
        with trt.Builder(TRT_LOGGER) as builder, builder.create_network(
            EXPLICIT_BATCH
        ) as network, builder.create_builder_config() as config, trt.OnnxParser(
            network, TRT_LOGGER
        ) as parser, trt.Runtime(
            TRT_LOGGER
        ) as runtime:
            config.max_workspace_size = 1 << 32  # 4GB
            builder.max_batch_size = 1
            # Parse model file
            if not os.path.exists(onnx_file_path):
                print(
                    "ONNX file {} not found, please run yolov3_to_onnx.py first to generate it.".format(onnx_file_path)
                )
                exit(0)
            print("Loading ONNX file from path {}...".format(onnx_file_path))
            with open(onnx_file_path, "rb") as model:
                print("Beginning ONNX file parsing")
                if not parser.parse(model.read()):
                    print("ERROR: Failed to parse the ONNX file.")
                    for error in range(parser.num_errors):
                        print(parser.get_error(error))
                    return None

            # # The actual yolov3.onnx is generated with batch size 64. Reshape input to batch size 1
            # network.get_input(0).shape = [1, 3, 608, 608]

            print("Completed parsing of ONNX file")
            print("Building an engine from file {}; this may take a while...".format(onnx_file_path))
            plan = builder.build_serialized_network(network, config)
            engine = runtime.deserialize_cuda_engine(plan)
            print("Completed creating Engine")
            with open(engine_file_path, "wb") as f:
                f.write(plan)
            return engine

    if os.path.exists(engine_file_path):
        # If a serialized engine exists, use it instead of building an engine.
        print("Reading engine from file {}".format(engine_file_path))
        with open(engine_file_path, "rb") as f, trt.Runtime(TRT_LOGGER) as runtime:
            return runtime.deserialize_cuda_engine(f.read())
    else:
        return build_engine()


def main():
    """Create a TensorRT engine for ONNX-based YOLOv3-608 and run inference."""

    # Try to load a previously generated YOLOv3-608 network graph in ONNX format:
    onnx_file_path = "best0605-sim.onnx"
    engine_file_path = "best0605-sim.engine"

    get_engine(onnx_file_path, engine_file_path)


if __name__ == "__main__":
    main()

转换.engine后,可以在yolov5的detect.py里可以直接调用,当然也可以自己写推理代码。
下图左侧是tensorrt加速后的显存占用率,右侧是未加速的显存占用率,可见tensorrt加速后,占用资源明显低于未加速的,GPU占用内存从3.8G降到了1.6G,这对一些计算能力不足边缘设备去运行yolov5提供了很大的方便,同时节省的算力也可以用来运行其他的功能等。

onnxruntime_gpu加载onnx模型_人工智能_03

如果遇到报错,要不是环境配置问题,要不就是版本问题,另外如果提示opest什么的错误,可以尝试修改一下这个数字:多试几次。

onnxruntime_gpu加载onnx模型_人工智能_04

最后还有很重要的提醒一下,onnx文件可以跨设备使用,但是在转换.engine时,最好还是在那个设备上用,就用那个设备去转,要不然如果在一台设备上转的.engine,却在另一台设备上用的话,可能会因为版本问题而报错。

还有就是在转engine时,设备会很吃电,供电电压也不能太小,我之前在AGX上转,有一次没用220v供电,而是用的电池供电,导致还没转完,就断电关机了。
以上就是我对yolov5进行tensorrt加速的过程,我主要是在windows11系统和AGX的Ubuntu18.04和TX2的Ubuntu18.04上进行的,都成功了,并且资源利用也大大减小了。有什么问题欢迎在评论区问我。