1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【第2回】ONNXの仕組みを理解しよう - グラフ・オペレータ・データ型

1
Posted at

ねらい

ONNXモデルの内部構造を理解し、変換時のトラブルに対処できるようになる。

対象

  • 第1回を読んでONNXの概要を理解した人
  • モデル変換でエラーに遭遇して困っている人
  • 「中身がどうなっているか」が気になる人

ゴール

  • ONNXモデルの構造(グラフ、ノード、オペレータ)を説明できる
  • opset versionの意味と重要性を理解する
  • 変換エラーの原因を推測できるようになる

TL;DR

  • ONNXモデル = 計算グラフ(DAG) をProtocol Buffersでシリアライズしたもの
  • グラフはノード(演算) と エッジ(データフロー) で構成
  • オペレータ は演算の種類(Add, MatMul, Conv など)
  • opset version でオペレータの仕様が決まる(互換性に要注意)

ONNXモデルの全体像

まず、ONNXモデルがどんな構造になっているか見てみよう。

The Open Neural Network Exchange (ONNX) represents machine learning models as a directed acyclic graph (DAG), which captures the computational topology of the model through a sequence of operations without cycles.

(Open Neural Network Exchange(ONNX)は、機械学習モデルを有向非巡回グラフ(DAG)として表現する。これは、サイクルのない一連の演算を通じてモデルの計算トポロジーをキャプチャする。)

出典: Grokipedia - Open Neural Network Exchange

ポイントは DAG(Directed Acyclic Graph、有向非巡回グラフ) という構造だ。

DAGってなに?

難しそうな名前だが、概念はシンプル。

  • Directed(有向): 矢印に向きがある
  • Acyclic(非巡回): ループがない
  • Graph(グラフ): 点と線でできている

つまり、「一方通行で、同じ場所に戻ってこない」経路図のようなもの。

ニューラルネットワークを思い浮かべてほしい。入力が入って、いくつかの層を通過して、出力が出る。途中で戻ったりしない。まさにDAGだ。

入力 → [Conv] → [ReLU] → [MaxPool] → [Linear] → 出力

この各ステップ(Conv, ReLU, etc.)が「ノード」、矢印が「エッジ」に相当する。


ONNXモデルの内部構造

ONNXモデルは .onnx という拡張子のファイルに保存される。中身を詳しく見てみよう。

The entire model is serialized into a compact binary file with the .onnx extension using Protocol Buffers, enabling efficient storage, transmission, and parsing across diverse environments.

(モデル全体はProtocol Buffersを使用して.onnx拡張子のコンパクトなバイナリファイルにシリアライズされ、多様な環境間での効率的な保存、転送、解析を可能にする。)

出典: Grokipedia - Open Neural Network Exchange

Protocol Buffersとは

Googleが開発したデータシリアライゼーション形式。JSONやXMLの仲間だが、バイナリ形式なのでコンパクトで高速。

JSON: {"name": "Alice", "age": 30}  → 人間に読みやすい、ファイルサイズ大
Protobuf: [バイナリ]                 → 人間に読めない、ファイルサイズ小

機械学習モデルは巨大になりがちなので、この「コンパクトさ」が重要になる。

ModelProtoの構造

ONNXモデルの最上位構造は ModelProto と呼ばれる。

At the core of an ONNX model is the ModelProto structure, which encapsulates the graph along with essential metadata.

(ONNXモデルの中心にはModelProto構造があり、グラフと必要なメタデータをカプセル化している。)

ModelProtoには以下の要素が含まれる:

ModelProto
├── ir_version        # ONNX IRのバージョン
├── opset_import      # 使用するopsetのバージョン
├── producer_name     # 生成したツール名(例: pytorch)
├── producer_version  # 生成したツールのバージョン
├── domain           # モデルのドメイン
├── model_version    # モデルのバージョン
├── doc_string       # ドキュメント(Markdown可)
├── graph            # ★ 計算グラフ本体
└── metadata_props   # その他のメタデータ

グラフの構成要素

graph の中身をさらに詳しく見てみよう。

The graph itself consists of nodes that define operations, input and output tensors that specify data shapes and types, initializers for constant tensors (such as weights and biases), and attributes that provide fixed parameters to operations.

(グラフ自体は、演算を定義するノード、データの形状と型を指定する入出力テンソル、定数テンソル(重みやバイアスなど)のためのイニシャライザ、および演算に固定パラメータを提供するアトリビュートで構成される。)

1. ノード(Node)

グラフの「点」に相当する部分。各ノードは1つの演算を表す。

ノード
├── op_type    # 演算の種類("Add", "MatMul", "Conv" など)
├── inputs     # 入力テンソルの名前リスト
├── outputs    # 出力テンソルの名前リスト
└── attributes # 演算固有のパラメータ

例えば、行列の掛け算をするノードはこんな感じ:

Node: MatMul
├── op_type: "MatMul"
├── inputs: ["X", "W"]
├── outputs: ["Y"]
└── attributes: {}

2. テンソル(Tensor)

データの入れ物。NumPyのndarrayに相当する。

A tensor is a multidimensional array. It is defined by: a type: the element type, the same for all elements in the tensor; a shape: an array with all dimensions, this array can be empty, a dimension can be null.

(テンソルは多次元配列である。テンソルは以下によって定義される:型(要素の型、テンソル内のすべての要素で同じ)、形状(すべての次元を含む配列、この配列は空でもよく、次元はnullでもよい)。)

出典: ONNX Documentation - Concepts

サポートされているデータ型:

ONNX型 説明 NumPy相当
FLOAT 32bit浮動小数点 float32
FLOAT16 16bit浮動小数点 float16
DOUBLE 64bit浮動小数点 float64
INT8 8bit整数 int8
INT32 32bit整数 int32
INT64 64bit整数 int64
BOOL 真偽値 bool
STRING 文字列 object

3. イニシャライザ(Initializer)

学習済みの重みやバイアスを保持する部分。

モデルを動かすとき、入力データは毎回変わるが、重みは(推論時には)固定だ。この「固定の値」をイニシャライザに格納する。

Initializer: W
├── name: "W"
├── data_type: FLOAT
├── dims: [784, 128]
└── raw_data: [バイナリデータ]

4. アトリビュート(Attribute)

演算の「設定値」。例えば、畳み込み層のカーネルサイズやストライドなど。

An attribute is a fixed parameter of an operator. Operator Gemm has four attributes, alpha, beta, transA, transB. Unless the runtime allows it through its API, once it has loaded the ONNX graph, these values cannot be changed.

(アトリビュートは演算子の固定パラメータである。演算子Gemmには4つのアトリビュート(alpha、beta、transA、transB)がある。ランタイムがAPIを通じて許可しない限り、ONNXグラフがロードされた後、これらの値は変更できない。)

出典: ONNX Documentation - Concepts

重要なのは、アトリビュートは固定 ということ。推論時に動的に変えることはできない。


オペレータの世界

ONNXの心臓部とも言えるのが オペレータ(Operator) だ。

The main list is described here: ONNX Operators. It merges standard matrix operators (Add, Sub, MatMul, Transpose, Greater, IsNaN, Shape, Reshape…), reductions (ReduceSum, ReduceMin, …) image transformations (Conv, MaxPool, …), deep neural networks layer (RNN, DropOut, …), activations functions (Relu, Softmax, …).

(メインリストはONNX Operatorsに記載されている。これには、標準的な行列演算子(Add, Sub, MatMul, Transpose, Greater, IsNaN, Shape, Reshape...)、リダクション(ReduceSum, ReduceMin, ...)、画像変換(Conv, MaxPool, ...)、ディープニューラルネットワーク層(RNN, DropOut, ...)、活性化関数(Relu, Softmax, ...)が含まれる。)

出典: ONNX Documentation - Concepts

主要なオペレータの分類

基本演算

  • Add, Sub, Mul, Div(四則演算)
  • MatMul, Gemm(行列演算)
  • Transpose, Reshape, Squeeze(形状操作)

ニューラルネットワーク層

  • Conv, ConvTranspose(畳み込み)
  • MaxPool, AveragePool, GlobalAveragePool(プーリング)
  • BatchNormalization, LayerNormalization(正規化)
  • Dropout(ドロップアウト)

活性化関数

  • Relu, LeakyRelu, PRelu
  • Sigmoid, Tanh
  • Softmax, LogSoftmax

リカレント層

  • RNN, LSTM, GRU

ドメインの概念

オペレータは「ドメイン」でグループ分けされている。

The main list of operators is identified with a domain ai.onnx. A domain can be defined as a set of operators. (...) The main list is also missing tree based models very popular in standard machine learning. These are part of another domain ai.onnx.ml.

(メインのオペレータリストはドメインai.onnxで識別される。ドメインはオペレータのセットとして定義できる。(...)メインリストには、標準的な機械学習で人気のある木ベースのモデルがない。これらは別のドメインai.onnx.mlの一部である。)

ドメイン 内容
ai.onnx 標準的な演算子(NN、行列演算など)
ai.onnx.ml 伝統的ML用(決定木、SVM、前処理など)
com.microsoft Microsoft独自の拡張

opset versionの重要性

ONNXで最もハマりやすいのが opset version の問題だ。

opset versionとは

オペレータの「バージョン」のこと。同じ名前のオペレータでも、バージョンによって仕様が異なる場合がある。

例えば、Upsample オペレータは:

  • opset 7以前: 実験的な実装
  • opset 9: 安定版として仕様策定
  • opset 10以降: 非推奨(Resizeを使うべき)

なぜ問題になるか

よくあるエラー:

RuntimeError: Unsupported operator: Upsample version 1

これは、「あなたのモデルはopset 1のUpsampleを使っているけど、このランタイムはそのバージョンをサポートしていない」という意味。

対処法

  1. エクスポート時にopset versionを指定
torch.onnx.export(model, x, "model.onnx", opset_version=11)
  1. バージョンコンバータを使う
from onnx import version_converter
converted_model = version_converter.convert_version(model, target_version=13)
  1. ランタイムを更新する

一般的には、opset 9以上を使う のが安全。多くのランタイムがこのあたりから安定してサポートしている。


視覚化してみよう

ONNXモデルの構造を視覚的に確認するツールがある。

Netron

最も人気のあるONNXビューア。ブラウザ上で動く。

.onnxファイルをドラッグ&ドロップするだけで、グラフ構造を可視化できる。

使い方:
1. https://netron.app/ を開く
2. .onnxファイルをドラッグ&ドロップ
3. ノードをクリックして詳細を確認

各ノードをクリックすると、入出力の型、形状、アトリビュートなどが確認できる。変換エラーのデバッグに非常に便利。

Pythonでの確認

import onnx

# モデルを読み込む
model = onnx.load("model.onnx")

# モデルの検証
onnx.checker.check_model(model)

# グラフの情報を表示
print(f"IR Version: {model.ir_version}")
print(f"Producer: {model.producer_name}")
for opset in model.opset_import:
    print(f"Opset: {opset.domain or 'ai.onnx'} version {opset.version}")

# ノード数
print(f"Number of nodes: {len(model.graph.node)}")

# 入出力の情報
for input in model.graph.input:
    print(f"Input: {input.name}")
for output in model.graph.output:
    print(f"Output: {output.name}")

よくある変換エラーと原因

「Unsupported operator」

原因: そのオペレータがONNXに存在しない、または指定したopset versionでサポートされていない。

対処:

  • opset versionを上げる
  • カスタムオペレータを実装する
  • モデルのアーキテクチャを変更する

「Shape inference error」

原因: 入出力のテンソル形状を推論できない。

対処:

  • 入力サイズを明示的に指定する
  • dynamic_axesを適切に設定する

「TracingWarning: Converting a tensor to a Python...」

原因: PyTorchのトレース時に、テンソルをPythonのスカラーに変換している。

対処:

  • モデルのコードを修正して、テンソル演算のままにする
  • torch.jit.script を使う

まとめ

  • ONNXモデルは DAG(有向非巡回グラフ) として表現される
  • Protocol Buffers でシリアライズされ、.onnxファイルに保存
  • グラフは ノード、テンソル、イニシャライザ、アトリビュート で構成
  • オペレータ は演算の種類を定義(Add, Conv, ReLU など)
  • opset version によってオペレータの仕様が決まる(互換性に注意)
  • Netron で視覚的に確認できる

次回予告

第3回では、いよいよ実践編。PyTorchモデルをONNXに変換する具体的な手順を、コード付きで解説する。動的入力サイズへの対応や、よくあるトラブルシューティングも扱う予定だ。


参考文献

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?