YOLO Vision 2026:

So exportierst du PyTorch-Modelle, die keine YOLO-Modelle sind, mit Ultralytics#

Ultralytics bietet eigenständige Export-Dienstprogramme unter ultralytics.utils.export an, die mehrere Backends hinter einer einheitlichen Schnittstelle kapseln. Du kannst jedes torch.nn.Module, einschließlich timm Bildmodellen, torchvision Klassifikatoren und Detektoren oder deine eigenen benutzerdefinierten Architekturen, ohne separates Einarbeiten in jedes Backend nach ONNX, TorchScript, OpenVINO, CoreML, NCNN, PaddlePaddle, MNN, ExecuTorch und TensorFlow SavedModel exportieren.

Die Bereitstellung von PyTorch-Modellen in der Produktion erfordert normalerweise das Jonglieren mit einem anderen Exporter für jedes Ziel: 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. Diese Dienstprogramme fassen dies in einem einzigen Aufrufmuster zusammen.

Warum Ultralytics für den Nicht-YOLO-Export verwenden?#

  • Eine API für 10 Formate: Lerne eine einzige Aufrufkonvention statt eines Dutzends.
  • Gemeinsame Dienstprogrammoberfläche: Die Export-Hilfsfunktionen befinden sich unter ultralytics.utils.export, sodass du nach der Installation der Backend-Pakete über verschiedene Formate hinweg dasselbe Aufrufmuster beibehalten kannst.
  • Derselbe Codepfad wie bei YOLO-Exporten: Dieselben Helfer steuern jeden Ultralytics YOLO-Export.
  • FP16- und INT8-Quantisierung ist für unterstützte Formate (OpenVINO, CoreML, MNN, NCNN) integriert.
  • Funktioniert auf der CPU: Für den Export-Schritt selbst ist keine GPU erforderlich, sodass du ihn lokal auf jedem Laptop ausführen kannst.

Kurzanleitung#

Der schnellste Weg ist ein zweizeiliger Export nach ONNX ganz ohne YOLO-Code und ohne Einrichtung abgesehen von 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 nehmen ein standardmäßiges torch.nn.Module und einen Beispiel-Eingabetensor entgegen. MNN, TF SavedModel und TF Frozen Graph durchlaufen ein intermediäres ONNX- oder Keras-Artefakt. In beiden Fällen sind keine YOLO-spezifischen 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 erfolgen als Zwischenschritt über ONNX. Exportiere zuerst nach ONNX und konvertiere dann.

Metadaten einbetten

Mehrere Exportfunktionen akzeptieren ein optionales metadata-Wörterbuch (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 dieselbe Einrichtung: 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-Normalisierung und andere Nur-Trainings-Schichten 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 eine dynamische Batch-Größe übergib ein dynamic-Wörterbuch:

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

Das Standard-Opset ist 14 und der Standard-Eingabename ist "images". Überschreibe diese mit den Argumenten opset, input_names oder output_names.

Export nach TorchScript#

Keine zusätzlichen Abhängigkeiten erforderlich. Verwendet torch.jit.trace im Hintergrund.

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 Paar aus model.xml und model.bin mit festem Namen:

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

Übergebe dynamic=True für dynamische Eingabeformen, quantize=16 für FP16 oder quantize=8 für INT8-Quantisierung. INT8 erfordert zusätzlich ein calibration_dataset-Argument.

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

Für Klassifizierungsmodelle übergebe 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. Wird 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 schlägt das Laden der nativen C-Erweiterung fehl. Verwende Python 3.10–3.13 für den CoreML-Export.

Export nach TensorFlow SavedModel#

Der Export von TF SavedModel 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 außerdem 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
  • ai-edge-litert>=1.2.0,<1.4.0 unter macOS (ai-edge-litert>=1.2.0 auf anderen Plattformen)
  • onnxslim>=0.1.82
  • onnx>=1.12.0,<2.0.0
  • protobuf>=5

Export nach TensorFlow Frozen Graph#

Konvertiere ausgehend vom obigen SavedModel-Export das zurückgegebene keras_model in einen eingefrorenen .pb-Graphen:

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 bei der ersten Verwendung auf ncnn und pnnx.

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 quantize=16 für FP16 und quantize=8 für INT8-Quantisierung. Erfordert MNN>=2.9.6 und 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 Parameterdateien:

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

Erfordert x2paddle und die passende 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

Wird 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). Zur Nutzung der Laufzeitumgebung siehe die ExecuTorch-Integration.

Überprüfe dein exportiertes Modell#

Verifiziere nach dem Export die numerische Parität mit dem originalen PyTorch-Modell vor dem Versand. Ein schneller Rauchtest mit ONNXBackend aus ultralytics.nn.backends vergleicht die Ausgaben und erkennt Tracing- oder Quantisierungsfehler frühzeitig:

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}")  # typically ~1e-5, well under 1e-4 for FP32
Erwartete Differenz

Bei FP32-Exporten liegt die maximale absolute Differenz typischerweise bei etwa 1e-5 und sollte deutlich unter 1e-4 bleiben. Größere Differenzen 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 anhand realer Daten anstelle von Zufallstensoren.

Bei anderen 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" verwendet.

Bekannte Einschränkungen#

  • Unterstützung für mehrere Eingaben ist uneinheitlich: torch2onnx und torch2openvino akzeptieren ein Tupel oder eine Liste von Beispieltensoren für Modelle mit mehreren Eingaben. torch2torchscript, torch2coreml, torch2ncnn, torch2paddle und torch2executorch gehen von einem einzigen Eingabetensor aus.
  • ExecuTorch benötigt flatc: Die ExecuTorch-Laufzeitumgebung erfordert den FlatBuffers-Compiler. Installiere diesen mit brew install flatbuffers unter macOS oder apt install flatbuffers-compiler unter Ubuntu.
  • Keine Inferenz über Ultralytics: Exportierte Nicht-YOLO-Modelle können nicht über YOLO() für die Inferenz zurückgeladen werden. Verwende die native Laufzeitumgebung für jedes Format (ONNX Runtime, OpenVINO Runtime usw.).
  • Nur-YOLO-Formate: Axelera- und 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 die edgetpu_compiler-Binärdatei (nur Linux).

Fazit#

Diese Dienstprogramme bringen jedes PyTorch-Modell von einem einfachen torch.nn.Module zu einem bereitstellungsfertigen ONNX-, OpenVINO-, CoreML-, TensorFlow- oder Mobile-Runtime-Artefakt über eine einheitliche API. Wähle das Format, das zu deiner Zielhardware passt, überprüfe die numerische Parität gegenüber dem Originalmodell und folge dann der passenden Integrationsanleitung für laufzeitspezifische Schritte zur Bereitstellung.

FAQ#

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

  • 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 Exportprozess selbst ist keine GPU erforderlich. TensorRT ist das einzige Format, das eine NVIDIA GPU benötigt.

  • Verwende Ultralytics >=8.4.38, welches das ultralytics.utils.export-Modul und die standardisierten Argumente output_file/output_dir enthält.

  • Ja. torchvision-Klassifikatoren, -Detektoren und -Segmentierungsmodelle werden über torch2coreml nach .mlpackage exportiert. Für Bildklassifizierungsmodelle übergebe eine Liste von Klassennamen an classifier_names, um einen Klassifizierungskopf fest einzubauen. Führe den Export unter macOS oder Linux aus. CoreML wird unter Windows nicht unterstützt. Siehe die CoreML-Integration für Details zur iOS-Bereitstellung.

  • Ja, für mehrere Formate. Übergebe quantize=16 für FP16 oder quantize=8 für INT8 beim Export nach OpenVINO, CoreML, MNN oder NCNN. INT8 in OpenVINO erfordert zusätzlich ein calibration_dataset-Argument für die Post-Training-Quantisierung. Siehe die Integrationsseite jedes Formats für Quantisierungskompromisse.

  • Führe das originale PyTorch-Modell und das exportierte Modell mit derselben Eingabe aus und vergleiche dann die Ausgaben. Lade die exportierte Datei mit dem passenden Backend (zum Beispiel ONNXBackend für ONNX) und überprüfe die maximale absolute Differenz. Bei FP32-Exporten liegt sie typischerweise bei etwa 1e-5 und sollte deutlich unter 1e-4 bleiben; größere Abweichungen deuten auf nicht unterstützte Operationen, eine falsche Eingabeform oder ein Modell hin, das sich nicht im Evaluierungsmodus befindet. Siehe Exportiertes Modell verifizieren für ein ausführbares Beispiel.

Kommentare