TensorRT加速推理入门-1:Pytorch转ONNX
这篇文章,用于记录将TransReID的pytorch模型转换为onnx的学习过程,期间参考和学习了许多大佬编写的博客,在参考文章这一章节中都已列出,非常感谢。
1. 在pytorch下使用ONNX主要步骤
1.1. 环境准备
安装onnxruntime包
安装教程可参考:
onnx模型预测环境安装笔记
onnxruntime配置
CPU版本:
直接pip安装
pip install onnxruntime
GPU版本:
先查看自己CUDA版本然后在下面的链接去找对应的onnxruntime的版本
CUDA版本的查询,可参考这个
onnxruntime版本查询
查询到对应版本,直接pip安装即可,例如
pip install onnxruntime-gpu==1.13.1
安装onnxsim包
pip install onnx-simplifier
1.2. 搭建 PyTorch 模型(TransReID)
def get_net(model_path,opt_=False):if opt_:cfg.merge_from_file("/home/TransReID-main/configs/OCC_Duke/vit_transreid_stride.yml")#cfg.freeze()train_loader, train_loader_normal, val_loader, num_query, num_classes, camera_num, view_num = make_dataloader(cfg)net = make_model(cfg, num_class=num_classes, camera_num=camera_num, view_num = view_num)else:cfg.merge_from_file("/home/TransReID-main/configs/OCC_Duke/vit_transreid_stride.yml")train_loader, train_loader_normal, val_loader, num_query, num_classes, camera_num, view_num = make_dataloader(cfg)net = make_model(cfg, num_class=num_classes, camera_num=camera_num, view_num = view_num)#state_dict = torch.load(model_path, map_location=torch.device('cpu'))['state_dict']state_dict = torch.load(model_path, map_location=torch.device('cpu'))model_state_dict=net.state_dict()for key in list(state_dict.keys()):if key[7:] in model_state_dict.keys():model_state_dict[key[7:]]=state_dict[key]net.load_state_dict(model_state_dict)return net
1.3. pytorch模型转换为 ONNX 模型
这个提供了静态转换(静态转换支持静态输入)和动态转换(动态转换支持动态输入)两个函数,可根据需要选择。
def convert_onnx_dynamic(model,save_path,simp=False):x = torch.randn(4, 3, 256,128)input_name = 'input'output_name = 'class'torch.onnx.export(model,x,save_path,input_names = [input_name],output_names = [output_name],dynamic_axes= {input_name: {0: 'B'},output_name: {0: 'B'}})if simp:onnx_model = onnx.load(save_path) model_simp, check = simplify(onnx_model,input_shapes={'input':(4,3,256,128)},dynamic_input_shape=True)assert check, "Simplified ONNX model could not be validated"onnx.save(model_simp, save_path)print('simplify onnx done')def convert_onnx(model,save_path,batch=1,simp=False):input_names = ['input']output_names=['class']x = torch.randn(batch, 3, 256, 128)for para in model.parameters():para.requires_grad = False# model_script = torch.jit.script(model)# model_trace = torch.jit.trace(model, x)torch.onnx.export(model, x, save_path,input_names =input_names,output_names=output_names, opset_version=12)if simp:onnx_model = onnx.load(save_path) model_simp, check = simplify(onnx_model)assert check, "Simplified ONNX model could not be validated"onnx.save(model_simp, save_path)print('simplify onnx done')
pytorch 转 onnx 仅仅需要一个函数 torch.onnx.export
,来看看该函数的参数和用法。
torch.onnx.export(model, args, path, export_params, verbose, input_names, output_names, do_constant_folding, dynamic_axes, opset_version)
参数 | 用法 |
---|---|
model | 需要导出的pytorch模型 |
args | 模型的任意一组输入(模拟实际输入数据的大小,比如三通道的512*512大小的图片,就可以设置为torch.randn(1, 3 , 512, 512) |
path | 输出的onnx模型的位置,例如yolov5.onnx |
export_params | 输出模型是否可训练。default=True,表示导出trained model, 否则untrained。 |
verbose | 是否打印模型转换信息,default=None |
opset_version | onnx算子集的版本 |
input_names | 模型的输入节点名称(自己定义的),如果不写,默认输出数字类型 的名称 |
output_name | 模型的输出节点名称(自己定义的), 如果不写,默认输出数字类型的名称 |
do_constant_folding | 是否使用常量折叠,默认即可。default=True。 |
dynamic_axes | 设置动态输入输出,用法:“输入输出名:[支持动态的维度”,如"支持动态的维度设置为[0, 2, 3]"则表示第0维,第2维,第3维支持动态输入输出。 |
模型的输入输出有时是可变的,如rnn,或者输出图像的batch可变,可通过该参数设置。如输入层的shape为(b, 3, h, w), 其中batch、height、width是可变的,但是chancel是固定三通道。 | 格式如下:1)仅list(int)dynamic_axes={‘input’:[0, 2, 3], ‘output’:{0:‘batch’, 1:‘c’}} 2)仅dict<int, string> dynamic_axes={‘input’:{‘input’:{0:‘batch’, 2:‘height’, 3:‘width’}, ‘output’:{0:‘batch’, 1:‘c’}} 3)mixed dynamic_axes={‘input’:{0:‘batch’, 2:‘height’, 3:‘width’}, ‘output’:[0,1]} |
注意onnx不支持结构中带有if语句的模型,如:
当我们在网络中嵌入一些if选择性的语句时,不好意思,模型不会考虑这些, 它只会记录下运行时走过的节点,不会根据if的实际情况来选择走哪条路, 所以势必会丢弃一部分节点,而丢弃哪些则是根据我们转模型时的输入来定的,一旦指定了,后面运行onnx模型都会如此。另一个问题就是,我们在代码中有一些循环或者迭代的操作时,要注意,尤其是我们的迭代次数是根据输入不同 会有变化时,也会因为这些操作导致后面的推理出现意外错误,正像前面说的,模型转换不喜欢不确定的东西,它会把这些变量dump成常量,所以会导致推理 错误。
对于实际部署的需求,很多时候pytorch是不满足的,所以需要转成其他模型格式来加快推理。常用的就是onnx,onnx天然支持很多框架模型的转换,如Pytorch,tf,darknet,caffe等。而pytorch也给我们提供了对应的接口,就是torch.onnx.export。下面具体到每一步。
原文来自:Windows下使用ONNX+pytorch记录
首先,环境和依赖:onnx包,cuda和cudnn,我用的版本号分别是1.7.0, 10.1, 7.5.4。
我们需要提供一个pytorch的模型,然后调用torch.onnx.export,同时还需要提供另外一些参数。我们一个个来分析,一是我们要给一个dummy input, 就是随便指定一个和我们实际输入时尺寸相同的一个随机数,是Tensor类型的,然后我们要指定转换的device,即是在gpu还是cpu。 然后我们要给一个input_names和output_names,这是绑定输入和输出,当然输入和输出可能不止一个,那就根据实际的输入和输出个数来给出name列表,
如果我们指定的输入和输出名和实际的网络结构不一致的话,onnx会自动给我们设置一个名字。一般是数字字符串。
输入和输出的绑定之后,我我们们可以看到还有一个参数叫做dynamic_axes,这是做什么的呢?哦,这是指定动态输入的,为了满足我们实际推理过程中,可能每张图片的分辨率不一样,所以允许我们给每个维度设置动态输入,这样是不是灵活多了?然后,设置完这些参数和输入,我们就可以开始转换模型了,如果不报错就是成功了,会在当前目录下生成一个.onnx文件。
原文来自: 一文掌握Pytorch-onnx-tensorrt模型转换
1.4 onnx-simplifier简化onnx模型
model_simp, check = simplify(onnx_model,input_shapes={'input':(4,3,256,128)},dynamic_input_shape=True)
Pytorch转换为ONNX的完整代码:pytorch_to_onnx.py
import json
import os
import onnx
import torch
import argparse
import torch.nn as nn
from onnxsim import simplify
from collections import OrderedDict
import torch.nn.functional as F# TransReID的模型构建需要的包
from model.make_model import *
from config import cfg
from datasets import make_dataloader os.environ['CUDA_VISIBLE_DEVICES'] = '1'def convert_onnx_dynamic(model,save_path,simp=False):x = torch.randn(4, 3, 256,128)input_name = 'input'output_name = 'class'torch.onnx.export(model,x,save_path,input_names = [input_name],output_names = [output_name],dynamic_axes= {input_name: {0: 'B'},output_name: {0: 'B'}})if simp:onnx_model = onnx.load(save_path) model_simp, check = simplify(onnx_model,input_shapes={'input':(4,3,256,128)},dynamic_input_shape=True)assert check, "Simplified ONNX model could not be validated"onnx.save(model_simp, save_path)print('simplify onnx done')def convert_onnx(model,save_path,batch=1,simp=False):input_names = ['input']output_names=['class']x = torch.randn(batch, 3, 256, 128)for para in model.parameters():para.requires_grad = False# model_script = torch.jit.script(model)# model_trace = torch.jit.trace(model, x)torch.onnx.export(model, x, save_path,input_names =input_names,output_names=output_names, opset_version=12)if simp:onnx_model = onnx.load(save_path) model_simp, check = simplify(onnx_model)assert check, "Simplified ONNX model could not be validated"onnx.save(model_simp, save_path)print('simplify onnx done')def get_net(model_path,opt_=False):if opt_:cfg.merge_from_file("/home/TransReID-main/configs/OCC_Duke/vit_transreid_stride.yml")#cfg.freeze()train_loader, train_loader_normal, val_loader, num_query, num_classes, camera_num, view_num = make_dataloader(cfg)net = make_model(cfg, num_class=num_classes, camera_num=camera_num, view_num = view_num)else:cfg.merge_from_file("/home/TransReID-main/configs/OCC_Duke/vit_transreid_stride.yml")train_loader, train_loader_normal, val_loader, num_query, num_classes, camera_num, view_num = make_dataloader(cfg)net = make_model(cfg, num_class=num_classes, camera_num=camera_num, view_num = view_num)#state_dict = torch.load(model_path, map_location=torch.device('cpu'))['state_dict']state_dict = torch.load(model_path, map_location=torch.device('cpu'))model_state_dict=net.state_dict()for key in list(state_dict.keys()):if key[7:] in model_state_dict.keys():model_state_dict[key[7:]]=state_dict[key]net.load_state_dict(model_state_dict)return netif __name__=="__main__":parser = argparse.ArgumentParser(description='torch to onnx describe.')parser.add_argument("--model_path",type = str,default="/home/TransReID-main/weights/vit_transreid_occ_duke.pth",help="torch weight path, default is MobileViT_Pytorch/weights-file/model_best.pth.tar.")parser.add_argument("--save_path",type=str,default="/home/TransReID-main/weights/vit_transreid_occ_duke_v2.onnx",help="save direction of onnx models,default is ./target/MobileViT.onnx.")parser.add_argument("--batch",type=int,default=1,help="batchsize of onnx models, default is 1.")parser.add_argument("--opt",default=False, action='store_true',help="model optmization , default is False.")parser.add_argument("--dynamic",default=False, action='store_true',help="export dynamic onnx model , default is False.")args = parser.parse_args()
# print(args)#net = get_net(args.model_path,opt_=args.opt)net = get_net(args.model_path)if args.dynamic:convert_onnx_dynamic(net,args.save_path,simp=True)else:with torch.no_grad():convert_onnx(net,args.save_path,simp=True,batch=args.batch)
1.5 查看onnx模型
当将pytorch模型保存为 ONNX 之后,可以使用一款名为 Netron 的软件打开 .onnx 文件,查看模型结构。
2. 参考文章
[1] Windows下使用ONNX+pytorch记录
[2] pytorch-onnx-tensorrt全链路简单教程(支持动态输入)
[3] PyTorch语义分割模型转ONNX以及对比转换后的效果(PyTorch2ONNX、Torch2ONNX、pth2onnx、pt2onnx、修改名称、转换、测试、加载ONNX、运行ONNX)
[4] ONNX系列一:ONNX的使用,从转化到推理
相关文章:
TensorRT加速推理入门-1:Pytorch转ONNX
这篇文章,用于记录将TransReID的pytorch模型转换为onnx的学习过程,期间参考和学习了许多大佬编写的博客,在参考文章这一章节中都已列出,非常感谢。 1. 在pytorch下使用ONNX主要步骤 1.1. 环境准备 安装onnxruntime包 安装教程可…...
springboot常用扩展点
当涉及到Spring Boot的扩展和自定义时,Spring Boot提供了一些扩展点,使开发人员可以根据自己的需求轻松地扩展和定制Spring Boot的行为。本篇博客将介绍几个常用的Spring Boot扩展点,并提供相应的代码示例。 1. 自定义Starter(面试常问) Sp…...
19道ElasticSearch面试题(很全)
点击下载《19道ElasticSearch面试题(很全)》 1. elasticsearch的一些调优手段 1、设计阶段调优 (1)根据业务增量需求,采取基于日期模板创建索引,通过 roll over API 滚动索引; (…...
向爬虫而生---Redis 拓宽篇3 <GEO模块>
前言: 继上一章: 向爬虫而生---Redis 拓宽篇2 <Pub/Sub发布订阅>-CSDN博客 这一章的用处其实不是特别大,主要是针对一些地图和距离业务的;就是Redis的GEO模块。 GEO模块是Redis提供的一种高效的地理位置数据管理方案,它允许我们存储和查询…...
Vue项目里实现json对象转formData数据
平常调用后端接口传参都是json对象,当提交表单遇到有附件需要传递时,通常是把附件上传单独做个接口,也有遇到后端让提交接口一并把附件传递到后端,这种情况需要把参数转成formData的数据,需要用到new FormData()。json…...
leetcode刷题记录
栈 2696. 删除子串后的字符串最小长度 哈希表 1. 两数之和 用map来保存每个数和他的索引 383. 赎金信 用map来存储字符的个数 链表 2. 两数相加 指针的移动 动态规划 53. 最大子数组和 2707. 字符串中的额外字符 递归 101. 对称二叉树 数学 1276. 不浪费原料的汉堡…...
SpringMVC通用后台管理系统源码
整体的SSM后台管理框架功能已经初具雏形,前端界面风格采用了结构简单、 性能优良、页面美观大的Layui页面展示框架 数据库支持了SQLserver,只需修改配置文件即可实现数据库之间的转换。 系统工具中加入了定时任务管理和cron生成器,轻松实现系统调度问…...
深度解析Dubbo的基本应用与高级应用:负载均衡、服务超时、集群容错、服务降级、本地存根、本地伪装、参数回调等关键技术详解
负载均衡 官网地址: http://dubbo.apache.org/zh/docs/v2.7/user/examples/loadbalance/ 如果在消费端和服务端都配置了负载均衡策略, 以消费端为准。 这其中比较难理解的就是最少活跃调用数是如何进行统计的? 讲道理, 最少活跃数…...
备战2024美赛数学建模,文末获取历史优秀论文
总说(历年美赛优秀论文可获取) 数模的题型千变万化,我今天想讲的主要是一些「画图」、「建模」、「写作」和「论文结构」的思路,这些往往是美赛阅卷官最看重的点,突破了这些点,才能真正让你的美赛论文更上…...
Java加密解密大全(MD5、RSA)
目录 一、MD5加密二、RSA加解密(公加私解,私加公解)三、RSA私钥加密四、RSA私钥加密PKCS1Padding模式 一、MD5加密 密文形式:5eb63bbbe01eeed093cb22bb8f5acdc3 import java.math.BigInteger; import java.security.MessageDigest; import java.security…...
C语言程序设计考试掌握这些题妥妥拿绩点(写给即将C语言考试的小猿猴们)
目录 开篇说两句1. 水仙花数题目描述分析代码示例 2. 斐波那契数列题目描述分析代码示例 3. 猴子吃桃问题题目描述分析代码示例 4. 物体自由落地题目描述分析代码示例 5. 矩阵对角线元素之和题目描述分析代码示例 6. 求素数题目描述分析代码示例 7. 最大公约数和最小公倍数题目…...
编译ZLMediaKit(win10+msvc2019_x64)
前言 因工作需要,需要ZLMediaKit,为方便抓包分析,最好在windows系统上测试,但使用自己编译的第三方库一直出问题,无法编译通过。本文档记录下win10上的编译过程,供有需要的小伙伴使用 一、需要安装的软件…...
JS-基础语法(一)
JavaScript简单介绍 变量 常量 数据类型 类型转换 案例 1.JavaScript简单介绍 JavaScript 是什么? 是一种运行在客户端(浏览器)的编程语言,可以实现人机交互效果。 JS的作用 JavaScript的组成 JSECMAScript( 基础语法 )…...
18款Visual Studio实用插件(更新)
前言 俗话说的好工欲善其事必先利其器,安装一些Visual Studio实用插件对自己日常的开发和工作效率能够大大的提升,避免996从选一款好的IDE实用插件开始。以下是我认为比较实用的Visual Studio插件希望对大家有用,大家有更好的插件推荐可在文…...
三、java线性表(顺序表、链表、栈、队列)
java线性表 三、线性表1.1 顺序表1.2 链表1.2.1 单向链表(Singly Linked List)1.2.2 双向链表(Doubly Linked List) 1.3 LinkedList VS ArrayList1.3.7 使用 LinkedList 的场景 1.4 栈1.5 队列 三、线性表 线性表是一种经典的数据…...
PiflowX-MysqlCdc组件
MysqlCdc组件 组件说明 MySQL CDC连接器允许从MySQL数据库读取快照数据和增量数据。 计算引擎 flink 组件分组 cdc 端口 Inport:默认端口 outport:默认端口 组件属性 名称展示名称默认值允许值是否必填描述例子hostnameHostname“”无是MySQL…...
2023春季李宏毅机器学习笔记 03 :机器如何生成文句
资料 课程主页:https://speech.ee.ntu.edu.tw/~hylee/ml/2023-spring.phpGithub:https://github.com/Fafa-DL/Lhy_Machine_LearningB站课程:https://space.bilibili.com/253734135/channel/collectiondetail?sid2014800 一、大语言模型的两种…...
dplayer播放hls格式视频并自动开始播放
监控视频流为hls格式,需要打开或刷新页面自动开始播放,需要安装dplayer和hls.js插件,插件直接npm装就行,上代码 import DPlayer from dplayer import Hls from hls.js //jquery是用来注册点击事件,实现自动开始播放 i…...
使用Vivado Design Suite平台板、将IP目录与平台板流一起使用
使用Vivado Design Suite平台板流 Vivado设计套件允许您使用AMD目标设计平台板(TDP)创建项目,或者已经添加到板库的用户指定板。当您选择特定板,Vivado设计工具显示有关板的信息,并启用其他设计器作为IP定制的一部分以…...
PACS医学影像报告管理系统源码带CT三维后处理技术
PACS从各种医学影像检查设备中获取、存储、处理影像数据,传输到体检信息系统中,生成图文并茂的体检报告,满足体检中心高水准、高效率影像处理的需要。 自主知识产权:拥有完整知识产权,能够同其他模块无缝对接 国际标准…...
介绍几种常见的质数筛选法
质数筛选法 1.暴力筛选法 :smirk:2.普通优化 :rofl:3.埃氏筛法:cold_sweat:4.线性筛选法:scream: 质数:除了1和他本身没有其它因数的正整数就是质数。1不是质数,2是质数。 1.暴力筛选法 😏 原理 求x的质数,令y从2到 x \sqrt[]{x…...
Qt/QML编程学习之心得:Linux下读写GPIO(23)
在linux嵌入式系统中,经常需要一些底层操作,Linux就如window一样,也对底层BSP进行了封装,对device driver进行了封装,使用的话基本就是文件读写的方式来读取,所以也大大简化了上层应用对底层硬件的访问难度。 比如要对GPIO口进行访问,在Qt中有几种方法: 使用命令行方…...
Unity中URP下深度图的线性转化
文章目录 前言一、_ZBufferParams参数有两组值二、LinearEyeDepth1、使用2、Unity源码推导:3、使用矩阵推导: 三、Linear01Depth1、使用2、Unity源码推导3、数学推导: 前言 在之前的文章中,我们实现了对深度图的使用。因为&#…...
Low Poly Cartoon House Interiors
400个独特的低多边形预制件的集合,可以轻松创建高质量的室内场景。所有模型都已准备好放入场景中,并使用一个纹理创建,以提高性能!包含演示场景! 模型分类: - 墙壁(79件) - 地板(28块) - 浴室(33个) - 厨房(36件) - 厨房道具(68件) - 房间道具(85件) - 灯具(…...
[算法与数据结构][c++]:左值、右值、左值引用、右值引用和std::move()
左值、右值、左值引用、右值引用和std::move 1. 什么是左值、右值2. 什么是左值引用、右值引用3. **右值引用和std::move的应用场景**3.1 实现移动语义3.2 **实例:vector::push_back使用std::move提高性能** **4. 完美转发 std::forward**5. Reference 写在前面&…...
【QT】day3
1.登陆界面 2.登陆失败 3.登陆成功弹窗 4.点击OK后跳转 #include "mainwindow.h" #include "ui_mainwindow.h"MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow) {ui->setupUi(this); }MainWindow::~MainWindow…...
c++ fork, execl 参数 logcat | grep
Linux进程编程(PS: exec族函数、system、popen函数)_linux popen函数会新建进程吗-CSDN博客 execvp函数详解_如何在C / C 中使用execvp()函数-CSDN博客 C语言的多进程fork()、函数exec*()、system()与popen()函数_c语言 多进程-CSDN博客 Linux---fork…...
QT:单例
单例的定义 官方定义:单例是指确保一个类在任何情况下都绝对只有一个实例,并提供一个全局访问点。 单例的写法 抓住3点: 构造函数私有化(确保只有一个实例)提供一个可以获取构造实例的接口(提供唯一的实…...
IPv6路由协议---IPv6动态路由(OSPFv3-4)
OSPFv3的链路状态通告LSA类型 链路状态通告是OSPFv3进行路由计算的关键依据,链路状态通告包含链路状态类型、链路状态ID、通告路由器三元组唯一地标识了一个LSA。 OSPFv3的LSA头仍然保持20字节,但是内容变化了。在LSA头中,OSPFv2的LS age、Advertising Router、LS Sequence…...
移动通信原理与关键技术学习(4)
1.小尺度衰落 Small-Scale Fading 由于收到的信号是由通过不同的多径到达的信号的总和,接收信号的增强有一定的减小。 小尺度衰落的特点: 信号强度在很小的传播距离或时间间隔内的快速变化;不同多径信号多普勒频移引起的随机调频ÿ…...
sea wordpress/手机端怎么刷排名
项目背景和意义 目的:本课题主要目标是设计并能够实现一个基于web网页的疫情核酸检查预约系统,整个网站项目使用了B/S架构,基于java的springboot框架下开发;;通过后台设置医院信息、录入医院科室信息、录入医生信息、设…...
东莞小学网站建设/友情链接推广平台
最近学习了一下JS,发现JS获取完整rul的方法是如此简单。现在简单说一下JS和ASP一行代码如何获取完整URL地址以及参数的。 JS、 <script language"javascript"> var urlwindow.location.href; document.write(rul); </script…...
wordpress 页面文章列表/什么平台可以免费发广告
?(1)?{X?(1)(1),X?(1)(2),列X?(1)(n)},定义残差为 ,X?(1)(j) e(0)(j)?X(1)(j)?X?若取ji,i1,…,n,则与X(1)及X(1)对应的残差序列为e(0)?{e(0)(i),e(0)(i?1),为便于计算上式改写为,e(0)(n)}?e(0)(2?), e(0)?{e(0)(1),e(0)的累加生成序列为,e(0)(n?)}?…...
用html做卖珠宝的网站/宁波网络推广联系方式
这段时间学习JAVA EE,按照书本教材在GlassFish v3中布署样例数据库,建立连接池及JDBC资源示未发现异常,PING成功。但是在运行程序时,却出现NamingException: Lookup failed for java:/comp/env/jdbc/crcrms in SerialContext [Roo…...
如何设置wordpress的语言/google推广方式和手段有哪些
有可能是作用域的问题...
做服装外贸的网站/网络销售工作靠谱吗
pg_stat_activity是PostgreSQL原生工具,官方说明如下:The pg_stat_activity view will have one row per server process, showing information related to the current activity of that process(该pg_stat_activity视图将为每个服务器进程显…...