PyTorchモデルをONNXに変換:知っておくべき5つのポイントとtorch.onnx.OnnxRegistryの使い方


torch.onnx.OnnxRegistry は、PyTorch モデルを ONNX 形式に変換する際に、PyTorch オペレーターと ONNX オペレーターの対応関係を管理するレジストリです。このレジストリにより、PyTorch モデルを ONNX 形式に効率的に変換し、様々なプラットフォームやライブラリで実行することができます。

機能

  • ONNX モデルのエクスポート時に、未登録オペレーターの処理方法を指定する
  • 未登録のオペレーターをカスタム オペレーターとして登録する
  • PyTorch オペレーターと ONNX オペレーターの対応関係を登録/取得/削除する

利点

  • カスタム オペレーターを ONNX モデルに組み込むことができる
  • 様々なプラットフォームやライブラリで PyTorch モデルを実行できる
  • PyTorch モデルを ONNX 形式に効率的に変換できる
import torch
import torch.onnx

# 例:PyTorch オペレーターと ONNX オペレーターの対応関係を確認する
print(torch.onnx.OnnxRegistry.get_registered_op("add"))

# 例:未登録オペレーターをカスタム オペレーターとして登録する
@torch.onnx.register_custom_op_loader
def custom_op_loader(op_name):
    # カスタム オペレーターの実装

# 例:ONNX モデルのエクスポート時に、未登録オペレーターを無視するように設定する
torch.onnx.export(model, inputs, torch.onnx.ExportParams(opset=13, custom_op_loader=custom_op_loader, export_params=True))
  • カスタム オペレーターを登録するには、C++ コードで実装する必要があります。
  • torch.onnx.OnnxRegistry は、PyTorch 1.1 以降で使用できます。


import torch
import torch.onnx

# 例:PyTorch オペレーター "add" と ONNX オペレーター "Add" の対応関係を確認する
print(torch.onnx.OnnxRegistry.get_registered_op("add"))

出力

<ONNXOp>
    name: Add
    domain: ''
    version: 7
    doc_string: ''
    input: [<ONNXArg>
                name: x,
                type: <ONNXType>
                    tensor_type:
                        elem_type: int32
                        shape: {dims: []}
                    optional: false
            >, <ONNXArg>
                name: y,
                type: <ONNXType>
                    tensor_type:
                        elem_type: int32
                        shape: {dims: []}
                    optional: false
            >]
    output: [<ONNXArg>
                name: z,
                type: <ONNXType>
                    tensor_type:
                        elem_type: int32
                        shape: {dims: []}
                    optional: false
            >]
</ONNXOp>

説明

このコードは、PyTorch オペレーター "add" と ONNX オペレーター "Add" の対応関係を torch.onnx.OnnxRegistry.get_registered_op() 関数を使用して取得します。

未登録オペレーターをカスタム オペレーターとして登録する

import torch
import torch.onnx

# 例:カスタム オペレーター "my_add" を定義する
def my_add(x, y):
    return x + y + 1

# カスタム オペレーターを ONNX レジストリに登録する
torch.onnx.register_custom_op_loader(my_add, "my_add")

# PyTorch モデルを ONNX 形式にエクスポートする
model = torch.nn.Sequential(
    torch.nn.Linear(10, 10),
    torch.nn.ReLU(),
    torch.nn.Linear(10, 1),
)

x = torch.randn(1, 10)
torch.onnx.export(model, x, torch.onnx.ExportParams(opset=13, custom_op_loader=my_add, export_params=True))

説明

このコードは、my_add という名前のカスタム オペレーターを定義し、torch.onnx.register_custom_op_loader() 関数を使用して ONNX レジストリに登録します。その後、PyTorch モデルを ONNX 形式にエクスポートし、カスタム オペレーター "my_add" を使用できるようにします。

ONNX モデルのエクスポート時に、未登録オペレーターを無視するように設定する

import torch
import torch.onnx

# PyTorch モデルを ONNX 形式にエクスポートする
model = torch.nn.Sequential(
    torch.nn.Linear(10, 10),
    torch.nn.ReLU(),
    torch.nn.Linear(10, 1),
)

x = torch.randn(1, 10)
torch.onnx.export(model, x, torch.onnx.ExportParams(opset=13, export_params=True, export_type=torch.onnx.ExportTypes.ONNX))

説明

このコードは、export_type パラメータを torch.onnx.ExportTypes.ONNX に設定することで、未登録オペレーターを無視するように設定して、PyTorch モデルを ONNX 形式にエクスポートします。

  • export_type パラメータを torch.onnx.ExportTypes.ONNX に設定すると、未登録オペレーターは無視されますが、警告が表示されます。
  • カスタム オペレーターを登録するには、C++ コードで実装する必要があります。


import torch
import torch.jit

# カスタム オペレーター "my_add" を TorchScript で定義する
@torch.jit.script
def my_add(x, y):
    return x + y + 1

# PyTorch モデルを ONNX 形式にエクスポートする
model = torch.nn.Sequential(
    torch.jit.script(my_add),
    torch.nn.Linear(10, 1),
)

x = torch.randn(1, 10)
torch.onnx.export(model, x, torch.onnx.ExportParams(opset=13, export_params=True))

説明

このコードは、@torch.jit.script デコレータを使用して、my_add という名前のカスタム オペレーターを TorchScript で定義します。その後、PyTorch モデルを ONNX 形式にエクスポートし、カスタム オペレーター "my_add" を使用できるようにします。

利点

  • コードがよりシンプルで読みやすい
  • C++ コードでカスタム オペレーターを実装する必要がない

欠点

  • パフォーマンスが低下する可能性がある
  • すべてのオペレーターが TorchScript で定義できるわけではない

ONNX Runtime を使用する

ONNX Runtime は、PyTorch モデルを効率的に実行するためのランタイムです。ONNX Runtime を使用すると、torch.onnx.OnnxRegistry を使用せずに、PyTorch モデルを ONNX 形式に変換して実行することができます。

import torch
import onnxruntime

# PyTorch モデルを ONNX 形式にエクスポートする
model = torch.nn.Sequential(
    torch.nn.Linear(10, 10),
    torch.nn.ReLU(),
    torch.nn.Linear(10, 1),
)

x = torch.randn(1, 10)
torch.onnx.export(model, x, torch.onnx.ExportParams(opset=13, export_params=True))

# ONNX モデルを読み込む
ort_session = onnxruntime.InferenceSession("model.onnx")

# 入力データを準備する
input_data = x.numpy()

# 推論を実行する
output_data = ort_session.run(None, {"x": input_data})

# 出力データを処理する
print(output_data)

説明

このコードは、PyTorch モデルを ONNX 形式にエクスポートし、ONNX Runtime を使用して推論を実行します。

利点

  • 様々なプラットフォームで実行可能
  • 高速な推論速度
  • ONNX Runtime でサポートされていないオペレーターは使用できない