终于更新了,本篇是实现了SSD的tensorrt 推理【python版】。YOLOv4以及YOLOv5C++版的tensorrt推理可以看我之前的文章。

SSD代码我这里是在b站up主Bubbliiiing的pytorch版SSD的基础上进行的实现。


环境说明

windows10

cuda10.2

cudnn8.2.1

pytorch1.7

tensorrt8.2.5.1

python 3.7

显卡:NVIDIA 1650 4G(比较拉跨)

注:linux下我还没有试,可能有些代码需要改,而且trt的版本也会受影响


首先说一下网络输出部分我修改了哪些。

其实这部分不看也可以,可以直接跳过1,2,3节,直接从转onnx开始看

再转onnx之前需要修改一些地方,我们知道SSD有6个输出,代码中的输出output是包含了loc【位置】,conf【每个先验框对应类的置信度】,先验框数量。在代码中分train模式和test模式【这两个模式好像在后面的版本中进行了整合】。

train模式下的输出为:

output = (loc.view(loc.size(0), -1, 4),conf.view(conf.size(0), -1, self.num_classes),self.priors)

test模式下的输出为:

        if self.phase == "test":output = self.detect.forward(loc.view(loc.size(0), -1, 4),  # (batch_size, num_anchors,4) = (batch_size, num_anchors,(x,y,w,h))self.softmax(conf.view(conf.size(0), -1, self.num_classes)),  # (batch_size,num_anchors, num_classes)self.priors              )

因此我们首先要做的是修改一些输出,至于为什么要修改呢,是因为如果我导ONNX的时候进行检测的时候发现没有任何检测结果,分析内部数据的时候发现在num_classes以及对应的conf维度上无结果,因此当我以train模式导出onnx模式并在外面采用detect时发现是可以的。【反正就是我的个人经验得来的,大家用就可以了】

目录

1.修改ouputput

2.修改box解码

3.获得输出

4.转onnx[可以直接从这部分看]

5.ONNX推理

6.engine推理

7.FPS测试


1.修改ouputput

所以需要将output改为以下【在nets/ssd.py】:

        if self.phase == "test":output = self.detect.forward(loc.view(loc.size(0), -1, 4),  # (batch_size, num_anchors,4) = (batch_size, num_anchors,(x,y,w,h))self.softmax(conf.view(conf.size(0), -1, self.num_classes)),  # (batch_size,num_anchors, num_classes)self.priors              )else:# output = (#     loc.view(loc.size(0), -1, 4),#     conf.view(conf.size(0), -1, self.num_classes),#     self.priors# )loc = torch.tensor(loc.view(loc.size(0), -1, 4)),conf = torch.tensor(conf.view(conf.size(0), -1, self.num_classes)),self.priors = torch.tensor(self.priors)#return outputreturn loc, conf, self.priors

2.修改box解码

接下来再去nets/ssd_layers.py中的Dectect中的forward()中添加一行:

prior_data = prior_data.cpu()

也就是把先验框放在cpu上,不然在box解码的时候会出问题。

3.获得输出

然后在工程文件中的ssd.py中的检测部分添加下面的代码:

因为我们的输出现在有三个,所以要将其送入detect中【如果你是pytorch1.5以后版本要加上forward不然会报错】

            preds = self.net(photo)if self.onnx:loc = preds[0]conf = preds[1]priors = preds[2]preds = self.detect.forward(loc, nn.Softmax(dim=-1).forward(conf), priors)

4.转onnx

运行以下代码,仅需要修改torch权重路径即可以及类别:

python torch2onnx.py

torch转onnx模型我这里以及写好了,如果你是自己的数据集,需要修改num_classes,ckpt中torch的模型,output_namse和input_names是输出以及输入结点,因为有三个输出,所以是三个结点名字。最终导出的模型会保存在model_data文件下。

这里导出onnx有两个模式,你可以选择是否开启simplity,如果开启改功能可以更详细的看清楚每个卷积输出的尺寸大小,而且也会对onnx模型进行一定的优化。

import onnx
from nets.ssd import get_ssd
import torch
from utils.config import Config
from onnxsim import simplify
import numpy as npSimplity = Falseoutput_path = "model_data/ssd.onnx"
num_classes = 21
model = get_ssd('train', num_classes)
model_dict = model.state_dict()
device = torch.device('cuda')
ckpt = torch.load('./model_data/ssd_weights.pth',map_location=device)
ckpt = {k: v for k, v in ckpt.items() if np.shape(model_dict[k]) == np.shape(ckpt[k])}
model_dict.update(ckpt)
model.load_state_dict(model_dict)
model.eval()
model.to(device)
x = torch.zeros(1, 3, 300, 300).to(device)
output_names = ["output0","output1", "output2"]
input_names = ["images"]
torch.onnx.export(model, x, output_path, verbose=True, input_names=input_names,output_names=output_names, do_constant_folding=True, opset_version=12)
if Simplity:onnx_model = onnx.load(output_path)  # load onnx modelmodel_simp, check = simplify(onnx_model)assert check, "Simplified ONNX model could not be validated"onnx.save(model_simp, output_path)print('finished exporting onnx')

输出onnx部分图

5.ONNX推理

在推理前,你需要进入ssd.py中修改以下部分,将ONNX设置为True:

_defaults = {"model_path"    : 'model_data/ssd.onnx', # 权重路径"classes_path"  : 'model_data/voc_classes.txt',"confidence"    : 0.5,"nms_iou"       : 0.45,"cuda"          : True,
}
#---------------------------------------------------#
#   初始化SSD
#---------------------------------------------------#
def __init__(self, input_shape=None, ONNX=False, TRT=False, **kwargs):if input_shape is None:input_shape = [300, 300]  # 支持300和512大小self.input_shape = input_shapeself.onnx = ONNX  # 是否开启onnx推理self.engine = TRT  # 是否开启trt推理self.__dict__.update(self._defaults)self.class_names = self._get_class()self.generate()

注意:输入大小以及要和你onnx、engine输入大小一致!【我这里没做动态输入】

然后运行predict.py即可。

ONNX推理这部分代码是参考了YOLOV5中的方式,代码如下:

import torch
import torch.nn as nn
import numpy as npclass DetectMultiBackend(nn.Module):def __init__(self, weights, device=torch.device('cpu'), fp16=False):super(DetectMultiBackend, self).__init__()cuda = torch.cuda.is_available()if weights.split('.')[-1] == "onnx":import onnxruntimeproviders = ['CUDAExecutionProvider', 'CPUExecutionProvider'] if cuda else ['CPUExecutionProvider']session = onnxruntime.InferenceSession(weights, None)output_names = [x.name for x in session.get_outputs()]print("Output_names: ", output_names)meta = session.get_modelmeta().custom_metadata_map  # metadataself.__dict__.update(locals())def forward(self, im):global yif self.weights.split('.')[-1] == 'onnx':im = im.cpu().numpy()y = self.session.run(self.output_names, {self.session.get_inputs()[0].name: im})if isinstance(y, (list, tuple)):  # 多输出return self.from_numpy(y[0]) if len(y) == 1 else [self.from_numpy(x) for x in y]else:return self.from_numpy(y)def from_numpy(self, x):return torch.from_numpy(x).to(self.device) if isinstance(x, np.ndarray) else x

推理结果


6.engine推理

将ssd.py中的model_path路径设置为engine路径,如下:

_defaults = {"model_path"    : 'model_data/ssd.engine',"classes_path"  : 'model_data/voc_classes.txt',"confidence"    : 0.5,"nms_iou"       : 0.45,"cuda"          : True,
}

将TRT功能打开,设置为True,同时注意网络输入尺寸:

def __init__(self, input_shape=None, ONNX=False, TRT=True, **kwargs):if input_shape is None:input_shape = [300, 300]self.input_shape = input_shapeself.onnx = ONNXself.engine = TRTself.__dict__.update(self._defaults)self.class_names = self._get_class()self.generate()

运行predict.py,输入图像路径进行推理:

10/26/2022-17:38:05] [TRT] [I] [MemUsageChange] Init CUDA: CPU +421, GPU +0, now: CPU 5526, GPU 896 (MiB)
[10/26/2022-17:38:07] [TRT] [I] Loaded engine size: 131 MiB
[10/26/2022-17:38:09] [TRT] [I] [MemUsageChange] Init cuBLAS/cuBLASLt: CPU +326, GPU +70, now: CPU 5998, GPU 1097 (MiB)
[10/26/2022-17:38:10] [TRT] [I] [MemUsageChange] Init cuDNN: CPU +108, GPU +88, now: CPU 6106, GPU 1185 (MiB)
[10/26/2022-17:38:10] [TRT] [I] [MemUsageChange] TensorRT-managed allocation in engine deserialization: CPU +0, GPU +131, now: CPU 0, GPU 131 (MiB)
[10/26/2022-17:38:10] [TRT] [I] [MemUsageChange] Init cuBLAS/cuBLASLt: CPU +0, GPU +10, now: CPU 5983, GPU 1177 (MiB)
[10/26/2022-17:38:10] [TRT] [I] [MemUsageChange] Init cuDNN: CPU +0, GPU +8, now: CPU 5983, GPU 1185 (MiB)
[10/26/2022-17:38:10] [TRT] [I] [MemUsageChange] TensorRT-managed allocation in IExecutionContext creation: CPU +0, GPU +168, now: CPU 0, GPU 299 (MiB)
model_data/ssd.engine model, anchors, and classes loaded.
Input image filename:

如果是视频推理就运行video.py即可


7.FPS测试

如果是用torch模型进行测试,将FPS_test.py中的TORCH设置为True,然后在ssd.py中输入权重路径,然后运行FPS_test.py即可。

如果是用onnx或者engine模型进行测试,将FPS_test.py中的TORCH设置为False,然后在ssd.py中输入权重路径,然后运行FPS_test.py即可。

如果输入大小为300 * 300,在我的显卡上FPS如下,可以看到其实提升还是可以的,提升了十几帧:

NVIDIA 1650 4G
# engine:300*300 41FPS
# onnx:300*300 4FPS
# torch:300*300 28FPS

详细使用请看readme.md

代码:

https://github.com/YINYIPENG-EN/SSD_tensorRT_pytorch.git

权重:

链接:https://pan.baidu.com/s/1YAF_cruDG254ZZD5InPsbg 
提取码:yypn

SSD目标检测网络tensorRT推理【附代码】相关推荐

  1. 解析目标检测全流程!附代码数据

    ↑↑↑关注后"星标"Datawhale 每日干货 & 每月组队学习,不错过 Datawhale干货 作者:王程伟,算法工程师,Datawhale成员 在计算机视觉中,红外弱 ...

  2. 神经网络: SSD目标检测网络解析

    一.SSD(Single Shot MultiBox Detector)简介 SSD是2016年ICCV的一篇论文,是目前为止主要的目标检测算法. 算法的主要优点: 速度比Faster-Rcnn快,精 ...

  3. yolov3网络结构图_目标检测——YOLO V3简介及代码注释(附github代码——已跑通)...

    GitHub: liuyuemaicha/PyTorch-YOLOv3​github.com 注:该代码fork自eriklindernoren/PyTorch-YOLOv3,该代码相比master分 ...

  4. 丢弃Transformer!旷视和西安交大提出基于FCN的端到端目标检测网络

    点击上方,选择星标或置顶,不定期资源大放送! 阅读大概需要15分钟 Follow小博主,每天更新前沿干货 本文作者:王剑锋  | 编辑:Amusi https://zhuanlan.zhihu.com ...

  5. retinanet 部署_RetinaNet: Focal loss在目标检测网络中的应用

    介绍 RetinaNet是2018年Facebook AI团队在目标检测领域新的贡献.它的重要作者名单中Ross Girshick与Kaiming He赫然在列.来自Microsoft的Sun Jia ...

  6. MobileViT: 一种更小,更快,高精度的轻量级Transformer端侧网络架构(附代码实现)...

    点击上方,选择星标或置顶,不定期资源大放送! 阅读大概需要5分钟 Follow小博主,每天更新前沿干货 [导读]之前详细介绍了轻量级网络架构的开源项目,详情请看深度学习中的轻量级网络架构总结与代码实现 ...

  7. Pytorch搭建SSD目标检测平台

    学习前言 什么是SSD目标检测算法 源码下载 SSD实现思路 一.预测部分 1.主干网络介绍 2.从特征获取预测结果 3.预测结果的解码 4.在原图上进行绘制 二.训练部分 1.真实框的处理 2.利用 ...

  8. 计算机视觉算法——目标检测网络总结

    计算机视觉算法--目标检测网络总结 计算机视觉算法--目标检测网络总结 1. RCNN系列 1.1 RCNN 1.1.1 关键知识点--网络结构及特点 1.1.2 关键知识点--RCNN存在的问题 1 ...

  9. 收藏 | 如何定义目标检测网络的正负例:Anchor-based

    点上方计算机视觉联盟获取更多干货 仅作学术分享,不代表本公众号立场,侵权联系删除 转载于:作者:知乎-Lighthouse 地址:https://www.zhihu.com/org/lighthous ...

  10. 《基于海思35xx nnie引擎进行经典目标检测算法模型推理》视频课程介绍

    前言 沉寂两个月,终于将新的视频课程<<基于海思35xx nnie引擎进行经典目标检测算法模型推理>>(其链接为https://edu.csdn.net/course/deta ...

最新文章

  1. Linux基础知识——常用shell命令介绍(一)
  2. deepin 远程linux,在Deepin Linux操作系统中如何连接Microsoft OneDrive
  3. Java入门教程五(数字和日期处理)
  4. SQLite Select 语句(http://www.w3cschool.cc/sqlite/sqlite-select.html)
  5. 【公开课预告】:多媒体开源PI
  6. 冒泡排序 C++实现
  7. 微博:冬奥期间累计共清理相关违规内容近31万条
  8. 二叉树的迭代遍历(JavaScript)
  9. 第 45 届国际大学生程序设计竞赛(ICPC)亚洲区域赛(南京)签到题E Evil Coordinate
  10. Oracle记录表删除操作简单方法
  11. 2001年李彦宏DoNews三篇搜索引擎Blog
  12. 2015InfoQ软件大会技术记录
  13. MySQL基础 - 带搜索条件的查询
  14. Tableau常用可视化图形介绍及其适用场景
  15. 小知识 - 恢复chmod执行权限
  16. Cousera-Introduction to Data Science in Python Assignment1-4答案
  17. 30行代码实现微信朋友圈自动点赞
  18. Windows 上使用 batch批处理获取时间并更改时间格式
  19. 12个乒乓球称重问题
  20. KNN和Kmeans

热门文章

  1. 南山驿站机器人_fc机器人大战钢铁之魂攻略
  2. Cooley-Tukey算法 (蝶形算法)
  3. 高中计算机基础知识课件,高中信息技术基础教案
  4. 瑞星linux病毒库位置,瑞星杀毒软件V16+怎样离线升级病毒库 病毒库离线升级办法...
  5. win10怎么手动修改自己的IP地址
  6. 软件技巧:优蛋开启出现Failed to set data for错误
  7. MySQL安装配置教程(超级详细、保姆级)
  8. 图文并茂教你如何用PLC控制伺服电机!
  9. 卷积神经网络原理简述
  10. 机械制图中有关螺纹的命名及标注