Ultralytics YOLO27: Únete a la lista de espera.
Get Started
Entrena tu primer modelo YOLO·Publicar·Lección 10/10
Lecciónprincipiante

Exportar para el despliegue

Exporta best.pt a ONNX, OpenVINO, TensorRT, CoreML, LiteRT o QNN y, antes de desplegarlo, demuestra que la exportación coincide con el modelo PyTorch.

Tu best.pt necesita Python y PyTorch para funcionar; los móviles, los navegadores, los Jetson y los servidores de producción normalmente no disponen de ellos. El modo Export convierte el modelo en un archivo autónomo para esos entornos de ejecución con una sola llamada. El problema es que el hecho de que una exportación se cargue no significa que sea correcta, y una comparación descuidada puede hacer que una exportación correcta parezca defectuosa o esconder los fallos de una defectuosa.

En esta lección exportarás a ONNX el modelo de pastillas, lo ejecutarás con la misma API YOLO, demostrarás que coincide con PyTorch en las cajas y en el mAP de validación con los mismos ajustes y elegirás el formato que necesita tu destino: ONNX, OpenVINO, TensorRT, CoreML, LiteRT o QNN.

Resultado

Puedes exportar un modelo entrenado al formato adecuado para el destino de despliegue y demostrar, mediante una comparación equivalente y una validación, que la exportación coincide con best.pt.

Vía rápida
Si ya tienes experiencia, aquí tienes un resumen.
  1. yolo export model=runs/detect/pills_v1/weights/best.pt format=onnx: empieza por aquí.

  2. OpenVINO para CPU Intel; TensorRT para GPU NVIDIA y Jetson; CoreML para Apple; LiteRT para Android; QNN para NPU Snapdragon.

  3. Compara .pt y la exportación en la misma imagen, con rect=False en el lado de .pt.

  4. Valida ambos con el imgsz del entrenamiento; el mAP50-95 debería coincidir.

Práctico

Ejemplo práctico: exportar a ONNX#

Pestaña Export del modelo en Ultralytics Platform con formatos de despliegue como ONNX, TensorRT, CoreML y OpenVINO

yolo export model=runs/detect/pills_v1/weights/best.pt format=onnx
PyTorch: starting from 'runs/detect/pills_v1/weights/best.pt' with input shape (1, 3, 320, 320) BCHW and output shape(s) (1, 5, 2100) (5.2 MB)
ONNX: export success ✅ 0.9s, saved as 'runs/detect/pills_v1/weights/best.onnx' (9.3 MB)
Predict:         yolo predict task=detect model=runs/detect/pills_v1/weights/best.onnx imgsz=320
Validate:        yolo val task=detect model=runs/detect/pills_v1/weights/best.onnx imgsz=320 data=my_dataset/data.yaml

Línea por línea:

  • input shape (1, 3, 320, 320): una imagen, 3 canales de color y un cuadrado fijo de 320×320: el imgsz del entrenamiento, integrado en el archivo.
  • output shape(s) (1, 5, 2100): 4 valores de caja más 1 puntuación de clase para 2100 cajas candidatas; NMS se ejecuta fuera del grafo de forma predeterminada.
  • 9.3 MB: el archivo ONNX almacena pesos FP32, por lo que es más grande que .pt en FP16.
  • Predict: / Validate:: comandos listos para el archivo exportado, ya configurados con el imgsz adecuado.

Bastan unos pocos argumentos para cubrir la mayoría de los casos; la guía de integración de ONNX enumera los demás.

ParámetroPredeterminadoPara qué sirve
imgszTamaño de entrenamientoExportar con otro tamaño de entrada fijo, por ejemplo, imgsz=640
dynamicFalseAceptar tamaños de entrada variables en lugar de una única forma fija
quantizeNinguno (FP32)16 para pesos FP16 (yolo26n.onnx reduce el tamaño de 9,5 MB a 4,8 MB); 8 para INT8 si el formato lo admite
nmsNingunonms=True integra NMS en el grafo, de modo que el entorno de ejecución devuelve las cajas finales

Ejemplo práctico: demostrar que la exportación coincide#

La clase YOLO también carga archivos exportados, por lo que el código de predicción anterior funciona sin cambios. Compara ambos archivos con la misma imagen de validación:

from ultralytics import YOLO

image = "my_dataset/images/val/Frame_144.jpg"
pt = YOLO("runs/detect/pills_v1/weights/best.pt")(image, rect=False, verbose=False)[0]  # square input, like ONNX
onnx = YOLO("runs/detect/pills_v1/weights/best.onnx")(image, verbose=False)[0]

print(f"pt:   {len(pt.boxes)} pills, mean conf {pt.boxes.conf.mean():.3f}")
print(f"onnx: {len(onnx.boxes)} pills, mean conf {onnx.boxes.conf.mean():.3f}")
print(f"max box difference: {(pt.boxes.xyxy - onnx.boxes.xyxy).abs().max():.4f} px")
pt:   25 pills, mean conf 0.870
onnx: 25 pills, mean conf 0.870
max box difference: 0.0002 px

Mismo recuento, misma confianza y cajas idénticas con una precisión de una fracción de píxel. Ahora, la comprobación más rigurosa: validación en todo el subconjunto:

from ultralytics import YOLO

pt = YOLO("runs/detect/pills_v1/weights/best.pt").val(data="my_dataset/data.yaml", rect=False, verbose=False)
onnx = YOLO("runs/detect/pills_v1/weights/best.onnx").val(data="my_dataset/data.yaml", verbose=False)
print(f".pt   mAP50-95 {pt.box.map:.4f}")
print(f".onnx mAP50-95 {onnx.box.map:.4f}")
.pt   mAP50-95 0.6570
.onnx mAP50-95 0.6570

Idénticos. (La validación rectangular predeterminada del archivo .pt obtuvo 0,659: una pequeña diferencia debida al relleno de entrada, no a la exportación).

Cuando coincidan, mide el tiempo con yolo benchmark en el dispositivo de destino para conocer su velocidad real antes de desplegarlo.

Elige un formato para tu destino#

Ciclo de vida de Ultralytics Platform: anotar con la anotación inteligente de SAM, entrenar en GPU en la nube y desplegar en regiones de todo el mundo, con logotipos de socios de integración

ObjetivoFormatoNotas
Opción portátil predeterminada: servidores y equipos de escritorio con Linux, Windows y MaconnxONNX Runtime en CPU o GPU; la exportación más rápida de verificar
GPU NVIDIA y Jetsonengine (TensorRT)La opción más rápida en NVIDIA; exporta en el dispositivo. Consulta Optimiza con TensorRT
CPU e iGPU de IntelopenvinoAceleraciones reales de CPU gracias a los kernels de Intel. Consulta OpenVINO en CPU
Aplicaciones para iPhone, iPad y MaccoremlNativo; usa el motor neuronal de Apple
Android y otros dispositivos móviles o integradoslitertSe recomienda INT8 para móviles
NPU SnapdragonqnnAceleración Hexagon HTP; pesos INT8 con activaciones de 16 bits de forma predeterminada; elige la arquitectura HTP con name
Navegador webonnx con ONNX Runtime WebLos modelos más pequeños son viables: n y s
from ultralytics import YOLO

model = YOLO("runs/detect/pills_v1/weights/best.pt")

model.export(format="onnx")  # Multiplataforma: ONNX Runtime
model.export(format="openvino")  # CPU / iGPU de Intel
model.export(format="engine", quantize=16)  # NVIDIA TensorRT, FP16 (ejecútalo en la GPU de destino)
model.export(format="coreml")  # Apple iOS / macOS
model.export(format="litert", quantize=8, data="my_dataset/data.yaml")  # Android / edge, INT8
model.export(format="qnn", name="73", data="my_dataset/data.yaml")  # NPU Qualcomm Snapdragon (HTP v73); calibra con tus propios datos

Cada exportación se guarda junto a los pesos: best.onnx, best_openvino_model/, best.engine, etc. Empieza con ONNX aunque acabes usando otro formato: es el más rápido de verificar y sirve como entrada para varias cadenas de herramientas. La guía de opciones de despliegue compara todos los formatos, y Elige un destino de despliegue te guía en la decisión.

La cuantización del modelo sacrifica precisión para reducir el tamaño y aumentar la velocidad. FP16 (quantize=16) reduce el tamaño del archivo a la mitad con una precisión casi idéntica. INT8 (quantize=8) reduce aún más el tamaño y aumenta la velocidad, pero necesita imágenes de calibración: fotogramas representativos que se procesan durante la exportación para elegir los rangos de valores; Ultralytics recomienda al menos 300. Valida siempre un modelo INT8 antes de ponerlo en producción: la pérdida puede ser insignificante o considerable, según el modelo y el conjunto de calibración.

Evita estos errores#

Comparar entradas distintas

Síntoma: el modelo .pt detecta 35 pastillas en Frame_144.jpg y el archivo ONNX detecta 25; parece que la exportación está rota. Causa: la inferencia de PyTorch rellena cada imagen hasta el rectángulo más pequeño alineado con el stride (192×320 para estos fotogramas de 16:9), mientras que un modelo ONNX estático siempre recibe un cuadrado de 320×320. Las entradas distintas producen detecciones distintas con baja confianza. Solución: al comparar, pasa rect=False al modelo .pt, como en parity.py.

Una exportación estática ignora tu imgsz

Síntoma: pasas imgsz=640 a best.onnx, pero el registro sigue indicando 320x320. Causa: una exportación estática tiene un único tamaño de entrada, establecido en el momento de la exportación. Solución: exporta con el tamaño que vayas a usar (imgsz=640) o exporta con dynamic=True.

Los motores de TensorRT dependen del dispositivo

Un .engine creado en una A100 no funcionará en una Jetson Orin y puede que no sobreviva a una actualización de TensorRT. Exporta en el dispositivo de destino y con la versión de TensorRT que vaya a usar. ONNX es portable; los motores no.

INT8 se calibra con COCO8 si no indicas lo contrario

Si omites data en una exportación INT8, Ultralytics muestra una advertencia y después calibra con la muestra predeterminada de COCO8: ocho imágenes que no se parecen en nada a tus pastillas. Pasa tu propia muestra: model.export(format="litert", quantize=8, data="my_dataset/data.yaml").

Ya lo has puesto en producción#

Ahora tienes un best.pt entrenado, pruebas de validación junto a una línea de base, un archivo exportado para tu entorno de ejecución y la confirmación de que la exportación coincide con el original. Ese es el ciclo completo —datos, entrenamiento, validación, exportación y despliegue—, y los equipos de producción lo ejecutan según un calendario. Ultralytics YOLO en producción parte de tu exportación verificada y abarca entornos de ejecución optimizados, flujos de trabajo de seguimiento, servicio de varios flujos y supervisión.

Pruébalo

Exporta tu pills_v1/weights/best.pt a ONNX y ejecuta parity.py y val_export.py. Vuelve a ejecutar parity.py sin rect=False y registra cómo cambia el recuento de .pt. Entrega cuatro datos: el recuento de detecciones coincidentes, la diferencia máxima entre cajas, los dos valores de mAP50-95 y una línea que indique el formato que necesita tu destino de despliegue real y por qué.

Commit
git add -A && git commit -m "feat(deploy): exported best.pt to onnx for production runtime"
Cuándo se considera terminado
Has terminado la lección cuando se cumplen todas estas condiciones.
  • runs/detect/pills_v1/weights/best.onnx existe y predice mediante YOLO().

  • Con rect=False, los recuentos de detecciones coinciden y la diferencia máxima entre cajas es inferior a 1 px.

  • La validación de ONNX y .pt arroja el mismo mAP50-95 con la misma configuración, y has indicado el formato de destino y el motivo.

Mostrar solución
from ultralytics import YOLO

# Train
model = YOLO("yolo26n.pt")
model.train(data="my_dataset/data.yaml", epochs=10, imgsz=320, name="pills_e2e")

# Validate
metrics = model.val()
print(f"mAP50-95 = {metrics.box.map:.3f}")  # 0.659

# Export
model.export(format="onnx")
parity.py:      pt 25 pills, onnx 25 pills, max box difference 0.0002 px
without rect:   pt 35 pills (192x320 input) vs onnx 25 (320x320): input mismatch, not an export bug
val_export.py:  .pt 0.6570, .onnx 0.6570
Target:         Intel laptop CPU -> openvino, for faster CPU inference than ONNX Runtime
Qué viene después

Curso completado: haz el cuestionario final para conseguir tu certificado de Entrena tu primer modelo YOLO y, después, continúa con Ultralytics YOLO en producción.