Open Neural Network Exchange

Open Neural Network Exchange（略称：ONNX）とは、オープンソースで開発されている機械学習や人工知能のモデルを表現する為の代表的なフォーマットである。実行エンジンとしてONNX Runtimeも開発されている。
概要.
機械学習、特にニューラルネットワークモデルは様々なフレームワーク上で学習され、また様々なハードウェア上で実行（推論）される。各環境に特化したモデルは他のフレームワーク・ハードウェアで利用できず相互運用性を欠いてしまう。また実装者は環境ごとにサポートをおこなう必要があり大きな労力を必要とする。
ONNXはモデルを記述する統一インターフェース（フォーマット）を提供し、これらの問題を解決する。各フレームワークは学習したモデルをONNX形式で出力する。各ハードウェアはONNX実行環境を提供することで、どのフレームワークで学習されたかを問わずモデル推論を実行する。このように相互運用可能なモデルフォーマットとしてONNXは開発されている。
2017年に開発が開始された。
開発背景.
以下の特性を補完する意図にて開発が進められた。
フレームワークの相互運用性.
開発工程や機械学習の高速処理、ネットワークの基本設計における柔軟性やモバイルデバイスでの推論などの特定の段階において、開発者が複数のフレームワークでのデータのやり取りを簡単に行えるようにする。
最適化の共有.
ハードウェアベンダーなどは、ONNXを対象に調整を行うことで、複数のフレームワークにおけるニューラルネットワークのパフォーマンスを一度に改善することができる。
沿革.
2017年9月に、FacebookとMicrosoftは、PyTorchやCaffe2などの機械学習フレームワーク間において相互運用を可能にする為の取り組みとして、このプロジェクトを始動した。その後、IBM、Huawei、Intel、AMD、ARM、Qualcommがこの取り組みに対して積極的な支援を表明した。
2017年10月に、MicrosoftはCognitive ToolkitおよびProject Brainwaveプラットフォームにおいて、ONNXのサポートを発表した。
2019年11月、ONNXはLinux Foundation AIの卒業生プロジェクトとして承認された。 
構成.
ONNXは、推論（評価）に焦点を当て、拡張可能な計算グラフモデル、組み込み演算子、および標準データ型の定義を提供する。
それぞれのデータフローグラフは、有向非巡回グラフを形成するノードのリストになっている。ノードには入力と出力があり、各ノードが処理を呼び出すようになっている。メタデータはグラフを文書化する。組み込み演算子は、ONNXをサポートする各フレームワークで利用可能である。
グラフは Protocol Buffers を使用して拡張子 .onnx のバイナリファイルとして保存可能である。このファイルは様々な機械学習のライブラリから読み書き可能である。
ONNX仕様は2つのサブ仕様、IRとOperatorからなる。この2つの仕様はそれぞれバージョニングされており、ONNX仕様のバージョンはこの2つのサブ仕様の特定版を指定したものとなっている。2021-12-22現在の最新バージョンは version 1.10.2 であり、これはIR v8とOperator v15-v2-v1 から成る。
ONNX IR.
Open Neural Network Exchange Intermediate Representation (ONNX IR) はONNXの基本データ型と計算グラフを定義するサブ仕様である。ONNX IRは計算グラフを構成する codice_1, codice_2, codice_3 等の要素、入出力 codice_4, codice_5, codice_6 およびデータ codice_7, codice_8, codice_9 等の基本データ型を定義する。2021-12-22現在の最新バージョンは version 8 である。 
ONNX IRが定義する要素として以下が挙げられる。 
すなわちcodice_2に収納された各codice_3が入出力をもった演算 (例: Conv) になっており、Node/Graph入出力名に基づいてNode群がグラフ構造を取っている。
拡張演算子.
ONNX IRはONNX Operatorで定義される標準演算子に追加して、独自の拡張演算子を受け入れられるように設計されている。これによりONNXの "Extensible/拡張可能" 特性を実現している。拡張演算子セットを codice_1 の codice_30 属性に指定することで実行エンジン側へ拡張演算子の利用を通知する仕組みである。ONNXを受け取った実行エンジンは codice_30 を確認し、指定された演算子セット全てをサポートしていれば受け入れ、そうでなければ codice_1 全体を拒絶する。
ONNX Operator.
ONNXのビルトイン演算子はサブ仕様 Operator specifications により定義される。3種類の演算子セット（Opset）codice_33, codice_34, codice_35 が定義されており、codice_33 がデフォルトである。2022年12月12日現在、codice_33 の最新バージョンは version 18 である。 
例えばOpset codice_33 v15ではRNN系演算子として codice_39 、codice_40 、codice_41 が定義されている。 
量子化.
ONNXは入出力の量子化やそれに対する操作を演算子として持つ。codice_42はスケール・シフトパラメータに基づく線形量子化をおこなう。codice_43は入力ベクトルのmin/maxに基づく動的uint8量子化をおこなう。int8入力に対する演算にはcodice_44、codice_45、codice_46、codice_47などがある。
ONNX Runtime.
ONNX Runtime (略称: ORT) は様々な環境におけるONNXモデルの推論・学習高速化を目的としたオープンソースプロジェクトである。フレームワーク・OS・ハードウェアを問わず単一のRuntime APIを介してONNXモデルを利用できる。またデプロイ環境に合わせた最適化を自動でおこなう。ONNX Runtimeは設計方針としてアクセラレータ・ランタイム抽象化とパフォーマンス最適化の両立を掲げており、ONNXモデルの自動分割と最適アクセラレータによるサブモデル実行によりこれを実現している。
ONNX Runtimeがサポートする最適化には以下が挙げられる。
対応するバックエンドに関しては#ONNXバックエンドを参照。
ONNXモデル.
ONNXのモデルはPythonスクリプトから生成したり（#例を参照）、他のフレームワークから変換したりすることで作ることができる。他のフレームワークからの変換には以下のような方法が存在する：
またONNXのモデル集としては以下が存在する；
ONNXバックエンド.
ONNX Runtime は共有ライブラリの Execution Providers によって多数のバックエンドをサポートしている。これには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 バックエンドなどが存在する。
また ONNX からNVIDIA GPU向けのTensorRTバイナリ (.trt) を生成するものとして NVIDIA の Polygraphy や trtexec も存在する。
また OONX を LLVM の MLIR によってコンパイルするための onnx-mlir も存在する。
例.
線形回帰モデルの学習結果として formula_1 が得られたとして、それを 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]