pytorch转onnx其实也就是python转的 ,之前有个帖子了讲的怎么操作,这个就是在说说为什么这么做~~~

(1)Pytorch转ONNX的意义

一般来说转ONNX只是一个手段,在之后得到ONNX模型后还需要再将它做转换,比如转换到TensorRT上完成部署,或者有的人多加一步,从ONNX先转换到caffe,再从caffe到tensorRT。原因是Caffe对tensorRT更为友好,这里关于友好的定义后面会谈。

因此在转ONNX工作开展之前,首先必须明确目标后端。ONNX只是一个格式,就和json一样。只要你满足一定的规则,都算是合法的,因此单纯从Pytorch转成一个ONNX文件很简单。但是不同后端设备接受的onnx是不一样的,因此这才是坑的来源。

Pytorch自带的torch.onnx.export转换得到的ONNX,ONNXRuntime需要的ONNX,TensorRT需要的ONNX都是不同的。

这里面举一个最简单的Maxpool的例:

Maxunpool可以被看作Maxpool的逆运算,咱们先来看一个Maxpool的例子,假设有如下一个C*H*W的tensor(shape[2, 3, 3]),其中每个channel的二维矩阵都是一样的,如下所示

在这种情况下,如果我们在Pytorch对它调用MaxPool(kernel_size=2, stride=1,pad=0)

那么会得到两个输出,第一个输出是Maxpool之后的值:

另一个是Maxpool的Idx,即每个输出对应原来的哪个输入,这样做反向传播的时候就可以直接把输出的梯度传给对应的输入:

细心的同学会发现其实Maxpool的Idx还可以有另一种写法:

即每个channel的idx放到一起,并不是每个channel单独从0开始。这两种写法都没什么问题,毕竟只要反向传播的时候一致就可以。

但是当我在支持OpenMMEditing的时候,会涉及到Maxunpool,即Maxpool的逆运算:输入MaxpoolId和Maxpool的输出,得到Maxpool的输入。

Pytorch的MaxUnpool实现是接收每个channel都从0开始的Idx格式,而Onnxruntime则相反。因此如果你希望用Onnxruntime跑一样的结果,那么必须对输入的Idx(即和Pytorch一样的输入)做额外的处理才可以。换言之,Pytorch转出来的神经网络图和ONNXRuntime需要的神经网络图是不一样的。

(2)ONNX与Caffe

主流的模型部署有两种路径,以TensorRT为例,一种是Pytorch->ONNX->TensorRT,另一种是Pytorch->Caffe->TensorRT。个人认为目前后者更为成熟,这主要是ONNX,Caffe和TensorRT的性质共同决定的

上面的表列了ONNX和Caffe的几点区别,其中最重要的区别就是op的粒度。举个例子,如果对Bert的Attention层做转换,ONNX会把它变成MatMul,Scale,SoftMax的组合,而Caffe可能会直接生成一个叫做Multi-Head Attention的层,同时告诉CUDA工程师:“你去给我写一个大kernel“(很怀疑发展到最后会不会把ResNet50都变成一个层。。。)

因此如果某天一个研究员提了一个新的State-of-the-art的op,很可能它直接就可以被转换成ONNX(如果这个op在Pytorch的实现全都是用Aten的库拼接的),但是对于Caffe的工程师,需要重新写一个kernel。

细粒度op的好处就是非常灵活,坏处就是速度会比较慢。这几年有很多工作都是在做op fushion(比如把卷积和它后面的relu合到一起算),XLA和TVM都有很多工作投入到了op fushion,也就是把小op拼成大op。

TensorRT是NVIDIA推出的部署框架,自然性能是首要考量的,因此他们的layer粒度都很粗。在这种情况下把Caffe转换过去有天然的优势。

除此之外粗粒度也可以解决分支的问题。TensorRT眼里的神经网络就是一个单纯的DAG:给定固定shape的输入,执行相同的运算,得到固定shape的输出。

**目前TensorRT的一个发展方向是支持dynamic shape,但是还很不成熟。

tensor i = funcA();
if(i==0)
j = funcB(i);
else
j = funcC(i);
funcD(j);

对于上面的网络,假设funcA,funcB,funcC和funcD都是onnx支持的细粒度算子,那么ONNX就会面临一个困难,它转换得到的DAG要么长这样:funcA->funcB->funcD,要么funcA->funcC->funcD。但是无论哪种肯定都是有问题的。

而Caffe可以用粗粒度绕开这个问题

开这个问题

tensor i = funcA();
coarse_func(tensor i) {
if(i==0) return funcB(i);
else return funcC(i);
}
funcD(coarse_func(i))

因此它得到的DAG是:funcA->coarse_func->funcD

当然,Caffe的代价就是苦逼的HPC工程师就要手写一个coarse_func kernel。。。(希望Deep Learning Compiler可以早日解放HPC工程师)

(3)Pytorch本身的局限

熟悉深度学习框架的同学都知道,Pytorch之所以可以在tensorflow已经占据主流的情况下横空出世,成功抢占半壁江山,主要的原因是它很灵活。举个不恰当的例子,tensorflow就像是C++,而Pytorch就是Python。

tensorflow会把整个神经网络在运行前做一次编译,生成一个DAG(有向无环图),然后再去跑这张图。Pytorch则相反,属于走一步看一步,直到运行到这个节点算出结果,才知道下一个节点该算啥。

ONNX其实就是把上层深度学习框架中的网络模型转换成一张图,因为tensorflow本身就有一张图,因此只需要直接把这张图拿到手,修修补补就可以。

但是对于Pytorch,没有任何图的概念,因此如果想完成Pytorch到ONNX的转换,就需要让ONNX再旁边拿个小本子,然后跑一遍Pytorch,跑到什么就把什么记下来,把记录的结果抽象成一张图。因此Pytorch转ONNX有两个天然的局限。

1. 转换的结果只对特定的输入。如果换一个输入导致网络结构发生了变化,ONNX是无法察觉的(最常见的情况是如果网络中有if语句,这次的输入走了if的话,ONNX就只会生成if对应的图,把else里面全部的信息都丢掉)。

2. 需要比较多的计算量,因为需要真刀真枪的跑一遍神经网络。

PS:针对于以上的两个局限,我的本科毕设论文提出了一种解决方案,就是通过编译器里面的词法分析,语法分析直接扫描Pytorch或者tensorflow的源代码得到图结构,这样可以轻量级的完成模型到ONNX的转换,同时也可以得到分支判断等信息,这里放一个github链接(https://github.com/drcut/NN_transform),希望大家多多支持

*目前Pytorch官方希望通过用TorchScript的方式解决分支语句的问题,但据我所知还不是很成熟。

whaosoft aiot http://143ai.com

Pytorch~ONNX相关推荐

  1. Pytorch → ONNX → TensorRT

    Pytorch → ONNX → TensorRT 由于实验室与应急减灾中心关于道路检测的项目需加快推理速度,在尝试手动融合模型的Con层和bn层发现推理速度提升不明显之后,我的"mento ...

  2. onnx:Resize in opset 11 to support Pytorch‘s behavior

    报错内容: D:\Anaconda3\lib\site-packages\torch\onnx\symbolic_helper.py:243: UserWarning: You are trying ...

  3. pytorch C++部署模型 ONNX tensorRT

    (1) C++部署pytorch模型(上) (2) TensorRT5介绍及Pytorch转TensorRT5代码示例 TensorRT的使用步骤:(假设以及有一个训练好的模型) (1) 根据模型创建 ...

  4. 【yolov5】pytorch模型导出为onnx模型

    博主想拿官网的yolov5训练好pt模型,然后转换成rknn模型,然后在瑞芯微开发板上调用模型检测.但是官网的版本对npu不友好,所以采用改进结构的版本: 将Focus层改成Conv层 将Swish激 ...

  5. YOLOv3最全复现代码合集(含PyTorch/TensorFlow和Keras等)

    点击上方"CVer",选择"置顶公众号" 重磅干货,第一时间送达 前戏 2018年3月26日,CVer第一时间推文:YOLOv3:你一定不能错过 2019年3月 ...

  6. 【TensorRT】将 PyTorch 转化为可部署的 TensorRT

    文章目录 一.什么是 ONNX 二.PyTorch 转 ONNX 三.什么是 TensorRT 四.ONNX 转 TensorRT 在深度学习模型落地的过程中,会面临将模型部署到边端设备的问题,模型训 ...

  7. onnx 测试_pytorch onnx onnxruntime tensorrt踩坑 各种问题

    做了一个小测试,发现pytorch onnx tensorrt三个库的版本存在微妙的联系,在我之前的错误实验中,PyTorch==1.3.0/1.4.0:Onnx==1.6.0:tensorrt=7. ...

  8. PyTorch开发者福音, OpenVINO整合PyTorch实现推理加速!

    作者: Ashish Datta, Sai Jayanthi, Natalie Kershaw (Microsoft), Yamini Nimmagadda, Sesh Seshagiri 编译:李翊 ...

  9. Pytorch图像分类实战笔记Task01-Task07|Datawhale组队学习

    学习计划 Task01:构建自己的图像分类数据集 第一节配套的代码:(按照顺序学习) 1.1配置环境 tqdm库官方说明:https://github.com/tqdm/tqdm#documentat ...

最新文章

  1. Java在Quant应用_java – 如何绘制quantil band(在R中)
  2. 清华北大亚洲第一第二!就在刚刚,2020 泰晤士亚洲大学排名公布!
  3. Word2Vec揭秘: 这是深度学习中的一小步,却是NLP中的巨大跨越
  4. Java复习2-对象与类
  5. PHP函数参数传递方法的具体改进技巧
  6. bzoj1833: [ZJOI2010]count 数字计数USACO37 Cow Queueing 数数的梦(数位DP)
  7. 我买网勾搭搜狐吃货自媒体联盟 大搞自媒体“晒图”营销?
  8. Spark的性能调优
  9. 后置四摄已安排?华为P30 Pro设计渲染图曝光
  10. CSS层叠样式表的理解(一)
  11. python︱写markdown一样写网页,代码快速生成web工具:streamlit lay-out布局(四)
  12. 10个Jquery幻灯片插件教程
  13. python:画图调整图例位置
  14. dosbox进行debug调试教程
  15. android开源系统brvah,Brvah——一个强大的Adapter框架
  16. 蜂鸣器驱动电路的改进设计
  17. Win10 IPv6 远程桌面连接(小米路由器)
  18. 太平洋服务器cpu型号,Intel正式发布:新一代6W的超低功耗平台CPU
  19. android 基带版本,基带是什么 基带版本是什么
  20. 常见HTTP/FTP/WebSockets状态码大全

热门文章

  1. y7000p 2020 vbios_联想发布拯救者2020笔记本:硬件升级,顶配8核CPU+RXT2080S显卡
  2. 《敢达SEED 宿命 CE世纪》5结局一览
  3. 基于python下django框架 实现网上图片分享平台详细设计
  4. Imagination光线追踪助力开发者打造优质移动游戏
  5. 开开心心爬APP,结果一坑连一坑
  6. 皮尔逊相关系数矩阵热图 代码
  7. 致远推出全分销A6+,走协同OA差异化竞争路
  8. 【Go ~ 0到1 】 第三天 6月27 slice,map 与 函数
  9. 基于色度或其他彩色属性设计一个简单的肤色检测器
  10. 15 - reduce-pratial偏函数-lsu_cache