Guía de configuración de modelos YAML

El archivo de configuración YAML del modelo sirve como el plano arquitectónico para las redes neuronales de Ultralytics. Define cómo se conectan las capas, qué parámetros utiliza cada módulo y cómo se escala toda la red a través de diferentes tamaños de modelo.

Model YAML configuration workflow.

Estructura de configuración

Los archivos YAML de modelo están organizados en tres secciones principales que funcionan juntas para definir la arquitectura.

Sección de parámetros

La sección parameters especifica las características globales y el comportamiento de escalado del modelo:

# Parameters
nc: 80 # number of classes
scales: # compound scaling constants [depth, width, max_channels]
    n: [0.50, 0.25, 1024] # nano: shallow layers, narrow channels
    s: [0.50, 0.50, 1024] # small: shallow depth, standard width
    m: [0.50, 1.00, 512] # medium: moderate depth, full width
    l: [1.00, 1.00, 512] # large: full depth and width
    x: [1.00, 1.50, 512] # extra-large: maximum performance
kpt_shape: [17, 3] # pose models only
  • nc establece el número de clases que predice el modelo.
  • scales define factores de escalado compuestos que ajustan la profundidad, anchura y canales máximos del modelo para producir variantes de diferentes tamaños (desde nano hasta extra-large).
  • kpt_shape se aplica a modelos de pose. Puede ser [N, 2] para keypoints (x, y) o [N, 3] para (x, y, visibility).
Reduce la redundancia con `scales`

El parámetro scales te permite generar múltiples tamaños de modelo a partir de un único YAML base. Por ejemplo, cuando cargas yolo26n.yaml, Ultralytics lee el yolo26.yaml base y aplica los factores de escalado n (depth=0.50, width=0.25) para construir la variante nano.

`nc` y `kpt_shape` dependen del dataset

Si tu dataset especifica un nc o kpt_shape diferente, Ultralytics sobrescribirá automáticamente la configuración del modelo en tiempo de ejecución para que coincida con el YAML del dataset.

Arquitectura de Backbone y Head

La arquitectura del modelo consiste en secciones de backbone (extracción de características) y head (específica para la tarea):

backbone:
    # [from, repeats, module, args]
    - [-1, 1, Conv, [64, 3, 2]] # 0: Initial convolution
    - [-1, 1, Conv, [128, 3, 2]] # 1: Downsample
    - [-1, 3, C2f, [128, True]] # 2: Feature processing

head:
    - [-1, 1, nn.Upsample, [None, 2, nearest]] # 6: Upsample
    - [[-1, 2], 1, Concat, [1]] # 7: Skip connection
    - [-1, 3, C2f, [256]] # 8: Process features
    - [[8], 1, Detect, [nc]] # 9: Detection layer

Formato de especificación de capas

Cada capa sigue el patrón constante: [from, repeats, module, args]

ComponentePropósitoEjemplos
fromConexiones de entrada-1 (anterior), 6 (capa 6), [4, 6, 8] (entrada múltiple)
repeatsNúmero de repeticiones1 (simple), 3 (repetir 3 veces)
moduleTipo de móduloConv, C2f, TorchVision, Detect
argsArgumentos del módulo[64, 3, 2] (canales, kernel, stride)

Patrones de conexión

El campo from crea patrones de flujo de datos flexibles a través de tu red:

- [-1, 1, Conv, [64, 3, 2]]    # Takes input from previous layer
Indexación de capas

Las capas se indexan empezando desde 0. Los índices negativos hacen referencia a capas anteriores (-1 = capa anterior), mientras que los índices positivos hacen referencia a capas específicas por su posición.

Repetición de módulos

El parámetro repeats crea secciones de red más profundas:

- [-1, 3, C2f, [128, True]] # Creates 3 consecutive C2f blocks
- [-1, 1, Conv, [64, 3, 2]] # Single convolution layer

El recuento real de repeticiones se multiplica por el factor de escalado de profundidad de la configuración del tamaño de tu modelo.

Módulos disponibles

Los módulos están organizados por funcionalidad y definidos en el directorio de módulos de Ultralytics. Las siguientes tablas muestran los módulos más utilizados por categoría, con muchos más disponibles en el código fuente:

Operaciones básicas

MóduloPropósitoFuenteArgumentos
ConvConvolución + BatchNorm + Activaciónconv.py[out_ch, kernel, stride, pad, groups]
nn.UpsampleUpsampling espacialPyTorch[size, scale_factor, mode]
nn.IdentityOperación de pasoPyTorch[]

Bloques compuestos

MóduloPropósitoFuenteArgumentos
C2fBottleneck CSP con 2 convolucionesblock.py[out_ch, shortcut, expansion]
SPPFSpatial Pyramid Pooling (rápido)block.py[out_ch, kernel_size]
ConcatConcatenación por canalesconv.py[dimension]

Módulos especializados

MóduloPropósitoFuenteArgumentos
TorchVisionCargar cualquier modelo de torchvisionblock.py[out_ch, model_name, weights, unwrap, truncate, split]
IndexExtraer tensor específico de la listablock.py[out_ch, index]
DetectHead de detección YOLOhead.py[nc, anchors, ch]
Lista completa de módulos

Esto representa un subconjunto de los módulos disponibles. Para obtener la lista completa de módulos y sus parámetros, explora el directorio de módulos.

Características avanzadas

Integración con TorchVision

El módulo TorchVision permite la integración fluida de cualquier modelo TorchVision como backbone:

from ultralytics import YOLO

# Model with ConvNeXt backbone
model = YOLO("convnext_backbone.yaml")
results = model.train(data="coco8.yaml", epochs=100)
Características multiescala

Establece el último parámetro en True para obtener mapas de características intermedios para detección multiescala.

Módulo Index para selección de características

Al usar modelos que generan múltiples mapas de características, el módulo Index selecciona salidas específicas:

backbone:
    - [-1, 1, TorchVision, [768, convnext_tiny, DEFAULT, True, 2, True]] # Multi-output
head:
    - [0, 1, Index, [192, 4]] # Select 4th feature map (192 channels)
    - [0, 1, Index, [384, 6]] # Select 6th feature map (384 channels)
    - [0, 1, Index, [768, 8]] # Select 8th feature map (768 channels)
    - [[1, 2, 3], 1, Detect, [nc]] # Multi-scale detection

Sistema de resolución de módulos

Entender cómo Ultralytics localiza e importa módulos es crucial para la personalización:

Proceso de búsqueda de módulos

Ultralytics utiliza un sistema de tres niveles en parse_model:

# Core resolution logic
m = getattr(torch.nn, m[3:]) if "nn." in m else getattr(torchvision.ops, m[4:]) if "ops." in m else globals()[m]
  1. Módulos PyTorch: Nombres que empiezan con 'nn.' → namespace torch.nn
  2. Operaciones TorchVision: Nombres que empiezan con 'ops.' → namespace torchvision.ops
  3. Módulos de Ultralytics: Todos los demás nombres → espacio de nombres global mediante importaciones

Cadena de importación de módulos

Los módulos estándar están disponibles a través de importaciones en tasks.py:

from ultralytics.nn.modules import (  # noqa: F401
    SPPF,
    C2f,
    Conv,
    Detect,
    # ... many more modules
    Index,
    TorchVision,
)

Integración de módulos personalizados

Modificación del código fuente

Modificar el código fuente es la forma más versátil de integrar tus módulos personalizados, pero puede resultar complicado. Para definir y utilizar un módulo personalizado, sigue estos pasos:

  1. Instala Ultralytics en modo de desarrollo utilizando el método de clonación de Git de la guía de inicio rápido.

  2. Define tu módulo en ultralytics/nn/modules/block.py:

    class CustomBlock(nn.Module):
        """Custom block with Conv-BatchNorm-ReLU sequence."""
    
        def __init__(self, c1, c2):
            """Initialize CustomBlock with input and output channels."""
            super().__init__()
            self.layers = nn.Sequential(nn.Conv2d(c1, c2, 3, 1, 1), nn.BatchNorm2d(c2), nn.ReLU())
    
        def forward(self, x):
            """Forward pass through the block."""
            return self.layers(x)
  3. Expón tu módulo a nivel de paquete en ultralytics/nn/modules/__init__.py:

    from .block import CustomBlock  # noqa makes CustomBlock available as ultralytics.nn.modules.CustomBlock
  4. Añádelo a las importaciones en ultralytics/nn/tasks.py:

    from ultralytics.nn.modules import CustomBlock  # noqa
  5. Gestiona los argumentos especiales (si es necesario) dentro de parse_model() en ultralytics/nn/tasks.py:

    # Add this condition in the parse_model() function
    if m is CustomBlock:
        c1, c2 = ch[f], args[0]  # input channels, output channels
        args = [c1, c2, *args[1:]]
  6. Utiliza el módulo en el YAML de tu modelo:

    # custom_model.yaml
    nc: 1
    backbone:
        - [-1, 1, CustomBlock, [64]]
    head:
        - [-1, 1, Classify, [nc]]
  7. Comprueba los FLOPs para asegurarte de que el paso hacia adelante (forward pass) funciona:

    from ultralytics import YOLO
    
    model = YOLO("custom_model.yaml", task="classify")
    model.info()  # should print non-zero FLOPs if working

Ejemplos de configuración

Modelo de detección básico

# Simple YOLO detection model
nc: 80
scales:
    n: [0.33, 0.25, 1024]

backbone:
    - [-1, 1, Conv, [64, 3, 2]] # 0-P1/2
    - [-1, 1, Conv, [128, 3, 2]] # 1-P2/4
    - [-1, 3, C2f, [128, True]] # 2
    - [-1, 1, Conv, [256, 3, 2]] # 3-P3/8
    - [-1, 6, C2f, [256, True]] # 4
    - [-1, 1, SPPF, [256, 5]] # 5

head:
    - [-1, 1, Conv, [256, 3, 1]] # 6
    - [[6], 1, Detect, [nc]] # 7

Modelo de backbone de TorchVision

# ConvNeXt backbone with YOLO head
nc: 80

backbone:
    - [-1, 1, TorchVision, [768, convnext_tiny, DEFAULT, True, 2, True]]

head:
    - [0, 1, Index, [192, 4]] # P3 features
    - [0, 1, Index, [384, 6]] # P4 features
    - [0, 1, Index, [768, 8]] # P5 features
    - [[1, 2, 3], 1, Detect, [nc]] # Multi-scale detection

Modelo de clasificación

# Simple classification model
nc: 1000

backbone:
    - [-1, 1, Conv, [64, 7, 2, 3]]
    - [-1, 1, nn.MaxPool2d, [3, 2, 1]]
    - [-1, 4, C2f, [64, True]]
    - [-1, 1, Conv, [128, 3, 2]]
    - [-1, 8, C2f, [128, True]]
    - [-1, 1, nn.AdaptiveAvgPool2d, [1]]

head:
    - [-1, 1, Classify, [nc]]

Mejores prácticas

Consejos de diseño de arquitectura

Empieza de forma sencilla: Comienza con arquitecturas probadas antes de personalizar. Utiliza configuraciones de YOLO existentes como plantillas y modifícalas de forma incremental en lugar de construir desde cero.

Prueba de forma incremental: Valida cada modificación paso a paso. Añade un módulo personalizado cada vez y verifica que funciona antes de proceder con el siguiente cambio.

Controla los canales: Asegúrate de que las dimensiones de los canales coincidan entre las capas conectadas. Los canales de salida (c2) de una capa deben coincidir con los canales de entrada (c1) de la siguiente capa en la secuencia.

Utiliza conexiones de salto (skip connections): Aprovecha la reutilización de características con patrones [[-1, N], 1, Concat, [1]]. Estas conexiones ayudan al flujo de gradiente y permiten al modelo combinar características de diferentes escalas.

Escala adecuadamente: Elige las escalas del modelo según tus restricciones computacionales. Usa nano (n) para dispositivos de borde (edge devices), small (s) para un rendimiento equilibrado y escalas más grandes (m, l, x) para una precisión máxima.

Consideraciones sobre el rendimiento

Profundidad frente a anchura: Las redes profundas capturan características jerárquicas complejas a través de múltiples capas de transformación, mientras que las redes anchas procesan más información en paralelo en cada capa. Equilíbralas según la complejidad de tu tarea.

Conexiones de salto: Mejoran el flujo de gradiente durante el entrenamiento y permiten la reutilización de características a lo largo de la red. Son especialmente importantes en arquitecturas más profundas para evitar la desaparición de gradientes.

Bloques de cuello de botella (bottleneck blocks): Reducen el coste computacional manteniendo la capacidad de expresión del modelo. Módulos como C2f utilizan menos parámetros que las convoluciones estándar mientras preservan la capacidad de aprendizaje de características.

Características multiescala: Esenciales para detectar objetos de diferentes tamaños en la misma imagen. Utiliza patrones de Feature Pyramid Network (FPN) con múltiples cabezales de detección a diferentes escalas.

Solución de problemas

Problemas comunes

ProblemaCausaSolución
KeyError: 'ModuleName'Módulo no importadoAñadir a las importaciones de tasks.py
Desajuste en la dimensión del canalEspecificación de args incorrectaVerificar compatibilidad de canales de entrada/salida
AttributeError: 'int' object has no attributeTipo de argumento incorrectoComprobar la documentación del módulo para conocer los tipos de argumentos correctos
El modelo no se construyeReferencia from no válidaAsegurarse de que las capas referenciadas existan

Consejos de depuración

Al desarrollar arquitecturas personalizadas, la depuración sistemática ayuda a identificar problemas pronto:

Utiliza un cabezal de identidad para probar

Reemplaza los cabezales complejos con nn.Identity para aislar los problemas del backbone:

nc: 1
backbone:
    - [-1, 1, CustomBlock, [64]]
head:
    - [-1, 1, nn.Identity, []] # Pass-through for debugging

Esto permite la inspección directa de las salidas del backbone:

import torch

from ultralytics import YOLO

model = YOLO("debug_model.yaml")
output = model.model(torch.randn(1, 3, 640, 640))
print(f"Output shape: {output.shape}")  # Should match expected dimensions

Inspección de la arquitectura del modelo

Comprobar el recuento de FLOPs e imprimir cada capa también puede ayudar a depurar problemas con la configuración de tu modelo personalizado. El recuento de FLOPs no debería ser cero para un modelo válido. Si es cero, es probable que haya un problema con el paso hacia adelante. Ejecutar un paso hacia adelante simple debería mostrar el error exacto que se está encontrando.

from ultralytics import YOLO

# Build model with verbose output to see layer details
model = YOLO("debug_model.yaml", verbose=True)

# Check model FLOPs. Failed forward pass causes 0 FLOPs.
model.info()

# Inspect individual layers
for i, layer in enumerate(model.model.model):
    print(f"Layer {i}: {layer}")

Validación paso a paso

  1. Empieza de forma mínima: Prueba primero con la arquitectura más simple posible
  2. Añade gradualmente: Construye la complejidad capa a capa
  3. Comprueba las dimensiones: Verifica la compatibilidad del canal y del tamaño espacial
  4. Valida el escalado: Prueba con diferentes escalas de modelo (n, s, m)

Preguntas frecuentes

¿Cómo cambio el número de clases en mi modelo?

Establece el parámetro nc en la parte superior de tu archivo YAML para que coincida con el número de clases de tu conjunto de datos.

nc: 5 # 5 classes

¿Puedo utilizar un backbone personalizado en el YAML de mi modelo?

Sí. Puedes utilizar cualquier módulo compatible, incluidos los backbones de TorchVision, o definir tu propio módulo personalizado e importarlo como se describe en Integración de módulos personalizados.

¿Cómo escalo mi modelo para diferentes tamaños (nano, small, medium, etc.)?

Utiliza la sección scales (escalas) en tu YAML para definir los factores de escalado para la profundidad, la anchura y los canales máximos. El modelo los aplicará automáticamente cuando cargues el archivo YAML base con la escala añadida al nombre del archivo (ej. yolo26n.yaml).

¿Qué significa el formato [from, repeats, module, args]?

Este formato especifica cómo se construye cada capa:

  • from: fuente(s) de entrada
  • repeats: número de veces que se repite el módulo
  • module: el tipo de capa
  • args: argumentos para el módulo

¿Cómo soluciono los errores de desajuste de canales?

Comprueba que los canales de salida de una capa coincidan con los canales de entrada esperados de la siguiente. Utiliza print(model.model.model) para inspeccionar la arquitectura de tu modelo.

¿Dónde puedo encontrar una lista de los módulos disponibles y sus argumentos?

Consulta el código fuente en el directorio ultralytics/nn/modules para ver todos los módulos disponibles y sus argumentos.

¿Cómo añado un módulo personalizado a mi configuración YAML?

Define tu módulo en el código fuente, impórtalo como se muestra en Modificación del código fuente y haz referencia a él por su nombre en tu archivo YAML.

¿Puedo utilizar pesos preentrenados con un YAML personalizado?

Sí, puedes usar model.load("path/to/weights") para cargar pesos de un checkpoint preentrenado. Sin embargo, solo se cargarán correctamente los pesos de las capas que coincidan.

¿Cómo valido la configuración de mi modelo?

Usa model.info() para comprobar si el recuento de FLOPs no es cero. Un modelo válido debería mostrar un recuento de FLOPs distinto de cero. Si es cero, sigue las sugerencias en Consejos de depuración para encontrar el problema.

Comentarios