TensorRT综述

TensorRT综述

概述

TensorRT是NVIDIA提供的用于深度学习推理的高性能推理引擎,它可以优化深度学习模型的推理速度和性能,以满足实时应用的需求。

TensorRT采用了多种优化技术,包括网络剪枝、量化、层融合等,可以自动优化网络结构以减少运行时间和内存占用。与常规的深度学习框架相比,TensorRT可以将模型的推理速度提高数倍,同时减少了计算和内存的开销。

TensorRT支持多种类型的神经网络,包括卷积神经网络、循环神经网络、生成对抗网络等,可以在多种平台上运行,包括GPU、CPU、嵌入式设备等。同时,TensorRT还提供了C++和Python API,可以方便地集成到现有的深度学习框架和应用程序中。

总之,TensorRT是一款优秀的深度学习推理引擎,可以大大提高深度学习模型的推理速度和性能,适用于许多实时应用场景。

环境搭建(基于docker环境)

Docker环境有以下几个优势:

  1. 跨平台:Docker容器可以在不同的操作系统上运行,包括Linux、Windows、Mac等,这使得应用程序可以更加容易地在不同的环境中部署和运行。
  2. 隔离性:Docker容器提供了一种隔离应用程序的方式,使得应用程序不会互相干扰,同时可以避免不同应用程序之间的依赖冲突。这样可以让应用程序更加稳定、可靠,也更容易管理。
  3. 可移植性:Docker容器是一种轻量级的虚拟化技术,可以将应用程序和其依赖项打包到一个镜像中,并在不同的环境中运行,这使得应用程序可以更加方便地进行部署、迁移和扩展。
  4. 快速部署:使用Docker容器可以极大地简化应用程序的部署过程,只需要将容器部署到目标环境中即可,无需安装依赖项、配置环境等繁琐的过程。
  5. 可伸缩性:Docker容器可以在多个主机上运行,并可以通过Docker Swarm等容器编排工具进行管理,从而实现应用程序的快速扩展和伸缩。

总之,Docker环境可以让应用程序更加轻量、可移植、可靠,同时也更容易部署和管理。这使得Docker成为了现代应用程序开发和部署的重要工具之一。

  • 进入NVIDIA官网
https://catalog.ngc.nvidia.com/orgs/nvidia/containers/tensorrt/tags
  • 选择需要的tensorrt版本

在这里插入图片描述

  • 下载TensorRT docker镜像
docker pull nvcr.io/nvidia/tensorrt:21.07-py3
  • 启动容器,并进入镜像
docker run --gpus all -it --rm -v /work/jxp/project/:/models nvcr.io/nvidia/tensorrt:21.07-py3
  • 安装opencv
pip install opencv-python-headless -i https://pypi.doubanio.com/simple

注意:如果安装opencv-python会报错ImportError: libGL.so.1: cannot open shared object file: No such file or directory

ONNX转TensorRT

  • 全精度转换(FP32)
trtexec --onnx=efficientnet.onnx --explicitBatch --minShapes=input:1x3x224x224 --optShapes=input:16x3x224x224 --maxShapes=input:32x3x224x224 --saveEngine=efficientnet.plan --verbose
  • 半精度转换(FP16)
 trtexec --onnx=efficientnet.onnx --explicitBatch --minShapes=input:1x3x224x224 --optShapes=input:16x3x224x224 --maxShapes=input:32x3x224x224 --saveEngine=efficientnet.plan  --fp16 --verbose

TensorRT 推理

TensorRT推理的流程一般包括以下几个步骤:

  1. 定义模型:首先需要定义深度学习模型,可以使用常见的深度学习框架(如TensorFlow、PyTorch等)或者使用C++或Python API直接定义模型。
  2. 优化模型:使用TensorRT进行模型优化,包括层融合、剪枝、量化、深度缩减等优化技术,以达到加速和减小模型大小的目的。
  3. 创建执行引擎:将优化后的模型转化为TensorRT执行引擎,以供后续推理使用。执行引擎包括计算图、内存分配、网络优化等信息,可以根据需要序列化到文件中。
  4. 加载数据:将输入数据加载到内存中,包括图像、音频、文本等数据。
  5. 前处理:对输入数据进行前处理,包括归一化、裁剪、缩放、格式转换等操作,以满足模型输入的要求。
  6. 推理计算:将前处理后的数据输入到TensorRT执行引擎中进行推理计算,得到输出结果。
  7. 后处理:对输出结果进行后处理,包括格式转换、解码、可视化等操作,以满足应用程序的需求。
  8. 输出结果:将后处理后的输出结果输出到文件、数据库、网络等存储介质中,以供后续应用程序使用。

总之,TensorRT推理的流程包括了模型定义、模型优化、执行引擎创建、数据加载、前处理、推理计算、后处理、输出结果等多个步骤,需要综合考虑各个步骤的性能、准确性、可靠性等因素,以满足应用程序的需求。

加载EfficientNet TensorRT模型

#---------------------------------------------------------------
#   加载EfficientNet TensorRT模型
#---------------------------------------------------------------
engine_file_path = "/path/to/efficientnet.engine"
with open(engine_file_path, "rb") as f, trt.Runtime(trt.Logger()) as runtime:
    engine = runtime.deserialize_cuda_engine(f.read())
    context = engine.create_execution_context()

分配GPU、将输入数据复制到GPU内存中、将输出数据从GPU内存复制到主机内存中

    #---------------------------------------------------------------
    #   分配GPU、将输入数据复制到GPU内存中、将输出数据从GPU内存复制到主机内存中
    #---------------------------------------------------------------
    def allocate_buffers(self, engine, max_batch_size=32):
        inputs = []
        outputs = []
        bindings = []
        stream = cuda.Stream()
        for binding in engine:
            dims = engine.get_binding_shape(binding)
            # print(dims)
            if dims[0] == -1:
                assert(max_batch_size is not None)
                dims[0] = max_batch_size  # 动态batch_size适应

            size = trt.volume(dims) * engine.max_batch_size
            dtype = trt.nptype(engine.get_binding_dtype(binding))

            host_mem = cuda.pagelocked_empty(size, dtype)  # 开辟出一片显存
            device_mem = cuda.mem_alloc(host_mem.nbytes)

            bindings.append(int(device_mem))

            if engine.binding_is_input(binding):
                inputs.append(HostDeviceMem(host_mem, device_mem))
            else:
                outputs.append(HostDeviceMem(host_mem, device_mem))
        return inputs, outputs, bindings, stream

前处理

 	#---------------------------------------------------------------
    #   前处理
    #---------------------------------------------------------------
    def img_pre_process(self, img):
        img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        img = cv2.resize(img, (self.input_size[1], self.input_size[0]), interpolation=cv2.INTER_LINEAR)
        try:
            cv2.imwrite("test.jpg", img)
            img = img.astype(np.float32)
            img /= 255.0
            img_mean = (0.485,0.456,0.406)
            img_std = (0.229,0.224,0.225)
            img = img - img_mean
            img = (img/img_std)
        except Exception as e:
            print("img_pre_process===wrong!!!",e)
        return img


    def pre_process(self, img_list):
        self.batch_size = len(img_list)
        batch_img = []
        self.batch_data = []
        self.context.set_binding_shape(0, (self.batch_size, 3, self.input_size[0], self.input_size[1]))
        self.inputs, self.outputs, self.bindings, self.stream = self.allocate_buffers(
            self.engine, max_batch_size=self.batch_size)  # 构建输入,输出,流指针

        imgs_result = self.thread_pool.map(self.img_pre_process, img_list)
        imgs_list_res = list(zip(imgs_result))

        for r in imgs_list_res:
            batch_img.append(r[0])
            
        self.batch_data = np.stack(batch_img, axis=0)

        return self.batch_data

推理

    #---------------------------------------------------------------
    #   推理
    #---------------------------------------------------------------
    def do_inference_v2(self, context, bindings, inputs, outputs, stream):
        [cuda.memcpy_htod_async(inp.device, inp.host, stream) for inp in inputs]
        context.execute_async_v2(bindings=bindings, stream_handle=stream.handle)
        [cuda.memcpy_dtoh_async(out.host, out.device, stream) for out in outputs]
        stream.synchronize()
        return [out.host for out in outputs]

    def model_predict(self):
        np.copyto(self.inputs[0].host, self.batch_data.ravel())
        result = self.do_inference_v2(self.context, self.bindings, self.inputs, self.outputs, self.stream)[0]
        return result

后处理

#---------------------------------------------------------------
#   推理
#---------------------------------------------------------------
def post_process(self,result):
    result = result.reshape(-1,4)
    for r in result:
        index = np.argmax(r, axis=0)
        print("=======index===========",index)

完整代码:

import os
import time
import glob
import cv2
import numpy as np
import pycuda.autoinit
import pycuda.driver as cuda
import tensorrt as trt
import concurrent.futures



class HostDeviceMem(object):
    def __init__(self, host_mem, device_mem):
        self.host = host_mem
        self.device = device_mem

    def __str__(self):
        return "Host:\n" + str(self.host) + "\nDevice:\n" + str(self.device)

    def __repr__(self):
        return self.__str__()


class TrtModel(object):
    def __init__(self, engine_path, input_size):
        try:
            self.engine_path = engine_path
            TRT_LOGGER = trt.Logger(trt.Logger.WARNING)
            self.runtime = trt.Runtime(TRT_LOGGER)

            self.engine = self.load_engine(self.runtime, self.engine_path)
            self.context = self.engine.create_execution_context()

            self.thread_pool = concurrent.futures.ThreadPoolExecutor()
            self.input_size = input_size
        except Exception as e:
            print("TrtModel******init*********wrong")

    # 加载EfficientNet TensorRT模型
    def load_engine(self, trt_runtime, engine_path):
        try:
            with open(engine_path, "rb") as f:
                engine_data = f.read()
            engine = trt_runtime.deserialize_cuda_engine(engine_data)
        except Exception as e:
            print("load_engine filled")
        return engine

    # 分配GPU内存、将输入数据复制到GPU内存中、将输出数据从GPU内存复制到主机内存中
    def allocate_buffers(self, engine, max_batch_size=32):
        inputs = []
        outputs = []
        bindings = []
        stream = cuda.Stream()
        for binding in engine:
            dims = engine.get_binding_shape(binding)
            if dims[0] == -1:
                assert(max_batch_size is not None)
                dims[0] = max_batch_size  # 动态batch_size适应
            size = trt.volume(dims) * engine.max_batch_size
            dtype = trt.nptype(engine.get_binding_dtype(binding))
            host_mem = cuda.pagelocked_empty(size, dtype)  # 开辟出一片显存
            device_mem = cuda.mem_alloc(host_mem.nbytes)
            bindings.append(int(device_mem))
            if engine.binding_is_input(binding):
                inputs.append(HostDeviceMem(host_mem, device_mem))
            else:
                outputs.append(HostDeviceMem(host_mem, device_mem))
        return inputs, outputs, bindings, stream


    #---------------------------------------------------------------
    #   前处理
    #---------------------------------------------------------------
    def img_pre_process(self, img):
        img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
        img = cv2.resize(img, (self.input_size[1], self.input_size[0]), interpolation=cv2.INTER_LINEAR)
        try:
            cv2.imwrite("test.jpg", img)
            img = img.astype(np.float32)
            img /= 255.0
            img_mean = (0.485,0.456,0.406)
            img_std = (0.229,0.224,0.225)
            img = img - img_mean
            img = (img/img_std)
        except Exception as e:
            print("img_pre_process===wrong!!!",e)
        return img


    def pre_process(self, img_list):
        self.batch_size = len(img_list)
        batch_img = []
        self.batch_data = []
        self.context.set_binding_shape(0, (self.batch_size, 3, self.input_size[0], self.input_size[1]))
        self.inputs, self.outputs, self.bindings, self.stream = self.allocate_buffers(
            self.engine, max_batch_size=self.batch_size)  # 构建输入,输出,流指针

        imgs_result = self.thread_pool.map(self.img_pre_process, img_list)
        imgs_list_res = list(zip(imgs_result))

        for r in imgs_list_res:
            batch_img.append(r[0])
            
        self.batch_data = np.stack(batch_img, axis=0)

        return self.batch_data

    #---------------------------------------------------------------
    #   推理
    #---------------------------------------------------------------
    def do_inference_v2(self, context, bindings, inputs, outputs, stream):
        [cuda.memcpy_htod_async(inp.device, inp.host, stream) for inp in inputs]
        context.execute_async_v2(bindings=bindings, stream_handle=stream.handle)
        [cuda.memcpy_dtoh_async(out.host, out.device, stream) for out in outputs]
        stream.synchronize()
        return [out.host for out in outputs]

    def model_predict(self):
        np.copyto(self.inputs[0].host, self.batch_data.ravel())
        result = self.do_inference_v2(self.context, self.bindings, self.inputs, self.outputs, self.stream)[0]
        return result
    
    #---------------------------------------------------------------
    #   后处理
    #---------------------------------------------------------------
    def post_process(self,result):
        result = result.reshape(-1,4)
        for r in result:
            index = np.argmax(r, axis=0)
            print("=======index===========",index)

if __name__ == "__main__":

    img_path = 'data/'
    engine_path = 'model.plan'

    img_list = []
    for img in os.listdir(img_path):
        img_p = os.path.join(img_path,img)
        img_ = cv2.imread(img_p)
        img_list.append(img_)

    input_size = [224,224]
    trt_model = TrtModel(engine_path, input_size)

    trt_model.pre_process(img_list)
    result = trt_model.model_predict()
    trt_model.post_process(result)

版权声明:本文为qq128252原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
THE END
< <上一篇
下一篇>>