Open Neural Network Exchange(略称:ONNX)とは、オープンソースで開発されている機械学習や人工知能のモデルを表現する為の代表的なフォーマットである[3]。実行エンジンとしてONNX Runtimeも開発されている。
機械学習、特にニューラルネットワークモデルは様々なフレームワーク上で学習され、また様々なハードウェア上で実行(推論)される。各環境に特化したモデルは他のフレームワーク・ハードウェアで利用できず相互運用性を欠いてしまう。また実装者は環境ごとにサポートをおこなう必要があり大きな労力を必要とする。
ONNXはモデルを記述する統一インターフェース(フォーマット)を提供し、これらの問題を解決する。各フレームワークは学習したモデルをONNX形式で出力する。各ハードウェアはONNX実行環境を提供することで、どのフレームワークで学習されたかを問わずモデル推論を実行する。このように相互運用可能なモデルフォーマットとしてONNXは開発されている。
2017年に開発が開始された。
以下の特性を補完する意図にて開発が進められた。
開発工程や機械学習の高速処理、ネットワークの基本設計における柔軟性やモバイルデバイスでの推論などの特定の段階において、開発者が複数のフレームワークでのデータのやり取りを簡単に行えるようにする[4]。
ハードウェアベンダーなどは、ONNXを対象に調整を行うことで、複数のフレームワークにおけるニューラルネットワークのパフォーマンスを一度に改善することができる[4]。
2017年9月に、FacebookとMicrosoftは、PyTorchやCaffe2などの機械学習フレームワーク間において相互運用を可能にする為の取り組みとして、このプロジェクトを始動した。その後、IBM、Huawei、Intel、AMD、ARM、Qualcommがこの取り組みに対して積極的な支援を表明した[3]。
2017年10月に、MicrosoftはCognitive ToolkitおよびProject Brainwaveプラットフォームにおいて、ONNXのサポートを発表した[3]。
2019年11月、ONNXはLinux Foundation AIの卒業生プロジェクトとして承認された。
ONNXは、推論(評価)に焦点を当て、拡張可能な計算グラフモデル、組み込み演算子、および標準データ型の定義を提供する[4]。
それぞれのデータフローグラフは、有向非巡回グラフを形成するノードのリストになっている。ノードには入力と出力があり、各ノードが処理を呼び出すようになっている。メタデータはグラフを文書化する。組み込み演算子は、ONNXをサポートする各フレームワークで利用可能である[4]。
グラフは Protocol Buffers を使用して拡張子 .onnx のバイナリファイルとして保存可能である[5]。このファイルは様々な機械学習のライブラリから読み書き可能である。
ONNX仕様は2つのサブ仕様、IRとOperatorからなる。この2つの仕様はそれぞれバージョニングされており、ONNX仕様のバージョンはこの2つのサブ仕様の特定版を指定したものとなっている。2021-12-22現在の最新バージョンは version 1.10.2 であり、これはIR v8とOperator v15-v2-v1 から成る[6]。
Open Neural Network Exchange Intermediate Representation (ONNX IR) はONNXの基本データ型と計算グラフを定義するサブ仕様である[7]。ONNX IRは計算グラフを構成する Model, Graph, Node 等の要素、入出力 Tensor, Sequence, Map およびデータ FLOAT, INT8, BFLOAT16 等の基本データ型を定義する。2021-12-22現在の最新バージョンは version 8 である[6]。
Model
Graph
Node
Tensor
Sequence
Map
FLOAT
INT8
BFLOAT16
ONNX IRが定義する要素として以下が挙げられる。
input
initializer
output
node
name
doc_string
value_info
domain
op_type
attribute
すなわちGraphに収納された各Nodeが入出力をもった演算 (例: Conv) になっており、Node/Graph入出力名に基づいてNode群がグラフ構造を取っている。
ONNX IRはONNX Operatorで定義される標準演算子に追加して、独自の拡張演算子を受け入れられるように設計されている[10]。これによりONNXの "Extensible/拡張可能" 特性を実現している[11]。拡張演算子セットを Model の opset_import 属性に指定することで実行エンジン側へ拡張演算子の利用を通知する仕組みである[12]。ONNXを受け取った実行エンジンは opset_import を確認し、指定された演算子セット全てをサポートしていれば受け入れ、そうでなければ Model 全体を拒絶する[13]。
opset_import
ONNXのビルトイン演算子はサブ仕様 Operator specifications により定義される[14]。3種類の演算子セット(Opset)ai.onnx, ai.onnx.ml, ai.onnx.training が定義されており、ai.onnx がデフォルトである。2022年12月12日現在、ai.onnx の最新バージョンは version 18 である[6]。
ai.onnx
ai.onnx.ml
ai.onnx.training
例えばOpset ai.onnx v15ではRNN系演算子として RNN 、LSTM 、GRU が定義されている。
RNN
LSTM
GRU
ONNXは入出力の量子化やそれに対する操作を演算子として持つ。QuantizeLinearはスケール・シフトパラメータに基づく線形量子化をおこなう[15]。DynamicQuantizeLinearは入力ベクトルのmin/maxに基づく動的uint8量子化をおこなう[16]。int8入力に対する演算にはMatMulInteger、QLinearMatMul、ConvInteger、QLinearConvなどがある。
QuantizeLinear
DynamicQuantizeLinear
MatMulInteger
QLinearMatMul
ConvInteger
QLinearConv
ONNX Runtime (略称: ORT[17]) は様々な環境におけるONNXモデルの推論・学習高速化を目的としたオープンソースプロジェクトである[18]。フレームワーク・OS・ハードウェアを問わず単一のRuntime APIを介してONNXモデルを利用できる[19]。またデプロイ環境に合わせた最適化を自動でおこなう[20]。ONNX Runtimeは設計方針としてアクセラレータ・ランタイム抽象化とパフォーマンス最適化の両立を掲げており、ONNXモデルの自動分割と最適アクセラレータによるサブモデル実行によりこれを実現している[21]。
ONNX Runtimeがサポートする最適化には以下が挙げられる。
ONNX Runtime は共有ライブラリの Execution Providers によって多数のバックエンドをサポートしている[27]。これにはIntel の OpenVINO バックエンド (onnxruntime-openvino) 及び oneDNN バックエンド、NVIDIAの CUDA バックエンド (onnxruntime-gpu) 及び TensorRT バックエンド (onnxruntime-gpu)、AMDの ROCm バックエンド及び MIGraphX バックエンド、Windows の DirectML バックエンド (onnxruntime-directmlなど)、macOS / iOS の CoreML バックエンド、Android の NNAPI バックエンド、Microsoft Azure向けの Azure バックエンドなどが存在する[28][27]。
以下のデバイスがONNX Runtimeに対応している。[29]
主要なデバイスとしては Google の TPU, Edge TPU、AWS の Trainium, Inferentia が対応していない。Edge TPU は LiteRT のみだが、それ以外のデバイスは、JAX、TensorFlow、PyTorch に対応しているので、これらに変換することで動作し、AWS は Trainium, Inferentia は PyTorch 経由の動作を薦めている[38]。
ONNX Runtime Webはウェブブラウザを含めたJavaScript上で動作するONNX Rutime。Execution Providerとして、Web Neural Network (WebNN)、WebGPU、WebGL、WebAssemblyが利用可能である。WebNNはONNXのようにニューラルネットワークのモデルを表現できるので、GPUやNPUなどのアクセラレーションが有効であれば、これが最速である。WindowsではWebNNからDirectML経由でGPUやNPUで実行される。[39][40][41]
ONNXのモデルはPythonスクリプトから生成したり(#例を参照)、他のフレームワークから変換したりすることで作ることができる。他のフレームワークからの変換には以下のような方法が存在する:
ONNXのモデル集としては以下が存在する。
線形回帰モデルの学習結果として y = 2 x + 3 {\displaystyle y=2x+3} が得られたとして、それを ONNX ファイルに保存する Python での実装例。
import numpy as np import onnx from onnx import TensorProto, numpy_helper from onnx.helper import make_model, make_node, make_graph, make_tensor_value_info A = numpy_helper.from_array(np.array(2.0), "A") B = numpy_helper.from_array(np.array(3.0), "B") X = make_tensor_value_info("X", TensorProto.DOUBLE, []) Y = make_tensor_value_info("Y", TensorProto.DOUBLE, []) graph = make_graph([ make_node("Mul", ["A", "X"], ["AX"]), make_node("Add", ["AX", "B"], ["Y"]), ], "Linear Regression", [X], [Y], [A, B]) onnx.save(make_model(graph), "2x_3.onnx")
それを ONNX Runtime を使い実行する Python での実装例。
import numpy as np import onnxruntime as ort ort_sess = ort.InferenceSession("2x_3.onnx") y = ort_sess.run(None, {"X": np.array(4.0)})[0]