Saltar al contenido

Validaci贸n cruzada K-Fold con Ultralytics

Introducci贸n

Esta completa gu铆a ilustra la implementaci贸n de la Validaci贸n Cruzada K-Fold para conjuntos de datos de detecci贸n de objetos dentro del ecosistema Ultralytics . Aprovecharemos el formato de detecci贸n YOLO y las bibliotecas clave de Python , como sklearn, pandas y PyYaml, para guiarte por la configuraci贸n necesaria, el proceso de generaci贸n de vectores de caracter铆sticas y la ejecuci贸n de una divisi贸n K-Fold de conjuntos de datos.

Resumen de la validaci贸n cruzada K-Fold

Tanto si tu proyecto incluye el conjunto de datos de Fruit Detection como una fuente de datos personalizada, este tutorial pretende ayudarte a comprender y aplicar la Validaci贸n Cruzada K-Fold para reforzar la fiabilidad y solidez de tus modelos de aprendizaje autom谩tico. Mientras aplicamos k=5 pliegues para este tutorial, ten en cuenta que el n煤mero 贸ptimo de pliegues puede variar en funci贸n de tu conjunto de datos y de las particularidades de tu proyecto.

Sin m谩s pre谩mbulos, 隆vamos a sumergirnos!

Configurar

  • Tus anotaciones deben estar en el formato de detecci贸nYOLO .

  • Esta gu铆a asume que los archivos de anotaci贸n est谩n disponibles localmente.

  • Para nuestra demostraci贸n, utilizamos el conjunto de datos Detecci贸n de Frutas.

    • Este conjunto de datos contiene un total de 8479 im谩genes.
    • Incluye 6 etiquetas de clase, cada una con su recuento total de instancias indicado a continuaci贸n.
Etiqueta de clase Recuento de instancias
Manzana 7049
Uvas 7202
Pi帽a 1613
Naranja 15549
Pl谩tano 3536
Sand铆a 1976
  • Los paquetes necesarios de Python incluyen:

    • ultralytics
    • sklearn
    • pandas
    • pyyaml
  • Este tutorial funciona con k=5 pliegues. Sin embargo, debes determinar el mejor n煤mero de pliegues para tu conjunto de datos espec铆fico.

  • Inicia un nuevo entorno virtual Python (venv) para tu proyecto y act铆valo. Utiliza pip (o tu gestor de paquetes preferido) para instalarlo:

    • La biblioteca Ultralytics : pip install -U ultralytics. Alternativamente, puedes clonar el archivo oficial repo.
    • Scikit-learn, pandas y PyYAML: pip install -U scikit-learn pandas pyyaml.
  • Comprueba que tus anotaciones est谩n en el formato de detecci贸nYOLO .

    • Para este tutorial, todos los archivos de anotaci贸n se encuentran en la carpeta Fruit-Detection/labels directorio.

Generaci贸n de vectores de caracter铆sticas para el conjunto de datos de detecci贸n de objetos

  1. Comience por crear un nuevo archivo example.py Python para los pasos a continuaci贸n.

  2. Procede a recuperar todos los archivos de etiquetas de tu conjunto de datos.

    from pathlib import Path
    
    dataset_path = Path("./Fruit-detection")  # replace with 'path/to/dataset' for your custom data
    labels = sorted(dataset_path.rglob("*labels/*.txt"))  # all data in 'labels'
    
  3. Ahora, lee el contenido del archivo YAML del conjunto de datos y extrae los 铆ndices de las etiquetas de clase.

    yaml_file = "path/to/data.yaml"  # your data YAML with data directories and names dictionary
    with open(yaml_file, "r", encoding="utf8") as y:
        classes = yaml.safe_load(y)["names"]
    cls_idx = sorted(classes.keys())
    
  4. Inicializa una casilla vac铆a pandas Marco de datos.

    import pandas as pd
    
    indx = [l.stem for l in labels]  # uses base filename as ID (no extension)
    labels_df = pd.DataFrame([], columns=cls_idx, index=indx)
    
  5. Cuenta las instancias de cada clase-etiqueta presentes en los archivos de anotaci贸n.

    from collections import Counter
    
    for label in labels:
        lbl_counter = Counter()
    
        with open(label, "r") as lf:
            lines = lf.readlines()
    
        for l in lines:
            # classes for YOLO label uses integer at first position of each line
            lbl_counter[int(l.split(" ")[0])] += 1
    
        labels_df.loc[label.stem] = lbl_counter
    
    labels_df = labels_df.fillna(0.0)  # replace `nan` values with `0.0`
    
  6. A continuaci贸n se muestra una vista de ejemplo del Marco de Datos rellenado:

                                                           0    1    2    3    4    5
    '0000a16e4b057580_jpg.rf.00ab48988370f64f5ca8ea4...'  0.0  0.0  0.0  0.0  0.0  7.0
    '0000a16e4b057580_jpg.rf.7e6dce029fb67f01eb19aa7...'  0.0  0.0  0.0  0.0  0.0  7.0
    '0000a16e4b057580_jpg.rf.bc4d31cdcbe229dd022957a...'  0.0  0.0  0.0  0.0  0.0  7.0
    '00020ebf74c4881c_jpg.rf.508192a0a97aa6c4a3b6882...'  0.0  0.0  0.0  1.0  0.0  0.0
    '00020ebf74c4881c_jpg.rf.5af192a2254c8ecc4188a25...'  0.0  0.0  0.0  1.0  0.0  0.0
     ...                                                  ...  ...  ...  ...  ...  ...
    'ff4cd45896de38be_jpg.rf.c4b5e967ca10c7ced3b9e97...'  0.0  0.0  0.0  0.0  0.0  2.0
    'ff4cd45896de38be_jpg.rf.ea4c1d37d2884b3e3cbce08...'  0.0  0.0  0.0  0.0  0.0  2.0
    'ff5fd9c3c624b7dc_jpg.rf.bb519feaa36fc4bf630a033...'  1.0  0.0  0.0  0.0  0.0  0.0
    'ff5fd9c3c624b7dc_jpg.rf.f0751c9c3aa4519ea3c9d6a...'  1.0  0.0  0.0  0.0  0.0  0.0
    'fffe28b31f2a70d4_jpg.rf.7ea16bd637ba0711c53b540...'  0.0  6.0  0.0  0.0  0.0  0.0
    

Las filas indexan los archivos de etiquetas, cada uno de los cuales corresponde a una imagen de tu conjunto de datos, y las columnas corresponden a tus 铆ndices de etiquetas de clase. Cada fila representa un pseudovector de caracter铆sticas, con el recuento de cada etiqueta de clase presente en tu conjunto de datos. Esta estructura de datos permite aplicar la Validaci贸n Cruzada K-Fold a un conjunto de datos de detecci贸n de objetos.

Dividir el conjunto de datos K-Fold

  1. Ahora utilizaremos KFold clase de sklearn.model_selection para generar k divisiones del conjunto de datos.

    • Importante:
      • Configurar shuffle=True garantiza una distribuci贸n aleatoria de las clases en tus divisiones.
      • Estableciendo random_state=M donde M es un n煤mero entero elegido, puedes obtener resultados repetibles.
    from sklearn.model_selection import KFold
    
    ksplit = 5
    kf = KFold(n_splits=ksplit, shuffle=True, random_state=20)  # setting random_state for repeatable results
    
    kfolds = list(kf.split(labels_df))
    
  2. El conjunto de datos se ha dividido en k pliegues, cada uno con una lista de train y val 铆ndices. Construiremos un DataFrame para mostrar estos resultados con mayor claridad.

    folds = [f"split_{n}" for n in range(1, ksplit + 1)]
    folds_df = pd.DataFrame(index=indx, columns=folds)
    
    for idx, (train, val) in enumerate(kfolds, start=1):
        folds_df[f"split_{idx}"].loc[labels_df.iloc[train].index] = "train"
        folds_df[f"split_{idx}"].loc[labels_df.iloc[val].index] = "val"
    
  3. Ahora calcularemos la distribuci贸n de las etiquetas de clase de cada pliegue como proporci贸n de las clases presentes en val a los presentes en train.

    fold_lbl_distrb = pd.DataFrame(index=folds, columns=cls_idx)
    
    for n, (train_indices, val_indices) in enumerate(kfolds, start=1):
        train_totals = labels_df.iloc[train_indices].sum()
        val_totals = labels_df.iloc[val_indices].sum()
    
        # To avoid division by zero, we add a small value (1E-7) to the denominator
        ratio = val_totals / (train_totals + 1e-7)
        fold_lbl_distrb.loc[f"split_{n}"] = ratio
    

    El escenario ideal es que todas las proporciones de clase sean razonablemente similares para cada divisi贸n y entre las clases. Sin embargo, esto depender谩 de las caracter铆sticas espec铆ficas de tu conjunto de datos.

  4. A continuaci贸n, creamos los directorios y los archivos YAML del conjunto de datos para cada divisi贸n.

    import datetime
    
    supported_extensions = [".jpg", ".jpeg", ".png"]
    
    # Initialize an empty list to store image file paths
    images = []
    
    # Loop through supported extensions and gather image files
    for ext in supported_extensions:
        images.extend(sorted((dataset_path / "images").rglob(f"*{ext}")))
    
    # Create the necessary directories and dataset YAML files (unchanged)
    save_path = Path(dataset_path / f"{datetime.date.today().isoformat()}_{ksplit}-Fold_Cross-val")
    save_path.mkdir(parents=True, exist_ok=True)
    ds_yamls = []
    
    for split in folds_df.columns:
        # Create directories
        split_dir = save_path / split
        split_dir.mkdir(parents=True, exist_ok=True)
        (split_dir / "train" / "images").mkdir(parents=True, exist_ok=True)
        (split_dir / "train" / "labels").mkdir(parents=True, exist_ok=True)
        (split_dir / "val" / "images").mkdir(parents=True, exist_ok=True)
        (split_dir / "val" / "labels").mkdir(parents=True, exist_ok=True)
    
        # Create dataset YAML files
        dataset_yaml = split_dir / f"{split}_dataset.yaml"
        ds_yamls.append(dataset_yaml)
    
        with open(dataset_yaml, "w") as ds_y:
            yaml.safe_dump(
                {
                    "path": split_dir.as_posix(),
                    "train": "train",
                    "val": "val",
                    "names": classes,
                },
                ds_y,
            )
    
  5. Por 煤ltimo, copia las im谩genes y las etiquetas en el directorio respectivo ("tren" o "val") para cada divisi贸n.

    • NOTA: El tiempo necesario para esta parte del c贸digo variar谩 en funci贸n del tama帽o de tu conjunto de datos y del hardware de tu sistema.
    import shutil
    
    for image, label in zip(images, labels):
        for split, k_split in folds_df.loc[image.stem].items():
            # Destination directory
            img_to_path = save_path / split / k_split / "images"
            lbl_to_path = save_path / split / k_split / "labels"
    
            # Copy image and label files to new directory (SamefileError if file already exists)
            shutil.copy(image, img_to_path / image.name)
            shutil.copy(label, lbl_to_path / label.name)
    

Guardar registros (Opcional)

Opcionalmente, puedes guardar los registros de los DataFrames de divisi贸n K-Fold y distribuci贸n de etiquetas como archivos CSV para futuras consultas.

folds_df.to_csv(save_path / "kfold_datasplit.csv")
fold_lbl_distrb.to_csv(save_path / "kfold_label_distribution.csv")

Entrena YOLO utilizando K-Divisiones de Datos

  1. Primero, carga el modelo YOLO .

    from ultralytics import YOLO
    
    weights_path = "path/to/weights.pt"
    model = YOLO(weights_path, task="detect")
    
  2. A continuaci贸n, itera sobre los archivos YAML del conjunto de datos para ejecutar el entrenamiento. Los resultados se guardar谩n en un directorio especificado por la opci贸n project y name argumentos. Por defecto, este directorio es 'exp/runs#', donde # es un 铆ndice entero.

    results = {}
    
    # Define your additional arguments here
    batch = 16
    project = "kfold_demo"
    epochs = 100
    
    for k in range(ksplit):
        dataset_yaml = ds_yamls[k]
        model.train(data=dataset_yaml, epochs=epochs, batch=batch, project=project)  # include any train arguments
        results[k] = model.metrics  # save output metrics for further analysis
    

Conclusi贸n

En esta gu铆a, hemos explorado el proceso de utilizar la validaci贸n cruzada de K pliegues para entrenar el modelo de detecci贸n de objetos YOLO . Hemos aprendido a dividir nuestro conjunto de datos en K particiones, garantizando una distribuci贸n de clases equilibrada en los distintos pliegues.

Tambi茅n exploramos el procedimiento de creaci贸n de DataFrames de informes para visualizar las divisiones de datos y las distribuciones de etiquetas en dichas divisiones, lo que nos proporcion贸 una visi贸n clara de la estructura de nuestros conjuntos de entrenamiento y validaci贸n.

Opcionalmente, guardamos nuestros registros para futuras consultas, lo que podr铆a ser especialmente 煤til en proyectos a gran escala o al solucionar problemas de rendimiento del modelo.

Por 煤ltimo, implementamos el entrenamiento real del modelo utilizando cada divisi贸n en un bucle, guardando nuestros resultados de entrenamiento para su posterior an谩lisis y comparaci贸n.

Esta t茅cnica de validaci贸n cruzada K-Fold es una forma s贸lida de aprovechar al m谩ximo los datos disponibles, y ayuda a garantizar que el rendimiento de tu modelo es fiable y coherente en diferentes subconjuntos de datos. El resultado es un modelo m谩s generalizable y fiable, con menos probabilidades de sobreajustarse a patrones de datos espec铆ficos.

Recuerda que, aunque en esta gu铆a hemos utilizado YOLO , estos pasos son en su mayor铆a transferibles a otros modelos de aprendizaje autom谩tico. Comprender estos pasos te permitir谩 aplicar eficazmente la validaci贸n cruzada en tus propios proyectos de aprendizaje autom谩tico. 隆Feliz programaci贸n!

PREGUNTAS FRECUENTES

驴Qu茅 es la Validaci贸n Cruzada K-Fold y por qu茅 es 煤til en la detecci贸n de objetos?

La validaci贸n cruzada por K pliegues es una t茅cnica en la que el conjunto de datos se divide en "k" subconjuntos (pliegues) para evaluar el rendimiento del modelo de forma m谩s fiable. Cada pliegue sirve como datos de entrenamiento y de validaci贸n. En el contexto de la detecci贸n de objetos, utilizar la Validaci贸n Cruzada K-Fold ayuda a garantizar que el rendimiento de tu modelo Ultralytics YOLO es robusto y generalizable a trav茅s de diferentes divisiones de datos, mejorando su fiabilidad. Para obtener instrucciones detalladas sobre la configuraci贸n de la Validaci贸n Cruzada K-Fold con Ultralytics YOLO , consulta Validaci贸n Cruzada K-Fold con Ultralytics.

驴C贸mo aplico la validaci贸n cruzada K-Fold utilizando Ultralytics YOLO ?

Para aplicar la Validaci贸n Cruzada K-Fold con Ultralytics YOLO , tienes que seguir estos pasos:

  1. Comprueba que las anotaciones est谩n en el formato de detecci贸nYOLO .
  2. Utiliza bibliotecas Python como sklearn, pandasy pyyaml.
  3. Crea vectores de caracter铆sticas a partir de tu conjunto de datos.
  4. Divide tu conjunto de datos utilizando KFold de sklearn.model_selection.
  5. Entrena el modelo YOLO en cada divisi贸n.

Para obtener una gu铆a completa, consulta la secci贸n Dividir conjuntos de datos K-Fold de nuestra documentaci贸n.

驴Por qu茅 deber铆a utilizar Ultralytics YOLO para la detecci贸n de objetos?

Ultralytics YOLO ofrece detecci贸n de objetos en tiempo real de 煤ltima generaci贸n, con gran precisi贸n y eficacia. Es vers谩til y admite m煤ltiples tareas de visi贸n por ordenador, como la detecci贸n, la segmentaci贸n y la clasificaci贸n. Adem谩s, se integra perfectamente con herramientas como Ultralytics HUB para el entrenamiento y despliegue de modelos sin c贸digo. Para m谩s detalles, explora las ventajas y caracter铆sticas en nuestra p谩ginaUltralytics YOLO .

驴C贸mo puedo asegurarme de que mis anotaciones tienen el formato correcto para Ultralytics YOLO ?

Tus anotaciones deben seguir el formato de detecci贸n YOLO . Cada archivo de anotaci贸n debe enumerar la clase de objeto, junto con las coordenadas de su cuadro delimitador en la imagen. El formato YOLO garantiza un procesamiento de datos racionalizado y estandarizado para el entrenamiento de modelos de detecci贸n de objetos. Para m谩s informaci贸n sobre el formato adecuado de las anotaciones, visita la gu铆a del formato de detecci贸nYOLO .

驴Puedo utilizar la Validaci贸n Cruzada K-Fold con conjuntos de datos personalizados distintos de la Detecci贸n de Frutas?

S铆, puedes utilizar la Validaci贸n Cruzada K-Fold con cualquier conjunto de datos personalizado, siempre que las anotaciones est茅n en el formato de detecci贸n YOLO . Sustituye las rutas del conjunto de datos y las etiquetas de clase por las espec铆ficas de tu conjunto de datos personalizado. Esta flexibilidad garantiza que cualquier proyecto de detecci贸n de objetos pueda beneficiarse de una s贸lida evaluaci贸n del modelo mediante la Validaci贸n Cruzada K-Fold. Para ver un ejemplo pr谩ctico, consulta nuestra secci贸n Generaci贸n de vectores de caracter铆sticas.



Creado 2023-11-12, Actualizado 2024-07-05
Autores: glenn-jocher (10), IvorZhu331 (1), Burhan-Q (1)

Comentarios