Link to this sectionComment exporter des modèles PyTorch non-YOLO avec Ultralytics#
Ultralytics propose des utilitaires d'exportation autonomes via ultralytics.utils.export qui regroupent de multiples backends derrière une interface cohérente. Tu peux exporter n'importe quel torch.nn.Module, y compris les modèles d'image timm, les classificateurs et détecteurs torchvision, ou tes propres architectures personnalisées, vers ONNX, TorchScript, OpenVINO, CoreML, NCNN, PaddlePaddle, MNN, ExecuTorch et TensorFlow SavedModel sans avoir à apprendre chaque backend séparément.
Déployer des modèles PyTorch en production implique généralement de jongler avec un exportateur différent pour chaque cible : torch.onnx.export pour ONNX, coremltools pour les appareils Apple, onnx2tf pour TensorFlow, pnnx pour NCNN, et ainsi de suite. Chaque outil possède sa propre API, ses spécificités de dépendances et ses conventions de sortie. Ces utilitaires condensent tout cela en un seul modèle d'appel.
Link to this sectionPourquoi utiliser Ultralytics pour l'exportation non-YOLO ?#
- Une seule API pour 10 formats : apprends une convention d'appel unique au lieu d'une douzaine.
- Surface utilitaire partagée : les assistants d'exportation se trouvent sous
ultralytics.utils.export, donc une fois les packages backend installés, tu peux conserver le même modèle d'appel entre les formats. - Même chemin de code que les exportations YOLO : les mêmes assistants alimentent toutes les exportations YOLO d'Ultralytics.
- Quantification FP16 et INT8 intégrée pour les formats qui la prennent en charge (OpenVINO, CoreML, MNN, NCNN).
- Fonctionne sur CPU : aucun GPU requis pour l'étape d'exportation elle-même, tu peux donc l'exécuter localement sur n'importe quel ordinateur portable.
Link to this sectionDémarrage rapide#
Le chemin le plus rapide est une exportation en deux lignes vers ONNX sans code YOLO et sans autre configuration que 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")Link to this sectionFormats d'exportation pris en charge#
Les fonctions torch2* prennent un torch.nn.Module standard et un exemple de tenseur d'entrée. MNN, TF SavedModel et TF Frozen Graph passent par un artefact intermédiaire ONNX ou Keras. Aucun attribut spécifique à YOLO n'est requis dans les deux cas.
| Format | Fonction | Installer | Sortie |
|---|---|---|---|
| ONNX | torch2onnx() | pip install onnx | Fichier .onnx |
| TorchScript | torch2torchscript() | inclus avec PyTorch | Fichier .torchscript |
| OpenVINO | torch2openvino() | pip install openvino | Répertoire _openvino_model/ |
| CoreML | torch2coreml() | pip install coremltools | .mlpackage |
| TF SavedModel | onnx2saved_model() | voir les exigences détaillées ci-dessous | Répertoire _saved_model/ |
| TF Frozen Graph | keras2pb() | voir les exigences détaillées ci-dessous | Fichier .pb |
| NCNN | torch2ncnn() | pip install ncnn pnnx | Répertoire _ncnn_model/ |
| MNN | onnx2mnn() | pip install MNN | Fichier .mnn |
| PaddlePaddle | torch2paddle() | pip install paddlepaddle x2paddle | Répertoire _paddle_model/ |
| ExecuTorch | torch2executorch() | pip install executorch | Répertoire _executorch_model/ |
Les exportations MNN, TF SavedModel et TF Frozen Graph passent par ONNX comme étape intermédiaire. Exporte d'abord vers ONNX, puis convertis.
Plusieurs fonctions d'exportation acceptent un dictionnaire metadata optionnel (par exemple, torch2torchscript(..., metadata={"author": "me"})) qui intègre des paires clé-valeur personnalisées dans l'artefact exporté lorsque le format le prend en charge.
Link to this sectionExemples étape par étape#
Chaque exemple ci-dessous utilise la même configuration, un ResNet-18 pré-entraîné de timm en mode évaluation :
import timm
import torch
model = timm.create_model("resnet18", pretrained=True).eval()
im = torch.randn(1, 3, 224, 224)Le Dropout, la batch normalization et d'autres couches réservées à l'entraînement se comportent différemment pendant l'inférence. Omettre .eval() produit des exportations avec des sorties incorrectes.
Link to this sectionExporter vers ONNX#
from ultralytics.utils.export import torch2onnx
torch2onnx(model, im, output_file="resnet18.onnx")Pour une taille de lot dynamique, passe un dictionnaire dynamic :
torch2onnx(model, im, output_file="resnet18_dyn.onnx", dynamic={"images": {0: "batch_size"}})L'opset par défaut est 14 et le nom d'entrée par défaut est "images". Remplace-les avec les arguments opset, input_names ou output_names.
Link to this sectionExporter vers TorchScript#
Aucune dépendance supplémentaire requise. Utilise torch.jit.trace en interne.
from ultralytics.utils.export import torch2torchscript
torch2torchscript(model, im, output_file="resnet18.torchscript")Link to this sectionExporter vers OpenVINO#
from ultralytics.utils.export import torch2openvino
ov_model = torch2openvino(model, im, output_dir="resnet18_openvino_model")Le répertoire contient une paire model.xml et model.bin au nom fixe :
resnet18_openvino_model/
├── model.xml
└── model.binPasse dynamic=True pour des formes d'entrée dynamiques, quantize=16 pour du FP16, ou quantize=8 pour une quantification INT8. L'INT8 nécessite en outre un argument calibration_dataset.
Nécessite openvino>=2024.0.0 (ou >=2025.2.0 sur macOS 15.4+) et torch>=2.1.
Link to this sectionExporter vers 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")Pour les modèles de classification, passe une liste de noms de classes à classifier_names pour ajouter une tête de classification au modèle CoreML.
Nécessite coremltools>=9.0, torch>=1.11 et numpy<=2.3.5. Non pris en charge sur Windows.
coremltools>=9.0 fournit des wheels pour Python 3.10–3.13 sur macOS et Linux. Sur les versions plus récentes de Python, l'extension native C échoue au chargement. Utilise Python 3.10–3.13 pour l'exportation CoreML.
Link to this sectionExporter vers TensorFlow SavedModel#
L'exportation TF SavedModel passe par ONNX comme étape intermédiaire :
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")La fonction renvoie un modèle Keras et génère également des fichiers TFLite (.tflite) dans le répertoire de sortie :
resnet18_saved_model/
├── saved_model.pb
├── variables/
├── resnet18_float32.tflite
├── resnet18_float16.tflite
└── resnet18_int8.tfliteExigences :
tensorflow>=2.0.0,<=2.19.0onnx2tf>=1.26.3,<1.29.0tf_keras<=2.19.0sng4onnx>=1.0.1onnx_graphsurgeon>=0.3.26(installe avec--extra-index-url https://pypi.ngc.nvidia.com)ai-edge-litert>=1.2.0,<1.4.0sur macOS (ai-edge-litert>=1.2.0sur d'autres plateformes)onnxslim>=0.1.82onnx>=1.12.0,<2.0.0protobuf>=5
Link to this sectionExporter vers TensorFlow Frozen Graph#
En poursuivant depuis l'exportation SavedModel ci-dessus, convertis le keras_model renvoyé en un graphe .pb figé :
from pathlib import Path
from ultralytics.utils.export import keras2pb
keras2pb(keras_model, output_file=Path("resnet18_saved_model/resnet18.pb"))Link to this sectionExporter vers NCNN#
from ultralytics.utils.export import torch2ncnn
torch2ncnn(model, im, output_dir="resnet18_ncnn_model")Le répertoire contient des fichiers param et bin au nom fixe ainsi qu'un wrapper Python :
resnet18_ncnn_model/
├── model.ncnn.param
├── model.ncnn.bin
└── model_ncnn.pytorch2ncnn() vérifie la présence de ncnn et pnnx lors de la première utilisation.
Link to this sectionExporter vers MNN#
L'exportation MNN nécessite un fichier ONNX en entrée. Exporte d'abord vers ONNX, puis convertis :
from ultralytics.utils.export import onnx2mnn, torch2onnx
torch2onnx(model, im, output_file="resnet18.onnx")
onnx2mnn("resnet18.onnx", output_file="resnet18.mnn")Prend en charge quantize=16 pour du FP16 et quantize=8 pour une quantification INT8. Nécessite MNN>=2.9.6 et torch>=1.10.
Link to this sectionExporter vers PaddlePaddle#
from ultralytics.utils.export import torch2paddle
torch2paddle(model, im, output_dir="resnet18_paddle_model")Le répertoire contient le modèle PaddlePaddle et les fichiers de paramètres :
resnet18_paddle_model/
├── model.pdmodel
└── model.pdiparamsNécessite x2paddle et la distribution PaddlePaddle correcte pour ta plateforme :
paddlepaddle-gpu>=3.0.0,<3.3.0sur CUDApaddlepaddle==3.0.0sur CPU ARM64paddlepaddle>=3.0.0,<3.3.0sur d'autres CPU
Non pris en charge sur NVIDIA Jetson.
Link to this sectionExporter vers ExecuTorch#
from ultralytics.utils.export import torch2executorch
torch2executorch(model, im, output_dir="resnet18_executorch_model")Le fichier .pte exporté est enregistré dans le répertoire de sortie :
resnet18_executorch_model/
└── model.pteNécessite torch>=2.9.0 et un runtime ExecuTorch correspondant (pip install executorch). Pour l'utilisation du runtime, consulte l'intégration ExecuTorch.
Link to this sectionVérifie ton modèle exporté#
Après l'exportation, vérifie la parité numérique avec le modèle PyTorch original avant la mise en production. Un test rapide avec ONNXBackend issu de ultralytics.nn.backends compare les sorties et signale rapidement les erreurs de traçage ou de quantification :
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 FP32Pour les exportations FP32, la différence absolue maximale est généralement d'environ 1e-5 et devrait rester bien inférieure à 1e-4. Des différences plus grandes indiquent des opérations non prises en charge, une forme d'entrée incorrecte ou un modèle qui n'est pas en mode évaluation. Les exportations FP16 et INT8 ont des tolérances plus larges. Valide sur des données réelles plutôt que sur des tenseurs aléatoires.
Pour d'autres runtimes, le nom du tenseur d'entrée peut différer. OpenVINO, par exemple, utilise le nom de l'argument forward du modèle (généralement x pour les modèles génériques), tandis que torch2onnx utilise "images" par défaut.
Link to this sectionLimitations connues#
- La prise en charge des entrées multiples est inégale :
torch2onnxettorch2openvinoacceptent un tuple ou une liste de tenseurs exemples pour les modèles avec des entrées multiples.torch2torchscript,torch2coreml,torch2ncnn,torch2paddleettorch2executorchsupposent un tenseur d'entrée unique. - ExecuTorch nécessite
flatc: Le runtime ExecuTorch nécessite le compilateur FlatBuffers. Installe-le avecbrew install flatbufferssur macOS ouapt install flatbuffers-compilersur Ubuntu. - Pas d'inférence via Ultralytics : Les modèles non-YOLO exportés ne peuvent pas être rechargés via
YOLO()pour l'inférence. Utilise le runtime natif pour chaque format (ONNX Runtime, OpenVINO Runtime, etc.). - Formats spécifiques à YOLO : Les exports Axelera et Sony IMX500 nécessitent des attributs de modèle spécifiques à YOLO et ne sont pas disponibles pour les modèles génériques.
- Formats spécifiques à la plateforme : TensorRT nécessite un GPU NVIDIA. RKNN nécessite le SDK
rknn-toolkit2(Linux uniquement). Edge TPU nécessite le binaireedgetpu_compiler(Linux uniquement).
Link to this sectionConclusion#
Ces utilitaires prennent n'importe quel modèle PyTorch, d'un simple torch.nn.Module vers un artefact ONNX, OpenVINO, CoreML, TensorFlow ou runtime mobile prêt pour le déploiement via une API unique et cohérente. Choisis le format qui correspond à ton matériel cible, vérifie la parité numérique par rapport au modèle original, puis suis le guide d'intégration correspondant pour les étapes de déploiement spécifiques au runtime.
Link to this sectionFAQ#
Link to this sectionQuels modèles puis-je exporter avec Ultralytics ?#
N'importe quel torch.nn.Module. Cela inclut les modèles de timm, torchvision ou tout modèle PyTorch personnalisé. Le modèle doit être en mode évaluation (model.eval()) avant l'exportation. ONNX et OpenVINO acceptent en outre un tuple de tenseurs exemples pour les modèles à entrées multiples.
Link to this sectionQuels formats d'exportation fonctionnent sans GPU ?#
Tous les formats pris en charge (TorchScript, ONNX, OpenVINO, CoreML, TF SavedModel, TF Frozen Graph, NCNN, PaddlePaddle, MNN, ExecuTorch) peuvent être exportés sur CPU. Aucun GPU n'est requis pour le processus d'exportation lui-même. TensorRT est le seul format qui nécessite un GPU NVIDIA.
Link to this sectionDe quelle version d'Ultralytics ai-je besoin ?#
Utilise Ultralytics >=8.4.38, qui inclut le module ultralytics.utils.export et les arguments standardisés output_file/output_dir.
Link to this sectionPuis-je exporter un modèle torchvision vers CoreML pour un déploiement iOS ?#
Oui. Les classifieurs, détecteurs et modèles de segmentation torchvision s'exportent en .mlpackage via torch2coreml. Pour les modèles de classification d'images, passe une liste de noms de classes à classifier_names pour intégrer une tête de classification. Exécute l'exportation sur macOS ou Linux. CoreML n'est pas pris en charge sur Windows. Consulte l'intégration CoreML pour les détails sur le déploiement iOS.
Link to this sectionPuis-je quantifier mon modèle exporté en INT8 ou FP16 ?#
Oui, pour plusieurs formats. Passe quantize=16 pour du FP16 ou quantize=8 pour de l'INT8 lors de l'exportation vers OpenVINO, CoreML, MNN ou NCNN. L'INT8 dans OpenVINO nécessite en outre un argument calibration_dataset pour la post-training quantization. Consulte la page d'intégration de chaque format pour connaître les compromis liés à la quantification.
Link to this sectionComment vérifier qu'un modèle exporté correspond à l'original ?#
Exécute le modèle PyTorch original et le modèle exporté sur la même entrée, puis compare les sorties. Charge le fichier exporté avec le backend correspondant (par exemple, ONNXBackend pour ONNX) et vérifie la différence absolue maximale. Pour les exportations FP32, elle est généralement d'environ 1e-5 et devrait rester bien inférieure à 1e-4 ; des écarts plus grands indiquent des opérations non prises en charge, une forme d'entrée incorrecte ou un modèle qui n'est pas en mode évaluation. Voir Vérifier ton modèle exporté pour un exemple exécutable.