YOLO Vision 2026:

Validação Cruzada K-Fold com Ultralytics#

Introdução#

Este guia abrangente ilustra a implementação da validação cruzada K-Fold para conjuntos de dados de detecção de objetos dentro do ecossistema Ultralytics. Vamos aproveitar o formato de detecção YOLO e bibliotecas Python essenciais, como sklearn, pandas e PyYAML, para guiar-te pela configuração necessária, pelo processo de geração de vetores de características e pela execução de uma divisão de conjunto de dados K-Fold.

K-fold cross validation data splitting

Quer o teu projeto envolva o conjunto de dados Fruit Detection ou uma fonte de dados personalizada, este tutorial visa ajudar-te a compreender e aplicar a Validação Cruzada K-Fold para reforçar a fiabilidade e robustez dos teus modelos de machine learning. Embora estejamos a aplicar k=5 folds para este tutorial, tem em mente que o número ideal de folds pode variar dependendo do teu conjunto de dados e das especificidades do teu projeto. A Validação Cruzada K-Fold oferece o máximo valor quando o teu conjunto de dados é pequeno, ruidoso ou altamente variável; para conjuntos de dados grandes e diversos, uma divisão de treino/validação/teste bem construída é normalmente suficiente.

Vamos começar.

Configuração#

  • As tuas anotações devem estar no formato de detecção YOLO.

  • Este guia assume que os arquivos de anotação estão disponíveis localmente.

  • Para a nossa demonstração, utilizamos o conjunto de dados Fruit Detection.

    • Este conjunto de dados contém um total de 8479 imagens.
    • Inclui 6 rótulos de classe, cada um com suas contagens totais de instâncias listadas abaixo.
Rótulo de ClasseContagem de Instâncias
Apple7049
Grapes7202
Pineapple1613
Orange15549
Banana3536
Watermelon1976
  • Os pacotes Python necessários incluem:

    • ultralytics
    • sklearn
    • pandas
    • pyyaml
  • Este tutorial funciona com k=5 folds. No entanto, deves determinar o melhor número de folds para o teu conjunto de dados específico.

  1. Inicia um novo ambiente virtual Python (venv) para o teu projeto e ativa-o. Usa pip (ou o teu gestor de pacotes preferido) para instalar:

    • A biblioteca Ultralytics: pip install -U ultralytics. Em alternativa, podes clonar o repositório oficial.
    • Scikit-learn, pandas e PyYAML: pip install -U scikit-learn pandas pyyaml.
  2. Verifica se as tuas anotações estão no formato de detecção YOLO.

    • Para este tutorial, todos os ficheiros de anotação encontram-se no diretório Fruit-Detection/labels.

Gerando Vetores de Características para o Conjunto de Dados de Detecção de Objetos#

  1. Começa por criar um novo ficheiro Python example.py para os passos abaixo.

  2. Carrega as imagens de treino e validação configuradas através do proprietário do dataset do pacote, deixando a divisão de teste intacta.

    from pathlib import Path
    
    from ultralytics.data.dataset import YOLODataset
    from ultralytics.data.utils import check_det_dataset
    
    yaml_file = "path/to/data.yaml"
    data = check_det_dataset(yaml_file)
    dataset_path = Path(data["path"])
    sources = []
    for split in ("train", "val"):
        source = data.get(split)
        if source:
            sources.extend(source if isinstance(source, list) else [source])
    dataset = YOLODataset(sources, data=data, augment=False)
    images = [Path(p) for p in dataset.im_files]
  3. Agora, leia o conteúdo do arquivo YAML do conjunto de dados e extraia os índices dos rótulos de classe.

    classes = data["names"]
    cls_idx = sorted(classes.keys())
  4. Inicializa um DataFrame pandas vazio.

    import pandas as pd
    
    labels_df = pd.DataFrame(0.0, columns=cls_idx, index=images)
  5. Conte as instâncias de cada rótulo de classe presente nos arquivos de anotação.

    from collections import Counter
    
    for image, label in zip(images, dataset.labels):
        lbl_counter = Counter(label["cls"].flatten().astype(int))
        labels_df.loc[image, list(lbl_counter)] = list(lbl_counter.values())
  6. A seguir, uma visualização de amostra do DataFrame populado:

                                                           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

As linhas usam caminhos de imagem absolutos e as colunas correspondem aos índices das classes. Rótulos em falta permanecem como linhas de fundo preenchidas com zeros. Esta estrutura de dados permite a aplicação de K-Fold Cross Validation a um dataset de deteção de objetos.

Divisão de Conjunto de Dados K-Fold#

  1. Agora vamos usar a classe KFold de sklearn.model_selection para gerar k divisões do conjunto de dados.

    • Importante:
      • Definir shuffle=True garante uma distribuição aleatória das classes nas tuas divisões.
      • Ao definir random_state=M, onde M é um número inteiro escolhido, podes obter resultados repetíveis.
    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. O conjunto de dados foi agora dividido em k folds, cada um com uma lista de índices train e val. Vamos construir um DataFrame para exibir estes resultados de forma mais clara.

    folds = [f"split_{n}" for n in range(1, ksplit + 1)]
    folds_df = pd.DataFrame(index=labels_df.index, columns=folds)
    
    for i, (train, val) in enumerate(kfolds, start=1):
        folds_df.loc[labels_df.index[train], f"split_{i}"] = "train"
        folds_df.loc[labels_df.index[val], f"split_{i}"] = "val"
  3. Agora vamos calcular a distribuição dos rótulos de classe para cada fold como um rácio entre as classes presentes em val e as presentes em 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

    O cenário ideal é que todas as proporções de classe sejam razoavelmente semelhantes para cada divisão e entre as classes. Isso, no entanto, estará sujeito às especificidades do seu conjunto de dados.

  4. Escreve listas de imagens e um YAML de dataset para cada divisão. As listas de texto evitam copiar o dataset k vezes.

    import yaml
    
    save_path = dataset_path.parent / f"{ksplit}-Fold_Cross-val"
    save_path.mkdir(parents=True, exist_ok=True)
    ds_yamls = []
    
    for split in folds_df.columns:
        for partition in ("train", "val"):
            split_images = folds_df.index[folds_df[split] == partition]
            paths = "\n".join(map(str, split_images))
            (save_path / f"{split}_{partition}.txt").write_text(f"{paths}\n")
    
        dataset_yaml = save_path / f"{split}.yaml"
        ds_yamls.append(dataset_yaml)
        with open(dataset_yaml, "w") as ds_y:
            yaml.safe_dump(
                {
                    "path": save_path.as_posix(),
                    "train": f"{split}_train.txt",
                    "val": f"{split}_val.txt",
                    "names": classes,
                },
                ds_y,
            )

Salvar Registros (Opcional)#

Opcionalmente, você pode salvar os registros dos DataFrames de divisão K-Fold e distribuição de rótulos como arquivos CSV para referência futura.

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

Treinar YOLO usando Divisões de Dados K-Fold#

  1. Primeiro, carregue o modelo YOLO.

    from ultralytics import YOLO
    
    weights_path = "path/to/weights.pt"  # use yolo26n.pt for a small model
    model = YOLO(weights_path, task="detect")
  2. Em seguida, faz um ciclo pelos ficheiros YAML do conjunto de dados para executar o treino. Os resultados serão guardados num diretório especificado pelos argumentos project e name. Por predefinição, este diretório é 'runs/detect/train#', onde # é um índice inteiro.

    results = {}
    
    # Define your additional arguments here
    batch = 16
    project = "kfold_demo"
    epochs = 100
    
    for k, dataset_yaml in enumerate(ds_yamls):
        model = YOLO(weights_path, task="detect")
        results[k] = model.train(
            data=dataset_yaml, epochs=epochs, batch=batch, project=project, name=f"fold_{k + 1}"
        )  # include any additional train arguments
  3. Também podes usar a função Ultralytics data.split.autosplit para a divisão automática do conjunto de dados:

    from ultralytics.data.split import autosplit
    
    # Automatically split dataset into train/val/test
    autosplit(path="path/to/images", weights=(0.8, 0.2, 0.0), annotated_only=True)

Conclusão#

Neste guia, explorámos o processo de utilização de validação cruzada K-Fold para treinar o modelo de deteção de objetos YOLO. Aprendemos como dividir o conjunto de treino e validação em K partições e usar a tabela de rácios gerada para inspecionar o equilíbrio de classes após a divisão aleatória.

Também exploramos o procedimento para criar DataFrames de relatório para visualizar as divisões de dados e distribuições de rótulos entre essas divisões, fornecendo uma visão clara da estrutura de nossos conjuntos de treinamento e validação.

Opcionalmente, salvamos nossos registros para referência futura, o que pode ser particularmente útil em projetos de grande escala ou ao solucionar o desempenho do modelo.

Finalmente, implementamos o treinamento real do modelo usando cada divisão em um loop, salvando nossos resultados de treinamento para análise e comparação posteriores.

Esta técnica de validação cruzada K-Fold é uma forma robusta de tirar o máximo partido dos teus dados disponíveis e ajuda a garantir que o desempenho do teu modelo é fiável e consistente em diferentes subconjuntos de dados. Isto resulta num modelo mais generalizável e fiável, com menor probabilidade de sobreajuste a padrões de dados específicos.

Lembre-se de que, embora tenhamos usado YOLO neste guia, esses passos são, em sua maioria, transferíveis para outros modelos de machine learning. Entender esses passos permite que você aplique a validação cruzada de forma eficaz em seus próprios projetos de machine learning.

FAQ#

  • A validação cruzada K-Fold é uma técnica em que o conjunto de dados é dividido em 'k' subconjuntos (folds) para avaliar o desempenho do modelo de forma mais fiável. Cada fold serve simultaneamente como dados de treino e dados de validação. No contexto da detecção de objetos, utilizar a validação cruzada K-Fold ajuda a garantir que o desempenho do teu modelo Ultralytics YOLO é robusto e generalizável em diferentes divisões de dados, melhorando a sua fiabilidade. Para instruções detalhadas sobre como configurar a validação cruzada K-Fold com o Ultralytics YOLO, consulta Validação cruzada K-Fold com o Ultralytics.

  • Para implementar a Validação Cruzada K-Fold com Ultralytics YOLO, você precisa seguir estes passos:

    1. Verifica se as anotações estão no formato de detecção YOLO.
    2. Usa bibliotecas Python como sklearn, pandas e pyyaml.
    3. Crie vetores de características a partir do seu conjunto de dados.
    4. Divide o teu conjunto de dados utilizando KFold de sklearn.model_selection.
    5. Treine o modelo YOLO em cada divisão.

    Para um guia abrangente, consulta a secção Divisão do conjunto de dados K-Fold na nossa documentação.

  • O fluxo de trabalho neste guia foca-se no formato de deteção YOLO, mas a mesma abordagem adapta-se a todas as tarefas de YOLO — a tarefa altera a forma como assumes a composição dos folds, e não se a validação cruzada ajuda:

    TarefaDesign dos folds
    detectDivide ao nível da imagem, equilibrando as distribuições de objetos e classes entre os folds. Mantém imagens relacionadas (o mesmo paciente, sequência de vídeo, câmara ou local) dentro de um único fold.
    segmentUsa a mesma estratégia ao nível da imagem que na deteção, preservando adicionalmente a cobertura de máscaras e classes em cada fold.
    classifyPrefere folds estratificados para que as frequências das classes se mantenham equilibradas entre o treino e a validação.
    poseDivide por sujeito ou sequência para que a mesma pessoa ou animal nunca apareça em ambos os lados de um fold.
    obbDivide ao nível da imagem, mantendo tiles ou recortes da mesma cena juntos — especialmente importante para imagens aéreas.

    Qualquer que seja a tarefa, mantém amostras quase duplicadas e relacionadas fora de folds opostos: esse tipo de fuga de dados inflaciona as métricas de validação muito além do que o modelo alcançará em produção.

  • O Ultralytics YOLO oferece detecção de objetos em tempo real de última geração com alta precisão e eficiência. É versátil, suportando múltiplas tarefas de visão computacional, tais como detecção, segmentação de instâncias, segmentação semântica e classificação. Além disso, integra-se perfeitamente com ferramentas como a Ultralytics Platform para treino e implementação de modelos sem código. Para mais detalhes, explora os benefícios e funcionalidades na nossa página do Ultralytics YOLO.

  • As tuas anotações devem seguir o formato de detecção YOLO. Cada ficheiro de anotação deve listar a classe do objeto, juntamente com as suas coordenadas de caixa delimitadora na imagem. O formato YOLO garante um processamento de dados otimizado e estandardizado para treinar modelos de detecção de objetos. Para mais informações sobre a formatação correta de anotações, visita o guia do formato de detecção YOLO.

  • Sim, podes usar a validação cruzada K-Fold com qualquer conjunto de dados personalizado, desde que as anotações estejam no formato de detecção YOLO. Substitui os caminhos do conjunto de dados e os rótulos de classe pelos específicos do teu conjunto de dados personalizado. Esta flexibilidade garante que qualquer projeto de detecção de objetos pode beneficiar de uma avaliação robusta do modelo utilizando a validação cruzada K-Fold. Para um exemplo prático, revê a nossa secção Geração de vetores de características.

Comentários