AlphaGo 击败围棋世界冠军李世石以来,对于人工智能和深度学习的钻研出现井喷之势。
各种新的算法和网络模型层出不穷,令人目迷五色。与之相随的,深度学习的训练和推理框架也在一直的新陈代谢,比拟驰名的有:微软的 CNTK、Google 的 TensorFlow、Facebook 的 PyTorch、Apple 的 CoreML、Intel 的 OpenVINO、英伟达的 cuDNN 和 TensorRT、腾讯的 TNN 和 NCNN、阿里的 MNN 等等。
这些框架都有相似之处,他们的输出是一个或者一组多维数据,数据通过多层运算单元之后输入运算后果。训练框架反对 BackPropogation 等训练方法,能够主动调整模型参数,用于算法设计。推理框架则是单纯只能用于模型推理运算,不能调整模型自身,用于算法部署落地。
这些框架中,Google 的 TensorFlow 的这个名字尤其具备美感。多维数据是为张量(Tensor),数据在多层运算单元中的运算和传递是为流(FLow),看到这个词就好像看到了一个数据和运算的图(Computation Graph),真堪称妙手偶得之佳作。这些框架都须要构建算子,并且将这些算子依照肯定的秩序连接起来,能够称之为网络模型。
Why ONNX?
每个深度学习框架都有本人独有的格局来解释和存储网络模型,并且这些框架的侧重点不同,有些用于训练学习,有些用于部署推理。在深度学习算法开发中,在不同的阶段会抉择不同的框架,所以模型形容格局的不同,在主观上造成了深度学习算法开发和落地的艰难。
笔者之前曾开发深度神经网络算法,过后抉择的训练框架是 Caffe,须要落地部署到 Linux、iOS、Android 等多个平台。Linux 抉择的是 Nvidia 的 cuDNN;iOS 抉择的是 CoreML;Android 抉择的是 NNAPI,Caffe 的模型形容格局是 caffemodel。
它应用自定义的 Protobuf (https://github.com/BVLC/caffe…),然而显然,无论是 cuDNN、CoreML、NNAPI 都无奈间接应用 caffemodel,CoreML 的模型形容应用另一种定义 (https://apple.github.io/corem…),cuDNN 和 NNAPI 都是 low-level 的推理引擎,须要使用者将这个模型组装起来。
对于 CoreML 来说,咱们须要把 caffemodel 转为 coremlmodel 格局,对于 cuDNN 和 NNAPI,咱们须要解析 caffemodel,而后本人组装出残缺的网络模型。这个过程繁琐而且容易出错,过后有强烈的激动,心愿定义一个对立的模型形容格局,所有的训练框架训练所得的网络模型,都是用这个格局来形容,在设施上部署推理时,相应的推理引擎反对解析这个对立的形容格局,间接实现部署落地,岂不美哉。
当然此事并不容易,要定义个对立的模型形容格局,不仅仅须要对机器学习技术有深刻的了解,而且将之推广成为事实上的行业标准,更须要有很大的行业影响力,并不是如笔者这样的无名英雄能够为之。所幸曾经有社区在做这个事件了,这就是 Open Neural Network Exchange(ONNX)。
用 ONNX 本人的话来说,ONNX 是一个对计算网络 (Computation Graph) 的一个通用形容(Intermediate Representation)。它心愿被设计成为凋谢的网络形容格局,缩小开发者在各个训练和推理框架间切换的代价,能够让开发者专一于算法和优化。尽管 ONNX 还处于比拟晚期的阶段,不过曾经有约来越多的人开始关注到它,将来会有机会失去更宽泛的利用。
计算模型形容
ONNX 有两个分类:根底的 ONNX 次要用于形容神经网络、ONNX-ML 是对根底 ONNX 的扩大,减少了神经网络之外的其余机器学习算法的反对。本文不会波及 ONNX-ML,接下来的文字以一个简略的 ONNX 模型为例,介绍一下 ONNX 是如何来形容一个计算网络的。该模型能够在 ONNX 的 Github 上下载(https://github.com/onnx/model…).
ONNX 的模型形容采纳了 Google 的 Protocol Buffer 语言。最外层的构造是 ModelProto,ModelProto 的定义如下:
message ModelProto {
int64 ir_version = 1;
repeated OperatorSetIdProto opset_import = 8;
string producer_name = 2;
string producer_version = 3;
string domain = 4;
int64 model_version = 5;
string doc_string = 6;
GraphProto graph = 7;
repeated StringStringEntryProto metadata_props = 14;
repeated TrainingInfoProto training_info = 20;
repeated FunctionProto functions = 25;
}
比拟重要的字段有: lr_version : 以后的 ONNX 模型文件的版本,目前公布的最新版本为 IR_VERSION_2019_3_18 = 6. 公布于 2019 年,版本 7 还在制订中. opset_import: 以后的模型文件所依赖的算子 domain 和版本. graph: 这个模型执行的运算图,这个是最重要的字段.
GraphProto 的定义如下:
message GraphProto {
repeated NodeProto node = 1;
string name = 2; // namespace Graph
repeated TensorProto initializer = 5;
repeated SparseTensorProto sparse_initializer = 15;
string doc_string = 10;
repeated ValueInfoProto input = 11;
repeated ValueInfoProto output = 12;
repeated ValueInfoProto value_info = 13;
repeated TensorAnnotation quantization_annotation = 14;
}
比拟重要的字段有: initializer : 模型的每一网络层的参数, 模型训练实现之后参数就被固定下来. input : 模型的输出格局. output : 模型的输入格局. nodes : 定义了模型的所有运算模块,按照推理的秩序排布.
NodeProto 的定义如下:
message NodeProto {
repeated string input = 1; // namespace Value
repeated string output = 2; // namespace Value
string name = 3; // namespace Node
string op_type = 4; // namespace Operator
string domain = 7; // namespace Domain
repeated AttributeProto attribute = 5;
string doc_string = 6;
}
比拟重要的字段有: input : 输出参数的名字. output : 输入参数的名字,这里须要注意的是,每一个网络层之间的连贯应用输出和输入的名字来确立的. op_type : 算子的类型. attributes : 算子的属性,其解析取决于算子的类型.
ONNX 中最简单的局部就是对于各种算子的形容,这也能够了解,形成神经网络的主体就是这些算子. attributes 就是算子的一组带名字的属性. 本文中,咱们介绍一个在 mobilenetv2-7.onnx 应用最多的算子: conv.
卷积神经网络在语音,图像,视频等解决上取得了巨大成功. ONNX 对于卷积网络层的属性定义次要有: dilations: 扩大卷积,默认为 1,即一般卷积. 其数学定义如下
一般卷积扩大卷积
group: 分组卷积, 其定义见文献 14. 默认为 1,即不分组. kernel_shape: 定义了卷积核的大小. pads: 定义了上下左右填充的像素数. strides: 定义了卷积运算的步长。
ONNX 的反对状况
各家的训练和推理框架还在持续倒退,ONNX 想成为行业标准显然还为时尚早,然而目前尚没有看到其余更好的通用模型形容格局,咱们简略演绎一下当初的 ONNX 的反对状况(不残缺):
Reference
[1] ONNX: https://github.com/onnx/onnx
[2] TENSORFLOW: https://www.tensorflow.org/
[3] CNTK: https://github.com/Microsoft/…
[4] PYTORCH: https://pytorch.org/
[5] TNN: https://github.com/Tencent/TNN
[6] MNN: https://github.com/alibaba/MNN
[7] CUDNN: https://developer.nvidia.com/…
[8] TENSORRT: https://developer.nvidia.com/…
[9] COREML: https://developer.apple.com/d…
[10] NCNN: https://github.com/Tencent/ncnn
[11] NNAPI: https://developer.android.com…
[12] Protocol Buffers: https://developers.google.com…
[13] Dilated Convolutions https://arxiv.org/abs/1511.07122
[14] Dynamic Group Convolutions https://arxiv.org/abs/2007.0424