So exportierst du PyTorch-Modelle ohne YOLO mit Ultralytics

Das Bereitstellen von PyTorch-Modellen für die Produktion bedeutet normalerweise, für jedes Ziel einen anderen Exporter zu jonglieren:torch.onnx.export für ONNX, coremltools für Apple-Geräte, onnx2tf für TensorFlow, pnnx für NCNN und so weiter. Jedes Tool hat seine eigene API, Abhängigkeitsbesonderheiten und Ausgabekonventionen.

Ultralytics bietet eigenständige Export-Utilities, die mehrere Backends unter einer konsistenten Schnittstelle zusammenfassen. Du kannst beliebige torch.nn.Module erweitern, einschließlich timm Bildmodelle, torchvision Klassifikatoren und Detektoren oder deine eigenen benutzerdefinierten Architekturen nach ONNX, TorchScript, OpenVINO, CoreML, NCNN, PaddlePaddle, MNN, ExecuTorch, und TensorFlow SavedModel exportieren, ohne jedes Backend einzeln lernen zu müssen.

Warum Ultralytics für Exporte ohne YOLO nutzen?

  • Eine API für 10 Formate: lerne eine einzige Aufrufkonvention anstelle eines Dutzends.
  • Gemeinsame Utility-Oberfläche: die Export-Hilfsmittel befinden sich unter ultralytics.utils.export, sodass du nach der Installation der Backend-Pakete das gleiche Aufrufmuster über alle Formate hinweg beibehalten kannst.
  • Gleicher Code-Pfad wie bei YOLO-Exporten: dieselben Hilfsmittel treiben jeden Ultralytics YOLO-Export an.
  • FP16 und INT8 Quantisierung integriert für Formate, die dies unterstützen (OpenVINO, CoreML, MNN, NCNN).
  • Funktioniert auf der CPU: kein GPU für den Export-Schritt selbst erforderlich, sodass du ihn lokal auf jedem Laptop ausführen kannst.

Schnellstart

Der schnellste Weg ist ein Export in zwei Zeilen zu ONNX ohne YOLO-Code und ohne weitere Einrichtung als pip install ultralytics onnx timm:

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")

Unterstützte Exportformate

Die torch2* Funktionen akzeptieren einen Standard torch.nn.Module und einen Beispiel-Input-Tensor. MNN, TF SavedModel und TF Frozen Graph durchlaufen ein zwischengeschaltetes ONNX- oder Keras-Artefakt. In keinem Fall sind YOLO-spezifische Attribute erforderlich.

FormatFunktionInstallierenAusgabe
ONNXtorch2onnx()pip install onnx.onnx Datei
TorchScripttorch2torchscript()in PyTorch enthalten.torchscript Datei
OpenVINOtorch2openvino()pip install openvino_openvino_model/ Verzeichnis
CoreMLtorch2coreml()pip install coremltools.mlpackage
TF SavedModelonnx2saved_model()siehe detaillierte Anforderungen unten_saved_model/ Verzeichnis
TF Frozen Graphkeras2pb()siehe detaillierte Anforderungen unten.pb Datei
NCNNtorch2ncnn()pip install ncnn pnnx_ncnn_model/ Verzeichnis
MNNonnx2mnn()pip install MNN.mnn Datei
PaddlePaddletorch2paddle()pip install paddlepaddle x2paddle_paddle_model/ Verzeichnis
ExecuTorchtorch2executorch()pip install executorch_executorch_model/ Verzeichnis
ONNX als Zwischenformat

MNN, TF SavedModel, und TF Frozen Graph-Exporte durchlaufen ONNX als Zwischenschritt. Exportiere zuerst nach ONNX und konvertiere dann.

Metadaten einbetten

Mehrere Exportfunktionen akzeptieren ein optionales metadata Dictionary (z. B. torch2torchscript(..., metadata={"author": "me"})), das benutzerdefinierte Schlüssel-Wert-Paare in das exportierte Artefakt einbettet, sofern das Format dies unterstützt.

Schritt-für-Schritt-Beispiele

Jedes Beispiel unten verwendet das gleiche Setup, ein vortrainiertes ResNet-18 von timm im Evaluierungsmodus:

import timm
import torch

model = timm.create_model("resnet18", pretrained=True).eval()
im = torch.randn(1, 3, 224, 224)
Rufe immer `model.eval()` vor dem Exportieren auf

Dropout, Batch Normalization und andere reine Trainings-Layer verhalten sich während der Inferenz anders. Das Überspringen von .eval() führt zu Exporten mit falschen Ausgaben.

Export nach ONNX

from ultralytics.utils.export import torch2onnx

torch2onnx(model, im, output_file="resnet18.onnx")

Für dynamische Batch-Größen übergib ein dynamic Dictionary:

torch2onnx(model, im, output_file="resnet18_dyn.onnx", dynamic={"images": {0: "batch_size"}})

Der Standard-Opset ist 14 und der Standard-Input-Name ist "images". Überschreibe dies mit den opset, input_names, oder output_names Argumenten.

Export nach TorchScript

Keine zusätzlichen Abhängigkeiten erforderlich. Verwendet torch.jit.trace unter der Haube.

from ultralytics.utils.export import torch2torchscript

torch2torchscript(model, im, output_file="resnet18.torchscript")

Export nach OpenVINO

from ultralytics.utils.export import torch2openvino

ov_model = torch2openvino(model, im, output_dir="resnet18_openvino_model")

Das Verzeichnis enthält ein model.xml und Fortschritten im Bereich model.bin Paar mit festem Namen:

resnet18_openvino_model/
├── model.xml
└── model.bin

Übergib dynamic=True für dynamische Input-Formen, half=True für FP16 oder int8=True für INT8 Quantisierung. INT8 erfordert zusätzlich ein calibration_dataset Arguments.

Erfordert openvino>=2024.0.0 (oder >=2025.2.0 unter macOS 15.4+) und torch>=2.1.

Export nach 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, output_file="resnet18.mlpackage")

Für Klassifizierung Modelle, übergib eine Liste von Klassennamen an classifier_names, um dem CoreML-Modell einen Klassifizierungskopf hinzuzufügen.

Erfordert coremltools>=9.0, torch>=1.11, und numpy<=2.3.5. Unter Windows nicht unterstützt.

`BlobWriter not loaded` Fehler

coremltools>=9.0 liefert Wheels für Python 3.10–3.13 unter macOS und Linux aus. Bei neueren Python-Versionen kann die native C-Erweiterung nicht geladen werden. Verwende Python 3.10–3.13 für den CoreML-Export.

Export nach TensorFlow SavedModel

Der TF SavedModel-Export erfolgt über ONNX als Zwischenschritt:

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")

Die Funktion gibt ein Keras-Modell zurück und generiert auch TFLite-Dateien (.tflite) im Ausgabeverzeichnis:

resnet18_saved_model/
├── saved_model.pb
├── variables/
├── resnet18_float32.tflite
├── resnet18_float16.tflite
└── resnet18_int8.tflite

Anforderungen:

  • 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 (installiere mit --extra-index-url https://pypi.ngc.nvidia.com)
  • ai-edge-litert>=1.2.0,<1.4.0 auf macOS (ai-edge-litert>=1.2.0 auf anderen Plattformen)
  • onnxslim>=0.1.71
  • onnx>=1.12.0,<2.0.0
  • protobuf>=5

Export nach TensorFlow Frozen Graph

Weiterführend vom obigen SavedModel-Export, konvertiere das zurückgegebene Keras-Modell in einen eingefrorenen .pb Graph:

from pathlib import Path

from ultralytics.utils.export import keras2pb

keras2pb(keras_model, output_file=Path("resnet18_saved_model/resnet18.pb"))

Export nach NCNN

from ultralytics.utils.export import torch2ncnn

torch2ncnn(model, im, output_dir="resnet18_ncnn_model")

Das Verzeichnis enthält param- und bin-Dateien mit festem Namen sowie einen Python-Wrapper:

resnet18_ncnn_model/
├── model.ncnn.param
├── model.ncnn.bin
└── model_ncnn.py

torch2ncnn() prüft auf ncnn und Fortschritten im Bereich pnnx heruntergeladen.

Export nach MNN

Der MNN-Export erfordert eine ONNX-Datei als Eingabe. Exportiere zuerst nach ONNX und konvertiere dann:

from ultralytics.utils.export import onnx2mnn, torch2onnx

torch2onnx(model, im, output_file="resnet18.onnx")
onnx2mnn("resnet18.onnx", output_file="resnet18.mnn")

Unterstützt half=True für FP16 und int8=True für INT8 Quantisierung. Erfordert MNN>=2.9.6 und Fortschritten im Bereich torch>=1.10.

Export nach PaddlePaddle

from ultralytics.utils.export import torch2paddle

torch2paddle(model, im, output_dir="resnet18_paddle_model")

Das Verzeichnis enthält das PaddlePaddle-Modell und die Parameterdateien:

resnet18_paddle_model/
├── model.pdmodel
└── model.pdiparams

Erfordert x2paddle und die korrekte PaddlePaddle-Distribution für deine Plattform:

  • paddlepaddle-gpu>=3.0.0,<3.3.0 auf CUDA
  • paddlepaddle==3.0.0 auf ARM64 CPU
  • paddlepaddle>=3.0.0,<3.3.0 auf anderen CPUs

Auf NVIDIA Jetson nicht unterstützt.

Export nach ExecuTorch

from ultralytics.utils.export import torch2executorch

torch2executorch(model, im, output_dir="resnet18_executorch_model")

Die exportierte .pte Datei wird im Ausgabeverzeichnis gespeichert:

resnet18_executorch_model/
└── model.pte

Erfordert torch>=2.9.0 und eine passende ExecuTorch-Laufzeitumgebung (pip install executorch). Informationen zur Nutzung der Laufzeitumgebung findest du in der ExecuTorch-Integration.

Verifiziere dein exportiertes Modell

Verifiziere nach dem Export die numerische Parität mit dem ursprünglichen PyTorch-Modell, bevor du es bereitstellst. Ein schneller Rauchtest mit ONNXBackend von ultralytics.nn.backends vergleicht die Ausgaben und zeigt Fehler bei der Tracing- oder Quantisierung frühzeitig an:

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}")  # should be < 1e-5
Erwartete Differenz

Bei FP32-Exporten sollte die maximale absolute Differenz unter 1e-5 liegen. Größere Unterschiede deuten auf nicht unterstützte Operationen, eine falsche Eingabeform oder ein Modell hin, das sich nicht im Evaluierungsmodus befindet. FP16- und INT8-Exporte haben größere Toleranzen. Validiere auf echten Daten statt auf zufälligen Tensoren.

Für andere Laufzeitumgebungen kann der Name des Eingabetensors abweichen. OpenVINO verwendet beispielsweise den Namen des Forward-Arguments des Modells (typischerweise x für generische Modelle), während torch2onnx standardmäßig "images".

Bekannte Einschränkungen

  • Unterstützung für mehrere Eingaben ist uneinheitlich: torch2onnx und Fortschritten im Bereich torch2openvino akzeptieren ein Tupel oder eine Liste von Beispiel-Tensoren für Modelle mit mehreren Eingaben. torch2torchscript, torch2coreml, torch2ncnn, torch2paddle, und torch2executorch gehen von einem einzelnen Eingabetensor aus.
  • ExecuTorch benötigt flatc: Die ExecuTorch-Laufzeitumgebung erfordert den FlatBuffers-Compiler. Installiere ihn mit brew install flatbuffers auf macOS oder apt install flatbuffers-compiler auf Ubuntu.
  • Keine Inferenz über Ultralytics: Exportierte Nicht-YOLO-Modelle können nicht zur Inferenz zurück in YOLO() geladen werden. Verwende die native Laufzeitumgebung für jedes Format (ONNX Runtime, OpenVINO Runtime, etc.).
  • YOLO-spezifische Formate: Axelera und Fortschritten im Bereich Sony IMX500 Exporte erfordern YOLO-spezifische Modellattribute und sind für generische Modelle nicht verfügbar.
  • Plattformspezifische Formate: TensorRT erfordert eine NVIDIA GPU. RKNN erfordert das rknn-toolkit2 SDK (nur Linux). Edge TPU erfordert das edgetpu_compiler Binary (nur Linux).

FAQ

Welche Modelle kann ich mit Ultralytics exportieren?

Jedes torch.nn.Module. Dies schließt Modelle von timm, torchvision oder jedes benutzerdefinierte PyTorch-Modell ein. Das Modell muss sich vor dem Export im Evaluierungsmodus befinden (model.eval()). ONNX und OpenVINO akzeptieren zusätzlich ein Tupel von Beispiel-Tensoren für Modelle mit mehreren Eingaben.

Welche Exportformate funktionieren ohne GPU?

Alle unterstützten Formate (TorchScript, ONNX, OpenVINO, CoreML, TF SavedModel, TF Frozen Graph, NCNN, PaddlePaddle, MNN, ExecuTorch) können auf der CPU exportiert werden. Für den Exportvorgang selbst ist keine GPU erforderlich. TensorRT ist das einzige Format, das eine NVIDIA GPU erfordert.

Welche Ultralytics-Version benötige ich?

Verwende Ultralytics >=8.4.38, das das ultralytics.utils.export Modul und die standardisierte output_file/output_dir Argumenten.

Kann ich ein torchvision-Modell für die iOS-Bereitstellung nach CoreML exportieren?

Ja. torchvision-Klassifizierungs-, Detektions- und Segmentierungsmodelle exportieren nach .mlpackage via torch2coreml. Für Bildklassifizierungsmodelle übergibst du eine Liste von Klassennamen an classifier_names um einen Klassifizierungskopf zu integrieren. Führe den Export auf macOS oder Linux aus. CoreML wird unter Windows nicht unterstützt. Siehe die CoreML-Integration für Details zur iOS-Bereitstellung.

Kann ich mein exportiertes Modell auf INT8 oder FP16 quantisieren?

Ja, für verschiedene Formate. Übergebe half=True für FP16 oder int8=True für INT8 beim Export nach OpenVINO, CoreML, MNN oder NCNN. INT8 in OpenVINO erfordert zusätzlich ein calibration_dataset Argument für post-training quantization. Siehe die Integrationsseite des jeweiligen Formats für Kompromisse bei der Quantisierung.

Kommentare