Ultralytics YOLO27: Únete a la lista de espera.
Get Started
Lecciónintermedio

Etiquetar y entrenar la segmentación de instancias

Escribe etiquetas de polígonos, compruébalas en el código, entrena yolo26n-seg.pt con COCO8-seg y diagnostica un modelo a partir de la diferencia entre sus métricas de cajas y máscaras.

La segmentación de instancias proporciona a cada objeto su propio contorno, algo necesario cuando la decisión depende del área, el solapamiento o un límite. Los polígonos son las etiquetas más costosas que compran la mayoría de los equipos, y una fila mal formada no hace que falle el entrenamiento: entrena silenciosamente con la forma incorrecta. En esta lección se corrige el formato de las filas, se comprueba un conjunto de etiquetas con código y se entrena un primer modelo para que veas qué aporta el etiquetado adicional: una segunda métrica que evalúa los contornos, no solo las posiciones.

Resultado

Comprueba que el conjunto de etiquetas de polígonos no contenga filas mal formadas, entrena yolo26n-seg.pt con coco8-seg.yaml y decide qué corregir a partir de la diferencia entre mAP50-95 de cajas y de máscaras.

Vía rápida
Si ya tienes experiencia, aquí tienes un resumen.
  1. Escribe una fila por objeto: índice de clase y, después, pares de vértices x y normalizados, con al menos tres vértices.

  2. Ejecuta una comprobación de etiquetas para detectar cantidades de valores impares, coordenadas fuera de rango y polígonos con un relleno sospechosamente bajo.

  3. yolo segment train data=coco8-seg.yaml model=yolo26n-seg.pt epochs=1 imgsz=320.

  4. Establece el umbral con mAP50-95 de máscaras (metrics.seg.map) y usa la diferencia con mAP50-95 de cajas (metrics.box.map) para el diagnóstico.

Práctico

La fila de etiqueta del polígono#

Segmentación de instancias de Ultralytics YOLO de un paso de peatones urbano, con una máscara independiente para cada coche, el autobús y cada peatón

Un archivo de etiquetas de segmentación tiene una fila por objeto, como una etiqueta de detección, pero en lugar de una caja enumera el contorno del objeto mediante pares de vértices normalizados. Una fila real de COCO8-seg, recortada:

45 0.782016 0.986521 0.937078 0.874167 0.957297 0.782021 0.950562 0.739333 0.825844 0.561792 ...
PosiciónFila de detecciónFila de segmentación
1índice de clase (45 es bowl)índice de clase
2–5x_center y_center width heightlos dos primeros vértices, x1 y1 x2 y2
6+—más vértices, tantos como necesite el contorno
Unidadesnormalizado de 0 a 1normalizado de 0 a 1 (x del píxel ÷ anchura de la imagen, y del píxel ÷ altura de la imagen)

Tres reglas son fundamentales: al menos tres vértices por objeto, coordenadas divididas por el tamaño de la imagen y una fila por instancia, incluso cuando se tocan dos objetos de la misma clase. La guía de conjuntos de datos de segmentación contiene la especificación completa.

Las etiquetas de polígonos también sirven para entrenar cuadros y mapas de clases

Los polígonos son un superconjunto de las etiquetas de cuadros. La misma carpeta de etiquetas sirve para entrenar yolo26n.pt (Ultralytics obtiene cada cuadro a partir de su polígono) y yolo26n-sem.pt (rasteriza los polígonos y los convierte en mapas de clases); entrenamos ambos con coco8-seg.yaml. Si el plan cambia después del etiquetado, el presupuesto no se pierde.

Comprueba las etiquetas antes de entrenar#

Una fila con un número impar de valores, una coordenada escrita en píxeles o un contorno trazado alrededor del elemento equivocado no detendrá el entrenamiento. Este comprobador lee el conjunto de datos con el cargador propio de Ultralytics, rechaza las filas mal formadas e imprime el área de cada polígono junto a la caja que Ultralytics derivará de él:

from pathlib import Path

import numpy as np

from ultralytics.data.utils import check_det_dataset

data = check_det_dataset("coco8-seg.yaml")  # resolves paths, downloads if needed
for label in sorted(Path(data["path"], "labels", "train").glob("*.txt"))[:2]:
    for n, row in enumerate(label.read_text().splitlines(), 1):
        cls, *coords = row.split()
        if len(coords) % 2 or len(coords) < 6:
            print(f"{label.name}:{n} BAD: needs an even number of values and at least 3 vertices")
            continue
        xy = np.array(coords, dtype=float).reshape(-1, 2)
        if xy.min() < 0 or xy.max() > 1:
            print(f"{label.name}:{n} BAD: coordinates must be normalized to 0-1")
            continue
        x, y = xy[:, 0], xy[:, 1]
        area = 0.5 * abs(np.dot(x, np.roll(y, 1)) - np.dot(y, np.roll(x, 1)))  # shoelace formula
        w, h = xy.max(0) - xy.min(0)  # the box Ultralytics derives from the polygon
        name = data["names"][int(cls)]
        print(f"{label.stem} {name:9s} {len(xy):3d} vertices  polygon {area:.3f}  box {w * h:.3f}  fill {area / (w * h):.2f}")
000000000009 bowl       12 vertices  polygon 0.391  box 0.569  fill 0.69
000000000009 bowl       14 vertices  polygon 0.145  box 0.238  fill 0.61
000000000009 broccoli   50 vertices  polygon 0.161  box 0.252  fill 0.64
000000000009 bowl       55 vertices  polygon 0.079  box 0.531  fill 0.15
000000000009 orange     13 vertices  polygon 0.007  box 0.011  fill 0.64
000000000009 orange     13 vertices  polygon 0.005  box 0.009  fill 0.61
000000000009 orange     18 vertices  polygon 0.012  box 0.019  fill 0.61
000000000009 orange     12 vertices  polygon 0.010  box 0.022  fill 0.44
000000000025 giraffe    82 vertices  polygon 0.072  box 0.234  fill 0.31
000000000025 giraffe    19 vertices  polygon 0.010  box 0.027  fill 0.38

Las áreas son fracciones de la imagen, así que el primer cuenco ocupa el 39 % de su foto. Relleno es el área del polígono dividida por el área de la caja, y es la columna que debes revisar:

  • La mayoría de los objetos compactos (cuencos, naranjas, brócoli) se sitúan en torno a 0,6–0,7.
  • El 0,31 de la jirafa es real: las patas largas y el cuello dejan vacía la mayor parte de su caja; por eso este objeto necesita una máscara.
  • El 0,15 del tercer cuenco es la fila que debería revisar una persona. Solo se ve un borde fino del cuenco alrededor de la comida, así que su contorno es una banda estrecha dentro de una caja grande. En este caso es correcto; en tus datos, un relleno tan bajo suele indicar que se ha trazado el contorno alrededor del objeto equivocado.
Criterio de decisión

Corrige todas las filas BAD antes de entrenar. Después, ordénalas por relleno y abre en una herramienta de anotación el porcentaje más bajo de filas de cada clase: un relleno bajo indica un objeto fino u ocluido (consérvalo) o un contorno incorrecto (corrígelo).

Consigue polígonos sin trazar cada borde#

Trazar contornos a mano es la parte costosa del etiquetado de datos. Antes de que nadie empiece, comprueba qué método abreviado puedes usar:

Ya tienesHerramienta
JSON de COCO con segmentaciónconvert_coco(labels_dir, use_segments=True) de ultralytics.data.converter
Máscaras PNG (valor del píxel = índice de clase + 1; 0 = fondo)convert_segment_masks_to_yolo_seg(masks_dir, output_dir, classes): los objetos de una misma clase que se tocan se convierten en un solo polígono, así que sepáralos durante la revisión
Solo etiquetas de cajasyolo_bbox2segment(im_dir): solicita a SAM que genere un polígono para cada caja
Aún no tienes nadaAnotación inteligente y etiquetado por lotes: haz clic una vez y revisa el polígono

En Ultralytics Platform, el modo Smart ejecuta SAM: un clic positivo sobre el objeto y otro negativo sobre lo que debe excluirse generan una máscara que después revisas.

Modo Smart de Ultralytics Platform con SAM 2.1 Tiny seleccionado: un clic positivo y otro negativo sobre un robot de almacén generan su máscara

Revisa todos los polígonos generados automáticamente

Una máscara que se extiende al fondo enseña al modelo a hacer lo mismo. Revisa los polígonos generados automáticamente según el criterio de calidad de Cuadros frente a máscaras y vuelve a ejecutar la comprobación de etiquetas anterior.

Entrena con COCO8-seg#

Mosaico de entrenamiento de COCO8-seg: cebras, una jirafa, recipientes de comida con brócoli y naranjas, y un jarrón de flores; cada objeto tiene su propia máscara de color e índice de clase

El entrenamiento sigue el flujo de trabajo de detección, pero con un modelo -seg y un conjunto de datos de segmentación. Una época con imgsz=320 en la CPU de un portátil termina en segundos, suficiente para comprobar todo el proceso:

from ultralytics import YOLO

model = YOLO("yolo26n-seg.pt")
model.train(data="coco8-seg.yaml", epochs=1, imgsz=320, device="cpu")
metrics = model.val()
print(f"box  mAP50-95: {metrics.box.map:.3f}")
print(f"mask mAP50-95: {metrics.seg.map:.3f}")
                 Class     Images  Instances      Box(P          R      mAP50  mAP50-95)     Mask(P          R      mAP50  mAP50-95)
                   all          4         17      0.909      0.449      0.661      0.482      0.685      0.409      0.557      0.377
                 horse          1          2          1      0.993      0.995      0.564      0.619      0.857      0.663      0.199
box  mAP50-95: 0.482
mask mAP50-95: 0.377

Cuatro imágenes de validación hacen que estos números sean poco fiables; lo importante es que la ejecución termine y escriba weights/best.pt en runs/segment/. Para datos reales, sigue la guía de la tarea Segment y entrena durante todo el programa en una GPU.

Lee en paralelo las métricas de cajas y máscaras#

La tabla de validación tiene dos bloques. Box compara cada caja predicha con la caja que implica la etiqueta; Mask compara los píxeles predichos con el polígono etiquetado. Ambos usan el mismo mecanismo de mAP; solo cambia la IoU.

El mAP50-95 de máscaras casi siempre es inferior al de cajas, porque la IoU de píxeles es más estricta: una caja desplazada unos pocos píxeles sigue solapándose bastante, mientras que una máscara a la que le falta un brazo o que se extiende sobre la calzada pierde IoU rápidamente en los umbrales de 0,75–0,95. La fila horse es el caso más extremo: mAP50-95 de cajas de 0,564 y de máscaras de 0,199. El modelo encontró los dos caballos y los encuadró bien, pero no perfiló las patas ni las colas. Usa la diferencia para decidir qué corregir:

  • Ambas bajas: el problema es encontrar los objetos, no perfilar sus contornos. Primero, añade datos de las condiciones en las que no se detectaron.
  • Cajas buenas, máscaras mucho peores: el modelo encuentra los objetos, pero perfila mal sus contornos. Ejecuta la comprobación de etiquetas, prueba un modelo más grande o entrena y valida con un valor de imgsz mayor.
  • Las máscaras mejoran mientras las cajas se estancan: no pasa nada; en un producto de segmentación, el mAP50-95 de máscaras es el criterio de lanzamiento.
Dos parámetros que no cambian la resolución de la máscara

overlap_mask=True combina las máscaras de instancias en una sola imagen durante el entrenamiento, y mask_ratio=4 reduce la resolución de las máscaras de entrenamiento. Ninguno de los dos cambia la resolución de las máscaras predichas: eso depende de retina_masks, que se explica en la siguiente lección. Déjalos con sus valores predeterminados salvo que hayas medido un motivo para cambiarlos.

Pruébalo

Ejecuta check_seg_labels.py en todo COCO8-seg (entrenamiento y validación) y enumera las tres filas con el relleno más bajo. Después, entrena yolo26n-seg.pt con coco8-seg.yaml durante una época con imgsz=320, registra el mAP50-95 de cajas, el mAP50-95 de máscaras y la clase con la mayor diferencia, y abre val_batch0_pred.jpg en la carpeta de validación para encontrar un objeto cuya máscara sea claramente peor que su caja.

Cuándo se considera terminado
Has terminado la lección cuando se cumplen todas estas condiciones.
  • La comprobación de etiquetas indica que hay cero filas BAD y has indicado, para cada una, si deben conservarse o corregirse las tres filas con el relleno más bajo.

  • El entrenamiento ha terminado, best.pt existe en runs/segment/ y has registrado ambos valores de mAP50-95.

  • Has indicado la clase con la mayor diferencia entre cajas y máscaras, así como el siguiente paso que propone el diagrama de decisiones.

Mostrar solución

Para comprobar todas las particiones, sustituye la carpeta del bucle por Path(data["path"], "labels").rglob("*.txt"). Después, entrena:

from ultralytics import YOLO

model = YOLO("yolo26n-seg.pt")
model.train(data="coco8-seg.yaml", epochs=1, imgsz=320, device="cpu")
metrics = model.val()
print(f"box  mAP50-95: {metrics.box.map:.3f}")   # 0.482 in our run
print(f"mask mAP50-95: {metrics.seg.map:.3f}")   # 0.377 in our run

La diferencia de 0,1 es normal: la IoU de máscaras penaliza cada píxel del contorno; la IoU de cajas solo penaliza los cuatro bordes. En nuestra ejecución, la mayor diferencia corresponde a horse (cajas: 0,564; máscaras: 0,199). El mAP de cajas es bueno y el de máscaras es muy inferior, así que el diagrama apunta a la calidad de los contornos: comprueba primero esos polígonos y después prueba un modelo más grande o un valor de imgsz mayor.

Qué viene después

A continuación, convertimos las máscaras predichas en datos numéricos: áreas, contornos, solapamientos y recortes transparentes.