Cap2:Pytorch转TensorRT(上:Pytorch->ONNX)

文章目录

  • 1、pytorch导出onnx模型
  • 2、使用onnxruntime推理onnx模型
  • 3、精度对齐
  • 4、总结

深度学习框架种类繁多,想实现任意框架之间的模型转换是一件困难的事情。但现在有一个中间格式ONNX,任何框架模型都支持转为ONNX,然后也支持从ONNX转为自身框架,那么每一种框架都只需维护如何ONNX进行转换即可,大大降低了维护成本,也给使用的开发者带来遍历。

在这里插入图片描述
如图所示,中间件不止一种,但是ONNX是使用最广泛的一种。需要注意的是,中间件只是一个描述格式,比如resnet18.onnx这个从pytorch导出的onnx中间件中描述了每一个算子的属性,算子中的权重数值,算子之间的运算图。我们需要一个引擎或框架转为自身特定的格式后,再使用推理功能进行推理。(类似一张jpeg图片在电脑中只是一串数值,必须借用图片解析工具如照片浏览器等软件解析jpeg的数值后才能显示。所以需要区分数据和数据能实现的功能是两回事)

下面我们尝试从pytorch导出resnet18为onnx中间件,然后使用onnxruntime(和onnx不一样,这是一个推理引擎,只不过是专门针对onnx格式的,所以支持直接加载onnx模型推理。如果使用tensorrt推理引擎,则需要将onnx转为tensrort支持的格式后再加载推理)进行推理,并检查使用pytorch推理的结果和onnxruntime推理的结果之间的差异有多大。

1、pytorch导出onnx模型

首先需要安装:

pip install onnx  

pytorch提供了对onnx的支持,现在让我们尝试将pytorch的resnet18导出为onnx模型。

import torch
import torchvision# 创建一个符合输入shape的假数据
dummy_input = torch.rand(1, 3, 224, 224, dtype=torch.float32, device="cuda:0")
resnet18 = torchvision.models.resnet18(weights=torchvision.models.ResNet18_Weights.IMAGENET1K_V1).cuda()input_names = ["input:0"]  # 给输入节点取个名字,会伴随后续流程,方面我们定位输入节点
output_names = ["output:0"] # 同上
export_path = "resnet18.onnx"  # 保存路径# 导出
with torch.no_grad():torch.onnx.export(model=resnet18,args=dummy_input,f=export_path,opset_version=11,verbose=True,input_names=input_names,output_names=output_names)

在使用export函数时,我们手动定义了一个假数据,其shape和resnet18要求的输入一致。pytorch转onnx的原理不是通过分析语法进行转换的,而是让pytorch运行一次,然后通过追踪数据流,得到该组输入对应的计算图。 所以就是要给定一个输入,执行一遍模型,把对应的计算图记录下来,保存为onnx格式。export函数就是用的该种追踪方式导出的。(一个问题是如果模型中存在控制流,本次输入走分支1,那就只会记录只有分支1的模型,所以含有控制流的模型不能简单使用这种方法),所以这也就是为什么需要给定一组输入,同时为什么要with torch.no_grad了,因为我们只是追踪计算图而不需要梯度。

初次之外还定义了input_names和output_names,两个都是列表,因为某些模型不止一个输入输出。这里给每一个输入输出定义一个名字,后续我们可以根据名字直接定位到输入输出节点,获取数据。特别的如果想获取中间节点数据,也可以通过其名字定位节点获取数据。

opset_version是定义算子集。ONNX给每一个算子都有一个名字,比如ONNX定义了卷积名字为Conv,其他框架看到Conv开头的数据定义,明白这是一个卷积层, 会使用自身的卷积算子去映射,实现转换。但是深度学习各种算法更新很快,所以ONNX与时俱进会不断新增新的算子,你可以通过Operator Schemas查看到是否有自己想要得算子,以及它出现在那个版本。

2、使用onnxruntime推理onnx模型

当我们将pt模型转为onnx模型后,使用onnxruntime引擎进行推理。
首先需要安装推理引擎

Pip install onnxruntime  # 支持onnx中间件的推理引擎

完整的推理代码如下:

import cv2
import torchvision
import numpy as np
import onnxruntime# 获取ImageNet1K的标签
labels = torchvision.models.ResNet18_Weights.IMAGENET1K_V1.value.meta["categories"]
# 使用InferenceSession创建一个引擎以供后续推理,CPUExecutionProvider指定使用CPU
session = onnxruntime.InferenceSession("resnet18.onnx", providers=['CPUExecutionProvider'])def preprocess(cvimg):# 将图像大小调整为 (224, 224)image_resized = cv2.resize(cvimg, (224, 224))# 将图像转换为 NumPy 数组,并将像素值缩放到 [0, 1]image_normalized = image_resized / 255.0# 对图像进行归一化mean = np.array([0.485, 0.456, 0.406])std = np.array([0.229, 0.224, 0.225])image_normalized = (image_normalized - mean) / std# 调整图像维度顺序,OpenCV 默认通道顺序为 BGR,而 PyTorch 默认为 RGBreturn np.transpose(image_normalized, (2, 0, 1)).astype(np.float32)img = cv2.imread(img_path)
inp = preprocess(img)  # 预处理,得到shape=(3,224,224)的图片
inp = np.expand_dims(inp, axis=0)  # 升维得到shape=(1,3,224,224),BS和导出ONNX定义的假数据的BS一致# run函数用于推理,output_names指明了要获取哪个节点的数据,input_feed使用字典给所有的输入指定输入数据
output = session.run(output_names=["output:0"], input_feed={"input:0": inp}) # output是列表,其中是节点"output:0"的数据,shape=(1,1000)

实际上output列表中的一个元素就是一个节点的输出,如下图如果定义两个输出节点,表示我要获取这两个节点的数据。那么output列表长度就是节点数量。
在这里插入图片描述

3、精度对齐

当我们将pt模型转为onnx模型后,使用onnxruntime引擎进行推理。考虑到1)模型数据转换时存在误差;2)不同框架(pt和onnxruntime)对同一个算子的实现也可能存在差异;3)图像预处理实现方法不同等原因,两种框架的推理结果是有一定差异的。但是只要这个差异在容忍的范围内,都是可以接受的。

下面我们同时使用pytorch框架和onnxruntime框架对pt模型和onnx模型进行推理。onnxruntime的输入输出使用numpy的ndarray数据。

为了简明,使用numpy产生随机数据,然后同时给pytorch(转tensor)和onnxruntime,保证了输入的一致性。我们期望两个框架的输出也应该尽可能的相似。

下面的代码将随机生成20个假数据,然后pt和onnxruntime分别进行运算,并将结果储存在pt_output_array和onnx_output_array,最后计算这两个结果集的差异。

import torch
import torchvision
import numpy as np
import onnxruntimeresnet18 = torchvision.models.resnet18(weights=torchvision.models.ResNet18_Weights.IMAGENET1K_V1)
labels = torchvision.models.ResNet18_Weights.IMAGENET1K_V1.value.meta["categories"]
resnet18.eval()session = onnxruntime.InferenceSession("resnet18.onnx", providers=['CPUExecutionProvider'])# 创建ndarray用于储存输入和输出数据
pt_inp_array = np.zeros([20, 1, 3, 224, 224], dtype=np.float32)
onnx_inp_array = np.zeros([20, 1, 3, 224, 224], dtype=np.float32)pt_output_array = np.zeros([20, 1, 1000], dtype=np.float32)
onnx_output_array = np.zeros([20, 1, 1000], dtype=np.float32)for idx in range(20):dummy_input = np.random.random([1, 3, 224, 224]).astype(np.float32)  # 随机生成一个假数据pt_inp_array[idx] = dummy_input  # 将pytorch的输入记录with torch.no_grad():output = resnet18(torch.tensor(dummy_input))pt_output_array[idx] = output.cpu().detach().numpy()  # 将pytorch的输出记录onnx_inp_array[idx] = dummy_input  # 将onnx的输入记录output = session.run(output_names=["output:0","output:0"], input_feed={"input:0": dummy_input})onnx_output_array[idx] = output[0]  # 将onnx的输出记录# 检查pt和onnx输入的差异,因为是相同的,所以没有差异
np.testing.assert_allclose(pt_inp_array, onnx_inp_array, rtol=1e-10, atol=1e-10)# 检查pt和onnx输出的差异,经过测试在1e-06等级左右
np.testing.assert_allclose(pt_output_array, onnx_output_array, rtol=1e-10, atol=1e-10)

结果如图所示。np.testing.assert_allclose(pt_inp_array, onnx_inp_array, rtol=1e-10, atol=1e-10)是没有报错的,因为实际上输入是一样的,所以差异为0。但是输出报错了,总共有20000个参数,其中有19244个参数差异不满足设定的1e-10。实际上这里设定的阈值很小,一般设定在1e-5(不是绝对的,根据任务调整)。
在这里插入图片描述
设定阈值为1e-5后:np.testing.assert_allclose(pt_output_array, onnx_output_array, rtol=1e-5, atol=1e-5),不再报错,说明精度基本对齐。

4、总结

在本文中我们使用pytorch自带的工具将pt模型转为onnx模型,并使用onnxruntime推理引擎进行推理。为了保证模型转换过程中精度,进行了精度对齐的小实验,证明转换前后的误差在1e-6这个级别,是可以忍受的。

后续继续将onnx转为tensorRT进行部署,实现从pt–onnx–tensorRT这个部署路线。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/746780.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

案例分析篇00-【历年案例分析真题考点汇总】与【专栏文章案例分析高频考点目录】(2024年软考高级系统架构设计师冲刺知识点总结-案例分析篇-先导篇)

专栏系列文章: 2024高级系统架构设计师备考资料(高频考点&真题&经验)https://blog.csdn.net/seeker1994/category_12593400.html 案例分析篇01:软件架构设计考点架构风格及质量属性 案例分析篇11:UML设计考…

疫情网课管理系统|基于springboot框架+ Mysql+Java+Tomcat的疫情网课管理系统设计与实现(可运行源码+数据库+设计文档+部署说明)

推荐阅读100套最新项目 最新ssmjava项目文档视频演示可运行源码分享 最新jspjava项目文档视频演示可运行源码分享 最新Spring Boot项目文档视频演示可运行源码分享 目录 前台功能效果图 ​编辑 学生功能模块 管理员功能 教师功能模块 系统功能设计 数据库E-R图设计 lun…

Ubuntu上搭建TFTP服务

Ubuntu上搭建TFTP服务 TFTP服务简介搭建TFTP服务安装TFTP服务修改配置文件 重启服务 TFTP服务简介 TFTP是一个基于UDP协议实现的用于在客户机和服务器之间进行简单文件传输的协议,适用于开销不大、不复杂的应用场合。TFTP协议专门为小文件传输而设计,只…

虚拟游戏理财 - 华为OD统一考试(C卷)

OD统一考试(C卷) 分值: 100分 题解: Java / Python / C 题目描述 在一款虚拟游戏中生活,你必须进行投资以增强在虚拟游戏中的资产以免被淘汰出局。 现有一家Bank,它提供有若干理财产品m,风险及…

【PHP安全】PHP伪协议

PHP伪协议: file:// #访问本地文件系统http:// #访问HTTPs网址ftp:// #访问ftp URLphp:// #访问输入输出流zlib:// #压缩流data:// #数据(RFC 2397)ssh2:// #security shell2expect:// #处理交互式的流glob:// #查找匹配的文件路径phar:// #P…

Siamese Network(孪生神经网络)详解

Siamese和Chinese有点像。Siam是古时候泰国的称呼,中文译作暹罗。Siamese也就是“暹罗”人或“泰国”人。Siamese在英语中是“孪生”、“连体”的意思,这是为什么呢?十九世纪泰国出生了一对连体婴儿,当时的医学技术无法使两人分离…

软件功能测试内容有哪些?湖南长沙软件测评公司分享

软件功能测试主要是验证软件应用程序的功能,且不管功能是否根据需求规范运行。是通过给出适当的输入值,确定输出并使用预期输出验证实际输出来测试每个功能。也可以看作“黑盒测试”,因为功能测试不用考虑程序内部结构和内部特性,…

Orange3数据预处理(清理特征组件)

清理特征 移除未使用的属性值和无用的属性,并对剩余的值进行排序。 输入 数据: 输入数据集 输出 数据: 过滤后的数据集 命名属性定义有时包含在数据中不出现的值。即使原始数据中没有这种情况,数据过滤、选择示例子集等操作也可能移除…

(二十五)Flask之MTVMVC架构模式Demo【重点:原生session使用及易错点!】

目录: 每篇前言:MTV&MVC构建一个基于MTV模式的Demo项目:蹦出一个问题: 每篇前言: 🏆🏆作者介绍:【孤寒者】—CSDN全栈领域优质创作者、HDZ核心组成员、华为云享专家Python全栈领…

关于Transfomer的思考

为何诞生 在说transformer是什么,有什么优势之类的之前,先谈一谈它因何而诞生。transformer诞生最重要的原因是早先的语言模型,比如RNN,由于其本身的训练机制导致其并行度不高,特别是遇到一些长句子的情况下。其次&…

抖音开放平台第三方开发,实现代小程序备案申请

大家好,我是小悟 抖音小程序备案整体流程总共分为五个环节:备案信息填写、平台初审、工信部短信核验、通管局审核和备案成功。 服务商可以代小程序发起备案申请。在申请小程序备案之前,需要确保小程序基本信息已填写完成、小程序至少存在一个…

硬件笔记(26)---- 高速电路中滤波电容的选取

先要知道电容的等效电路 其中ESL取决于电容的类型和封装,一般用贴片陶瓷电容为例,对于直插式电解电容,他们的ESL很大。按下表,封装越大,ESL越大,但是0612有些例外 0612和1206就是 长短边的区别,…

什么是MVC三层结构

1.MVC(三层结构) MVC(Model-View-Controller)是一种常见的软件设计模式,用于将应用程序的逻辑和界面分离成三个不同的组件。每个组件负责特定的任务,从而提高代码的可维护性和可扩展性。 以前的模式。 遇到…

【网络安全渗透】常见文件上传漏洞处理与防范

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 所属的专栏:网络安全渗透 景天的主页:景天科技苑 文章目录 1.文件上传漏洞1.1. 描述1.2. 危害1.3. 有关文件上传的知识1.4…

【兔子机器人】修改GO、车轮电机ID(软件方法、硬件方法)以及修正VMC腿部初始化夹角

一、GO电机修改ID 1、硬件方法 利用上位机直接修改GO电机的id号: 打开调试助手,点击“调试”,查询电机,修改id号,即可。 但先将四个GO电机连接线拔掉,不然会将连接的电机一并修改。 利用24V电源给GO电机…

Java_12 杨辉三角 II

杨辉三角 II 给定一个非负索引 rowIndex,返回「杨辉三角」的第 rowIndex 行。 在「杨辉三角」中,每个数是它左上方和右上方的数的和。 示例 1: 输入: rowIndex 3 输出: [1,3,3,1] 示例 2: 输入: rowIndex 0 输出: [1] 示例 3: 输入: rowIndex 1 输…

【应急响应靶场web2】

文章目录 前言 一、应急响应 1、背景 2、webshell查杀 3、日志排查 1)apache日志 2)nginx日志 3)ftp日志 4、隐藏账户 5、文件筛选 二、漏洞复现 总结 前言 靶场来源:知攻善防实验室 一、应急响应 1、背景 小李在某…

VMware 配置虚拟机网络

之前需要完成的任务 (1)、下载和安装VMware-Workstation-Pro.exe软件,推荐16.0版本 (2)、下载centOS7镜像,可以在阿里云下载。 (3)、VM创建一个虚拟机,并且使用本地已下载…

中东社媒Snapchat如何注册?

Snapchat是一款图片分享软件应用。利用该应用程序,用户可以拍照、录制影片、撰写文字和图画,并传送到自己在该应用上的好友列表。现如今,Snapchat也成为独立战引流然而,即使如此受欢迎,Snapchat的注册使用仍然是新手的难题&#x…

Java基于 Springboot+Vue 的招生管理系统,前后端分离

博主介绍:✌程序员徐师兄、8年大厂程序员经历。全网粉丝15w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇…