Come esportare modelli PyTorch non YOLO con Ultralytics#
Ultralytics include utility di esportazione autonome in ultralytics.utils.export che integrano più backend in un'unica interfaccia coerente. Puoi esportare qualsiasi torch.nn.Module, inclusi i modelli di visione artificiale timm, i classificatori e rilevatori torchvision o le tue architetture personalizzate, nei formati TorchScript, ONNX, OpenVINO, CoreML, Core AI, TensorFlow SavedModel, TensorFlow Frozen Graph, PaddlePaddle, MNN, NCNN ed ExecuTorch, senza dover imparare a usare separatamente ogni backend.
Portare in produzione modelli PyTorch di solito significa destreggiarsi tra un esportatore diverso per ogni destinazione: torch.onnx.export per ONNX, coremltools per i dispositivi Apple, onnx2tf per TensorFlow, pnnx per NCNN e così via. Ogni strumento ha la propria API, dipendenze con peculiarità e convenzioni di output. Queste utility riuniscono tutto in un unico schema di chiamata.
Perché usare Ultralytics per esportare modelli non YOLO?#
- Un'unica API per 11 formati: impara un solo schema di chiamata invece di una dozzina.
- Stesso percorso del codice delle esportazioni YOLO: gli stessi helper gestiscono tutte le esportazioni YOLO di Ultralytics.
- Quantizzazione FP16 e INT8 tramite un unico argomento
quantizeper i formati che la supportano. - Funziona su CPU: non serve una GPU per la fase di esportazione, quindi puoi eseguirla localmente su un laptop; l'esportazione CoreML non è supportata su Windows, mentre l'esportazione Core AI richiede macOS 26 o versioni successive su silicio Apple, oppure Linux x86_64 con glibc 2.34 o versioni successive e Python dalla 3.11 alla 3.14.
Avvio rapido#
Il modo più rapido è esportare in ONNX con due righe, senza codice YOLO e senza alcuna configurazione oltre a 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")Formati di esportazione supportati#
Le funzioni torch2* accettano un torch.nn.Module standard e un tensore di input di esempio. MNN, TF SavedModel e TF Frozen Graph passano attraverso un artefatto intermedio ONNX o Keras. In entrambi i casi non servono attributi specifici di YOLO.
| Formato | Funzione | Installazione | Output |
|---|---|---|---|
| TorchScript | torch2torchscript() | incluso in PyTorch | file .torchscript |
| ONNX | torch2onnx() | pip install onnx | file .onnx |
| OpenVINO | torch2openvino() | pip install openvino | directory _openvino_model/ |
| CoreML | torch2coreml() | pip install coremltools | .mlpackage |
| Core AI | torch2coreai() | pip install coreai-torch (silicio Apple con macOS 26 o versioni successive, oppure Linux x86_64 con glibc 2.34 o versioni successive; Python dalla 3.11 alla 3.14) | directory .aimodel |
| TF SavedModel | onnx2saved_model() | consulta i requisiti dettagliati qui sotto | directory _saved_model/ |
| TF Frozen Graph | keras2pb() | consulta i requisiti dettagliati qui sotto | file .pb |
| PaddlePaddle | torch2paddle() | pip install paddlepaddle x2paddle | directory _paddle_model/ |
| MNN | onnx2mnn() | pip install MNN | file .mnn |
| NCNN | torch2ncnn() | pip install ncnn pnnx | directory _ncnn_model/ |
| ExecuTorch | torch2executorch() | pip install executorch | directory _executorch_model/ |
Diverse funzioni di esportazione accettano un dizionario metadata facoltativo (ad es. torch2torchscript(..., metadata={"author": "me"})) che incorpora coppie chiave-valore personalizzate nell'artefatto esportato, se il formato lo supporta.
Esempi passo passo#
Tutti gli esempi qui sotto usano la stessa configurazione: un ResNet-18 pretrained da timm in modalità di valutazione:
import timm
import torch
model = timm.create_model("resnet18", pretrained=True).eval()
im = torch.randn(1, 3, 224, 224)Dropout, normalizzazione batch e gli altri layer usati solo in addestramento si comportano diversamente durante l'inferenza. Se non esegui .eval(), le esportazioni produrranno output errati.
Esporta in ONNX#
from ultralytics.utils.export import torch2onnx
torch2onnx(model, im, output_file="resnet18.onnx")Per usare una dimensione del batch dinamica, passa un dizionario dynamic:
torch2onnx(model, im, output_file="resnet18_dyn.onnx", dynamic={"images": {0: "batch_size"}})L'opset predefinito è 14 e il nome di input predefinito è "images". Puoi cambiarli con gli argomenti opset, input_names o output_names.
Esportare in TorchScript#
Non servono dipendenze aggiuntive. Usa torch.jit.trace internamente.
from ultralytics.utils.export import torch2torchscript
torch2torchscript(model, im, output_file="resnet18.torchscript")Esportare in OpenVINO#
from ultralytics.utils.export import torch2openvino
ov_model = torch2openvino(model, im, output_dir="resnet18_openvino_model")La directory contiene una coppia model.xml e model.bin con nomi fissi:
resnet18_openvino_model/
├── model.xml
└── model.binPassa dynamic=True per le forme di input dinamiche, quantize=16 per FP16 oppure quantize=8 per la quantizzazione INT8. INT8 richiede anche l'argomento calibration_dataset.
Richiede openvino>=2024.0.0 (oppure >=2025.2.0 su macOS 15.4+) e torch>=2.1.
Esportare in 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")Per i modelli di classificazione, passa un elenco di nomi di classe a classifier_names per aggiungere una testa di classificazione al modello CoreML.
Richiede coremltools>=9.0, torch>=1.11 e numpy<=2.3.5. Non è supportato su Windows.
coremltools>=9.0 include wheel per Python 3.10–3.13 su macOS e Linux. Nelle versioni più recenti di Python, l'estensione C nativa non riesce a caricarsi. Per esportare in CoreML, usa Python 3.10–3.13.
Esportare in Core AI#
from ultralytics.utils.export import torch2coreai
torch2coreai(model, im, output_file="resnet18.aimodel")L'elemento .aimodel è una directory:
resnet18.aimodel/
├── main.mlirb
├── main.hash
└── metadata.jsonL'esportazione viene eseguita su macOS 26 o versioni successive su silicio Apple, oppure su Linux x86_64 con glibc 2.34 o versioni successive e Python dalla 3.11 alla 3.14 (pip install coreai-torch), mentre quantize=16 scrive un asset FP16 che accetta input float16; l'asset viene eseguito su iOS 27 e macOS 27. Consulta l'integrazione Core AI, inclusa la nota sugli asset FP16 che causano un arresto anomalo durante il caricamento.
Esportare in TensorFlow SavedModel#
L'esportazione TF SavedModel passa da ONNX come passaggio intermedio:
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 funzione restituisce un modello Keras e genera anche file [LiteRT](https://ultralytics-translation-0.invalid FP32 e FP16 (.tflite) nella directory di output:
resnet18_saved_model/
├── saved_model.pb
├── variables/
├── assets/
├── fingerprint.pb
├── resnet18_float32.tflite
└── resnet18_float16.tflitePassa quantize=8 per aggiungere un elemento .tflite INT8.
L'esportazione TensorFlow non funziona su macOS con Python 3.13 o versioni successive; su macOS usa Python 3.12 o versioni precedenti, oppure usa Linux.
Requisiti con Python 3.12 o versioni precedenti (con Python 3.13 o versioni successive, l'esportazione richiede invece tensorflow>2.19.0, tf_keras>2.19.0,
onnx2tf>=2.3.0,<2.3.16 e 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.26ai-edge-litert>=1.2.0,<1.4.0su macOS (ai-edge-litert>=1.2.0sulle altre piattaforme)onnxslim>=0.1.82onnx>=1.12.0,<2.0.0protobuf>=5
Esportare in TensorFlow Frozen Graph#
Partendo dall'esportazione SavedModel qui sopra, converti il keras_model restituito in un grafico .pb congelato:
from pathlib import Path
from ultralytics.utils.export import keras2pb
keras2pb(keras_model, output_file=Path("resnet18_saved_model/resnet18.pb"))Esportare in NCNN#
from ultralytics.utils.export import torch2ncnn
torch2ncnn(model, im, output_dir="resnet18_ncnn_model")La directory contiene file param e bin con nomi fissi, oltre a un wrapper Python:
resnet18_ncnn_model/
├── model.ncnn.param
├── model.ncnn.bin
└── model_ncnn.pyEsportare in MNN#
L'esportazione MNN richiede un file ONNX come input. Esporta prima in ONNX, poi converti:
from ultralytics.utils.export import onnx2mnn, torch2onnx
torch2onnx(model, im, output_file="resnet18.onnx")
onnx2mnn("resnet18.onnx", output_file="resnet18.mnn")Supporta quantize=16 per FP16 e quantize=8 per la quantizzazione INT8. Richiede MNN>=2.9.6 e torch>=1.10.
Esportare in PaddlePaddle#
from ultralytics.utils.export import torch2paddle
torch2paddle(model, im, output_dir="resnet18_paddle_model")La directory contiene il modello e i file dei parametri PaddlePaddle:
resnet18_paddle_model/
├── inference_model/
│ ├── model.json
│ └── model.pdiparams
├── model.pdparams
└── x2paddle_code.pyRichiede x2paddle e la distribuzione PaddlePaddle corretta per la tua piattaforma:
paddlepaddle-gpu>=3.0.0,<3.3.0su CUDApaddlepaddle==3.0.0su CPU ARM64paddlepaddle>=3.0.0,<3.3.0su altre CPU
Non supportato su NVIDIA Jetson.
Esportare in ExecuTorch#
from ultralytics.utils.export import torch2executorch
torch2executorch(model, im, output_dir="resnet18_executorch_model")Il file .pte esportato viene salvato nella directory di output:
resnet18_executorch_model/
└── model.pteRichiede torch>=2.9.0 e un runtime ExecuTorch compatibile (pip install executorch). Per usare il runtime, consulta l'integrazione ExecuTorch.
Verificare il modello esportato#
Dopo l'esportazione, verifica la parità numerica con il modello PyTorch originale prima di distribuirlo. Un rapido test di funzionamento con ONNXBackend da ultralytics.nn.backends confronta gli output e segnala tempestivamente gli errori di tracing o quantizzazione:
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 exportCon ResNet-18, la maggior parte delle esportazioni FP32 si discosta da PyTorch di circa 1e-5 al massimo, mentre TorchScript corrisponde esattamente. Tre runtime possono comunque calcolare un'esportazione FP32 con precisione ridotta e discostarsi di circa 1e-2–1e-1: NCNN abilita l'aritmetica FP16 sulle CPU che la supportano, MNNBackend carica i modelli con precision="low" e il plugin CPU OpenVINO esegue automaticamente in FP16, con la modalità di esecuzione predefinita PERFORMANCE, su alcuni hardware, come il silicio Apple. Una differenza molto superiore alla baseline del formato stesso indica operazioni non supportate, una forma di input errata o un modello non in modalità eval. Le esportazioni FP16 e INT8 hanno tolleranze più ampie. Convalida usando dati reali anziché tensori casuali.
Per altri runtime, il nome del tensore di input può essere diverso. OpenVINO, ad esempio, usa il nome dell'argomento forward del modello (in genere x per i modelli generici), mentre torch2onnx usa "images" come valore predefinito.
Eseguire il modello esportato#
Puoi caricare i modelli non YOLO esportati tramite la normale API YOLO(). Le esportazioni qui sopra non includono metadati Ultralytics relativi all'attività o alle dimensioni di input: passa quindi task in modo esplicito e imposta imgsz in modo che corrisponda al tensore di esempio usato per l'esportazione:
from ultralytics import YOLO
results = YOLO("resnet18.onnx", task="classify")("path/to/image.jpg", imgsz=224)
print(results[0].probs.top1)imgsz è importante quando l'esportazione ha una forma di input fissa: le esportazioni ONNX e TF SavedModel qui sopra rifiutano il valore predefinito 640. Le esportazioni TorchScript e NCNN qui sopra accettano anche altre dimensioni, ma nessuno dei due esportatori lo garantisce: entrambi eseguono il tracing a partire dal tensore di esempio, quindi un modello che appiattisce i dati in un layer Linear mantiene dimensioni fisse. Verifica la tua esportazione.
Il valore viene quindi arrotondato per eccesso al multiplo più vicino dello stride del modello, che senza metadati è 32. Un'esportazione con forma fissa di 200x200 riceve quindi un input di 224x224 e viene rifiutata, anche se imgsz=200 corrisponde. Per dimensioni di input che non sono multipli di 32, chiama direttamente il backend.
Chiamare direttamente un backend#
Per usare tensori grezzi senza preprocessing e post-processing di Ultralytics, usa le classi specifiche per formato in ultralytics.nn.backends, come nell'esempio di verifica qui sopra. Ogni classe accetta l'artefatto esportato e un dispositivo ed è richiamabile:
| Formato | Backend | Layout di input |
|---|---|---|
| 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 supporta due formati e usa format="saved_model" come valore predefinito, quindi passa format="pb" per un grafico congelato.
Tre operazioni che il percorso YOLO() gestisce al posto tuo, ma non una chiamata diretta:
- Layout di input:
CoreMLBackendeTensorFlowBackendsi aspettano BHWC. Trasponi prima conim.permute(0, 2, 3, 1); un tensore BCHW genera un errore di mancata corrispondenza della forma. - Autograd: racchiudi le chiamate in
torch.inference_mode().TorchScriptBackendrestituisce un tensore che mantiene un grafo del gradiente. - Post-processing: senza metadati, un backend lascia
taskcomeNoneenamesvuoti.LiteRTBackendcontinua a denormalizzare qualsiasi output 3D in base alle dimensioni dell'immagine, supponendo che contenga box YOLO: un comportamento errato per un modello non YOLO con output 3D. Gli output bidimensionali, come i logit di un classificatore, non ne risentono.
Limitazioni note#
- Il supporto multi-input è disomogeneo:
torch2onnx,torch2openvinoetorch2torchscriptaccettano una tupla di tensori di esempio per i modelli con più input.torch2coreml,torch2coreai,torch2ncnn,torch2paddleetorch2executorchpresuppongono un singolo tensore di input. - Formati riservati a YOLO: le esportazioni Axelera e Sony IMX500 richiedono attributi specifici dei modelli YOLO e non sono disponibili per i modelli generici.
- Formati specifici per piattaforma: TensorRT richiede una GPU NVIDIA. RKNN richiede l'SDK
rknn-toolkit2(solo Linux). Edge TPU richiede il binarioedgetpu_compiler(solo Linux).
Conclusione#
Queste utility convertono qualsiasi modello PyTorch, da un semplice torch.nn.Module a un artefatto ONNX, OpenVINO, CoreML, TensorFlow o per runtime mobile pronto per la distribuzione, tramite un'unica API coerente. Scegli il formato adatto all'hardware di destinazione, verifica la parità numerica rispetto al modello originale, poi segui la guida all'integrazione corrispondente per i passaggi di distribuzione specifici del runtime.
Domande frequenti#
Qualsiasi
torch.nn.Module. Sono inclusi i modelli di timm, torchvision e qualsiasi modello PyTorch personalizzato. Prima dell'esportazione, il modello deve essere in modalità di valutazione (model.eval()). Anche ONNX, OpenVINO e TorchScript accettano una tupla di tensori di esempio per i modelli con più input.Tutti i formati supportati (TorchScript, ONNX, OpenVINO, CoreML, Core AI, TF SavedModel, TF Frozen Graph, PaddlePaddle, MNN, NCNN ed ExecuTorch) possono essere esportati su CPU. Il processo di esportazione non richiede una GPU. TensorRT è l'unico formato che richiede una GPU NVIDIA.
Usa la versione più recente. L'argomento
quantizerichiede Ultralytics>=8.4.81, mentre l'esportazione Core AI richiede>=8.4.131(>=8.4.163su Linux o concoreai-torch>=0.4.3).Sì. I classificatori, i rilevatori e i modelli di segmentazione torchvision si esportano in
.mlpackagetramitetorch2coreml. Per i modelli di classificazione delle immagini, passa un elenco di nomi delle classi aclassifier_namesper integrare una testa di classificazione. Esegui l'esportazione su macOS o Linux. CoreML non è supportato su Windows. Consulta l'integrazione CoreML per i dettagli sul deployment su iOS.Sì, per diversi formati. Passa
quantize=16per FP16 oquantize=8per INT8 quando esporti in OpenVINO, CoreML o MNN;onnx2saved_modelaccettaquantize=8per un file LiteRT INT8, mentre NCNN e Core AI esportano in FP32 per impostazione predefinita, accettanoquantize=16per FP16 e non offrono un percorso INT8. INT8 in OpenVINO richiede inoltre un argomentocalibration_datasetper la quantizzazione post-addestramento. Consulta la pagina di integrazione di ciascun formato per conoscere i compromessi della quantizzazione.Esegui il modello PyTorch originale e il modello esportato sullo stesso input, quindi confronta gli output. Carica il file esportato con il backend corrispondente (ad esempio,
ONNXBackendper ONNX) e controlla la differenza assoluta massima. Valuta lo scarto rispetto alla baseline specifica del formato: NCNN,MNNBackende OpenVINO su alcune CPU possono eseguire le esportazioni FP32 con precisione ridotta, con scarti vicini a1e-2–1e-1, mentre la maggior parte degli altri formati si attesta intorno a1e-5. Uno scarto molto più ampio indica operazioni non supportate, una forma di input errata o un modello non in modalità eval. Consulta Verifica il modello esportato per un esempio eseguibile.