tensorrt deeplabv3+ 部署踩坑

deeplabv3+模型转onnx模型

一开始我用的paddlepaddle的实现,转换成onnx模型再转trt模型推理需要2s左右
后面我用得pytorch的deeplabv3+实现
https://github.com/yassouali/pytorch-segmentation
转换成onnx模型再转trt模型推理也在2s左右

后面参考tensorrtx项目和一个识别指针的项目使用c++手写deeplabv3+网络,然后再用gen_wrt.py把权重导出来再手动塞到c++手写的模型中,发现也是2s左右。

最后使用trt的打印每层执行时间发现在下采样部分特别慢,后面我把python里的和c++里的上采样使用近邻上采样替换掉双线性下采样后就快了,大概在20ms左右。

一开始这个应该是trt不支持双线性下采样,转过来的onnx模型使用卷积操作代替上采样所以很慢,网上百度,trt实现双线性下采样需要自己写插件,后面查看文档发现kLINEAR有写支持bilinear,但是我没找到api指定bilinear。

nvinfer1::ResizeMode只支持两种参数
支持的参数

trt文档 https://docs.nvidia.com/deeplearning/tensorrt/api/c_api/classnvinfer1_1_1_i_profiler.html

双线性上采样插件代码参考

/*
 * Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

#include "ResizeBilinear.hpp"
#include <cuda_fp16.h>
#include <cassert>

// TODO: Move this to a common header
inline bool is_CHW(nvinfer1::Dims const& dims) {
  return (dims.nbDims == 3 &&
          dims.type[0] == nvinfer1::DimensionType::kCHANNEL &&
          dims.type[1] == nvinfer1::DimensionType::kSPATIAL &&
          dims.type[2] == nvinfer1::DimensionType::kSPATIAL);
}

nvinfer1::Dims ResizeBilinearPlugin::getOutputDimensions(int index,
                                                        const nvinfer1::Dims *inputDims,
                                                        int nbInputs) {
  assert(nbInputs == 1);
  nvinfer1::Dims const& input = inputDims[0];
  assert(is_CHW(input));
  assert(_ndims == 2);
  assert(index == 0);
  nvinfer1::Dims output;
  output.nbDims = input.nbDims;
  int s = 0;
  for( int d=0; d<input.nbDims; ++d ) {
    output.type[d] = input.type[d];
    if( input.type[d] == nvinfer1::DimensionType::kSPATIAL ) {
      output.d[d] = int(input.d[d] * _scale[s++]);
    } else {
      output.d[d] = input.d[d];
    }
  }
  return output;
}

int ResizeBilinearPlugin::initialize() {
  _output_dims = this->getOutputDimensions(0, &this->getInputDims(0), 1);
  assert(is_CHW(this->getInputDims(0)));
  assert(is_CHW(_output_dims));
  assert(_ndims == 2);
  return 0;
}


template <typename Data>
__global__
void resize_bilinear_kernel_2d(int nbatch,
                              float2 scale,
                              int2 isize,
                              int2 osize,
                              Data const* idata, int istride, int ibatchstride,
                              Data*       odata, int ostride, int obatchstride) {
  int x0 = threadIdx.x + blockIdx.x * blockDim.x;
  int y0 = threadIdx.y + blockIdx.y * blockDim.y;
  int z0 = blockIdx.z;
  for( int batch=z0; batch<nbatch; batch+=gridDim.z ) {
    for( int oy=y0; oy<osize.y; oy+=blockDim.y*gridDim.y ) {
      for( int ox=x0; ox<osize.x; ox+=blockDim.x*gridDim.x ) {
        float ix = float(ox) / scale.x;
        float iy = float(oy) / scale.y;
        int w_low = ((int)ix < isize.x) ? (int)ix : (int)(isize.x - 1);
        int h_low = ((int)iy < isize.y) ? (int)iy : (int)(isize.y - 1);
        int w_high = w_low + 1 < isize.x ? w_low + 1 : (int)(isize.x - 1);
        int h_high = h_low + 1 < isize.y ? h_low + 1 : (int)(isize.y - 1);
        // int w_low = int(ix);
        // int h_low = int(iy);
        // int w_high = w_low + 1;
        // int h_high = h_low + 1;
        float lw = ix - w_low, lh = iy - h_low;
        float hw = 1 - lw,    hh = 1 - lh;
        Data W1 = (Data)(hh * hw), W2 = (Data)(hh * lw), W3 = (Data)(lh * hw), W4 = (Data)(lh * lw);
        Data v1 = idata[batch * ibatchstride + h_low * istride + w_low];
        Data v2 = idata[batch * ibatchstride + h_low * istride + w_high];
        Data v3 = idata[batch * ibatchstride + h_high * istride + w_low];
        Data v4 = idata[batch * ibatchstride + h_high * istride + w_high];
        odata[batch * obatchstride + oy * ostride + ox] = Data(W1 * v1) + Data(W2 * v2) + Data(W3 * v3) + Data(W4 * v4);

      }
    }
  }
}

int ResizeBilinearPlugin::enqueue(int batchSize,
                                 const void *const *inputs, void **outputs,
                                 void *workspace, cudaStream_t stream) {
  auto const& input_dims = this->getInputDims(0);
  int nchan = input_dims.d[0];
  switch( _ndims ) {
  case 2: {
    float2 scale = {_scale[1], _scale[0]};
    int2 isize = {input_dims.d[2], input_dims.d[1]};
    int2 osize = {_output_dims.d[2], _output_dims.d[1]};
    int istride =   input_dims.d[2];
    int ostride = _output_dims.d[2];
    int ibatchstride =   input_dims.d[1] * istride;
    int obatchstride = _output_dims.d[1] * ostride;
    dim3 block(16, 16);
    dim3 grid((osize.x - 1) / block.x + 1,
              (osize.y - 1) / block.y + 1,
              std::min(batchSize * nchan, 65535));
    if (getDataType()==nvinfer1::DataType::kFLOAT) {				
      resize_bilinear_kernel_2d<<<grid, block, 0, stream>>>
        (batchSize * nchan, scale, isize, osize,
         static_cast<float const*>( inputs[0]), istride, ibatchstride,
         static_cast<float*      >(outputs[0]), ostride, obatchstride);
    } else {
      resize_bilinear_kernel_2d<<<grid, block, 0, stream>>>
        (batchSize * nchan, scale, isize, osize,
         static_cast<__half const*>( inputs[0]), istride, ibatchstride,
         static_cast<__half*      >(outputs[0]), ostride, obatchstride);
    }
    return cudaGetLastError() != cudaSuccess;
  }
  default: return -1;
  }
}

https://github.com/chenjun2hao/onnx-tensorrt/commit/b5f9e9219cbc21ab1262018f42f12d8319217500

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
### 回答1: TensorRT是一个高性能的深度学习推理库,可以帮助您在 NVIDIA GPU 上加速深度学习推理。要在C++中部署YOLOv5,您需要进行以下步骤: 1.安装 TensorRT:在系统上安装 TensorRT 库和配套的驱动程序。 2.导出权重:在训练模型之后,您需要将权重导出到一个可以被 TensorRT 读取的格式,如 ONNXTensorRT 格式。 3.构建网络:使用 TensorRT 的 C++ API 构建网络,并将权重加载到网络中。 4.配置推理:设置网络的运行参数,如批量大小和精度。 5.运行推理:使用 TensorRT 运行网络,并得到结果。 6.解码结果:最后,您需要对结果进行解码,以便更好地理解结果。 希望这能帮到你。 ### 回答2: TensorRT是一个高性能的推理引擎,可以加速神经网络模型的推理,而yolov5 c是一种基于深度学习的物体检测模型,因此使用TensorRT部署yolov5 c可以提高模型的运行速度和效率。 下面是TensorRT部署yolov5 c的步骤: 1. 模型转换:将yolov5的模型文件转换为TensorRT可处理的格式。这可以使用yolov5_offical代码库中的convert.py脚本来完成。通过在终端中运行该脚本,可以生成一个TensorRT可识别的Engine文件。 2. Engine文件编写:将生成的Engine文件加载到CUDA内存中,并在CPU上分配空间。 3. 归一化和预处理:对于输入图片,进行归一化和预处理,使其适合模型的输入。 4. 推理:在CPU上运行推理,得出检测结果并处理。 5. 结果可视化:将推理结果可视化,可以使用OpenCV等工具库来实现。 TensorRT部署yolov5 c可以让模型实现更快的推理速度,同时提供高效能的计算功能,进一步提高了模型在实际应用中的作用。使用TensorRT,可以有效缩短模型推理的时间,提高应用的实时性和响应速度。 ### 回答3: TensorRT是一种针对机器学习模型的高性能推理引擎,它可以通过优化、量化、融合等技术将模型的推理速度提升数十倍。在使用TensorRT部署yolov5 c时,可以按照以下步骤进行: 1. 准备环境:首先需要安装yolov5 c和TensorRT,并安装CMake辅助构建工具。同时还需要下载yolov5的配置文件和权重文件。 2. 将模型转换为TensorRT引擎:使用TensorRT提供的API,将训练好的yolov5 c模型转换为TensorRT引擎。这个过程主要包含以下几个步骤: (1)通过TensorRT提供的Builder API创建一个Builder对象,用于定义TensorRT引擎的配置。 (2)将yolov5 c模型加载进来,通过Parser API解析为TensorRT的网络描述对象。 (3)使用Builder对象定义TensorRT引擎,包括设置精度、批大小、推理模式等。 (4)转换为TensorRT引擎,生成对应的.engine文件,以便进行后续推理。 3. 进行推理:使用生成的TensorRT引擎文件,进行推理操作。这个过程主要包含以下几个步骤: (1)创建一个执行上下文,用于对输入数据进行处理和输出结果。 (2)将输入数据加载到TensorRT引擎中,通过execute API进行推理。 (3)获取输出结果,将其解析为目标检测的结果,包括物体类别、位置和置信度等。 4. 部署到目标设备:最后根据实际应用需要,将部署好的yolov5 c模型TensorRT引擎部署到目标设备上,进行实时目标检测。 总之,TensorRT部署yolov5 c可以较大的提高其推理性能,使得其在实际应用场景中更加高效、准确和实时。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值