Ultralytics YOLO27: Únete a la lista de espera.
Get Started
Ultralytics YOLO en producción·Escalar y observar·Lección 9/9
Lecciónintermedio

Ajuste de costes y latencia

Perfila todo el pipeline, acciona por orden las palancas que realmente reducen la latencia y el coste, y detente al alcanzar el presupuesto.

Los equipos pierden semanas arañando milisegundos al modelo mientras que el verdadero cuello de botella es una escritura en la base de datos o un decodificador RTSP. Hay pocas palancas importantes y se pueden medir bien: YOLO26s tarda 2,2 veces más que YOLO26n en CPU para obtener 7,7 puntos más de mAP, y ejecutar la detección en uno de cada dos fotogramas reduce el trabajo a la mitad. En esta lección aprenderás a perfilar primero, accionar la palanca más eficaz que encaje y detenerte al alcanzar un presupuesto definido de antemano.

Resultado

Perfila un pipeline de principio a fin, aplica una palanca y compara la latencia y mAP antes y después, y justifica por qué te has detenido.

Vía rápida
Si ya tienes experiencia, aquí tienes un resumen.
  1. Perfila primero: las etapas de r.speed y tus propias mediciones de decodificación y envío de resultados.

  2. Palancas, por orden: modelo más pequeño → imgsz más pequeño → entorno de ejecución más rápido y FP16 → INT8 → vid_stride.

  3. Mide la latencia y mAP antes y después de cada cambio, en el hardware de destino y con el mismo conjunto de validación.

  4. Define primero el presupuesto (días, pérdida de mAP, FPS objetivo); cuando lo agotes, mejora los datos en su lugar.

Práctico

Mide primero todo el pipeline#

Cada objeto Results divide su propio tiempo en etapas:

from ultralytics import YOLO

model = YOLO("yolo26n.pt")
video = "https://github.com/ultralytics/assets/releases/download/v0.0.0/solutions_ci_demo.mp4"
totals = {"preprocess": 0.0, "inference": 0.0, "postprocess": 0.0}
for n, r in enumerate(model.predict(video, stream=True, verbose=False), 1):
    for stage in totals:
        totals[stage] += r.speed[stage]
print({stage: round(ms / n, 1) for stage, ms in totals.items()}, "ms per frame")
{'preprocess': 0.7, 'inference': 36.1, 'postprocess': 0.7} ms per frame

Aquí la inferencia representa el 95 % del tiempo del modelo, así que las palancas relacionadas con el modelo serán útiles. Mide también la decodificación y tus propios procesos de envío de resultados de la misma manera (con time.perf_counter() alrededor de cada uno) y, después, aplica la regla correspondiente a lo que encuentres:

Lo que midesQué corregir primero
60 ms de decodificación RTSP, 5 ms de inferenciaDecodificación por hardware, menor resolución del flujo o más hilos de decodificación
30 ms de inferencia, 100 ms de posprocesamiento en PythonVectoriza con NumPy o trasládalo a un proceso de trabajo
5 ms de inferencia, 200 ms de escrituras en la base de datosAgrupa las escrituras o hazlas de forma asíncrona
La inferencia es el factor dominanteLa clasificación de palancas de abajo

Clasificación de palancas#

Empieza por arriba y detente cuando alcances el presupuesto:

MedidaAumento de velocidad habitualCoste habitual en precisión
Modelo más pequeño (m → s, s → n)1.5–2.5×Entre 4,5 y 7,7 puntos de mAP en COCO; menos en tareas específicas
imgsz más pequeño (640 → 480)Aproximadamente 1,8×Primero, objetos pequeños y lejanos
Entorno de ejecución más rápido, FP16Aproximadamente 1,5× en GPUNormalmente ninguno; verifica que haya paridad
INT8 con calibraciónUn 1,2× adicional en GPU; hasta 2,9× en CPU1 punto (YOLO26n) a 4–6 puntos (modelos más grandes); QAT recupera la mayor parte
Menos fotogramas (vid_stride=N)Hasta N×Se pueden perder objetos rápidos y eventos breves
Lotes más grandes (servidores)Mayor rendimiento, no menor latenciaNinguno

Las cifras proceden de las tablas de pruebas de rendimiento de YOLO26, TensorRT y OpenVINO, así como de las mediciones de abajo; tus resultados serán distintos, así que mide.

Modelo más pequeño#

La tabla de pruebas de rendimiento de YOLO26 en COCO:

ModelomAP50-95CPU ONNX (ms)T4 TensorRT10 (ms)
YOLO26n40.938.91.7
YOLO26s48.687.22.5
YOLO26m53.1220.04.7

En CPU, cada paso hacia un modelo más pequeño es entre 2,2 y 2,5 veces más rápido. La diferencia de precisión en COCO representa el peor caso: un detector de almacén con 3 clases y objetos grandes suele perder mucho menos al pasar de m a n que un detector general de 80 clases, así que siempre merece la pena probar el modelo más pequeño con tu propio conjunto de validación.

Entrada más pequeña#

El cálculo escala aproximadamente con el número de píxeles, así que imgsz=480 requiere alrededor del 56 % del trabajo que requiere 640. Medición en la CPU del portátil de pruebas con ONNX Runtime y lote 1 (mediana de 25 ejecuciones en bus.jpg):

Modelo640480320
YOLO26n21.3 ms12.1 ms7.1 ms
YOLO26s55.0 ms24.2 ms12.9 ms

Criterio de decisión: si el objeto importante más pequeño sigue ocupando unos 10 píxeles o más con el nuevo tamaño, pruébalo; si los objetos son pequeños o lejanos (drones, estanterías alejadas de la cámara), conserva la resolución y reduce el tamaño del modelo.

Menos fotogramas#

Si la inferencia limita tu frecuencia de fotogramas y la escena se mueve despacio, ejecuta la detección en uno de cada N fotogramas con vid_stride=N y deja que el rastreador cubra los intervalos:

import time

from ultralytics import YOLO

model = YOLO("yolo26n.pt")
video = "https://github.com/ultralytics/assets/releases/download/v0.0.0/solutions_ci_demo.mp4"
model.predict(video, vid_stride=30, verbose=False)  # warm up so the first timing is fair

for stride in (1, 2, 3):
    start, ids, frames = time.perf_counter(), set(), 0
    for r in model.track(video, stream=True, vid_stride=stride, tracker="bytetrack.yaml", classes=[0], verbose=False):
        frames += 1
        if r.boxes.is_track:
            ids.update(r.boxes.id.int().tolist())
    print(f"vid_stride={stride}: {frames} frames in {time.perf_counter() - start:.2f} s, {len(ids)} person IDs")
vid_stride=1: 62 frames in 2.66 s, 32 person IDs
vid_stride=2: 31 frames in 1.19 s, 30 person IDs
vid_stride=3: 20 frames in 0.95 s, 28 person IDs

Procesar la mitad de los fotogramas cuesta aproximadamente la mitad de tiempo, y el rastreador mantuvo 30 de las 32 identidades. Con vid_stride=3 perdió 4, lo que indica que debes detenerte en esta escena a ritmo de paseo.

Reduce los costes en la nube#

Resumen de implementación de Ultralytics Platform: 59 solicitudes HTTP en 24 horas, una tasa de errores del 0 %, una latencia P95 de 226 ms y un endpoint de 1 vCPU y 4 GiB en us-west2 con un precio de 0,17 $ por hora

El coste equivale a las horas de instancia divididas entre el trabajo útil. Una tarjeta como esta muestra las dos cifras que necesitas: cuánto cuesta una hora (0,17 $ por 1 vCPU y 4 GiB en este caso) y cuánto trabajo realiza (59 solicitudes en 24 horas, con una latencia P95 de 226 ms; el endpoint está inactivo la mayor parte del tiempo). A continuación:

  • Aumenta la utilización. Una GPU con una utilización del 30 % desperdicia el 70 % de lo que pagas. Agrupa los flujos (lecciones anteriores) o sirve el modelo mediante Triton Inference Server.
  • Ajusta el tamaño. Compara el rendimiento en una GPU más pequeña o en una CPU con OpenVINO antes de dar por hecho que necesitas una GPU grande.
  • Usa capacidad bajo demanda o interrumpible para trabajos por lotes. El reprocesamiento de vídeo archivado tolera las interrupciones; los flujos en directo, no.

Errores habituales#

Optimizar el modelo cuando no es el cuello de botella

Síntoma: dos semanas de ajustes ahorran 10 ms y el sistema sigue siendo lento. Solución: analiza primero el perfil de toda la cadena de procesamiento y corrige la etapa más lenta, sea cual sea.

Saltar fotogramas después de la inferencia

Síntoma: usar if i % 2: continue dentro del bucle de resultados no ahorra nada. Solución: el modelo ya se ha ejecutado en ese fotograma; sáltatelo en la fuente con vid_stride.

Agrupar para reducir la latencia

Síntoma: ha aumentado el rendimiento, pero ahora cada fotograma llega más tarde. Solución: los lotes más grandes aumentan el rendimiento por euro, no reducen la latencia por fotograma; úsalos con muchas secuencias o en tareas sin conexión, no con una sola cámara en tiempo real.

La palanca de los datos

Cuando ya hayas agotado las opciones de mejora del modelo, la siguiente es mejorar los datos. Un conjunto de datos que se ajuste a la producción permite que un modelo más pequeño alcance la precisión que antes requería uno más grande: reduces los costes sin perder precisión.

Pruébalo

Define un presupuesto de optimización (días, pérdida máxima de mAP y FPS objetivo en el hardware de destino). Perfila tu flujo de trabajo con r.speed, además de tus propias mediciones de decodificación y salida; elige la principal palanca que se ajuste al cuello de botella, aplícala y registra la latencia y mAP50-95 antes y después en el mismo hardware y conjunto de validación. Entrega el presupuesto, el perfil, la tabla comparativa y el punto en el que te detuviste.

Commit
git add -A && git commit -m "perf(production): tuned model + runtime for target latency budget"
Cuándo se considera terminado
Has terminado la lección cuando se cumplen todas estas condiciones.
  • Sabes qué etapa predomina en el tiempo total de procesamiento de cada fotograma, y tienes cifras que lo demuestran.

  • Has aplicado una palanca y registrado la latencia y el mAP antes y después con el mismo hardware y conjunto de validación.

  • Te has detenido al alcanzar el presupuesto que definiste y puedes decir qué probarías a continuación.

Mostrar solución
from ultralytics import YOLO

if __name__ == "__main__":  # validation starts worker processes on macOS and Windows
    data, img = "coco8.yaml", "https://ultralytics.com/images/bus.jpg"  # use your val YAML and a production frame
    for weights, imgsz in (("yolo26s.pt", 640), ("yolo26n.pt", 640), ("yolo26n.pt", 480)):
        model = YOLO(weights)
        runs = [model(img, imgsz=imgsz, verbose=False)[0].speed["inference"] for _ in range(20)][5:]
        m = model.val(data=data, imgsz=imgsz, batch=1, plots=False, verbose=False).box.map
        print(f"{weights} imgsz={imgsz}: {sorted(runs)[len(runs) // 2]:.1f} ms, mAP50-95 {m:.3f}")

Cada fila descarta las cinco primeras ejecuciones como calentamiento y muestra la mediana del resto. Elige la primera fila que cumpla el presupuesto de latencia con una pérdida de mAP dentro de tu presupuesto. Un presupuesto de ejemplo: «dos días, como máximo 1 punto de mAP y 20 FPS en el equipo de la tienda». Si yolo26s a 640 no baja de 50 ms por fotograma y yolo26n a 640 sí lo consigue con una pérdida de hasta 1 punto en tu conjunto de validación, detente ahí; no dediques el segundo día a 480.

Qué viene después

Curso completado. Haz el examen para obtener tu certificado y, después, continúa con Desarrolla con Ultralytics Platform, que ejecuta este flujo de trabajo como un sistema integral gestionado.