Python多线程中使用TensorRT

Python多线程Threading模块中使用TensorRT遇到的问题以及解决方法

由于需要在Python程序中并行运行TensorRT,因此使用Threading模块调用TensorRT,但是程序出现了报错。

1.遇到的问题

不改动任何原有TensorRT程序直接在多线程中调用会出现如下报错:

ERROR:/rtSafe/cuda/reformat.cu (925) - Cuda Error in NCHWToNCHHW2: 400 (invalid resource handle)

2.解决方案

首先要用pycuda对cuda进行初始化,以防出现cuda驱动初始化的一些莫名其妙的错误

import pycuda.autoinit

(1) 在调用TensorRT的类的__init__()的首行加入下面语句:

self.cfx= cuda.Devvice(0).make_context()

(我自己的程序是在类中调用的TnsorRT以及进行相关操作,如果不是在类中进行操作,那就把上面那句放在所有关于TensorRT操作语句之前,记得去掉self)。
如果上述语句放置位置不对,程序还可能报以下错误:

"ERROR: ../rtSafe/safeContext.cpp (133) - Cudnn Error in configure: 7 (CUDNN_STATUS_MAPPING_ERROR)

(2) 此外还需要在推理函数(inference)的首行添加如下代码:

self.cfx.push()

(3) 最后还要在所有关于TensorRT操作结束后加上:

self.cfx.pop()

3.参考代码

附上我自己项目中关于这部分的代码,自行参考:

class TrtYOLOv3(object):
    """TrtYOLOv3 class encapsulates things needed to run TRT YOLOv3."""
    def allocate_buffers(self, engine):
        
        """Allocates all host/device in/out buffers required for an engine."""
        inputs = []
        outputs = []
        bindings = []
        stream = cuda.Stream()
        for binding in engine:
            size = trt.volume(engine.get_binding_shape(binding)) * \
                engine.max_batch_size
            dtype = trt.nptype(engine.get_binding_dtype(binding))
            # Allocate host and device buffers
            host_mem = cuda.pagelocked_empty(size, dtype)
            device_mem = cuda.mem_alloc(host_mem.nbytes)
            # Append the device buffer to device bindings.
            bindings.append(int(device_mem))
            # Append to the appropriate list.
            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 do_inference(self, context, bindings, inputs, outputs, stream, batch_size=1):
        """do_inference (for TensorRT 6.x or lower)
        
        This function is generalized for multiple inputs/outputs.
        Inputs and outputs are expected to be lists of HostDeviceMem objects.
        """
        self.cfx.push()
        # Transfer input data to the GPU.
        [cuda.memcpy_htod_async(inp.device, inp.host, stream) for inp in inputs]
        # Run inference.
        context.execute_async(batch_size=batch_size,
                            bindings=bindings,
                            stream_handle=stream.handle)
        # Transfer predictions back from the GPU.
        [cuda.memcpy_dtoh_async(out.host, out.device, stream) for out in outputs]
        # Synchronize the stream
        stream.synchronize()
        # Return only the host outputs.
        return [out.host for out in outputs]


    def do_inference_v2(self, context, bindings, inputs, outputs, stream):
        """do_inference_v2 (for TensorRT 7.0+)

        This function is generalized for multiple inputs/outputs for full
        dimension networks.
        Inputs and outputs are expected to be lists of HostDeviceMem objects.
        """
        self.cfx.push()
        # Transfer input data to the GPU.
        [cuda.memcpy_htod_async(inp.device, inp.host, stream) for inp in inputs]
        # Run inference.
        context.execute_async_v2(bindings=bindings, stream_handle=stream.handle)
        # Transfer predictions back from the GPU.
        [cuda.memcpy_dtoh_async(out.host, out.device, stream) for out in outputs]
        # Synchronize the stream
        stream.synchronize()
        # Return only the host outputs.
        return [out.host for out in outputs]

    def _load_engine(self):
        TRTbin = '%s.trt' % self.model
        with open(TRTbin, 'rb') as f, trt.Runtime(self.trt_logger) as runtime:
            return runtime.deserialize_cuda_engine(f.read())

    def _create_context(self):
        return self.engine.create_execution_context()

    def __init__(self, model, input_shape=(416, 416)):
        self.cfx = cuda.Device(0).make_context()
        """Initialize TensorRT plugins, engine and conetxt."""
        self.model = model
        self.input_shape = input_shape
        h, w = input_shape
        if 'tiny' in model:
            self.output_shapes = [(1, 36, h // 32, w // 32),
                                  (1, 36, h // 16, w // 16)]
        else:
            self.output_shapes = [(1, 36, h // 32, w // 32),
                                  (1, 36, h // 16, w // 16),
                                  (1, 36, h //  8, w //  8)]
        if 'tiny' in model:
            postprocessor_args = {
                # A list of 2 three-dimensional tuples for the Tiny YOLO masks
                'yolo_masks': [(3, 4, 5), (0, 1, 2)],
                # A list of 6 two-dimensional tuples for the Tiny YOLO anchors
                'yolo_anchors': [(10, 14), (23, 27), (37, 58),
                                 (81, 82), (135, 169), (344, 319)],
                # Threshold for non-max suppression algorithm, float
                # value between 0 and 1
                'nms_threshold': 0.5,
                'yolo_input_resolution': input_shape
            }
        else:
            postprocessor_args = {
                # A list of 3 three-dimensional tuples for the YOLO masks
                'yolo_masks': [(6, 7, 8), (3, 4, 5), (0, 1, 2)],
                # A list of 9 two-dimensional tuples for the YOLO anchors
                'yolo_anchors': [(10, 13), (16, 30), (33, 23),
                                 (30, 61), (62, 45), (59, 119),
                                 (116, 90), (156, 198), (373, 326)],
                # Threshold for non-max suppression algorithm, float
                # value between 0 and 1
                # between 0 and 1
                'nms_threshold': 0.5,
                'yolo_input_resolution': input_shape
            }
        self.postprocessor = PostprocessYOLO(**postprocessor_args)

        self.trt_logger = trt.Logger(trt.Logger.INFO)
        self.engine = self._load_engine()
        self.context = self._create_context()
        self.inputs, self.outputs, self.bindings, self.stream = \
            self.allocate_buffers(self.engine)
        self.inference_fn = self.do_inference if trt.__version__[0] < '7' \
                                         else self.do_inference_v2

    def __del__(self):
        """Free CUDA memories."""
        del self.stream
        del self.outputs
        del self.inputs

    def detect(self, img, conf_th=0.3):
        """Detect objects in the input image."""
        shape_orig_WH = (img.shape[1], img.shape[0])
        # print(str(img.shape[1])+str(img.shape[0]))
        img_resized = _preprocess_yolov3(img, self.input_shape)
        # print(str(img_resized.shape[1])+str(img_resized.shape[0]))
        # Set host input to the image. The do_inference() function
        # will copy the input to the GPU before executing.
        self.inputs[0].host = np.ascontiguousarray(img_resized)
        trt_outputs = self.inference_fn(
            context=self.context,
            bindings=self.bindings,
            inputs=self.inputs,
            outputs=self.outputs,
            stream=self.stream)

        # Before doing post-processing, we need to reshape the outputs
        # as do_inference() will give us flat arrays.
        
        trt_outputs = [output.reshape(shape) for output, shape
                       in zip(trt_outputs, self.output_shapes)]

        # Run the post-processing algorithms on the TensorRT outputs
        # and get the bounding box details of detected objects
        boxes, classes, scores = self.postprocessor.process(
            trt_outputs, shape_orig_WH, conf_th)
        self.cfx.pop()
        return boxes, scores, classes

4.总结

概括一下,要在多线程中使用TensorRT主要是通过添加【2】中提到的三个语句,这三个语句的位置非常重要,但是每个人的代码可能不完全一样,所以请自行斟酌参考。

5.参考链接

1]: https://forums.developer.nvidia.com/t/how-to-use-tensorrt-by-the-multi-threading-package-of-python/123085
2]: https://github.com/NVIDIA/TensorRT/issues/303

<think>嗯,用户想知道如何将YOLOv8模型通过TensorRT部署到Jetson Nano上。首先,我需要回忆一下相关的步骤和注意事项。根据之前的引用资料,用户可能已经训练好了YOLOv8模型,现在需要部署到Jetson Nano,但因为Nano的算力有限,所以需要TensorRT加速。 首先,应该检查环境配置。引用中提到Jetson Nano需要特定的环境,比如TensorRT 7.2.1.6,CUDA 10.2,PyTorch 1.6等。用户需要确保这些组件已经正确安装,并且版本兼容。因为不同版本的TensorRT和YOLO可能会有兼容性问题,这点需要注意。 接下来是模型转换。YOLOv8的官方支持可能没有直接导出到TensorRT的选项,所以可能需要先将模型转换为ONNX格式,然后再转为TensorRT的engine文件。根据引用[4],用户可能在转换ONNX时遇到问题,比如安装onnxoptimizer和onnxsim库失败,这时候可以在个人电脑上完成转换,再传输到Nano上。不过要注意文件时间不一致的问题,可以通过命令`sudo find ./* -exec touch {} +`来解决。 然后是生成engine文件。使用TensorRT的trtexec工具或者编写自定义脚本进行转换。需要根据模型结构调整参数,比如输入尺寸和精度。这里可能需要参考TensorRT的文档或者社区资源,确保参数设置正确,避免生成不可用的engine文件。 部署阶段需要编写推理代码,处理图像预处理、模型推理和后处理。考虑到Nano的内存限制,可能需要优化内存使用,比如使用FP16精度,或者调整batch size。同时,确保OpenCV版本兼容,因为引用[3]提到需要3.4.9以上版本。 性能优化方面,可以启用TensorRT的优化策略,如层融合和内存优化。另外,监控资源使用情况,避免CPU和内存成为瓶颈。用户可能还关心如何测试和验证模型的准确性,确保转换后的模型没有精度损失。 用户可能遇到的问题包括环境配置错误、模型转换失败、推理速度不理想等。需要提供一些常见问题的解决方法,比如检查版本兼容性,使用正确的转换脚本,调整模型参数等。 最后,生成相关问题时要考虑用户可能的后续疑问,比如如何验证模型转换的正确性,如何进一步优化推理速度,如何处理多线程推理等。这些问题可以帮助用户更深入地理解和解决部署过程中的挑战。</think>### 如何通过TensorRT将YOLOv8部署到Jetson Nano #### 1. **环境准备** - **硬件要求**:Jetson Nano需开启高性能模式(`sudo nvpmodel -m 0`),并安装JetPack 4.6+(包含TensorRT 7.2.1.6、CUDA 10.2、cuDNN 8.0)[^3]。 - **软件依赖**: - OpenCV ≥3.4.9(建议编译支持CUDA的版本) - PyTorch 1.6+(适配CUDA 10.2) - 安装TensorRTPython绑定:`pip install nvidia-tensorrt==7.2.3.4` #### 2. **模型转换流程** **步骤1:导出YOLOv8为ONNX** 使用Ultralytics官方工具导出ONNX模型: ```python from ultralytics import YOLO model = YOLO("yolov8n.pt") model.export(format="onnx", dynamic=True, simplify=True) ``` 若遇到`onnxsim`安装失败,可在x86主机上完成此步骤后传输到Nano[^4]。 **步骤2:ONNX转TensorRT Engine** 在Jetson Nano上使用TensorRT的`trtexec`工具生成引擎文件: ```bash trtexec --onnx=yolov8n.onnx --saveEngine=yolov8n.engine --fp16 --workspace=1024 ``` 参数说明: - `--fp16`:启用FP16精度加速 - `--workspace`:分配显存大小(需根据模型调整) #### 3. **部署与推理优化** **代码框架** 基于TensorRTPython推理代码需包含以下模块: 1. **预处理**:图像归一化、尺寸调整(与训练对齐) 2. **推理**:加载引擎文件并执行`context.execute_v2(bindings)` 3. **后处理**:解析输出张量,应用NMS过滤冗余框 **性能优化建议**: - 使用**CUDA流**实现异步推理 - 启用TensorRT的`layer fusion`优化策略[^2] - 避免频繁内存分配,复用显存缓冲区 #### 4. **常见问题与验证** - **版本冲突**:确保TensorRT、ONNX、PyTorch版本匹配(参考官方兼容性矩阵) - **精度验证**:对比ONNX与TensorRT在相同输入下的输出误差(允许FP16下的微小偏差) - **性能基准测试**:使用`nvtop`监控GPU利用率,目标FPS≥10(640x640输入) #### 5. **参考实现** 建议基于开源项目(如[tensorrtx](https://github.com/wang-xinyu/tensorrtx))修改适配YOLOv8,需注意: - 调整模型输出层的解码逻辑 - 修改anchor配置(若YOLOv8使用动态anchor) ---
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

卑微小岳在线debug

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值