Ultralytics YOLO27: Únete a la lista de espera.
Get Started
Fundamentos de visión artificial·Conjuntos de datos y etiquetas·Lección 7/10
Lecciónprincipiante

Calidad de las anotaciones

Descubre qué contiene una etiqueta YOLO, comprueba los archivos de etiquetas para detectar filas incorrectas y mantén la coherencia entre anotadores con una guía y una ronda de calibración cuantificada.

Un modelo entrenado con etiquetas incoherentes aprende esa incoherencia. Cincuenta mil recuadros dibujados con una regla clara superan a medio millón dibujados según veinte interpretaciones particulares, y volver a etiquetar casi siempre cuesta menos que usar un modelo más grande. En esta lección tendrás un validador de etiquetas, una guía de una página y una medida del acuerdo entre anotadores.

Resultado

Comprueba los archivos de etiquetas de un conjunto de datos, redacta una guía de una página para una clase y mide el acuerdo entre dos anotadores.

Vía rápida
Si ya tienes experiencia, aquí tienes un resumen.
  1. Identifica la fila de etiquetas correspondiente a tu tarea: recuadro, polígono, puntos clave o esquinas.

  2. Comprueba todos los archivos de etiquetas: número de columnas, ID de clase, coordenadas de 0 a 1 y recuadros duplicados.

  3. Guía de una página con una imagen de ejemplo para cada regla y una lista de elementos que no se deben etiquetar.

  4. Haz primero una ronda de calibración: todos etiquetan las mismas 50 imágenes; amplía el trabajo solo cuando se alcance el nivel de acuerdo requerido.

  5. Los revisores rechazan el trabajo indicando un motivo; nunca lo corrigen en silencio.

Práctico

Qué es realmente una etiqueta#

En el formato YOLO, cada imagen tiene un archivo .txt correspondiente, con una fila por objeto. Las coordenadas se normalizan de 0 a 1 según la anchura y la altura de la imagen, por lo que las etiquetas se conservan al cambiar el tamaño. La estructura de la fila depende de la tarea:

TareaUna etiquetaNotas
Detecciónclass x_center y_center width heightCentro y tamaño del recuadro
Segmentación de instanciasclass x1 y1 x2 y2 ... xn ynContorno del polígono
Poseclass x y w h px1 py1 v1 ... pxn pyn vnRecuadro y, a continuación, puntos clave con visibilidad opcional
OBBclass x1 y1 x2 y2 x3 y3 x4 y4Cuatro esquinas del recuadro girado
ClasificaciónSin archivo de etiquetasImágenes clasificadas en una carpeta por clase
Segmentación semánticaUna máscara PNG por imagenCada valor de píxel es un índice de clase
Estimación de profundidadUn PNG o NPY de profundidad por imagenCada valor de píxel es una distancia

Los índices de clase empiezan en 0 y se corresponden con los nombres del YAML del conjunto de datos. Una imagen sin objetos no necesita archivo de etiquetas: así funcionan las imágenes de fondo. Las páginas de conjuntos de datos sobre el formato de detección, la segmentación semántica y la profundidad incluyen ejemplos prácticos.

Comprueba tus archivos de etiquetas#

Las filas incorrectas pueden fallar sin avisar: una coordenada superior a 1, un ID de clase que el YAML no define o el mismo objeto encerrado en dos recuadros se convierten en ruido que el modelo intenta aprender. Un validador breve los detecta antes del entrenamiento:

from itertools import combinations
from pathlib import Path

from ultralytics.data.utils import check_det_dataset

def iou(a, b):
    """IoU of two normalized (x_center, y_center, width, height) boxes."""
    ax1, ay1, ax2, ay2 = a[0] - a[2] / 2, a[1] - a[3] / 2, a[0] + a[2] / 2, a[1] + a[3] / 2
    bx1, by1, bx2, by2 = b[0] - b[2] / 2, b[1] - b[3] / 2, b[0] + b[2] / 2, b[1] + b[3] / 2
    inter = max(0, min(ax2, bx2) - max(ax1, bx1)) * max(0, min(ay2, by2) - max(ay1, by1))
    return inter / (a[2] * a[3] + b[2] * b[3] - inter)

def check_labels(text, names):
    """Return a list of problems in one YOLO detection label file."""
    problems, boxes = [], []
    for i, row in enumerate(text.split("\n"), 1):
        values = row.split()
        if not values:
            continue
        if len(values) != 5:
            problems.append(f"row {i}: {len(values)} values, expected 5")
        elif int(values[0]) not in names:
            problems.append(f"row {i}: unknown class {values[0]}")
        elif not all(0 <= float(v) <= 1 for v in values[1:]):
            problems.append(f"row {i}: coordinates outside 0-1")
        else:
            boxes.append((i, int(values[0]), [float(v) for v in values[1:]]))
    for (i, ca, a), (j, cb, b) in combinations(boxes, 2):
        if ca == cb and iou(a, b) > 0.8:
            problems.append(f"row {j}: duplicate of row {i} (IoU {iou(a, b):.2f})")
    return problems

broken = "0 0.50 0.50 0.20 0.30\n0 0.51 0.50 0.20 0.30\n3 0.40 0.40 0.10 0.10\n0 1.20 0.50 0.10 0.10\n0 0.50 0.50 0.10"
print("\n".join(check_labels(broken, {0: "pill"})))

data = check_det_dataset("medical-pills.yaml")
files = sorted(Path(data["path"], "labels").rglob("*.txt"))
found = sum(len(check_labels(f.read_text(), data["names"])) for f in files)
print(f"medical-pills: {found} problems in {len(files)} label files")
row 3: unknown class 3
row 4: coordinates outside 0-1
row 5: 4 values, expected 5
row 2: duplicate of row 1 (IoU 0.90)
medical-pills: 0 problems in 115 label files

La muestra creada a mano muestra cada error que detecta el validador; el conjunto de datos real no presenta errores. Ejecútalo después de cada lote de etiquetado y antes de cada entrenamiento: solo tarda unos segundos.

Por qué varían las etiquetas#

Editor de anotaciones de Ultralytics Platform a pantalla completa: cajas de cartón sobre robots de almacén delineadas con polígonos, con la lista de clases abierta al lado

Fíjate en el panel de clases de este editor: los 14 polígonos de cajas de cartón están guardados en Grapes, mientras que más abajo en la lista aparece una clase Box; además, plane y Plane existen como dos clases distintas. Un validador no puede detectar ninguno de los dos problemas, porque todas las filas son válidas, pero un revisor que compruebe las etiquetas según la guía detectaría ambos en segundos. La mayoría de los errores de etiquetado son así: archivos válidos, decisiones equivocadas.

Rara vez los anotadores etiquetan mal por descuido. Etiquetan de forma incoherente porque las reglas son ambiguas y cada persona hace una suposición razonable, pero distinta:

  • ¿Dónde termina el recuadro? ¿En la sombra, en una bolsa transportada o en la carga de las horquillas de una carretilla elevadora?
  • Truncamiento. Si una persona está medio fuera del encuadre, ¿sigue siendo un person? ¿A partir de qué fracción visible?
  • Oclusión. Si un coche solo es visible por una rueda, ¿se etiqueta o se omite?
  • Límites entre clases. ¿Una camioneta es un car o un truck? ¿Un patinete es un bicycle o un other?
  • Casos que no se deben etiquetar. Reflejos, carteles y pantallas que muestran el objeto.

Cada opción es válida siempre que todos elijan la misma.

Una guía de una página#

Cabe en una página, incluye una imagen de ejemplo para cada regla y presenta primero los casos límite:

## Class: forklift

Include:
- Forklifts with at least 30% of the body visible, moving or parked, any size or color.

Do not label:
- Pallet jacks (no overhead mast) → class `pallet_jack`.
- Reflections in glass or polished floors, and forklifts on posters or screens.

Box rules:
- Include the mast and the full visible body.
- Exclude the load (pallets, boxes) — those have their own classes.
- For partly occluded forklifts, box the visible part only.

Mide el acuerdo en una ronda de calibración#

Antes de pasar de un anotador a veinte, todos etiquetan las mismas 50 imágenes y comparas los resultados:

El acuerdo es la proporción de objetos que ambos anotadores dibujaron con la misma clase y un IoU de al menos 0.5: la versión práctica de la fiabilidad entre evaluadores:

def iou(a, b):
    """IoU of two (x1, y1, x2, y2) pixel boxes."""
    w = max(0, min(a[2], b[2]) - max(a[0], b[0]))
    h = max(0, min(a[3], b[3]) - max(a[1], b[1]))
    inter = w * h
    return inter / ((a[2] - a[0]) * (a[3] - a[1]) + (b[2] - b[0]) * (b[3] - b[1]) - inter)

def agreement(boxes_a, boxes_b, threshold=0.5):
    """Share of objects both annotators drew with the same class and IoU >= threshold."""
    unmatched, matched = list(boxes_b), 0
    for cls_a, box_a in boxes_a:
        best = max(unmatched, key=lambda b: iou(box_a, b[1]) if b[0] == cls_a else -1, default=None)
        if best and best[0] == cls_a and iou(box_a, best[1]) >= threshold:
            unmatched.remove(best)
            matched += 1
    return matched / max(len(boxes_a), len(boxes_b))

# Two annotators label the same calibration image
alice = [("forklift", (100, 200, 400, 600)), ("person", (450, 220, 520, 480)), ("person", (600, 230, 660, 470))]
bob = [("forklift", (100, 120, 400, 600)), ("person", (452, 218, 522, 478)), ("pallet_jack", (600, 230, 660, 470))]
print(f"agreement: {agreement(alice, bob):.0%}")
agreement: 67%

En ese 67 % se esconden dos tipos de desacuerdo. El recuadro de la carretilla elevadora de Bob empieza 80 píxeles más arriba —incluyó la punta del mástil—, pero aun así coincide con un IoU de 0.83, así que cuenta como acuerdo; concreta la regla del recuadro si tu producto mide la altura. El tercer objeto es un conflicto real: Alice dice person y Bob dice pallet_jack. Hace falta una regla más clara y una imagen de ejemplo, y después otra ronda. Conserva las 50 imágenes de calibración: se convertirán en la prueba de incorporación de cada nuevo anotador.

Los revisores rechazan; no corrigen en silencio

Un revisor que corrige las etiquetas discretamente elimina el ciclo de retroalimentación, y los anotadores nunca aprenden qué han hecho mal. Rechaza la etiqueta indicando el motivo y deja que el anotador la corrija. Será más lento con las primeras cien imágenes, pero mucho más rápido después.

Qué debes medir#

MétricaQué te indica
Ritmo de trabajo (objetos por hora)Capacidad y coste
Tasa de rechazoSi la calidad está empeorando
Acuerdo en un conjunto común de imágenes superpuestasSi los anotadores siguen aplicando las mismas reglas

Cuando baja el acuerdo, algo ha cambiado: un nuevo anotador, una cámara nueva, un lote ambiguo o el cansancio. Si más adelante el modelo falla en una condición concreta, vuelve a etiquetar esas imágenes exactas: es el ciclo que automatiza el aprendizaje activo y la fuente de la mayoría de las mejoras de precisión en el mundo real. Examina y filtra los errores en tus conjuntos de datos en Ultralytics Platform y consulta Control de calidad de conjuntos de datos y Buenas prácticas de anotación para aplicar este proceso a gran escala.

Pruébalo

Ejecuta el validador en la carpeta de etiquetas de tu conjunto de datos. Después, redacta una guía de una página para la clase más ambigua, con una imagen de ejemplo por regla y una lista de elementos que no se deben etiquetar. Dásela a un compañero junto con 10 imágenes sin etiquetar, sin explicarle nada; etiqueta tú las mismas imágenes y calcula el acuerdo con el script. Anota la puntuación y cada regla que hayas cambiado debido a un desacuerdo.

Cuándo se considera terminado
Has terminado la lección cuando se cumplen todas estas condiciones.
  • El validador no detecta ningún problema en tus etiquetas o ya has corregido todos los que encontró.

  • Tienes una guía de una página con un ejemplo para cada regla y una lista de elementos que no se deben etiquetar.

  • Tienes una puntuación de acuerdo entre dos anotadores y una lista de las reglas que has cambiado a raíz de esa puntuación.

Mostrar solución

Una guía para la clase pill de medical-pills, redactada tras una ronda de calibración con 10 imágenes:

## Class: pill

Include:
- Every tablet inside a blister cavity, including half-visible ones at the image edge.
- Tablets seen through clear plastic, even when glare covers part of them.

Do not label:
- Empty cavities, torn foil, or tablets outside the pack.
- Reflections of tablets in the foil.

Box rules:
- Box the tablet itself, not the plastic bubble around it.
- If two tablets touch, draw two boxes.

Cómo interpretar la puntuación de acuerdo: supongamos que la primera ronda obtiene un 82 %. Ordena los objetos sin correspondencia por causa. En los blísteres, los dos casos más habituales son los recuadros dibujados alrededor de la burbuja de plástico en vez de la pastilla (se corrige con la primera regla sobre recuadros y una imagen de ejemplo) y las pastillas tapadas por reflejos que un anotador omitió (se corrige con la segunda regla de inclusión). Repite la prueba con 10 imágenes nuevas; amplía el trabajo solo cuando la puntuación supere el umbral del 90 %.

Qué viene después

A continuación: dividir los datos etiquetados para que tus métricas sean fiables, empezando por una filtración oculta en este mismo conjunto de datos.