【使用TensorRT自带的plugin】

2023-11-18

0. 背景

在之前的文章TensorRT的plugin实现中介绍了,如何从零实现一个TensorRT的plugin,这篇文章来介绍如何使用TensorRT自带的plugin,将其添加到Network Definition中加速我们的模型。

自TensorRT8.0之后,官方提供了大量的plugin,可用于常用目标分类,目标检测等算法的部署。

 本文章以batchedNMSPlugin举例,介绍如何向Network Definition中添加该plugin,并验证其性能。

1. batchedNMSPlugin介绍

上图为目标检测算法的常见推理过程,该plugin实现功能为最后一步去除冗余的检测框,保留最后的一个。

 本文不对NMS的具体实现过程做过多的赘述,主要介绍如何向Network中添加该plugin。

batchedNMSPlugin包含两个输入和四个输出。

两个输入:boxes input 和scores input.

boxes input: 此时输入的boxes信息是经过decode之后的,维度信息[batch_size, number_boxes, number_classes, number_box_parameters],

  • batch_size:批处理大小
  • number_boxes:bounding boxes的数量
  • number_classes:分类的类别数目
  • number_box_parameters:boxes的位置信息,通常由4个参数组成:[x1, y1, x2, y2]分别为左上和右下角点

Scores input: 维度信息[batch_size, number_boxes, number_classes],每一个box包含所有分类类别的置信度

四个输出:

  • num_detections: 维度信息[batch_size, 1],最后一维大小为1,类型为INT32,表示每一帧图像中有效的物体数
  • nums_boxes:维度信息[batch_size, keepTopK, 4] 类型为float32,包含经过NMS之后boxes的位置信息
  • numsed_scores:维度信息:[batch_size, keepTopK]类型为float32,表示boxes的得分信息
  • nmsed_classes:维度信息:[batch_size, keepTopK],类型为float32,表示boxes的类别信息

该plugin除了指定输入输出参数的信息之后,还提供了十余个可配置的参数。

 plugin需要知道的知识先介绍到这里,下面学习如何调用该plugin在Network中生成engine。

2. 调用plugin

下图为TensorRT的engine编译过程,其中最关键的是如何生成Network Definition,表示推理的网络结构。

 下面,我们基于plugin构建一个简单的Network,来展示如何调用plugin和验证性能。通过自定义合适的输入,推理,得到输出结果。

 其中上述Network Definition的具体实现代码如下:

    network = builder.create_network()    # 定义网络
    # 输入
    boxes = network.add_input('boxes', tensorrt.DataType.FLOAT, input_shape[0])
    scores = network.add_input('scores', tensorrt.DataType.FLOAT, input_shape[1])
    # 配置参数
    mPluginAttributes = list()
    topK = 6
    keepTok = 5
    iouThreshold = 0.7
    mPluginAttributes.append(trt.PluginField('shareLocation', np.array([1], dtype=np.int32), tensorrt.PluginFieldType.INT32))
    mPluginAttributes.append(trt.PluginField('backgroundLabelId', np.array([-1], dtype=np.int32), tensorrt.PluginFieldType.INT32))
    mPluginAttributes.append(trt.PluginField('numClasses', np.array([1], dtype=np.int32), tensorrt.PluginFieldType.INT32))
    mPluginAttributes.append(trt.PluginField('topK', np.array([topK], dtype=np.int32), tensorrt.PluginFieldType.INT32))
    mPluginAttributes.append(trt.PluginField('keepTopK', np.array([keepTok], dtype=np.int32), tensorrt.PluginFieldType.INT32))
    mPluginAttributes.append(trt.PluginField('scoreThreshold', np.array([0.3], dtype=np.float32), tensorrt.PluginFieldType.FLOAT32,))
    mPluginAttributes.append(trt.PluginField('iouThreshold', np.array([iouThreshold], dtype=np.float32), tensorrt.PluginFieldType.FLOAT32))
    mPluginAttributes.append(trt.PluginField('isNormalized', np.array([0], dtype=np.int32), tensorrt.PluginFieldType.INT32))
    mPluginAttributes.append(trt.PluginField('clipBoxes', np.array([0], dtype=np.int32), tensorrt.PluginFieldType.INT32))
    mPluginAttributes.append(trt.PluginField('scoreBits', np.array([4], dtype=np.int32), tensorrt.PluginFieldType.INT32))
    mPluginAttributes.append(trt.PluginField('caffeSemantics', np.array([0], dtype=np.int32), tensorrt.PluginFieldType.INT32))
    # 调用plugin
    layer = network.add_plugin_v2(
        [boxes, scores], 
        plugin_creator.create_plugin('BatchedNMS_TRT', tensorrt.PluginFieldCollection(mPluginAttributes))
    )
    # 获取输出
    num_detections = layer.get_output(0)
    num_detections.name = "num_detections"
    nmsed_boxes  = layer.get_output(1)
    nmsed_boxes.name = "nmsed_boxes"
    nmsed_scores  = layer.get_output(2)
    nmsed_scores.name = "nmsed_scores"
    nmsed_classes  = layer.get_output(3)
    nmsed_classes.name = "nmsed_classes"
    network.mark_output(num_detections)
    network.mark_output(nmsed_boxes)
    network.mark_output(nmsed_scores)
    network.mark_output(nmsed_classes)

上述代码,两个重要的点是,如何配置plugin对应的参数和调用plugin。参数配置可以参考源码实现中creator的构造函数在初始化参数的过程。

3. 验证plugin效果

NMS的python实现博客的python实现为对比,验证该plugin的效果。

import numpy as np
 
 
boxes=np.array([[100,100,210,210,0.72],
        [250,250,420,420,0.8],
        [220,220,320,330,0.92],
        [100,100,210,210,0.72],
        [230,240,325,330,0.81],
        [220,230,315,340,0.9]]) 
 
 
def py_cpu_nms(dets, thresh):
 
    x1 = dets[:,0]
    y1 = dets[:,1]
    x2 = dets[:,2]
    y2 = dets[:,3]
    areas = (y2-y1+1) * (x2-x1+1)
    scores = dets[:,4]
    keep = []
    index = scores.argsort()[::-1]
    while index.size >0:
        i = index[0]       # every time the first is the biggst, and add it directly
        keep.append(i)
 
 
        x11 = np.maximum(x1[i], x1[index[1:]])    # calculate the points of overlap 
        y11 = np.maximum(y1[i], y1[index[1:]])
        x22 = np.minimum(x2[i], x2[index[1:]])
        y22 = np.minimum(y2[i], y2[index[1:]])
        
 
        w = np.maximum(0, x22-x11+1)    # the weights of overlap
        h = np.maximum(0, y22-y11+1)    # the height of overlap
       
        overlaps = w*h
        ious = overlaps / (areas[i]+areas[index[1:]] - overlaps)
 
        idx = np.where(ious<=thresh)[0]
        index = index[idx+1]   # because index start from 1
 
    return keep
        
 
import matplotlib.pyplot as plt
def plot_bbox(dets, c='k'):
    x1 = dets[:,0]
    y1 = dets[:,1]
    x2 = dets[:,2]
    y2 = dets[:,3]
    
    plt.plot([x1,x2], [y1,y1], c)
    plt.plot([x1,x1], [y1,y2], c)
    plt.plot([x1,x2], [y2,y2], c)
    plt.plot([x2,x2], [y1,y2], c)
    plt.title(" nms")
 
    
plt.figure(1)
ax1 = plt.subplot(1,2,1)
ax2 = plt.subplot(1,2,2)
 
plt.sca(ax1)
plot_bbox(boxes,'k')   # before nms
 
keep = py_cpu_nms(boxes, thresh=0.7)
plt.sca(ax2)
plot_bbox(boxes[keep], 'r')# after nms

 通过运行如上的代码,我们可以得到下图

 同样通过如下的代码,在TensorRT的环境下推理也能得到同样的效果

    batch_size = 1
    num_boxes = 6       ###############
    boxes = np.array([100,100,210,210, 
                    250,250,420,420, 
                    220,220,320,330,
                    100,100,210,210,
                    230,240,325,330,
                    220,230,315,340],  dtype=np.float32).reshape(batch_size, num_boxes, 1, 4)        # shape:(batch_size, 3, 1, 4)
    scores = np.array([0.72, 0.8, 0.92, 0.72, 0.81, 0.9],  dtype=np.float32).reshape(batch_size, num_boxes, 1)       # shape: (batch_size, 3, 1)
    plt.figure(1)
    ax1 = plt.subplot(1,2,1)
    ax2 = plt.subplot(1,2,2)
    plt.sca(ax1)
    plot_bbox(boxes.reshape(num_boxes, 4),'k')   # before nms

    trt = TrtLite(build_engine, (boxes.shape[1:], scores.shape[1:]))
    # trt.print_info()

    d_buffers = trt.allocate_io_buffers(batch_size, True)
    # host -> device
    cuda.memcpy_htod(d_buffers[0], boxes)
    cuda.memcpy_htod(d_buffers[1], scores)
    trt.execute(d_buffers, batch_size)
    keepTok = 5         ##########
    num_detections = np.zeros((batch_size, 1), dtype=np.int32)
    nmsed_boxes  = np.zeros((batch_size, keepTok, 4), dtype=np.float32 )
    nmsed_scores  = np.zeros((batch_size, keepTok), dtype=np.float32 )
    nmsed_classes  = np.zeros((batch_size, keepTok), dtype=np.float32 )
    cuda.memcpy_dtoh(num_detections, d_buffers[2])
    cuda.memcpy_dtoh(nmsed_boxes, d_buffers[3])
    cuda.memcpy_dtoh(nmsed_scores, d_buffers[4])
    cuda.memcpy_dtoh(nmsed_classes, d_buffers[5])
    plt.sca(ax2)
    plot_bbox(nmsed_boxes[0][:num_detections[0][0]], 'r')# after nms

 通过上面的尝试,对于Yolo系列一个可行的方案是:网络前向传播得到三个不同尺度特征图的输出,然后链接一个YoloLayerPlugin来对检测框进行解码,最后链接batchedNMSPlugin去除冗余的检测框,这样生成的engine就可以实现“End-to-End"的部署且都是在GPU上完成应该可以加速网络的推理。

4. 有用的链接

NVIDIA/trt-samples-for-hackathon-cn: Simple samples for TensorRT programming (github.com)

NMS的python实现_a1103688841的博客-CSDN博客_nms python

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【使用TensorRT自带的plugin】 的相关文章

  • Conda常见命令总结

    以下是常见的conda命令列表 conda create 创建新的虚拟环境 安装指定的包 conda activate 激活虚拟环境 conda deactivate 停用当前虚拟环境 conda list 列出已安装的包 conda se

随机推荐

  • 能连蓝牙键盘吗_300多的小键盘,颜值很能打,GANSS ALT71蓝牙双模机械键盘很香...

    关于键盘配列 你是60 70 80 90 还是100 党 反正上述这些配列差不多我都集齐了 GANSS ALT71正好填补了70 的空缺 这次分享录制了视频 wifi足的可以看这个 更换封面 05 58 视频尚未发布 暂时无法播放 wifi
  • 启动hadoop时候报错:localhost: ssh: Could not resolve hostname localhost: Temporary failure in name resolut...

    这个错误是由于配置文件没有配置好 解决方案如下 1 打开profile文件 vim etc profile 2 在文件最后加入的内容应该如下 高亮的两句一般是大家缺少的 export JAVA HOME usr java jdk expor
  • EasyPoi导入Excel中的图片,空指针异常

    官方文档 1 1 介绍 Powered by MinDoc 导入easypoi依赖 版本可以选择最新的
  • element table显示滚动条

    1 tableX为要显示滚动条的类名 2 显示横向滚动条 3 tableX el table scrollable x el table body wrapper 4 padding 0 0 5px 0 5 margin 0 0 5px 0
  • 【最新】手把手教你在VMware中安装Ubuntu虚拟机

    手把手教你在Vmware中安装Ubuntu虚拟机 一 下载VMware和Ubuntu系统官方镜像 1 下载VMware 2 下载Ubuntu系统官方镜像 二 安装VMware和Ubuntu虚拟机 1 安装VMware 2 安装Ubuntu镜
  • 电源学习总结(二)——线性稳压主要特点及原理

    文章目录 主要特点 内部结构 常见的三端线性稳压 AMS1117 主要特点 线性稳压最为突出的优点主要有成本低 噪声低 体积小 由于线性稳压结构简单 生产相对容易 因此其生产成本可以很低 同时其需要的外围器件也很少 一般只需要在输入端和输出
  • 【Python】教你写一个一键上传git的脚本(打包成exe)

    本篇博客来教你用Python写一个简单的git自动上传脚本 前言 为什么需要一个这样的东西 有的时候 我的学习代码其实没啥好commit的 写一个自动上传的脚本 就可以自动执行完所有的命令 而不需要自己手动进行git三板斧操作 项目代码已开
  • unplugin-vue-components 源码原理分析

    unplugin vue components 是一款按需自动导入Vue组件的库 支持 Vue2 和 Vue3 同时支持组件和指令 使用此插件库后 不再需要手动导入组件 插件会自动识别按需导入组件以及对应样式 我们只需要像全局组件那样使用即
  • 【笔记】SemGCN

    一 论文总结 1 1 核心贡献 提出了一种改进的图卷积操作 称为语义图卷积 SemGConv 它源自cnn 其关键思想是学习图中暗示的边的信道权值 然后将它们与核矩阵结合起来 这大大提高了图卷积的能力 其次 我们引入了SemGCN 其中Se
  • Unity PlayerPrefs(数据持久化)

    PlayerPrefs Unity3D中的数据持久化是以键值的形式存储的 可以看作是一个字典 Unity3D中值是通过键名来读取的 当值不存在时 返回默认值 目前Unity3D中只支持int string float三种数据类型的读取 参考
  • android开发工具!Android性能优化常见问题,灵魂拷问

    前言 今年上半年其实就已经有了换工作的想法 奈何疫情原因和岗位缩减 加之信心不足 到六月底投递了百度的Android岗位 本以为像我这种非211 985没工作经验的渣渣只能被直接pass 结果却意外的收到了电话 真是受宠若惊 经过电面 技术
  • 51单片机入学第八课——8*8点阵屏

    文章目录 LED点阵屏 点阵屏电路图 74HC595芯片 串入并出 使用方法 编程 点亮一个点 显示汉字 PCtoLCD 2002 编写代码 总结 LED点阵屏 LED点阵屏和数码管工作都是是靠二极管发光 但工作原理与矩阵键盘有些类似 在后
  • springboot2.0整合logback日志(详细)

    一 近期自己的项目想要一个记录日志的功能 而springboot本身就内置了日志功能 然而想要输入想要的日志 并且输出到磁盘 然后按天归档 或者日志的切分什么的 自带的日志仅仅具有简单的功能 百度了一番 总结如下 适合大多数的应用场景 二
  • python线程池ThreadPoolExecutor使用

    假设我们必须多线程任务创建大量线程 由于线程太多 因此可能会有很多性能问题 这在计算上会是最昂贵的 一个主要问题可能是吞吐量受限 我们可以通过创建一个线程池来解决这个问题 一个线程池可以被定义为一组预先实例化和空闲的线程 它们随时可以开始工
  • 微信小程序请求库的封装方法

    1 文档地址 微信官方文档 wx request网络请求 2 项目使用 根目录下新建utils gt request js 作为请求通用库 接口地址 const DEV URL http localhost 22667 const PROD
  • 常用python程序

    压缩文件 import zipfile import os def zipDir dirpath outFullName 压缩指定文件夹 param dirpath 目标文件夹路径 param outFullName 压缩文件保存路径 xx
  • linux环境用opencv读取图片,基于Linux下OpenCV的人脸识别模块设计

    金笑雪 张琳琳 高丹 张黎 摘 要 近年来 图像识别技术正在向更加直观 可靠的方向发展 其中人脸识别技术具有极高的研究价值 应用得也最为广泛 通过对Linux系统下OpenCV的研究 利用OpenCv Python3 4设计出一个图像识别系
  • OpenWRT添加模块(一)Makefile和Config.in

    第一次接触到openwrt 真是被毁三观啊 不要说makefile 连源代码在哪里都找不到 知道嵌入式系统水深 没想到迈出第一步就没过了脖子 好在旁边有人指点 直接在芯片厂商提供的既有代码上做二次开发 项目进展倒也完全满足了前期计划的目标
  • Linux基础笔记

    第一章 一 网络配置 网络三要素 ip地址 子网掩码 255 255 255 0 网关 ifconfig 查看网络 hostname 查看本机名称 hostname 更改主机名 etc hosts 网络映射配置文件 etc sysconfi
  • 【使用TensorRT自带的plugin】

    0 背景 在之前的文章TensorRT的plugin实现中介绍了 如何从零实现一个TensorRT的plugin 这篇文章来介绍如何使用TensorRT自带的plugin 将其添加到Network Definition中加速我们的模型 自T