作者蒋思源

开源一年多的模型交换格式ONNX,已经一统框架江湖了?

近日,微软亚洲研究院和华为举办了 ONNX 合作伙伴研讨会,这是 ONNX 开源社区成立以来首次在中国举办的活动。在研讨会中,微软、Facebook、华为和英特尔等的开发者介绍了他们在 ONNX 上的开源贡献及思考。

在过去的一年多中,ONNX 这种「通用」的神经网络交换格式已经有了很长远的发展,用不同框架编写的模型可以在不同的平台中流通。在这次研讨会中,我们确切地感受到了这一点,因为开源社区围绕着 ONNX 介绍了很多优化工具和资源库。

微软上个月开源了 ONNX Runtime,其专为 ONNX 格式的模型设计了高性能推理引擎。Facebook 早两个月前开源了 ONNXIFI,其为 ONNX 提供了用于框架集成的接口,即一组用于加载和执行 ONNX 计算图的跨平台 API。更早一些,英特尔在今年 3 月份就开源 nGraph,它能编译 ONNX 格式的模型,并在 CPU 或 GPU 等硬件加速模型的运行。

而到了昨天,微软又开源了 ONNX.JS,它是一种在浏览器和 Node.js 上运行 ONNX 模型的 JavaScript 库。它部署的模型效率非常高,且能实现交互式的直观推理。该开源项目给出了图像分类的交互式演示,且在 Chrome 浏览器和 CPU 下比 TensorFlow.JS 快了近 8 倍,后文将详细介绍这一开源库。

当然除了这些开源工作,ONNX 社区还有更多的实践,例如如何部署 ONNX 模型到边缘设备、如何维护一个包罗万象的 ONNX Model Zoo 等。本文主要从什么是 ONNX、怎样用 ONNX,以及如何优化 ONNX 三方面看看 ONNX 是不是已经引领「框架间的江湖」了。

什么是 ONNX

很多开发者在玩 GitHub 的时候都有这样「悲痛」的经历,好不容易找到令人眼前一亮的项目,然而发现它使用我们不熟悉的框架写成。其实我们会发现很多优秀的视觉模型是用 Caffe 写的,很多新的研究论文是用 PyTorch 写的,而更多的模型用 TensorFlow 写成。因此如果我们要测试它们就必须拥有对应的框架环境,但 ONNX 交换格式令我们在同一环境下测试不同模型有了依靠。

简而言之 ONNX 就是一种框架间的转换格式,例如我们用 TensorFlow 写的模型可以转换为 ONNX 格式,并在 Caffe2 环境下运行该模型。

  • 项目地址:https://github.com/onnx/onnx

ONNX 定义了一种可扩展的计算图模型、一系列内置的运算单元(OP)和标准数据类型。每一个计算流图都定义为由节点组成的列表,并构建有向无环图。其中每一个节点都有一个或多个输入与输出,每一个节点称之为一个 OP。这相当于一种通用的计算图,不同深度学习框架构建的计算图都能转化为它。

如下所示,目前 ONNX 已经支持大多数框架,使用这些框架构建的模型可以转换为通用的 ONNX 计算图和 OP。现阶段 ONNX 只支持推理,所以导入的模型都需要在原框架完成训练。

其中 Frameworks 下的框架表示它们已经内嵌了 ONNX,开发者可以直接通过这些框架的内置 API 将模型导出为 ONNX 格式,或采用它们作为推理后端。而 Converters 下的框架并不直接支持 ONNX 格式,但是可以通过转换工具导入或导出这些框架的模型。

其实并不是所有框架都支持导入和导出 ONNX 格式的模型,有一些并不支持导入 ONNX 格式的模型,例如 PyTorch 和 Chainer 等,TensorFlow 的 ONNX 导入同样也正处于实验阶段。下图展示了各框架对 ONNX 格式的支持情况:

怎样使用 ONNX

对于内建了 ONNX 的框架而言,使用非常简单,只需要调用 API 导出或导入已训练模型就可以了。例如对 PyTorch 而言,只需要几个简单的步骤就能完成模型的导出和导入。简单而言,首先加载 torch.onnx 模块,然后导出预训练模型并查看模型结构信息,最后再将导出的 ONNX 模型加载到另外的框架就能执行推理了。

from torch.autograd import Variable
import torch.onnx
import torchvision

dummy_input = Variable(torch.randn(10, 3, 224, 224)).cuda()
model = torchvision.models.alexnet(pretrained=True).cuda()

input_names = [ "actual_input_1" ] + [ "learned_%d" % i for i in range(16) ]
output_names = [ "output1" ]

torch.onnx.export(model, dummy_input, "alexnet.onnx", verbose=True, input_names=input_names, output_names=output_names)

如上所示将导出 ONNX 格式的 AlexNet 模型,其中"alexnet.onnx"为保存的模型,input_names、output_names 和 verbose=True 都是为了打印出模型结构信息。同样随机产生的「图像」dummy_input 也是为了了解模型结构,因为我们可以通过它理解输入与每一层具体的参数维度。以下展示了 ONNX 输出的简要模型信息:

graph(%actual_input_1 : Float(10, 3, 224, 224)
      %learned_0 : Float(64, 3, 11, 11)
      %learned_1 : Float(64)
      # ---- omitted for brevity ----
      %learned_14 : Float(1000, 4096)
      %learned_15 : Float(1000)) {
  %17 : Float(10, 64, 55, 55) = onnx::Conv[dilations=[1, 1], group=1, kernel_shape=[11, 11], pads=[2, 2, 2, 2], strides=[4, 4]](%actual_input_1, %learned_0, %learned_1), scope: AlexNet/Sequential[features]/Conv2d[0]
  %18 : Float(10, 64, 55, 55) = onnx::Relu(%17), scope: AlexNet/Sequential[features]/ReLU[1]
  %19 : Float(10, 64, 27, 27) = onnx::MaxPool[kernel_shape=[3, 3], pads=[0, 0, 0, 0], strides=[2, 2]](%18), scope: AlexNet/Sequential[features]/MaxPool2d[2]
  # ---- omitted for brevity ----
  %output1 : Float(10, 1000) = onnx::Gemm[alpha=1, beta=1, broadcast=1, transB=1](%45, %learned_14, %learned_15), scope: AlexNet/Sequential[classifier]/Linear[6]
  return (%output1);
}

其实我们也可以借助 ONNX 检查中间表征,不过这里并不介绍。后面加载另外一个框架并执行推理同样非常简单。如下所示,我们可以从 caffe2 中加载 ONNX 的后端,并将前面保存的模型加载到该后端,从而在新框架下进行推理。这里我们能选择执行推理的硬件,并直接推理得出输出结果。

import caffe2.python.onnx.backend as backend
import numpy as np
import onnx

model = onnx.load("alexnet.onnx")
rep = backend.prepare(model, device="CUDA:0") # or "CPU"
outputs = rep.run(np.random.randn(10, 3, 224, 224).astype(np.float32))

其实也就两三行代码涉及 ONNX 的核心操作,即导出模型、加载模型和加载另一个框架的后端。TensorFlow 或 CNTK 等其它框架的具体 API 可能不一样,但主要过程也就这简单的几步。

怎样优化 ONNX

前面就已经介绍了 Model Zoo、ONNX Runtime 和 ONNX.JS,现在,我们可以具体看看它们都是什么,它们怎样才能帮助我们优化 ONNX 模型的选择与推理速度。

Model Zoo

ONNX Model Zoo 包含了一系列预训练模型,它们都是 ONNX 格式,且能获得当前最优的性能。因此只要下载这样的模型,我们本地不论是 TensorFlow 还是 MXNet,只要是只是能加载模型的框架,就能运行这些预训练模型。

  • 项目地址:https://github.com/onnx/models

更重要的是,这个 Model Zoo 不仅有调用预训练模型的代码,它还为每个预训练模型开放了对应的训练代码。训练和推理代码都是用 Jupyter Notebook 写的,数据和模型等都有对应的链接。

目前该 Model Zoo 主要从图像分类、检测与分割、图像超分辨、机器翻译语音识别等 14 个方向包含 19 种模型,还有更多的模型还在开发中。如下展示了图像分类中已经完成的模型,它们都是通用的 ONNX 格式。

此外在这次的研讨会中,Model Zoo 的维护者还和大家讨论了目前面临的问题及解决方法,例如目前的预训练模型主要集中在计算机视觉方面、ONNX 缺少一些特定的 OP、权重计算图下载慢等。因此 Model Zoo 接下来也会更关注其它语音和语言等模型,优化整个 GitHub 项目的下载结构。

ONNX Runtime

微软开源的 ONNX Runtime 推理引擎支持 ONNX 中定义的所有运算单元,它非常关注灵活性和推理性能。因此不论我们的开发环境是什么,Runtime 都会基于各种平台与硬件选择不同的自定义加速器,并希望以最小的计算延迟和资源占用完成推理。

  • 文档地址:https://docs.microsoft.com/en-us/python/api/overview/azure/onnx/intro

ONNX Runtime 可以自动调用各种硬件加速器,例如英伟达的 CUDA、TensorRT 和英特尔的 MKL-DNN、nGraph。如下所示,ONNX 格式的模型可以传入到蓝色部分的 Runtime,并自动完成计算图分割及并行化处理,最后我们只需要如橙色所示的输入数据和输出结果就行了。

其实在实际使用的时候,开发者根本不需要考虑蓝色的部分,不论是编译还是推理,代码都贼简单。如下所示,导入 onnxruntime 模块后,调用 InferenceSession() 方法就能导入 ONNX 格式的模型,并完成上图一系列复杂的优化。最后只需要 session.run() 就可以进行推理了,所有的优化过程都隐藏了细节。

import onnxruntime

session = onnxruntime.InferenceSession("your_model.onnx") 
prediction = session.run(None, {"input1": value})

在研讨会中,开发者表示 Runtime 的目标是构建高性能推理引擎,它需要利用最好的加速器和完整的平台支持。只需要几行代码就能把计算图优化一遍,这对 ONNX 格式的模型是个大福利。

ONNX.JS

ONNX.js 是一个在浏览器上运行 ONNX 模型的库,它采用了 WebAssembly 和 WebGL 技术,并在 CPU 或 GPU 上推理 ONNX 格式的预训练模型。

  • 项目地址:https://github.com/Microsoft/onnxjs

  • Demo 展示地址:https://microsoft.github.io/onnxjs-demo

通过 ONNX.js,开发者可以直接将预训练的 ONNX 模型部署到浏览器,这些预训练模型可以是 Model Zoo 中的,也可以是自行转换的。部署到浏览器有很大的优势,它能减少服务器与客户端之间的信息交流,并获得免安装和跨平台的机器学习模型体验。如下所示为部署到网页端的 SqueezeNet:

如上若是选择 GPU,它会采用 WebGL 访问 GPU。如果选择 CPU,那么其不仅会采用 WebAssembly 以接近原生的速度执行模型,同时也会采用 Web Workers 提供的「多线程」环境来并行化数据处理。该项目表明,通过充分利用 WebAssembly 和 Web Workers,CPU 可以获得很大的性能提升。这一点在项目提供的 Benchmarks 中也有相应的展示:

以上微软在 Chrome 和 Edge 浏览器中测试了 ResNet-50 的推理速度,其中比较显著的是 CPU 的推理速度。这主要是因为 Keras.js 和 TensorFlow.js 在任何浏览器中都不支持 WebAssembly。

最后,从 ONNXIFI 到 ONNX.js,开源社区已经为 ONNX 格式构建出众多的优化库、转换器和资源。很多需要支持多框架的场景也都将其作为默认的神经网络格式,也许以后,ONNX 真的能统一神经网络之间的江湖。

工程ONNX微软
51
相关数据
来也科技机构

「来也」是国内领先的人工智能交互平台,由常春藤盟校(Ivy League)归国博士和MBA团队发起,核心技术涵盖自然语言处理(NLP)、多轮对话控制和个性化推荐系统等。公司已获得数十项专利和国家高新技术企业认证。 来也的愿景是通过AI赋能,让每个人拥有助理。C 端产品小来是智能化的在线助理,通过业内创新的AI+Hi模式,提供日程、打车、咖啡、差旅和个性化查询等三十余项技能(覆盖400w用户和数十万服务者),让用户用自然语言发起需求并得到高效的满足。B端品牌吾来输出知识型的交互机器人和智能客户沟通系统,帮助各领域企业客户打造行业助理。目前已经在母婴,商旅,金融和汽车等行业的标杆企业实现商业化落地。

https://www.laiye.com/
英特尔机构

英特尔是计算创新领域的全球领先厂商,致力于拓展科技疆界,让最精彩体验成为可能。英特尔创始于1968年,已拥有近半个世纪产品创新和引领市场的经验。英特尔1971年推出了世界上第一个微处理器,后来又促进了计算机和互联网的革命,改变了整个世界的进程。如今,英特尔正转型成为一家数据公司,制定了清晰的数据战略,凭借云和数据中心、物联网、存储、FPGA以及5G构成的增长良性循环,提供独到价值,驱动日益发展的智能互联世界。英特尔专注于技术创新,同时也积极支持中国的自主创新,与产业伙伴携手推动智能互联的发展。基于明确的数据战略和智能互联全栈实力,英特尔瞄准人工智能、无人驾驶、5G、精准医疗、体育等关键领域,与中国深度合作。面向未来,英特尔致力于做中国高价值合作伙伴,在新科技、新经济、新消费三个方面,着力驱动产业协同创新,为实体经济增值,促进消费升级。

https://www.intel.com/content/www/us/en/company-overview/company-overview.html
相关技术
深度学习技术

深度学习(deep learning)是机器学习的分支,是一种试图使用包含复杂结构或由多重非线性变换构成的多个处理层对数据进行高层抽象的算法。 深度学习是机器学习中一种基于对数据进行表征学习的算法,至今已有数种深度学习框架,如卷积神经网络和深度置信网络和递归神经网络等已被应用在计算机视觉、语音识别、自然语言处理、音频识别与生物信息学等领域并获取了极好的效果。

权重技术

线性模型中特征的系数,或深度网络中的边。训练线性模型的目标是确定每个特征的理想权重。如果权重为 0,则相应的特征对模型来说没有任何贡献。

机器学习技术

机器学习是人工智能的一个分支,是一门多领域交叉学科,涉及概率论、统计学、逼近论、凸分析、计算复杂性理论等多门学科。机器学习理论主要是设计和分析一些让计算机可以自动“学习”的算法。因为学习算法中涉及了大量的统计学理论,机器学习与推断统计学联系尤为密切,也被称为统计学习理论。算法设计方面,机器学习理论关注可以实现的,行之有效的学习算法。

参数技术

在数学和统计学裡,参数(英语:parameter)是使用通用变量来建立函数和变量之间关系(当这种关系很难用方程来阐述时)的一个数量。

有向无环图技术

在图论中,如果一个有向图从任意顶点出发无法经过若干条边回到该点,则这个图是一个有向无环图(DAG图)。 因为有向图中一个点经过两种路线到达另一个点未必形成环,因此有向无环图未必能转化成树,但任何有向树均为有向无环图。

TensorFlow技术

TensorFlow是一个开源软件库,用于各种感知和语言理解任务的机器学习。目前被50个团队用于研究和生产许多Google商业产品,如语音识别、Gmail、Google 相册和搜索,其中许多产品曾使用过其前任软件DistBelief。

张量技术

张量是一个可用来表示在一些矢量、标量和其他张量之间的线性关系的多线性函数,这些线性关系的基本例子有内积、外积、线性映射以及笛卡儿积。其坐标在 维空间内,有 个分量的一种量,其中每个分量都是坐标的函数,而在坐标变换时,这些分量也依照某些规则作线性变换。称为该张量的秩或阶(与矩阵的秩和阶均无关系)。 在数学里,张量是一种几何实体,或者说广义上的“数量”。张量概念包括标量、矢量和线性算子。张量可以用坐标系统来表达,记作标量的数组,但它是定义为“不依赖于参照系的选择的”。张量在物理和工程学中很重要。例如在扩散张量成像中,表达器官对于水的在各个方向的微分透性的张量可以用来产生大脑的扫描图。工程上最重要的例子可能就是应力张量和应变张量了,它们都是二阶张量,对于一般线性材料他们之间的关系由一个四阶弹性张量来决定。

计算机视觉技术

计算机视觉(CV)是指机器感知环境的能力。这一技术类别中的经典任务有图像形成、图像处理、图像提取和图像的三维推理。目标识别和面部识别也是很重要的研究领域。

机器翻译技术

机器翻译(MT)是利用机器的力量「自动将一种自然语言(源语言)的文本翻译成另一种语言(目标语言)」。机器翻译方法通常可分成三大类:基于规则的机器翻译(RBMT)、统计机器翻译(SMT)和神经机器翻译(NMT)。

神经网络技术

(人工)神经网络是一种起源于 20 世纪 50 年代的监督式机器学习模型,那时候研究者构想了「感知器(perceptron)」的想法。这一领域的研究者通常被称为「联结主义者(Connectionist)」,因为这种模型模拟了人脑的功能。神经网络模型通常是通过反向传播算法应用梯度下降训练的。目前神经网络有两大主要类型,它们都是前馈神经网络:卷积神经网络(CNN)和循环神经网络(RNN),其中 RNN 又包含长短期记忆(LSTM)、门控循环单元(GRU)等等。深度学习是一种主要应用于神经网络帮助其取得更好结果的技术。尽管神经网络主要用于监督学习,但也有一些为无监督学习设计的变体,比如自动编码器和生成对抗网络(GAN)。

Alex网络技术

AlexNet是一个卷积神经网络的名字,最初是与CUDA一起使用GPU支持运行的,AlexNet是2012年ImageNet竞赛冠军获得者Alex Krizhevsky设计的。该网络达错误率大大减小了15.3%,比亚军高出10.8个百分点。AlexNet是由SuperVision组设计的,由Alex Krizhevsky, Geoffrey Hinton和Ilya Sutskever组成。

语音识别技术

自动语音识别是一种将口头语音转换为实时可读文本的技术。自动语音识别也称为语音识别(Speech Recognition)或计算机语音识别(Computer Speech Recognition)。自动语音识别是一个多学科交叉的领域,它与声学、语音学、语言学、数字信号处理理论、信息论、计算机科学等众多学科紧密相连。由于语音信号的多样性和复杂性,目前的语音识别系统只能在一定的限制条件下获得满意的性能,或者说只能应用于某些特定的场合。自动语音识别在人工智能领域占据着极其重要的位置。

MXNet技术

MXNet是开源的,用来训练部署深层神经网络的深度学习框架。它是可扩展的,允许快速模型训练,并灵活支持多种语言(C ++,Python,Julia,Matlab,JavaScript, Go,R,Scala,Perl,Wolfram语言)

推理引擎技术

推理机是实施问题求解的核心执行机构,常见于专家系统。它是对知识进行解释的程序,根据知识的语义,对按一定策略找到的知识进行解释执行,并把结果记录到动态库的适当空间中去。

图像分类技术

图像分类,根据各自在图像信息中所反映的不同特征,把不同类别的目标区分开来的图像处理方法。它利用计算机对图像进行定量分析,把图像或图像中的每个像元或区域划归为若干个类别中的某一种,以代替人的视觉判读。

Jupyter技术

Jupyter Notebook(此前被称为 IPython notebook)是一个交互式笔记本,支持运行 40 多种编程语言。 Jupyter Notebook 的本质是一个 Web 应用程序,便于创建和共享文学化程序文档,支持实时代码,数学方程,可视化和 markdown。 用途包括:数据清理和转换,数值模拟,统计建模,机器学习等等 。

推荐文章
真棒👍