Ver como Markdown

Validación y métricas

La validación pasa un modelo por un split de un dataset mediante val() y devuelve un diccionario plano de claves de métricas y valores float. Las claves son cadenas literales, y cuáles obtienes depende de la tarea, no de la familia.

Ejecutar una validación

val() recibe el dataset y devuelve las métricas.

Python
from libreyolo import LibreYOLO model = LibreYOLO("LibreYOLO9s.pt")metrics = model.val(data="coco8.yaml") print(metrics["metrics/mAP50-95"])print(metrics["metrics/mAP50"])print(metrics["speed/total_ms"])
CLI
libreyolo val model=LibreYOLO9s.pt data=coco8.yaml
En otro split
from libreyolo import LibreYOLO model = LibreYOLO("LibreYOLO9s.pt")metrics = model.val(data="coco8.yaml", split="train", batch=4) print(metrics)

El valor devuelto es un dict plano de claves de métricas y números. Todas las claves son literales, así que léelas por nombre y no por posición. En detect, segment y classify es una subclase de dict que además lleva resultados por clase como atributos, descritos más abajo.

Los argumentos principales son data, split, batch, imgsz, conf, iou, workers, device, augment, save_json y verbose. conf vale 0.001 por defecto e iou 0.6, ambos mucho más permisivos que los valores por defecto de predicción, porque un barrido de mAP necesita la cola de baja confianza. imgsz toma por defecto el tamaño de entrada del propio modelo en lugar de un número fijo. split acepta val, test o train y nada más. Sin data, un checkpoint entrenado se valida con el dataset con el que se entrenó; los pesos publicados no llevan ninguno y necesitan data=.

Cualquier otro campo de la configuración de validación se pasa como argumento con nombre, incluidos save_dir, max_det, eval_max_det, half, amp_dtype, cache, save_plots, single_cls y agnostic_nms. Con half=True en CUDA, la validación se ejecuta bajo autocast en amp_dtype, y las salidas en bfloat16 se convierten a float32 antes del postprocesado; el entrenamiento con amp_dtype="bfloat16" valida de la misma manera.

agnostic_nms=True conserva solo el box de mayor puntuación entre los boxes que se solapan por encima de iou, sean cuales sean sus clases. Se ejecuta sobre las detecciones ya terminadas de la familia, después de classes=, así que mAP, la matriz de confusión, las curvas y los recuentos por imagen puntúan los mismos boxes. Cubre detect y segment, y cualquier otra tarea lanza ValueError. La parte de predicción está en Umbrales y filtrado.

single_cls=True puntúa la detección como una sola clase. El ground truth se reduce a la clase 0, y las detecciones del modelo se limitan a classes= en el espacio de etiquetas propio del modelo y luego se reetiquetan como 0, así que un checkpoint entrenado con varias clases se puntúa como un detector de una sola clase.

Claves de métricas por tarea

La detección devuelve la familia de números de COCO:

metrics/mAP50-95   metrics/mAP50    metrics/mAP75metrics/mAP_small  metrics/mAP_medium  metrics/mAP_largemetrics/AR1  metrics/AR10  metrics/AR100  metrics/AR_max_detmetrics/AR_small  metrics/AR_medium  metrics/AR_largemetrics/precision  metrics/recallmetrics/precision(B)  metrics/recall(B)  metrics/mAP50(B)  metrics/mAP50-95(B)

Dos de ellas son trampas. metrics/precision y metrics/recall son alias que se mantienen por retrocompatibilidad: llevan los valores de mAP 50-95 y AR@100, no un par de precisión y recall. Usa las claves con nombre.

La segmentación de instancias devuelve las cifras de mAP y AR anteriores como números de máscara bajo las claves sin sufijo, con las versiones de caja bajo el sufijo (B) y las versiones de máscara repetidas bajo (M). En esta tarea, la precisión y el recall solo existen con sufijo, como metrics/precision(B)/metrics/recall(B) y metrics/precision(M)/metrics/recall(M), y ambos pares llevan los mismos valores alias que los de detect: el par (B) es el mAP50-95 de cajas y el AR@100 de cajas, y el par (M) es el mAP50-95 de máscaras y el AR@100 de máscaras.

TareaClaves
detectmetrics/mAP50-95, metrics/mAP50, metrics/mAP75, más los desgloses por tamaño y de recall anteriores
segmentversiones de máscara de las claves de detect anteriores (las claves sin sufijo son las de máscara); precision/recall solo existen como (B)/(M), ambos con el mismo alias
posemetrics/keypoints_mAP50-95, metrics/keypoints_mAP50, metrics/keypoints_mAP75, metrics/keypoints_mAP_M, metrics/keypoints_mAP_L, y las claves keypoints_AR correspondientes
obbmetrics/mAP50-95, metrics/mAP50, metrics/mAP75, metrics/precision, metrics/recall, más copias con sufijo (OBB)
classifymetrics/accuracy_top1, metrics/accuracy_top5
semanticmetrics/mIoU, metrics/pixel_accuracy
panopticmetrics/PQ, metrics/SQ, metrics/RQ, metrics/PQ_things, metrics/PQ_stuff, metrics/categories
depthmetrics/abs_rel, metrics/rmse, metrics/delta1, metrics/delta2, metrics/delta3
normalmetrics/mean_angular_error, metrics/median_angular_error, metrics/within_11_25, metrics/within_22_5, metrics/within_30
edgemetrics/ODS, metrics/OIS, metrics/best_threshold
restoremetrics/PSNR, metrics/SSIM
mattemetrics/MAE, metrics/Smeasure
ocrmetrics/det_precision, metrics/det_recall, metrics/det_hmean, metrics/e2e_precision, metrics/e2e_recall, metrics/e2e_f1, metrics/rec_1-NED
pointmetrics/precision, metrics/recall, metrics/f1, metrics/MLE, metrics/MAE, metrics/RMSE, más una clave de barrido de mAP

Los metrics/precision y metrics/recall de OBB no son alias: son la precisión y el recall reales con IoU 0.50, tomados en el punto de operación más permisivo (toda predicción que sobrevive a conf, por defecto 0.001). Las copias con sufijo (OBB) repiten los mismos cuatro valores bajo un nombre específico de la tarea, la misma convención que (B) y (M) de arriba.

accuracy_top5 es en realidad top-min(5, num_classes), así que en un dataset de tres clases es top-3, algo que cumple toda muestra y que por tanto marca 1.0. Los resultados de clasificación también exponen los dos valores como los atributos top1 y top5, junto a confusion_matrix.

La clave de barrido de la tarea point se construye a partir de los umbrales de distancia, así que con los valores por defecto queda metrics/mAP@[0.01:0.10] y la clave de umbral único queda metrics/mAP@0.01. Pasar dist_thresholds cambia ambas cadenas.

La mayoría de las tareas devuelven además una clave fitness, el número único que usa por defecto la selección del mejor checkpoint. Detección, segmentación y OBB no la llevan; sus familias se seleccionan por metrics/mAP50-95, que sus diccionarios sí devuelven. Pose no devuelve ni fitness ni metrics/mAP50-95; en su lugar, sus entrenadores fijan best_metric_key a metrics/keypoints_mAP50-95.

La clasificación ImageFolder añade las métricas macro metrics/precision, metrics/recall y metrics/f1, promediadas sobre las clases presentes en los targets de validación. Top-1 sigue siendo el criterio de selección por defecto. La detección también devuelve metrics/best_conf y metrics/best_conf_f1, eligiendo el umbral óptimo de micro-F1 con IoU 0.50, y deja los umbrales indexados por nombre de clase en metrics.box.best_conf_per_class. Las detecciones con la misma puntuación permanecen agrupadas; los empates eligen el umbral más alto. Si no hay F1 positivo, se devuelve 0.0. La segmentación no expone estas claves de umbral.

Matriz de confusión

Los resultados de detect, segment y classify llevan results.confusion_matrix. Se calcula en cada validación, se escriban o no gráficas, y su matrix es un array de enteros indexado como matrix[predicted, true].

Matriz de confusión
from libreyolo import LibreYOLO model = LibreYOLO("LibreYOLO9s.pt")metrics = model.val(data="coco8.yaml") cm = metrics.confusion_matrixprint(cm.matrix.shape)      # (81, 81): 80 clases más backgroundprint(cm.class_accuracy())  # nombre de clase: proporción de objetos encontrados a los que se dio esa clasetp, fp = cm.tp_fp()

En detect y segment, las predicciones con confianza 0.25, o conf si es mayor, se emparejan uno a uno con boxes de ground truth de cualquier clase con IoU 0.5, de mayor a menor IoU. Un par cuenta en su clase predicha y su clase verdadera, así que un box bien colocado con la clase equivocada cae fuera de la diagonal. La matriz tiene una fila y una columna extra background: un ground truth sin pareja cuenta en la fila background, y una predicción sin pareja en la columna background. Segmentation empareja boxes, no máscaras. Con classes=, el ground truth de las demás clases se deja fuera.

Las regiones COCO crowd (iscrowd=1) siguen la regla que aplica mAP. Una predicción a la que no se emparejó ningún ground truth de su clase, y que queda al menos a medias dentro de una región crowd de la misma clase (intersección sobre el área de la propia predicción), se ignora en lugar de contarse. box.image_metrics y las imágenes de visualize=True usan los mismos umbrales y la misma regla crowd. Las etiquetas en formato YOLO no tienen regiones crowd.

En classify, cada imagen cuenta una vez, en su clase top-1 frente a su etiqueta, y no hay background.

MétodoDevuelve
summary(normalize=False)Un dict por clase predicha, {"Predicted": name, <true class>: value}; con normalize, las proporciones de cada clase verdadera
to_csv(), to_json()El resumen como texto CSV o JSON
to_df()El resumen como DataFrame de Polars; necesita pip install polars
tp_fp()Verdaderos positivos por clase (la diagonal) y falsos positivos (el resto de la fila predicha)
nonzero()Las celdas rellenas como arrays alineados (predicted, true, count)
class_accuracy()Por clase, la proporción de sus instancias a las que se dio esa clase; en detección, solo de sus objetos encontrados
plot(normalize=True, save_dir="")Escribe confusion_matrix_normalized.png, o confusion_matrix.png con normalize=False, y devuelve la ruta

Por encima de 2,000 clases la matriz densa de clasificación no se construye: matrix, summary(), las exportaciones to_*() y plot() lanzan una excepción, mientras que tp_fp(), nonzero() y class_accuracy() siguen funcionando.

La clase es libreyolo.validation.ConfusionMatrix, construida como ConfusionMatrix(nc, iou_thres=0.5, conf_thres=0.25, *, names=None, task="detect"), donde task es "detect" o "classify".

Precisión, recall y F1 por clase

Los resultados de detect y segment llevan la precisión, el recall y el F1 de cada clase a través de los umbrales de confianza, emparejados con IoU 0.5.

Curvas por clase
from libreyolo import LibreYOLO model = LibreYOLO("LibreYOLO9s.pt")metrics = model.val(data="coco8.yaml") box = metrics.boxprint(box.px.shape, box.f1_curve.shape)  # (1000,) y (classes, 1000)for index, f1 in zip(box.ap_class_index, box.f1):    print(model.names[int(index)], round(float(f1), 3))

box.px contiene las 1000 confianzas, repartidas uniformemente en [0, 1]. box.p_curve, box.r_curve y box.f1_curve son arrays (classes, 1000), una fila por cada entrada de box.ap_class_index, los índices de clase que tienen ground truth en el split, en orden ascendente. box.p, box.r y box.f1 son los valores por clase en la confianza que maximiza el F1 medio sobre esas clases. Segmentation los calcula todos a partir de boxes. Son arrays vacíos cuando la ejecución no produjo curvas.

Métricas de cajas por imagen

Los resultados de detección y segmentación mantienen la compatibilidad con diccionarios y también exponen results.box.image_metrics. Cada nombre de archivo se asocia con precision, recall, f1, tp, fp y fn usando la regla de matching de visualización, incluso cuando esta está desactivada. La segmentación cuenta cajas aquí. Los nombres base duplicados usan rutas completas después de la primera aparición. Los denominadores cero dan 0.0. Estos registros no se recopilan entre los ranks distribuidos.

Claves de velocidad

Todos los validadores añaden tiempos:

speed/preprocess_ms   speed/inference_ms   speed/postprocess_msspeed/total_ms        speed/total_s        speed/images_seen

Son milisegundos por imagen promediados sobre la ejecución. Describen la máquina y los ajustes con los que ejecutaste la validación, así que una cifra sacada de ahí solo tiene sentido si se indica junto con su hardware, su tamaño de batch y su precisión.

Backend de evaluación

Las métricas de detección y segmentación se calculan a través de un evaluador COCO, y faster_coco_eval=True, el valor por defecto, selecciona el backend en C++ cuando el paquete faster-coco-eval está instalado. Cuando no lo está, la ejecución recurre a pycocotools con un aviso por proceso:

faster_coco_eval requested but not installed; falling back to pycocotools.Install with: pip install faster-coco-eval

Qué backend se ejecutó realmente queda registrado en el modelo como last_eval_backend, y la CLI lo muestra en su salida para las tareas de tipo detección. Define LIBREYOLO_FASTER_COCO_EVAL para sobrescribir el valor de la configuración desde el entorno.

iou_thresholds solo se respeta en la ruta de OBB. La ruta de COCO evalúa con su propio barrido fijo de 0.50 a 0.95 e ignora el valor.

Loss de validación

Por defecto la validación informa solo de la precisión. val_loss=True calcula además el objetivo de entrenamiento de la familia sobre los batches de validación.

Python
from libreyolo import LibreYOLO model = LibreYOLO("LibreYOLO9s.pt")model.train(data="coco8.yaml", epochs=10, val_loss=True)

Emite metrics/loss (la loss, es decir, la función de pérdida) más un metrics/loss/<component> por cada término, ponderados exactamente igual que los pondera el entrenamiento, de modo que los componentes suman el total. A través de un logger aparecen como val/loss y val/loss/<component>, y libreyolo monitor superpone metrics/loss con train/loss.

Los componentes son los propios de cada familia:

TareaFamiliasComponentes
detectyolo9, yolo9_p2, yolo9_e2ebox, cls, dfl
detectyolonascls, iou, dfl
detectrfdetrce, bbox, giou
detectrtdetr, rtdetrv2vfl, bbox, giou
detectdfinevfl, bbox, giou, fgl, ddf
detectdomedetrvfl, bbox, giou, fgl, ddf, defe_density, defe_reg
detectdeim, deimv2, rtdetrv4, ecmal, bbox, giou, fgl, ddf
detectrtmdetcls, bbox
detectpicodetcls, bbox, dfl
detectyoloxiou, obj, cls, l1
detectyolo7iou, obj, cls
pointfomoce
classifyresnet, convnext, mobilenetv4, efficientnetv2ce
semanticsegformer, lingbotvision, dinov2sem
restorenafnetrestore

Está desactivada por defecto porque la asignación de targets añade tiempo y memoria a la validación. El validador reutiliza la salida del modelo que ya se produjo para la métrica de precisión en lugar de hacer un segundo forward, se ejecuta bajo no_grad sobre el modelo de evaluación o EMA, y en entrenamiento multi-GPU se calcula localmente en el rank 0 sin operaciones colectivas. La selección del mejor checkpoint se mantiene sobre la métrica de precisión.

Hay tres cosas que deliberadamente no hace. Nunca incluye términos de contrastive denoising, porque esos necesitan el ground truth en el momento del forward y la validación hace el forward sin él. Informa del modelo en modo evaluación, así que donde el forward de entrenamiento y el de evaluación de una familia difieren de verdad, en las estadísticas de BatchNorm o en la stochastic depth, el número refleja el modo evaluación; esa es la comparación buscada. Y una tarea para la que una familia no lo ha implementado lanza un error de configuración durante la preparación en lugar de saltárselo en silencio:

val_loss=True currently supports RF-DETR detection only; segment, pose, OBB,classify, and semantic tasks are not supported

FOMO es la excepción que no cambia nada: su validador siempre calculó esta loss, y val_loss=True solo afecta a las claves bajo las que se publica.

La validación con aumento de datos y la loss de validación no se pueden combinar, y pedir ambas lanza un error.

Archivos que escribe una validación

val() siempre escribe config.yaml en su directorio de guardado, que por defecto es runs/val/<model>_<size>_<timestamp> cuando no se pasa save_dir. project, name y exist_ok lo eligen igual que en el entrenamiento: project/name, con un sufijo incremental salvo que exist_ok=True.

Escribir predicciones en formato COCO
from libreyolo import LibreYOLO model = LibreYOLO("LibreYOLO9s.pt")model.val(data="coco8.yaml", save_json=True, save_dir="runs/val/exp")

save_json=True escribe predictions.json para detección, y predictions_bbox.json más predictions_masks.json para segmentación. OBB no lo admite y lo dice.

save_plots=True, o su alias plots=True, escribe en un subdirectorio plots/ y necesita matplotlib, que instala pip install "libreyolo[plots]". La detección obtiene box_metrics.png, gráficas de AP y de recall por clase, curvas de precisión-recall y de confianza, las curvas de F1 por clase en f1_conf_box.png, la matriz de confusión como recuentos en confusion_matrix.png y como proporciones de cada clase verdadera en confusion_matrix_normalized.png, e imágenes de muestra anotadas cuando OpenCV está instalado. La segmentación añade copias del lado de máscara del gráfico de métricas, de las gráficas por clase y de las curvas de precisión-recall y de confianza; las curvas de F1 y la matriz de confusión se quedan a nivel de box. Pose tiene su propio conjunto de métricas y curvas. Classification escribe los dos archivos de la matriz de confusión, salvo por encima de 2,000 clases. Los demás validadores no implementan gráficas; semantic, panoptic, depth, normal, edge, restore, matte, OCR, OBB y point no escriben nada ahí. Un fallo al generar las gráficas avisa y nunca aborta la ejecución.

visualize=True escribe imágenes de TP/FP/FN de cajas teniendo en cuenta la clase para detección y segmentación, o imágenes que comparan la etiqueta con top-1 para clasificación ImageFolder, en visualize/errors/ y visualize/correct/. El matching usa IoU 0.5 y confianza max(0.25, conf). Los valores por defecto son visualize=False, show_labels=True y show_conf=True. Las tareas no compatibles y la validación de clips de V-JEPA 2 rechazan la visualización.

plot_samples=8 limita el gráfico de muestras separado; 0 lo desactiva y -1 conserva todas las imágenes. Esto no cambia las métricas ni la salida de visualización.

Validación durante el entrenamiento

El entrenamiento valida cada eval_interval épocas, y siempre tras la última época, sobre el split val del dataset, y las métricas que produce son las que gobiernan la selección de best.pt, la parada temprana por patience y las claves val/ de todos los loggers. La validación se ejecuta sobre los pesos EMA cuando EMA está activado. Sus archivos van a un directorio val/ dentro de la ejecución. val=False desactiva la validación durante el entrenamiento, última época incluida.

Consulta Hiperparámetros para eval_interval, patience y save_plots, y Loggers de experimentos para saber dónde van a parar los números.

  • Datasets para las claves de split y los formatos que leen los validadores.

Verificado con LibreYOLO v1.6.0.