ONNX简介
Open Neural Network Exchange(ONNX,开放神经网络交换)格式,是一个用于表示深度学习模型的标准,可使模型在不同框架之间进行转移。
【
ONNX是一种针对机器学习所设计的开放式的文件格式,用于存储训练好的模型。它使得不同的人工智能框架(如Pytorch, MXNet)可以采用相同格式存储模型数据并交互。 ONNX的规范及代码主要由微软,亚马逊 ,Facebook 和 IBM 等公司共同开发,以开放源代码的方式托管在Github上。目前官方支持加载ONNX模型并进行推理的深度学习框架有: Caffe2, PyTorch, MXNet,ML.NET,TensorRT 和 Microsoft CNTK,并且 TensorFlow 也非官方的支持ONNX。---维基百科
】
我们可能会在某一任务中将Pytorch或者TensorFlow模型转化为ONNX模型(ONNX模型一般用于中间部署阶段),然后再拿转化后的ONNX模型进而转化为我们使用不同框架部署需要的类型。
典型的几个线路:
Pytorch -> ONNX -> TensorRT
Pytorch -> ONNX -> TVM
TF – onnx – ncnn
等等,ONNX相当于一个翻译的作用,这也是为什么ONNX叫做Open Neural Network Exchange。
Pytorch模型定义和模型权重暂时不支持打包在一起,这在推理时候需要先用模型定义代码构建模型,再加载模型权重,比较麻烦。借助于onnx格式转换可以把模型打包一起,在ONNX Runtime中运行推理,ONNX Runtime 是针对 ONNX 模型的以性能为中心的引擎,可大大提升模型的性能。另外,onnx模型支持在不同框架之间转换,也支持tensorRT加速
举例:
假如我们利用Pytorch训练好一个模型,然后我们将其保存为.pt文件:
比如就叫做model.pt,这个我们应该很熟悉吧,二进制的模型权重文件,我们可以读取这个文件,相当于预加载了权重信息。
那ONNX呢,利用Pytorch我们可以将model.pt转化为model.onnx格式的权重,在这里onnx充当一个后缀名称,model.onnx就代表ONNX格式的权重文件,这个权重文件不仅包含了权重值,也包含了神经网络的网络流动信息以及每一层网络的输入输出信息和一些其他的辅助信息。
简单拿netron这个工具来可视化(读取ONNX文件)一下:
如图,ONNX中的一些信息都被可视化展示了出来,例如文件格式ONNX v3,该文件的导出方pytorch 0.4等等,这些信息都保存在ONNX格式的文件中。
假设一个场景:现在某组织因为主要开发用TensorFlow为基础的框架,现在有一个深度算法,需要将其部署在移动设备上,以观测变现。传统地我们需要用caffe2重新将模型写好,然后再训练参数;试想下这将是一个多么耗时耗力的过程。
此时,ONNX便应运而生,Caffe2,PyTorch,Microsoft Cognitive Toolkit,Apache MXNet等主流框架都对ONNX有着不同程度的支持。这就便于了我们的算法及模型在不同的框架之间的迁移。
ONNX
开放式神经网络交换(ONNX)是迈向开放式生态系统的第一步,它使AI开发人员能够随着项目的发展选择合适的工具。 ONNX为AI模型提供开源格式。 它定义了可扩展的计算图模型,以及内置运算符和标准数据类型的定义。 最初的ONNX专注于推理(评估)所需的功能。 ONNX解释计算图的可移植,它使用graph的序列化格式。 它不一定是框架选择在内部使用和操作计算的形式。 例如,如果在优化过程中操作更有效,则实现可以在存储器中以不同方式表示模型。
ONNX是一个开放式规范,由以下组件组成:
可扩展计算图模型的定义
标准数据类型的定义
内置运算符的定义
Protobuf
ONNX既然是一个文件格式,那么我们就需要一些规则去读取它,或者写入它,ONNX采用的是protobuf这个序列化数据结构协议去存储神经网络权重信息。
Protobuf是个什么东西,如果大家使用过caffe或者caffe2,那么想必可能对Protobuf比较熟悉,因为caffe的模型采用的存储数据结构协议也是Protobuf。
这里简单介绍一些protobuf吧,Protobuf是一种平台无关、语言无关、可扩展且轻便高效的序列化数据结构的协议,可以用于网络通信和数据存储。我们可以通过protobuf自己设计一种数据结构的协议,然后使用各种语言去读取或者写入,通常我们采用的语言就是C++。
为什么要用onnx
现在大家都喜欢用pytorch训练模型,而pytorch训练的模型转成pth,用C++推理也很难达到真正的加速效果,因为本质上最耗时的网络前向推理部分并没有太多的加速。并且采用libtorch C++推理pytorch并不是一件简单的事情,除非你的模型可以被trace。
在这种情况之下,引入onnx更合理,从目前整个DL生态来看,onnx具有以下好处:
它的模型格式比基于layer的老一代框架更加细粒度;
它拥有统一化的定义,并且基于任何框架都可以推理他;
它可以实现不同框架之间的互相转化。
我们今天要做的事情,就是在上面的onnx模型的基础上,采用TensorRT来进行推理。先做一个简单的速度对比:
框架
语言
耗时(s)
fps
Pytorch
python
0.012+0.022
29
ONNXRuntime
python
0.008+0.022
34
TensorRT
C++
0.004+0.001
250
真正落地的算法部署,毫无疑问,假如你的target是GPU,采用ONNX+TensorRT应该是目前最成熟、最优化的方案。假如你的target是一些嵌入式芯片,那么采用MNN也是可以通过onnx轻松实现CPU嵌入式端快速推理的。
既然ONNX和TensorRT这么好,为什么都不用呢?为什么都还在用Python写难看的推理的代码呢?原因也很简单:
入门太难,C++一般人玩不来;
既要懂模型的每一层输入输出,又要懂TensorRT的API,至少要很熟悉。
TensorRT
一般的深度学习项目,训练时为了加快速度,会使用多GPU分布式训练。但在部署推理时,为了降低成本,往往使用单个GPU机器甚至嵌入式平台(比如 NVIDIA Jetson)进行部署,部署端也要有与训练时相同的深度学习环境,如caffe,TensorFlow等。由于训练的网络模型可能会很大(比如,inception,resnet等),参数很多,而且部署端的机器性能存在差异,就会导致推理速度慢,延迟高。这对于那些高实时性的应用场合是致命的,比如自动驾驶要求实时目标检测,目标追踪等。所以为了提高部署推理的速度,出现了很多轻量级神经网络,比如squeezenet,mobilenet,shufflenet等。基本做法都是基于现有的经典模型提出一种新的模型结构,然后用这些改造过的模型重新训练,再重新部署。
TensorRT是一个高性能的深度学习推理(Inference)优化器,可以为深度学习应用提供低延迟、高吞吐率的部署推理。TensorRT可用于对超大规模数据中心、嵌入式平台或自动驾驶平台进行推理加速。TensorRT现已能支持TensorFlow、Caffe、Mxnet、Pytorch等几乎所有的深度学习框架,将TensorRT和NVIDIA的GPU结合起来,能在几乎所有的框架中进行快速和高效的部署推理。
TensorRT 是一个C++库,从 TensorRT 3 开始提供C++ API和Python API,主要用来针对 NVIDIA GPU进行 高性能推理(Inference)加速。现在最新版TensorRT是4.0版本。
TensorRT 之前称为GIE。
深度学习
训练
部署
训练(training)和 推理(inference)的区别:
训练(training)包含了前向传播和后向传播两个阶段,针对的是训练集。训练时通过误差反向传播来不断修改网络权值(weights)。
推理(inference)只包含前向传播一个阶段,针对的是除了训练集之外的新数据。可以是测试集,但不完全是,更多的是整个数据集之外的数据。其实就是针对新数据进行预测,预测时,速度是一个很重要的因素。
平常自学深度学习的时候关注的更多是训练的部分,即得到一个模型.而实际工作很大一块的工作内容集中于如何将模型部署到具体的芯片上.你自己写的模型效果是很难优于成熟的知名的模型的.
以无人驾驶为例,拍摄到图片后,芯片上的加载的模型要能够识别出图片里是什么.对自动驾驶这种场景而言,对实时性地要求是非常高的.试想,从图片输入到模型,到模型识别出图片中前方有个人花了1分钟,你正以100km/h行驶,后果自然是灾难性的.
这就引出了推理引擎.model里的信息其实就是一些权重矩阵信息而已.输入图片数据后,进行一大堆的矩阵运算,得到最终图片的分类.推理引擎干的事情就是优化矩阵运算,缩短运算时间.
而tensorRT 则是对训练好的模型进行优化。 tensorRT就只是推理优化器。当你的网络训练完之后,可以将训练模型文件直接丢进tensorRT中,而不再需要依赖深度学习框架(Caffe,TensorFlow等),如下:
可以认为tensorRT是一个只有前向传播的深度学习框架,这个框架可以将 Caffe,TensorFlow的网络模型解析,然后与tensorRT中对应的层进行一一映射,把其他框架的模型统一全部 转换到tensorRT中,然后在tensorRT中可以针对NVIDIA自家GPU实施优化策略,并进行部署加速。
TensorRT的核心就是一个深度学习的高性能C++的推理库, 基本适配主流的训练框架,如Tensorflow, Caffe, Pytorch, MXNet。
如果想了解更多关于tensorrt的介绍,可参考官网介绍
详细介绍参见这里
安装流程:
1.系统环境:cuda10.2 + cudnn7.6.5 ,Nvidia驱动安装版本为440.33,具体参见这里。
2.需要的cuDNN的版本,需要时自行下载
3.TensorRT安装及配置步骤:
tar -zxvf TensorRT-7.0.0.11.Ubuntu-16.04.x86_64-gnu.cuda-10.2.cudnn7.6.tar.gz
#解压得到TensorRT-7.0.0.11的文件夹,将里边的lib绝对路径添加到环境变量中
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/gavin/mysoft/TensorRT-7.0.0.11/lib
#安装TensorRT
cd TensorRT-7.0.0.11/python
#if python2
sudo pip2 install tensorrt-5.1.5.0-py2.py3-none-any.whl
#if python3
sudo pip3 install tensorrt-7.0.0.11-cp35-none-linux_x86_64.whl
#安装UFF
cd TensorRT-7.0.0.11/uff
#if python2
sudo pip2 install uff-0.6.5-py2.py3-none-any.whl
#if python3
sudo pip3 install uff-0.6.5-py2.py3-none-any.whl
#安装graphsurgeon
cd TensorRT-7.0.0.11/graphsurgeon
#if python2
sudo pip2 install graphsurgeon-0.4.1-py2.py3-none-any.whl
#if python3
sudo pip3 install graphsurgeon-0.4.1-py2.py3-none-any.whl
个人配置部分截图
测试:
python
import tensorflow
import tensorrt
import uff
不报错就对了。
cuda卸载:
到CUDA9.0的目录下,找到卸载的文件
/usr/local/cuda-9.0/bin
sudo /usr/local/cuda-9.0/bin/uninstall_cuda_9.0.pl
这个过程需要一分钟左右,
sudo rm -rf /usr/local/cuda-9.0/
卸载cuDNN
打开终端,输入
sudo rm -rf /usr/local/cuda/lib64/libcudnn
sudo rm -rf /usr/local/cuda/include/cudnn.h
关系
onnx可以认为是一个文件协议(表示机器学习模型的开放标准), 许多框架(包括 TensorFlow、PyTorch、SciKit-Learn、Keras、Chainer、MXNet 和 MATLAB)中的模型都可以导出或转换为标准 ONNX 格式。 模型采用 ONNX 格式后,可在各种平台和设备上运行。可以支持不同平台的CPU,GPU推理
tensortRT 是一个推理优化器,是一个C++库
目前pytorch比较成熟的方式:①trace 模型,然后 libtorch 前向 ② pytorch模型转到onnx模型,然后使用tensorrt部署;第二种部署方式更加有效率
模型加速越来越成为深度学习工程中的刚需了,最近的CVPR和ICLR会议中,模型的压缩和剪枝是受到的关注越来越多。毕竟工程上,算法工程师的深度学习模型是要在嵌入式平台跑起来,投入应用的。在模型的推理(inference)过程中,计算速度是很重要的。比如自动驾驶,如果使用一个经典的深度学习模型,很容易就跑到200毫秒的延时,那么这意味着,在实际驾驶过程中,你的车一秒钟只能看到5张图像,这当然是很危险的一件事。所以,对于实时响应比较高的任务,模型的加速时很有必要的一件事情了。
如果你使用英伟达的产品,比如PX2,那么在平台上部署模型投入应用,很多时候就需要用到专门的模型加速工具 —— TensorRT。
TensorRT下的模型是在做什么?
TensorRT只负责模型的推理(inference)过程,一般不用TensorRT来训练模型的哈。
TensorRT能加速模型吗?
能!根据官方文档,使用TensorRT,在CPU或者GPU模式下其可提供10X乃至100X的加速。本人的实际经验中,TensorRT提供了20X的加速。
TensorRT为什么能提升模型的运行速度?
TensorRT是英伟达针对自家平台做的加速包,TensorRT主要做了这么两件事情,来提升模型的运行速度。
TensorRT支持INT8和FP16的计算。深度学习网络在训练时,通常使用 32 位或 16 位数据。TensorRT则在网络的推理时选用不了这么高的精度,达到加速推断的目的。
TensorRT对于网络结构进行了重构,把一些能够合并的运算合并在了一起,针对GPU的特性做了优化。现在大多数深度学习框架是没有针对GPU做过性能优化的,而英伟达,GPU的生产者和搬运工,自然就推出了针对自己GPU的加速工具TensorRT。一个深度学习模型,在没有优化的情况下,比如一个卷积层、一个偏置层和一个reload层,这三层是需要调用三次cuDNN对应的API,但实际上这三层的实现完全是可以合并到一起的,TensorRT会对一些可以合并网络进行合并。我们通过一个典型的inception block来看一看这样的合并运算。
参考文献: