UltralyticsでYOLO以外のPyTorchモデルをエクスポートする方法#
Ultralyticsには、複数のバックエンドを一貫したインターフェースで利用できるスタンドアロンのエクスポートユーティリティが ultralytics.utils.export に用意されています。timm の画像モデル、torchvision の分類モデルや検出モデル、独自のカスタムアーキテクチャなど、あらゆる torch.nn.Module を、各バックエンドを個別に習得することなく、TorchScript、ONNX、OpenVINO、CoreML、Core AI、TensorFlow SavedModel、TensorFlow Frozen Graph、PaddlePaddle、MNN、NCNN、ExecuTorch にエクスポートできます。
PyTorchモデルを本番環境にデプロイする場合、通常はターゲットごとに異なるエクスポーターを使い分ける必要があります。ONNXにはtorch.onnx.export、Appleデバイスにはcoremltools、TensorFlowにはonnx2tf、NCNNにはpnnxなどを使用します。各ツールには独自のAPI、依存関係に関する注意点、出力形式があります。これらのユーティリティを使えば、呼び出し方法を一つに統一できます。
YOLO以外のモデルのエクスポートにUltralyticsを使う理由#
- 11種類のフォーマットで共通のAPI: 12種類もの呼び出し規約を覚える代わりに、1つだけ覚えれば済みます。
- YOLOのエクスポートと同じコードパス: すべてのUltralytics YOLOエクスポートで、同じヘルパーが使用されています。
- 対応フォーマットでは、1つの
quantize引数でFP16およびINT8量子化を行えます。 - CPUで動作します: エクスポート処理自体にGPUは必要ないため、ノートPC上でローカルに実行できます。CoreMLエクスポートはWindowsではサポートされていません。また、Core AIエクスポートには、Apple silicon搭載のmacOS 26以降、またはglibc 2.34以降のx86_64 Linuxと、Python 3.11~3.14が必要です。
クイックスタート#
最も手早い方法は、YOLOのコードを使わず、pip install ultralytics onnx timm以外のセットアップも不要な、ONNXへの2行のエクスポートです。
import timm
import torch
from ultralytics.utils.export import torch2onnx
model = timm.create_model("resnet18", pretrained=True).eval()
torch2onnx(model, torch.randn(1, 3, 224, 224), output_file="resnet18.onnx")サポートされているエクスポート形式#
torch2*関数は、標準的なtorch.nn.Moduleとサンプル入力テンソルを受け取ります。MNN、TF SavedModel、TF Frozen Graphでは、中間形式としてONNXまたはKerasのアーティファクトを使用します。いずれの場合も、YOLO固有の属性は必要ありません。
| 形式 | 関数 | インストール | 出力 |
|---|---|---|---|
| TorchScript | torch2torchscript() | PyTorchに同梱 | .torchscriptファイル |
| ONNX | torch2onnx() | pip install onnx | .onnxファイル |
| OpenVINO | torch2openvino() | pip install openvino | _openvino_model/ディレクトリ |
| CoreML | torch2coreml() | pip install coremltools | .mlpackage |
| Core AI | torch2coreai() | pip install coreai-torch(Apple silicon搭載macOS 26以降、またはglibc 2.34以降のx86_64 Linux、Python 3.11~3.14) | .aimodelディレクトリ |
| TF SavedModel | onnx2saved_model() | 詳しい要件はこちら | _saved_model/ディレクトリ |
| TF Frozen Graph | keras2pb() | 詳しい要件はこちら | .pbファイル |
| PaddlePaddle | torch2paddle() | pip install paddlepaddle x2paddle | _paddle_model/ディレクトリ |
| MNN | onnx2mnn() | pip install MNN | .mnnファイル |
| NCNN | torch2ncnn() | pip install ncnn pnnx | _ncnn_model/ディレクトリ |
| ExecuTorch | torch2executorch() | pip install executorch | _executorch_model/ディレクトリ |
一部のエクスポート関数では、オプションのmetadata辞書(例:torch2torchscript(..., metadata={"author": "me"}))を受け取ります。フォーマットが対応している場合、辞書のカスタムキーと値のペアをエクスポートしたアーティファクトに埋め込めます。
手順ごとの例#
以下のすべての例では、同じセットアップを使用します。timmの事前学習済みResNet-18を評価モードで読み込みます。
import timm
import torch
model = timm.create_model("resnet18", pretrained=True).eval()
im = torch.randn(1, 3, 224, 224)Dropout、バッチ正規化など、学習時のみ使用するレイヤーは推論時に異なる動作をします。.eval()を省略すると、出力が正しくないエクスポートが生成されます。
ONNXにエクスポート#
from ultralytics.utils.export import torch2onnx
torch2onnx(model, im, output_file="resnet18.onnx")バッチサイズを動的にするには、dynamic辞書を渡します。
torch2onnx(model, im, output_file="resnet18_dyn.onnx", dynamic={"images": {0: "batch_size"}})デフォルトのopsetは14で、デフォルトの入力名は"images"です。opset、input_names、またはoutput_names引数で変更できます。
TorchScriptにエクスポート#
追加の依存関係は不要です。内部ではtorch.jit.traceを使用します。
from ultralytics.utils.export import torch2torchscript
torch2torchscript(model, im, output_file="resnet18.torchscript")OpenVINOにエクスポート#
from ultralytics.utils.export import torch2openvino
ov_model = torch2openvino(model, im, output_dir="resnet18_openvino_model")ディレクトリには、固定名のmodel.xmlとmodel.binのペアが含まれます。
resnet18_openvino_model/
├── model.xml
└── model.bin入力形状を動的にするにはdynamic=True、FP16にはquantize=16、INT8量子化にはquantize=8を渡します。INT8には追加でcalibration_dataset引数が必要です。
openvino>=2024.0.0(またはmacOS 15.4以降では>=2025.2.0)とtorch>=2.1が必要です。
CoreMLにエクスポート#
import coremltools as ct
from ultralytics.utils.export import torch2coreml
inputs = [ct.TensorType("input", shape=(1, 3, 224, 224))]
ct_model = torch2coreml(model, inputs, im, classifier_names=None, output_file="resnet18.mlpackage")分類モデルの場合は、クラス名のリストをclassifier_namesに渡すと、CoreMLモデルに分類ヘッドが追加されます。
coremltools>=9.0、torch>=1.11、numpy<=2.3.5が必要です。Windowsではサポートされていません。
coremltools>=9.0は、macOSおよびLinux向けにPython 3.10~3.13のwheelを提供しています。それより新しいPythonバージョンでは、ネイティブC拡張の読み込みに失敗します。CoreMLへのエクスポートにはPython 3.10~3.13を使用してください。
Core AIにエクスポート#
from ultralytics.utils.export import torch2coreai
torch2coreai(model, im, output_file="resnet18.aimodel").aimodelアセットはディレクトリです。
resnet18.aimodel/
├── main.mlirb
├── main.hash
└── metadata.jsonエクスポートは、Apple silicon搭載のmacOS 26以降、またはglibc 2.34以降のx86_64 Linuxで、Python 3.11~3.14を使って実行されます(pip install coreai-torch)。quantize=16 はfloat16入力を受け取るFP16アセットを書き出し、このアセットはiOS 27およびmacOS 27で動作します。読み込み時に異常終了するFP16アセットに関する注意事項を含め、Core AIの統合ガイドをご覧ください。
TensorFlow SavedModelにエクスポート#
TF SavedModelへのエクスポートでは、中間処理にONNXを使用します。
from ultralytics.utils.export import onnx2saved_model, torch2onnx
torch2onnx(model, im, output_file="resnet18.onnx")
keras_model = onnx2saved_model("resnet18.onnx", output_dir="resnet18_saved_model")この関数はKerasモデルを返し、出力ディレクトリ内にFP32およびFP16のLiteRTファイル(.tflite)も生成します。
resnet18_saved_model/
├── saved_model.pb
├── variables/
├── assets/
├── fingerprint.pb
├── resnet18_float32.tflite
└── resnet18_float16.tflitequantize=8を渡すと、それらに加えてINT8の.tfliteが追加されます。
TensorFlowのエクスポートは、Python 3.13以降を使用するmacOSでは実行できません。macOSではPython 3.12以前を使用するか、Linuxを使用してください。
Python 3.12以前での要件(Python 3.13以降では、エクスポートに代わりtensorflow>2.19.0、tf_keras>2.19.0、
onnx2tf>=2.3.0,<2.3.16、protobuf>=6.31.1,<7.0.0が必要です)。
tensorflow>=2.0.0,<=2.19.0onnx2tf>=1.26.3,<1.29.0tf_keras<=2.19.0sng4onnx>=1.0.1onnx_graphsurgeon>=0.3.26- macOSでは
ai-edge-litert>=1.2.0,<1.4.0(その他のプラットフォームではai-edge-litert>=1.2.0) onnxslim>=0.1.82onnx>=1.12.0,<2.0.0protobuf>=5
TensorFlow Frozen Graphにエクスポート#
上記のSavedModelへのエクスポートに続けて、返されたkeras_modelを変換し、凍結した.pbグラフを作成します。
from pathlib import Path
from ultralytics.utils.export import keras2pb
keras2pb(keras_model, output_file=Path("resnet18_saved_model/resnet18.pb"))NCNNにエクスポート#
from ultralytics.utils.export import torch2ncnn
torch2ncnn(model, im, output_dir="resnet18_ncnn_model")ディレクトリには、固定名のparamファイルとbinファイル、およびPythonラッパーが含まれます。
resnet18_ncnn_model/
├── model.ncnn.param
├── model.ncnn.bin
└── model_ncnn.pyMNNにエクスポート#
MNNへのエクスポートには、入力としてONNXファイルが必要です。まずONNXにエクスポートしてから変換してください。
from ultralytics.utils.export import onnx2mnn, torch2onnx
torch2onnx(model, im, output_file="resnet18.onnx")
onnx2mnn("resnet18.onnx", output_file="resnet18.mnn")FP16にはquantize=16、INT8量子化にはquantize=8を使用できます。MNN>=2.9.6とtorch>=1.10が必要です。
PaddlePaddleにエクスポート#
from ultralytics.utils.export import torch2paddle
torch2paddle(model, im, output_dir="resnet18_paddle_model")ディレクトリには、PaddlePaddleモデルとパラメータファイルが含まれます。
resnet18_paddle_model/
├── inference_model/
│ ├── model.json
│ └── model.pdiparams
├── model.pdparams
└── x2paddle_code.pyx2paddleと、使用するプラットフォームに適したPaddlePaddleディストリビューションが必要です。
- CUDA環境での
paddlepaddle-gpu>=3.0.0,<3.3.0 - ARM64 CPU環境での
paddlepaddle==3.0.0 - その他のCPU環境での
paddlepaddle>=3.0.0,<3.3.0
NVIDIA Jetsonではサポートされていません。
ExecuTorchにエクスポート#
from ultralytics.utils.export import torch2executorch
torch2executorch(model, im, output_dir="resnet18_executorch_model")エクスポートされた.pteファイルは、出力ディレクトリ内に保存されます。
resnet18_executorch_model/
└── model.ptetorch>=2.9.0と、対応するExecuTorchランタイム(pip install executorch)が必要です。ランタイムの使用方法については、ExecuTorchの統合ガイドを参照してください。
エクスポートしたモデルを検証する#
エクスポート後、本番環境にデプロイする前に、元のPyTorchモデルとの数値的な一致を検証してください。ultralytics.nn.backendsのONNXBackendを使った簡単なスモークテストで出力を比較し、トレースや量子化のエラーを早期に検出できます。
import numpy as np
import timm
import torch
from ultralytics.nn.backends import ONNXBackend
model = timm.create_model("resnet18", pretrained=True).eval()
im = torch.randn(1, 3, 224, 224)
with torch.no_grad():
pytorch_output = model(im).numpy()
onnx_model = ONNXBackend("resnet18.onnx", device=torch.device("cpu"))
onnx_output = onnx_model(im)[0]
diff = np.abs(pytorch_output - onnx_output).max()
print(f"Max difference: {diff:.6f}") # ~1e-6 for an FP32 ONNX exportResNet-18では、ほとんどのFP32エクスポートはPyTorchとの差が約 1e-5 以内に収まり、TorchScriptは完全に一致します。ただし、3つのランタイムでは、FP32エクスポートを低精度で計算し、1e-2~1e-1 程度の差が生じることがあります。NCNNは対応CPUでFP16演算を有効にし、MNNBackend は precision="low" を使用してモデルを読み込みます。また、OpenVINO CPUプラグインは、Apple siliconなど一部のハードウェアで、デフォルトの PERFORMANCE 実行モード時に自動的にFP16で動作します。フォーマット固有のベースラインを大幅に上回る差がある場合は、未サポートの演算、誤った入力形状、またはモデルが評価モードになっていないことが原因として考えられます。FP16およびINT8エクスポートでは許容誤差が大きくなります。ランダムテンソルではなく、実データで検証してください。
その他のランタイムでは、入力テンソル名が異なる場合があります。たとえばOpenVINOではモデルのforward引数名(汎用モデルでは通常x)が使用されますが、torch2onnxのデフォルトは"images"です。
エクスポートしたモデルを実行する#
エクスポートしたYOLO以外のモデルは、通常のYOLO() APIで再度読み込めます。上記のエクスポートにはUltralyticsのタスク情報や入力サイズのメタデータが含まれないため、taskを明示的に渡し、imgszにはエクスポート時に使用したサンプルテンソルに対応する値を渡してください。
from ultralytics import YOLO
results = YOLO("resnet18.onnx", task="classify")("path/to/image.jpg", imgsz=224)
print(results[0].probs.top1)エクスポート時に入力形状が固定されている場合、imgszが重要になります。上記のONNXおよびTF SavedModelエクスポートでは、デフォルトの640は受け付けられません。上記のTorchScriptおよびNCNNエクスポートでは他のサイズも受け付けますが、どちらのエクスポーターもそれを保証しません。どちらもサンプルテンソルからトレースするため、Linearレイヤーに平坦化するモデルでは、そのサイズが固定されます。ご自身のエクスポートを確認してください。
値はモデルのストライド(メタデータがない場合は32)の倍数に切り上げられます。そのため、200x200で固定形状としてエクスポートしたモデルには224x224が入力され、imgsz=200が一致していても拒否されます。32の倍数ではない入力サイズを使う場合は、バックエンドを直接呼び出してください。
バックエンドを直接呼び出す#
Ultralyticsの前処理や後処理を行わずに生のテンソルを扱うには、上記の検証例と同様に、ultralytics.nn.backendsにあるフォーマットごとのクラスを使用してください。各クラスにはエクスポートしたアーティファクトとデバイスを渡し、呼び出し可能な形式で使用します。
| 形式 | バックエンド | 入力レイアウト |
|---|---|---|
| TorchScript | TorchScriptBackend | BCHW |
| ONNX | ONNXBackend | BCHW |
| OpenVINO | OpenVINOBackend | BCHW |
| CoreML | CoreMLBackend | BHWC |
| Core AI | CoreAIBackend | BCHW |
| TF SavedModel、Frozen Graph | TensorFlowBackend | BHWC |
| LiteRT | LiteRTBackend | BCHW |
| PaddlePaddle | PaddleBackend | BCHW |
| MNN | MNNBackend | BCHW |
| NCNN | NCNNBackend | BCHW |
| ExecuTorch | ExecuTorchBackend | BCHW |
TensorFlowBackendは2つのフォーマットに対応し、デフォルトではformat="saved_model"を使用します。Frozen Graphではformat="pb"を渡してください。
YOLO()を使う方法では処理されますが、直接呼び出す場合には処理されない点が3つあります。
- 入力レイアウト:
CoreMLBackendとTensorFlowBackendはBHWCを想定しています。まずim.permute(0, 2, 3, 1)で転置してください。BCHWテンソルを渡すと、形状の不一致が発生します。 - Autograd: 呼び出しを
torch.inference_mode()でラップしてください。TorchScriptBackendは勾配グラフを保持したテンソルを返します。 - 後処理: メタデータがない場合、バックエンドは
taskをNoneとして返し、namesは空のままにします。LiteRTBackendは、3次元の出力にYOLOのBBoxが含まれると想定して、画像サイズに基づく非正規化を行います。YOLO以外のモデルの3次元出力では誤った処理になります。分類ロジットなどの2次元出力には影響しません。
既知の制限事項#
- 複数入力への対応状況にはばらつきがあります:
torch2onnx、torch2openvino、torch2torchscriptは、複数入力モデル用にサンプルテンソルのタプルを受け取れます。torch2coreml、torch2coreai、torch2ncnn、torch2paddle、torch2executorchは、単一の入力テンソルを前提としています。 - YOLO専用フォーマット: AxeleraおよびSony IMX500へのエクスポートでは、YOLO固有のモデル属性が必要なため、汎用モデルには対応していません。
- プラットフォーム固有のフォーマット: TensorRTにはNVIDIA GPUが必要です。RKNNには
rknn-toolkit2SDKが必要です(Linuxのみ)。Edge TPUにはedgetpu_compilerバイナリが必要です(Linuxのみ)。
まとめ#
これらのユーティリティを使えば、一般的なtorch.nn.Moduleから、デプロイ可能なONNX、OpenVINO、CoreML、TensorFlow、モバイルランタイム向けのアーティファクトまで、あらゆるPyTorchモデルを一貫したAPIで変換できます。ターゲットのハードウェアに合ったフォーマットを選び、元のモデルとの数値的な一致を検証してから、ランタイム固有のデプロイ手順について該当する統合ガイドを参照してください。
よくある質問#
任意の
torch.nn.Moduleが対象です。timm、torchvision、または任意のカスタムPyTorchモデルを含みます。エクスポート前に、モデルを評価モード(model.eval())にする必要があります。ONNX、OpenVINO、TorchScriptでは、複数入力モデル用にサンプルテンソルのタプルも受け取れます。サポートされているすべてのフォーマット(TorchScript、ONNX、OpenVINO、CoreML、Core AI、TF SavedModel、TF Frozen Graph、PaddlePaddle、MNN、NCNN、ExecuTorch)は、CPUでエクスポートできます。エクスポート処理自体にGPUは必要ありません。NVIDIA GPUが必要なのはTensorRTのみです。
最新リリースを使用してください。
quantize引数にはUltralytics>=8.4.81が必要です。また、Core AIエクスポートには>=8.4.131が必要です(Linuxの場合、またはcoreai-torch>=0.4.3を使用する場合は>=8.4.163)。はい。torchvisionの分類モデル、検出モデル、セグメンテーションモデルは、
torch2coremlを介して.mlpackageにエクスポートできます。画像分類モデルの場合は、クラス名のリストをclassifier_namesに渡すと、分類ヘッドを組み込めます。macOSまたはLinuxでエクスポートを実行してください。CoreMLはWindowsではサポートされていません。iOSへのデプロイの詳細は、CoreMLの統合をご覧ください。はい。一部のフォーマットで対応しています。OpenVINO、CoreML、またはMNNへのエクスポート時に、FP16には
quantize=16、INT8にはquantize=8を指定します。onnx2saved_modelはINT8 LiteRTファイル用にquantize=8を受け取ります。NCNNとCore AIはデフォルトでFP32を出力し、FP16にはquantize=16を指定できますが、INT8には対応していません。OpenVINOのINT8には、学習後量子化用のcalibration_dataset引数も必要です。量子化のトレードオフについては、各フォーマットの統合ガイドをご覧ください。元のPyTorchモデルとエクスポートしたモデルに同じ入力を渡して実行し、出力を比較します。対応するバックエンドでエクスポートファイルを読み込み(ONNXの場合は
ONNXBackendなど)、最大絶対差を確認します。差をフォーマット固有のベースラインと比較して評価してください。NCNN、MNNBackend、および一部のCPU上のOpenVINOでは、FP32エクスポートを低精度で実行する場合があり、差は1e-2~1e-1程度になります。一方、ほとんどの他のフォーマットでは1e-5程度です。差が大幅に大きい場合は、未サポートの演算、誤った入力形状、またはモデルが評価モードになっていないことが原因として考えられます。実行可能な例については、エクスポートしたモデルの検証をご覧ください。