概要
ONNX(Open Neural Network Exchange:オープン・ニューラル・ネットワーク・エクスチェンジ)は、機械学習・ディープラーニングモデルを異なるフレームワーク間で交換・共有するための共通フォーマット(標準規格)です。2017年にMicrosoftとFacebookが共同で提案し、現在はLinux Foundation傘下のAI標準化プロジェクトとして多くの企業が参加しています。
ONNX登場の背景:
機械学習フレームワークはTensorFlow・PyTorch・MXNet・Caffe2など多数が存在し、それぞれ独自のモデル形式を持っていました。これにより以下の問題が生じていました。
- PyTorchで学習したモデルをモバイル向けTFLiteに変換するのが困難
- フレームワークごとに異なるデプロイツールが必要
- 推論エンジンの最適化がフレームワーク依存で断片化
ONNXはこれらの問題を「共通の中間表現フォーマット」として解決します。
[学習フェーズ] [推論フェーズ]
PyTorch ──┐ ┌── ONNX Runtime
TensorFlow─┤→ ONNX形式 → 変換 →┤── TensorRT
MXNet ────┘ (.onnx) ├── OpenVINO
JAX ──────┘ ├── CoreML
├── TFLite
└── 独自NPUランタイム
歴史・背景
| 年 | 出来事 |
|---|---|
| 2017年9月 | MicrosoftとFacebookがONNX v1.0を共同発表 |
| 2018年 | IBMなど多数の企業がコミュニティに参加 |
| 2019年 | ONNX Runtime(ORT)v1.0リリース |
| 2020年 | Linux Foundation AI配下に移管 |
| 2021年 | ONNX Runtime MobileがiOS/Android対応 |
| 2022年 | ONNXオペレータセット v17、量子化演算子強化 |
| 2023年 | ONNX Runtime v1.16、LLM向け大規模推論対応 |
| 2024年 | ONNX v22、スパース演算・動的形状の改善 |
参加企業・プロジェクト(主要なもの):
Microsoft、Meta(Facebook)、IBM、Intel、NVIDIA、Qualcomm、ARM、AMD、Baidu、Apple(非公式ながらCore ML変換サポート)、など100社超が参加。
技術仕様
ファイルフォーマット
ONNXはProtocol Buffers(protobuf)を使って定義されています。.onnxファイルはバイナリprotobuf形式です。
// onnx.proto3の主要定義(簡略版)
message ModelProto {
int64 ir_version = 1; // IR(中間表現)バージョン
repeated OperatorSetIdProto opset_import = 8;
string domain = 2;
int64 model_version = 5;
string doc_string = 6;
GraphProto graph = 7; // 計算グラフ
repeated TensorProto initializer = 11; // 重みデータ
}
message GraphProto {
repeated NodeProto node = 1; // 演算ノードのリスト
string name = 2;
repeated TensorProto initializer = 5; // 定数テンソル
repeated ValueInfoProto input = 11;
repeated ValueInfoProto output = 12;
}
message NodeProto {
repeated string input = 1; // 入力テンソル名
repeated string output = 2; // 出力テンソル名
string name = 3;
string op_type = 4; // 演算子種別(Conv, ReLU, etc)
string domain = 7;
repeated AttributeProto attribute = 5;
}
オペレータセット(opset)
ONNXは演算子の集合を「オペレータセット」としてバージョン管理します。モデルはどのopsetバージョンを使っているかを明示します。
import onnx
model = onnx.load('model.onnx')
print(f"IR Version: {model.ir_version}")
for opset in model.opset_import:
print(f"Opset: domain={opset.domain!r}, "
f"version={opset.version}")
# 出力例:
# IR Version: 8
# Opset: domain='', version=17
主要演算子カテゴリ
| カテゴリ | 演算子例 |
|---|---|
| たたみ込み | Conv, ConvTranspose, DepthwiseConv |
| プーリング | MaxPool, AveragePool, GlobalAveragePool |
| 活性化 | Relu, Sigmoid, Tanh, Softmax, Gelu |
| 正規化 | BatchNormalization, LayerNormalization |
| 変形 | Reshape, Transpose, Concat, Split, Slice |
| 演算 | Add, Mul, Gemm, MatMul, Pad |
| リカレント | LSTM, GRU, RNN |
| 量子化 | QuantizeLinear, DequantizeLinear |
テンソルデータ型
| 型名 | 説明 | バイト数 |
|---|---|---|
| FLOAT | 32bit浮動小数点 | 4 |
| DOUBLE | 64bit浮動小数点 | 8 |
| FLOAT16 | 16bit浮動小数点 | 2 |
| BFLOAT16 | Brain Float 16 | 2 |
| INT8 | 8bit符号付き整数 | 1 |
| UINT8 | 8bit符号なし整数 | 1 |
| INT16/INT32/INT64 | 整数型 | 2/4/8 |
| BOOL | 論理値 | 1 |
動作原理
モデル変換の流れ
# PyTorch → ONNX 変換例
import torch
import torch.onnx
# 学習済みモデル
model = MyModel()
model.load_state_dict(torch.load('weights.pth'))
model.eval()
# ダミー入力(形状の確認用)
dummy_input = torch.randn(1, 3, 224, 224)
# ONNX形式でエクスポート
torch.onnx.export(
model,
dummy_input,
'model.onnx',
export_params=True, # 重みを含める
opset_version=17, # opsetバージョン
do_constant_folding=True, # 定数畳み込み最適化
input_names=['input'],
output_names=['output'],
dynamic_axes={ # 動的バッチサイズ対応
'input': {0: 'batch_size'},
'output': {0: 'batch_size'}
}
)
print("ONNX変換完了")
# TensorFlow / Keras → ONNX 変換例
import tf2onnx
import tensorflow as tf
model = tf.keras.models.load_model('model.h5')
# 変換
onnx_model, _ = tf2onnx.convert.from_keras(
model,
opset=17
)
import onnx
onnx.save(onnx_model, 'model.onnx')
ONNXモデルの検証と最適化
import onnx
from onnxruntime.tools import optimizer
# モデルの妥当性チェック
model = onnx.load('model.onnx')
onnx.checker.check_model(model)
print("モデル検証OK")
# グラフの最適化(Fusion、定数折り畳みなど)
optimized_model = optimizer.optimize_model(
'model.onnx',
model_type='bert', # bert, gpt2, vit など
optimization_level=99
)
optimized_model.save_model_to_file('model_opt.onnx')
ONNX Runtime での推論
import onnxruntime as ort
import numpy as np
# セッション作成(EPを指定可能)
session_options = ort.SessionOptions()
session_options.graph_optimization_level = (
ort.GraphOptimizationLevel.ORT_ENABLE_ALL
)
# Execution Provider(実行バックエンド)の選択
providers = [
('CUDAExecutionProvider', {'device_id': 0}), # GPU
'CPUExecutionProvider' # フォールバック
]
session = ort.InferenceSession(
'model.onnx',
session_options,
providers=providers
)
# 入力情報確認
input_name = session.get_inputs()[0].name
input_shape = session.get_inputs()[0].shape
print(f"入力: {input_name}, shape={input_shape}")
# 推論実行
input_data = np.random.randn(1, 3, 224, 224).astype(np.float32)
outputs = session.run(None, {input_name: input_data})
print(f"出力shape: {outputs[0].shape}")
ONNX量子化(INT8への変換)
from onnxruntime.quantization import quantize_dynamic, QuantType
# ダイナミック量子化(キャリブレーション不要)
quantize_dynamic(
model_input='model.onnx',
model_output='model_int8.onnx',
weight_type=QuantType.QInt8
)
# 静的量子化(高精度、キャリブレーション必要)
from onnxruntime.quantization import quantize_static, CalibrationDataReader
class MyCalibrationReader(CalibrationDataReader):
def get_next(self):
# キャリブレーション用データを返す
return {'input': calibration_data}
quantize_static(
model_input='model.onnx',
model_output='model_static_int8.onnx',
calibration_data_reader=MyCalibrationReader()
)
用途・ユースケース
フレームワーク間の移植
研究目的でPyTorchを使って学習したモデルを、本番環境のTensorRT(NVIDIA GPU)やOpenVINO(Intel)に展開する際に、ONNXが橋渡しとなります。
研究環境 → ONNX → 本番環境
PyTorch (研究) TensorRT (NVIDIA GPU)
TensorFlow (研究) OpenVINO (Intel)
JAX (Google) CoreML (Apple)
MXNet (AWS) ORT Mobile (スマートフォン)
エッジデバイスへのデプロイ
ONNX RuntimeはAndroid/iOSのモバイルアプリにも組み込め、ONNXモデルを直接実行できます。
// Android での ORT Mobile 使用例 (Java)
OrtEnvironment env = OrtEnvironment.getEnvironment();
OrtSession session = env.createSession(
"model.onnx",
new OrtSession.SessionOptions()
);
Map<String, OnnxTensor> inputs = Map.of(
"input",
OnnxTensor.createTensor(env, inputData)
);
OrtSession.Result results = session.run(inputs);
AIモデル開発エコシステム
ONNX Model Zooには事前学習済みの標準モデルが公開されており、すぐに推論に使えます。
| モデル | タスク | サイズ |
|---|---|---|
| ResNet-50 | 画像分類 | 約100MB |
| MobileNetV2 | 画像分類 | 約14MB |
| YOLOv8n | 物体検出 | 約6MB |
| BERT-base | 自然言語処理 | 約400MB |
| Whisper-tiny | 音声認識 | 約39MB |
実装・開発のポイント
ONNXモデルの可視化
Netronを使ってONNXモデルの計算グラフをブラウザで視覚化できます。
# Netronをインストールして使用
pip install netron
netron model.onnx
# → ブラウザでインタラクティブなグラフが開く
デバッグ:中間テンソルの確認
import onnxruntime as ort
import onnx
# 全ノードの出力を可視化用に追加
model = onnx.load('model.onnx')
for node in model.graph.node:
for output in node.output:
if output not in [o.name for o in model.graph.output]:
model.graph.output.extend([
onnx.helper.make_tensor_value_info(
output, onnx.TensorProto.FLOAT, None)
])
session = ort.InferenceSession(
model.SerializeToString()
)
results = session.run(None, {'input': input_data})
# 全中間テンソルの値を確認可能
各フレームワークからの変換ツール
| 元フレームワーク | 変換ツール | コマンド例 |
|---|---|---|
| PyTorch | torch.onnx | torch.onnx.export(model, ...) |
| TensorFlow/Keras | tf2onnx | python -m tf2onnx.convert --saved-model ... |
| scikit-learn | sklearn-onnx | to_onnx(clf, X_train) |
| LightGBM | onnxmltools | convert_lightgbm(model, ...) |
| PaddlePaddle | paddle2onnx | paddle2onnx --model_dir ... |
他技術との比較
| 比較軸 | ONNX | TFLite | CoreML | TensorRT |
|---|---|---|---|---|
| 汎用性 | 最高 | 中 | Apple専用 | NVIDIA専用 |
| エコシステム | 最大 | 大 | Apple向け | GPU向け |
| MCU対応 | △(ORT Mobile) | ○(TFLite Micro) | × | × |
| 変換の容易さ | 高 | 中(TF限定が多い) | 中 | 難(独自形式) |
| 推論性能 | 高 | 高 | 高(Apple) | 最高(NVIDIA) |
| 量子化 | INT8対応 | INT8対応 | INT8対応 | INT8/FP16対応 |
ONNXはエッジAIエコシステムの中で「共通語」として機能します。TensorFlow Liteや推論アクセラレータと組み合わせることで、フレームワークを問わず最適なハードウェアへのデプロイが可能になります。量子化もONNX上で直接実施でき、学習済みモデルの配布形式としても広く採用されています。