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

简介: 笔记

终于更新了,本篇是实现了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


所以需要将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 output
        return 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 np
Simplity = False
output_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 model
    model_simp, check = simplify(onnx_model)
    assert check, "Simplified ONNX model could not be validated"
    onnx.save(model_simp, output_path)
    print('finished exporting onnx')

10.png

输出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_shape
    self.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 np
class 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 onnxruntime
            providers = ['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  # metadata
        self.__dict__.update(locals())
    def forward(self, im):
        global y
        if 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


推理结果

11.jpeg

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_shape
    self.onnx = ONNX
    self.engine = TRT
    self.__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:


12.jpeg

如果是视频推理就运行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


相关实践学习
部署Stable Diffusion玩转AI绘画(GPU云服务器)
本实验通过在ECS上从零开始部署Stable Diffusion来进行AI绘画创作,开启AIGC盲盒。
目录
相关文章
|
1月前
|
机器学习/深度学习 PyTorch 算法框架/工具
目标检测实战(一):CIFAR10结合神经网络加载、训练、测试完整步骤
这篇文章介绍了如何使用PyTorch框架,结合CIFAR-10数据集,通过定义神经网络、损失函数和优化器,进行模型的训练和测试。
80 2
目标检测实战(一):CIFAR10结合神经网络加载、训练、测试完整步骤
|
1月前
|
机器学习/深度学习 数据可视化 计算机视觉
目标检测笔记(五):详细介绍并实现可视化深度学习中每层特征层的网络训练情况
这篇文章详细介绍了如何通过可视化深度学习中每层特征层来理解网络的内部运作,并使用ResNet系列网络作为例子,展示了如何在训练过程中加入代码来绘制和保存特征图。
55 1
目标检测笔记(五):详细介绍并实现可视化深度学习中每层特征层的网络训练情况
|
15天前
|
机器学习/深度学习 计算机视觉 网络架构
【YOLO11改进 - C3k2融合】C3k2DWRSeg二次创新C3k2_DWR:扩张式残差分割网络,提高特征提取效率和多尺度信息获取能力,助力小目标检测
【YOLO11改进 - C3k2融合】C3k2DWRSeg二次创新C3k2_DWR:扩张式残差分割网络,提高特征提取效率和多尺度信息获取能力,助力小目DWRSeg是一种高效的实时语义分割网络,通过将多尺度特征提取分为区域残差化和语义残差化两步,提高了特征提取效率。它引入了Dilation-wise Residual (DWR) 和 Simple Inverted Residual (SIR) 模块,优化了不同网络阶段的感受野。在Cityscapes和CamVid数据集上的实验表明,DWRSeg在准确性和推理速度之间取得了最佳平衡,达到了72.7%的mIoU,每秒319.5帧。代码和模型已公开。
【YOLO11改进 - C3k2融合】C3k2DWRSeg二次创新C3k2_DWR:扩张式残差分割网络,提高特征提取效率和多尺度信息获取能力,助力小目标检测
|
1月前
|
机器学习/深度学习 网络架构 计算机视觉
目标检测笔记(一):不同模型的网络架构介绍和代码
这篇文章介绍了ShuffleNetV2网络架构及其代码实现,包括模型结构、代码细节和不同版本的模型。ShuffleNetV2是一个高效的卷积神经网络,适用于深度学习中的目标检测任务。
67 1
目标检测笔记(一):不同模型的网络架构介绍和代码
|
4月前
|
编解码 Go 文件存储
【YOLOv8改进 - 特征融合NECK】 DAMO-YOLO之RepGFPN :实时目标检测的创新型特征金字塔网络
【YOLOv8改进 - 特征融合NECK】 DAMO-YOLO之RepGFPN :实时目标检测的创新型特征金字塔网络
|
15天前
|
机器学习/深度学习 计算机视觉 网络架构
【YOLO11改进 - C3k2融合】C3k2融合DWRSeg二次创新C3k2_DWRSeg:扩张式残差分割网络,提高特征提取效率和多尺度信息获取能力,助力小目标检测
【YOLO11改进 - C3k2融合】C3k2融合DWRSDWRSeg是一种高效的实时语义分割网络,通过将多尺度特征提取方法分解为区域残差化和语义残差化两步,提高了多尺度信息获取的效率。网络设计了Dilation-wise Residual (DWR) 和 Simple Inverted Residual (SIR) 模块,分别用于高阶段和低阶段,以充分利用不同感受野的特征图。实验结果表明,DWRSeg在Cityscapes和CamVid数据集上表现出色,以每秒319.5帧的速度在NVIDIA GeForce GTX 1080 Ti上达到72.7%的mIoU,超越了现有方法。代码和模型已公开。
|
2月前
|
机器学习/深度学习 监控 并行计算
深度学习之生物网络推理
基于深度学习的生物网络推理利用深度学习技术来解析和理解生物网络(如基因调控网络、代谢网络、蛋白质-蛋白质相互作用网络等)的复杂关系和动态行为。
48 5
|
6月前
|
机器学习/深度学习 算法 计算机视觉
[YOLOv8/YOLOv7/YOLOv5系列算法改进NO.5]改进特征融合网络PANET为BIFPN(更新添加小目标检测层yaml)
本文介绍了改进YOLOv5以解决处理复杂背景时可能出现的错漏检问题。
264 5
|
4月前
|
计算机视觉 网络架构
【YOLOv8改进 - 卷积Conv】DWRSeg:扩张式残差分割网络,提高特征提取效率和多尺度信息获取能力,助力小目标检测
YOLO目标检测专栏探讨了YOLO的创新改进,如多尺度特征提取的DWRSeg网络。该网络通过区域残差化和语义残差化提升效率,使用DWR和SIR模块优化高层和低层特征。DWRSeg在Cityscapes和CamVid数据集上表现优秀,速度与准确性兼备。论文和代码已公开。核心代码展示了一个包含DWR模块的卷积层。更多配置详情见相关链接。
|
5月前
|
机器学习/深度学习 算法 计算机视觉
没有公式,不要代码,让你理解 RCNN:目标检测中的区域卷积神经网络
没有公式,不要代码,让你理解 RCNN:目标检测中的区域卷积神经网络
99 0
没有公式,不要代码,让你理解 RCNN:目标检测中的区域卷积神经网络

热门文章

最新文章