Ultralytics YOLO27: ウェイティングリストに登録してください。
Get Started

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: 何十種類もの呼び出し規約を覚える代わりに、1つの規約を習得するだけで済みます。
  • YOLOのエクスポートと同じコードパス: Ultralytics YOLOのすべてのエクスポートで、同じヘルパーが使用されます。
  • FP16とINT8の量子化に対応する形式では、1つのquantize引数で実行できます。
  • CPUで動作: エクスポート処理自体にGPUは不要なため、ノートPC上でローカルに実行できます。CoreMLのエクスポートはWindowsではサポートされていません。また、Core AIのエクスポートには、Appleシリコン搭載の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固有の属性は必要ありません。

形式関数インストール出力
TorchScripttorch2torchscript()PyTorchに付属.torchscriptファイル
ONNXtorch2onnx()pip install onnx.onnxファイル
OpenVINOtorch2openvino()pip install openvino_openvino_model/ディレクトリ
CoreMLtorch2coreml()pip install coremltools.mlpackage
Core AItorch2coreai()pip install coreai-torch(Appleシリコン搭載のmacOS 26以降、x86_64 Linux・glibc 2.34以降、Python 3.11~3.14).aimodelディレクトリ
TF SavedModelonnx2saved_model()以下の詳細な要件を参照_saved_model/ディレクトリ
TF Frozen Graphkeras2pb()以下の詳細な要件を参照.pbファイル
PaddlePaddletorch2paddle()pip install paddlepaddle x2paddle_paddle_model/ディレクトリ
MNNonnx2mnn()pip install MNN.mnnファイル
NCNNtorch2ncnn()pip install ncnn pnnx_ncnn_model/ディレクトリ
ExecuTorchtorch2executorch()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)
エクスポートの前に必ず`model.eval()`を呼び出してください

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ではサポートされていません。

`BlobWriter not loaded`エラー

coremltools>=9.0は、macOSとLinux向けにPython 3.10~3.13のホイールを提供します。これより新しい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シリコン搭載の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.tflite

quantize=8を渡すと、これらに加えてINT8の.tfliteを追加できます。

Python 3.13以降を使用したmacOSではTensorFlowのエクスポートを実行できません。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.0
  • onnx2tf>=1.26.3,<1.29.0
  • tf_keras<=2.19.0
  • sng4onnx>=1.0.1
  • onnx_graphsurgeon>=0.3.26
  • macOSではai-edge-litert>=1.2.0,<1.4.0(その他のプラットフォームではai-edge-litert>=1.2.0)
  • onnxslim>=0.1.82
  • onnx>=1.12.0,<2.0.0
  • protobuf>=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.py

MNNにエクスポート#

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.py

x2paddleと、お使いのプラットフォームに適した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.pte

torch>=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-5 for an FP32 ONNX export
想定される差分

ResNet-18では、ほとんどのFP32エクスポートの差分はPyTorchに対して約1e-5以内に収まり、TorchScriptは完全に一致します。ただし、3つのランタイムではFP32エクスポートが低精度で計算され、1e-2から1e-1程度の差分になる場合があります。NCNNは、対応するCPUでFP16演算を有効にします。MNNBackendはprecision="low"でモデルを読み込みます。また、OpenVINO CPUプラグインは、一部のハードウェア(Appleシリコンなど)では、デフォルトの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の固定形状でエクスポートすると、imgsz=200が一致していても、224x224の入力が渡されて拒否されます。32の倍数ではない入力サイズを使う場合は、バックエンドを直接呼び出してください。

バックエンドを直接呼び出す#

Ultralyticsの前処理や後処理を行わずに生テンソルを扱うには、上記の検証例と同様に、ultralytics.nn.backendsにあるフォーマット別のクラスを使用します。各クラスには、エクスポートした成果物とデバイスを渡し、呼び出し可能です。

形式バックエンド入力レイアウト
TorchScriptTorchScriptBackendBCHW
ONNXONNXBackendBCHW
OpenVINOOpenVINOBackendBCHW
CoreMLCoreMLBackendBHWC
Core AICoreAIBackendBCHW
TF SavedModel、Frozen GraphTensorFlowBackendBHWC
LiteRTLiteRTBackendBCHW
PaddlePaddlePaddleBackendBCHW
MNNMNNBackendBCHW
NCNNNCNNBackendBCHW
ExecuTorchExecuTorchBackendBCHW

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は、YOLOのBBoxを含むという前提で、3次元出力を画像サイズでデノーマライズします。そのため、3次元出力を持つ非YOLOモデルでは誤った処理になります。分類ロジットなどの2次元出力には影響しません。

既知の制限事項#

  • 複数入力のサポートにはばらつきがあります:torch2onnx、torch2openvino、torch2torchscriptは、複数入力モデル向けにサンプルテンソルのタプルを受け付けます。torch2coreml、torch2coreai、torch2ncnn、torch2paddle、torch2executorchは、単一入力テンソルを想定しています。
  • YOLO専用フォーマット:AxeleraとSony IMX500へのエクスポートには、YOLO固有のモデル属性が必要なため、汎用モデルでは使用できません。
  • プラットフォーム固有のフォーマット:TensorRTにはNVIDIA GPUが必要です。RKNNにはrknn-toolkit2 SDKが必要です(Linuxのみ)。Edge TPUにはedgetpu_compilerバイナリが必要です(x86_64 Linuxのみ)。

結論#

これらのユーティリティを使うと、通常のtorch.nn.Moduleから、PyTorchモデルを一貫したAPIでデプロイ可能なONNX、OpenVINO、CoreML、TensorFlow、またはモバイルランタイム向けの成果物に変換できます。ターゲットのハードウェアに合ったフォーマットを選び、元のモデルとの数値的な一致を検証してから、ランタイム固有のデプロイ手順について、対応するインテグレーションガイドを確認してください。

よくある質問#

  • 任意の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程度です。差分が大幅に大きい場合は、未サポートの演算、誤った入力形状、またはモデルが評価モードになっていないことが考えられます。実行可能な例については、エクスポートしたモデルを検証するをご覧ください。

コメント