Link to this sectionCómo exportar modelos PyTorch que no son YOLO con Ultralytics#
Implementar modelos PyTorch en producción generalmente implica manejar un exportador diferente para cada destino: torch.onnx.export para ONNX, coremltools para dispositivos Apple, onnx2tf para TensorFlow, pnnx para NCNN, etc. Cada herramienta tiene su propia API, peculiaridades de dependencias y convenciones de salida.
Ultralytics ofrece utilidades de exportación independientes que integran múltiples backends bajo una interfaz coherente. Puedes exportar cualquier torch.nn.Module, incluidos modelos de imagen timm, clasificadores y detectores de torchvision, o tus propias arquitecturas personalizadas a ONNX, TorchScript, OpenVINO, CoreML, NCNN, PaddlePaddle, MNN, ExecuTorch y TensorFlow SavedModel sin tener que aprender cada backend por separado.
Link to this section¿Por qué usar Ultralytics para exportaciones que no son YOLO?#
- Una única API para 10 formatos: aprende una sola convención de llamada en lugar de una docena.
- Superficie de utilidad compartida: los asistentes de exportación se encuentran en
ultralytics.utils.export, por lo que una vez instalados los paquetes del backend, puedes mantener el mismo patrón de llamada entre diferentes formatos. - Misma ruta de código que las exportaciones de YOLO: los mismos asistentes impulsan todas las exportaciones de Ultralytics YOLO.
- Cuantización FP16 e INT8 integrada para formatos que la admiten (OpenVINO, CoreML, MNN, NCNN).
- Funciona en CPU: no se requiere GPU para el paso de exportación en sí, por lo que puedes ejecutarlo localmente en cualquier portátil.
Link to this sectionInicio rápido#
La ruta más rápida es una exportación de dos líneas a ONNX sin código YOLO y sin configuración más allá de 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 sectionFormatos de exportación compatibles#
Las funciones torch2* toman un torch.nn.Module estándar y un tensor de entrada de ejemplo. MNN, TF SavedModel y TF Frozen Graph pasan por un artefacto intermedio ONNX o Keras. No se requieren atributos específicos de YOLO en ninguno de los casos.
| Formato | Función | Instalar | Salida |
|---|---|---|---|
| ONNX | torch2onnx() | pip install onnx | archivo .onnx |
| TorchScript | torch2torchscript() | incluido con PyTorch | archivo .torchscript |
| OpenVINO | torch2openvino() | pip install openvino | directorio _openvino_model/ |
| CoreML | torch2coreml() | pip install coremltools | .mlpackage |
| TF SavedModel | onnx2saved_model() | consulta los requisitos detallados a continuación | directorio _saved_model/ |
| TF Frozen Graph | keras2pb() | consulta los requisitos detallados a continuación | archivo .pb |
| NCNN | torch2ncnn() | pip install ncnn pnnx | directorio _ncnn_model/ |
| MNN | onnx2mnn() | pip install MNN | archivo .mnn |
| PaddlePaddle | torch2paddle() | pip install paddlepaddle x2paddle | directorio _paddle_model/ |
| ExecuTorch | torch2executorch() | pip install executorch | directorio _executorch_model/ |
Las exportaciones a MNN, TF SavedModel y TF Frozen Graph pasan por ONNX como un paso intermedio. Exporta primero a ONNX y luego convierte.
Varias funciones de exportación aceptan un diccionario metadata opcional (p. ej., torch2torchscript(..., metadata={"author": "me"})) que incrusta pares clave-valor personalizados en el artefacto exportado cuando el formato lo admite.
Link to this sectionEjemplos paso a paso#
Cada ejemplo a continuación utiliza la misma configuración, un ResNet-18 preentrenado de timm en modo de evaluación:
import timm
import torch
model = timm.create_model("resnet18", pretrained=True).eval()
im = torch.randn(1, 3, 224, 224)El dropout, la normalización por lotes y otras capas solo de entrenamiento se comportan de forma diferente durante la inferencia. Omitir .eval() produce exportaciones con salidas incorrectas.
Link to this sectionExportar a ONNX#
from ultralytics.utils.export import torch2onnx
torch2onnx(model, im, output_file="resnet18.onnx")Para un tamaño de lote dinámico, pasa un diccionario dynamic:
torch2onnx(model, im, output_file="resnet18_dyn.onnx", dynamic={"images": {0: "batch_size"}})El opset predeterminado es 14 y el nombre de entrada predeterminado es "images". Sobrescríbelo con los argumentos opset, input_names o output_names.
Link to this sectionExportar a TorchScript#
No se necesitan dependencias adicionales. Utiliza torch.jit.trace internamente.
from ultralytics.utils.export import torch2torchscript
torch2torchscript(model, im, output_file="resnet18.torchscript")Link to this sectionExportar a OpenVINO#
from ultralytics.utils.export import torch2openvino
ov_model = torch2openvino(model, im, output_dir="resnet18_openvino_model")El directorio contiene un par de archivos model.xml y model.bin con nombre fijo:
resnet18_openvino_model/
├── model.xml
└── model.binPasa dynamic=True para formas de entrada dinámicas, half=True para FP16 o int8=True para cuantización INT8. INT8 requiere adicionalmente un argumento calibration_dataset.
Requiere openvino>=2024.0.0 (o >=2025.2.0 en macOS 15.4+) y torch>=2.1.
Link to this sectionExportar a 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")Para modelos de clasificación, pasa una lista de nombres de clase a classifier_names para añadir una cabecera de clasificación al modelo CoreML.
Requiere coremltools>=9.0, torch>=1.11 y numpy<=2.3.5. No es compatible con Windows.
coremltools>=9.0 incluye wheels para Python 3.10–3.13 en macOS y Linux. En versiones más recientes de Python, la extensión C nativa falla al cargarse. Utiliza Python 3.10–3.13 para la exportación a CoreML.
Link to this sectionExportar a TensorFlow SavedModel#
La exportación a TF SavedModel pasa por ONNX como un paso 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 función devuelve un modelo Keras y también genera archivos TFLite (.tflite) dentro del directorio de salida:
resnet18_saved_model/
├── saved_model.pb
├── variables/
├── resnet18_float32.tflite
├── resnet18_float16.tflite
└── resnet18_int8.tfliteRequisitos:
tensorflow>=2.0.0,<=2.19.0onnx2tf>=1.26.3,<1.29.0tf_keras<=2.19.0sng4onnx>=1.0.1onnx_graphsurgeon>=0.3.26(instala con--extra-index-url https://pypi.ngc.nvidia.com)ai-edge-litert>=1.2.0,<1.4.0en macOS (ai-edge-litert>=1.2.0en otras plataformas)onnxslim>=0.1.71onnx>=1.12.0,<2.0.0protobuf>=5
Link to this sectionExportar a TensorFlow Frozen Graph#
Continuando desde la exportación a SavedModel anterior, convierte el modelo Keras devuelto a un gráfico .pb congelado:
from pathlib import Path
from ultralytics.utils.export import keras2pb
keras2pb(keras_model, output_file=Path("resnet18_saved_model/resnet18.pb"))Link to this sectionExportar a NCNN#
from ultralytics.utils.export import torch2ncnn
torch2ncnn(model, im, output_dir="resnet18_ncnn_model")El directorio contiene archivos param y bin de nombre fijo junto con un envoltorio en Python:
resnet18_ncnn_model/
├── model.ncnn.param
├── model.ncnn.bin
└── model_ncnn.pytorch2ncnn() comprueba la existencia de ncnn y pnnx en el primer uso.
Link to this sectionExportar a MNN#
La exportación a MNN requiere un archivo ONNX como entrada. Exporta primero a ONNX y luego convierte:
from ultralytics.utils.export import onnx2mnn, torch2onnx
torch2onnx(model, im, output_file="resnet18.onnx")
onnx2mnn("resnet18.onnx", output_file="resnet18.mnn")Admite half=True para FP16 y int8=True para cuantización INT8. Requiere MNN>=2.9.6 y torch>=1.10.
Link to this sectionExportar a PaddlePaddle#
from ultralytics.utils.export import torch2paddle
torch2paddle(model, im, output_dir="resnet18_paddle_model")El directorio contiene el modelo PaddlePaddle y los archivos de parámetros:
resnet18_paddle_model/
├── model.pdmodel
└── model.pdiparamsRequiere x2paddle y la distribución de PaddlePaddle correcta para tu plataforma:
paddlepaddle-gpu>=3.0.0,<3.3.0en CUDApaddlepaddle==3.0.0en CPU ARM64paddlepaddle>=3.0.0,<3.3.0en otras CPUs
No es compatible con NVIDIA Jetson.
Link to this sectionExportar a ExecuTorch#
from ultralytics.utils.export import torch2executorch
torch2executorch(model, im, output_dir="resnet18_executorch_model")El archivo .pte exportado se guarda dentro del directorio de salida:
resnet18_executorch_model/
└── model.pteRequiere torch>=2.9.0 y un tiempo de ejecución de ExecuTorch compatible (pip install executorch). Para el uso en tiempo de ejecución, consulta la integración de ExecuTorch.
Link to this sectionVerifica tu modelo exportado#
Después de exportar, verifica la paridad numérica con el modelo PyTorch original antes de realizar el despliegue. Una prueba rápida con ONNXBackend de ultralytics.nn.backends compara las salidas e identifica errores de trazado o cuantización desde el principio:
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-5Para exportaciones en FP32, la diferencia absoluta máxima debe ser inferior a 1e-5. Diferencias mayores indican operaciones no admitidas, una forma de entrada incorrecta o un modelo que no está en modo de evaluación. Las exportaciones en FP16 e INT8 tienen tolerancias más flexibles. Valida con datos reales en lugar de tensores aleatorios.
Para otros tiempos de ejecución, el nombre del tensor de entrada puede variar. OpenVINO, por ejemplo, utiliza el nombre del argumento de forward del modelo (normalmente x para modelos genéricos), mientras que torch2onnx utiliza "images" por defecto.
Link to this sectionLimitaciones conocidas#
- El soporte para entradas múltiples es desigual:
torch2onnxytorch2openvinoaceptan una tupla o lista de tensores de ejemplo para modelos con múltiples entradas.torch2torchscript,torch2coreml,torch2ncnn,torch2paddleytorch2executorchasumen un único tensor de entrada. - ExecuTorch necesita
flatc: El tiempo de ejecución de ExecuTorch requiere el compilador de FlatBuffers. Instálalo conbrew install flatbuffersen macOS oapt install flatbuffers-compileren Ubuntu. - Sin inferencia a través de Ultralytics: Los modelos que no son YOLO exportados no pueden volver a cargarse mediante
YOLO()para realizar inferencias. Utiliza el tiempo de ejecución nativo para cada formato (ONNX Runtime, OpenVINO Runtime, etc.). - Formatos solo para YOLO: Las exportaciones a Axelera y Sony IMX500 requieren atributos de modelo específicos de YOLO y no están disponibles para modelos genéricos.
- Formatos específicos de plataforma: TensorRT requiere una GPU NVIDIA. RKNN requiere el SDK
rknn-toolkit2(solo Linux). Edge TPU requiere el binarioedgetpu_compiler(solo Linux).
Link to this sectionPreguntas frecuentes#
Link to this section¿Qué modelos puedo exportar con Ultralytics?#
Cualquier torch.nn.Module. Esto incluye modelos de timm, torchvision o cualquier modelo PyTorch personalizado. El modelo debe estar en modo de evaluación (model.eval()) antes de la exportación. ONNX y OpenVINO aceptan además una tupla de tensores de ejemplo para modelos de múltiples entradas.
Link to this section¿Qué formatos de exportación funcionan sin GPU?#
Todos los formatos compatibles (TorchScript, ONNX, OpenVINO, CoreML, TF SavedModel, TF Frozen Graph, NCNN, PaddlePaddle, MNN, ExecuTorch) pueden exportarse en CPU. No se requiere GPU para el proceso de exportación en sí. TensorRT es el único formato que requiere una GPU NVIDIA.
Link to this section¿Qué versión de Ultralytics necesito?#
Usa Ultralytics >=8.4.38, que incluye el módulo ultralytics.utils.export y los argumentos estandarizados output_file/output_dir.
Link to this section¿Puedo exportar un modelo de torchvision a CoreML para el despliegue en iOS?#
Sí. Los clasificadores, detectores y modelos de segmentación de torchvision se exportan a .mlpackage mediante torch2coreml. Para modelos de clasificación de imágenes, pasa una lista de nombres de clases a classifier_names para incluir una cabecera de clasificación. Realiza la exportación en macOS o Linux. CoreML no es compatible con Windows. Consulta la integración de CoreML para obtener detalles sobre el despliegue en iOS.
Link to this section¿Puedo cuantizar mi modelo exportado a INT8 o FP16?#
Sí, para varios formatos. Pasa half=True para FP16 o int8=True para INT8 al exportar a OpenVINO, CoreML, MNN o NCNN. INT8 en OpenVINO requiere además un argumento calibration_dataset para la cuantización post-entrenamiento. Consulta la página de integración de cada formato para conocer las ventajas y desventajas de la cuantización.