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. Utilizaremos o formato de detecção YOLO e bibliotecas-chave de python, como sklearn, pandas e PyYaml, para guiá-lo através da configuração necessária, o processo de geração de vetores de características e a execução de uma divisão de conjunto de dados K-Fold.

Se o seu projeto envolve o conjunto de dados Fruit Detection ou uma fonte de dados personalizada, este tutorial tem como objetivo ajudá-lo a compreender e aplicar a Validação Cruzada K-Fold para reforçar a confiabilidade e a robustez do seu aprendizado de máquina modelos. Enquanto estamos aplicando k=5 folds para este tutorial, lembre-se de que o número ideal de folds pode variar dependendo do seu conjunto de dados e das especificidades do seu projeto.
Sem mais delongas, vamos mergulhar!
Configuração
Suas 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 nossa demonstração, usamos o conjunto de dados de Detecção de Frutas.
- 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 da Classe | Contagem de Instâncias |
|---|---|
| Apple | 7049 |
| Uvas | 7202 |
| Abacaxi | 1613 |
| Laranja | 15549 |
| Banana | 3536 |
| Melancia | 1976 |
Os pacotes Python necessários incluem:
ultralyticssklearnpandaspyyaml
Este tutorial opera com
k=5folds. No entanto, você deve determinar o melhor número de folds para seu conjunto de dados específico.Iniciar um novo ambiente virtual Python (
venv) para o seu projeto e ative-o. Usepip(ou seu gerenciador de pacotes preferido) para instalar:- A biblioteca Ultralytics:
pip install -U ultralytics. Alternativamente, você pode clonar o repositório. - Scikit-learn, pandas e PyYAML:
pip install -U scikit-learn pandas pyyaml.
- A biblioteca Ultralytics:
Verifique se as suas anotações estão no formato de detecção YOLO.
- Para este tutorial, todos os arquivos de anotação são encontrados no
Fruit-Detection/labelsdiretório.
- Para este tutorial, todos os arquivos de anotação são encontrados no
Gerando Vetores de Características para Conjunto de Dados de Detecção de Objetos
Comece criando um novo
example.pyArquivo Python para os passos abaixo.Prossiga para recuperar todos os arquivos de rótulos para seu conjunto de dados.
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'Agora, leia o conteúdo do arquivo YAML do conjunto de dados e extraia os índices dos rótulos de classe.
import yaml yaml_file = "path/to/data.yaml" # your data YAML with data directories and names dictionary with open(yaml_file, encoding="utf8") as y: classes = yaml.safe_load(y)["names"] cls_idx = sorted(classes.keys())Inicializar um vazio
pandasDataFrame.import pandas as pd index = [label.stem for label in labels] # uses base filename as ID (no extension) labels_df = pd.DataFrame([], columns=cls_idx, index=index)Contar as instâncias de cada rótulo de classe presente nos arquivos de anotação.
from collections import Counter for label in labels: lbl_counter = Counter() with open(label) as lf: lines = lf.readlines() for line in lines: # classes for YOLO label uses integer at first position of each line lbl_counter[int(line.split(" ", 1)[0])] += 1 labels_df.loc[label.stem] = lbl_counter labels_df = labels_df.fillna(0.0) # replace `nan` values with `0.0`A seguir, uma amostra da visualização do DataFrame preenchido:
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 indexam os arquivos de rótulos, cada um correspondendo a uma imagem no seu conjunto de dados, e as colunas correspondem aos seus índices de rótulos de classe. Cada linha representa um pseudo vetor de características, com a contagem de cada rótulo de classe presente no seu conjunto de dados. Esta estrutura de dados permite a aplicação da Validação Cruzada K-Fold a um conjunto de dados de detecção de objetos.
Divisão de Conjunto de Dados K-Fold
Agora vamos usar o
KFoldclasse desklearn.model_selectionpara gerarkdivisões do conjunto de dados.- Importante:
- Configurando
shuffle=Truegarante uma distribuição aleatória de classes nas suas divisões. - Ao definir
random_state=MondeMé um número inteiro escolhido, o que permite obter resultados repetíveis.
- Configurando
import random from sklearn.model_selection import KFold random.seed(0) # for reproducibility ksplit = 5 kf = KFold(n_splits=ksplit, shuffle=True, random_state=20) # setting random_state for repeatable results kfolds = list(kf.split(labels_df))- Importante:
O conjunto de dados foi agora dividido em
kfolds, cada um com uma lista detrainevalíndices. Construiremos um DataFrame para exibir esses resultados de forma mais clara.folds = [f"split_{n}" for n in range(1, ksplit + 1)] folds_df = pd.DataFrame(index=index, columns=folds) for i, (train, val) in enumerate(kfolds, start=1): folds_df[f"split_{i}"].loc[labels_df.iloc[train].index] = "train" folds_df[f"split_{i}"].loc[labels_df.iloc[val].index] = "val"Agora vamos calcular a distribuição dos rótulos de classe para cada dobra como uma proporção das classes presentes em
valàqueles presentes emtrain.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}"] = ratioO cenário ideal é que todas as proporções de classes sejam razoavelmente semelhantes para cada divisão e entre as classes. No entanto, isso estará sujeito às especificidades do seu conjunto de dados.
Em seguida, criamos os diretórios e os arquivos YAML do conjunto de dados para cada divisão.
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 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, )Por fim, copie as imagens e etiquetas para o diretório respectivo ('train' ou 'val') para cada divisão.
- NOTA: O tempo necessário para esta parte do código irá variar com base no tamanho do seu dataset e no hardware do seu sistema.
import shutil from tqdm import tqdm for image, label in tqdm(zip(images, labels), total=len(images), desc="Copying files"): 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)
Salvar Registros (Opcional)
Opcionalmente, você pode salvar os registros da divisão K-Fold e os DataFrames de 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")
Treine o YOLO usando divisões de dados K-Fold
Primeiro, carregue o modelo YOLO.
from ultralytics import YOLO weights_path = "path/to/weights.pt" # use yolo11n.pt for a small model model = YOLO(weights_path, task="detect")Em seguida, itere sobre os arquivos YAML do conjunto de dados para executar o treinamento. Os resultados serão salvos em um diretório especificado pelo
projectenameargumentos. Por padrã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 argumentsPode também usar a função Ultralytics data.utils.autosplit para 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, exploramos o processo de uso da validação cruzada K-Fold para treinar o modelo de detecção de objetos YOLO. Aprendemos como dividir nosso conjunto de dados em K partições, garantindo uma distribuição de classe equilibrada entre as diferentes dobras.
Também exploramos o procedimento para criar DataFrames de relatório para visualizar as divisões de dados e as distribuições de rótulos nessas divisões, fornecendo-nos 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 problemas de 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 adicionais.
Esta técnica de validação cruzada K-Fold é uma forma robusta de aproveitar ao máximo os seus dados disponíveis e ajuda a garantir que o desempenho do seu modelo seja confiável e consistente em diferentes subconjuntos de dados. Isso resulta em um modelo mais generalizável e confiável, que é menos propenso a overfit em padrões de dados específicos.
Lembre-se de que, embora tenhamos usado o YOLO neste guia, estas etapas são, em sua maioria, transferíveis para outros modelos de machine learning. Compreender estas etapas permite-lhe aplicar a validação cruzada de forma eficaz nos seus próprios projetos de machine learning. Boa programação!
FAQ
O que é Validação Cruzada K-Fold e por que ela é útil na detecção de objetos?
A Validação Cruzada K-Fold é uma técnica onde o conjunto de dados é dividido em 'k' subconjuntos (folds) para avaliar o desempenho do modelo de forma mais confiável. Cada fold serve como dados de treinamento e validação. No contexto da detecção de objetos, usar a Validação Cruzada K-Fold ajuda a garantir que o desempenho do seu modelo Ultralytics YOLO seja robusto e generalizável em diferentes divisões de dados, aumentando sua confiabilidade. Para obter instruções detalhadas sobre como configurar a Validação Cruzada K-Fold com Ultralytics YOLO, consulte Validação Cruzada K-Fold com Ultralytics.
Como implementar a validação cruzada K-Fold usando Ultralytics YOLO?
Para implementar a validação cruzada K-Fold com Ultralytics YOLO, você precisa seguir estes passos:
- Verifique se as anotações estão no formato de detecção YOLO.
- Use bibliotecas Python como
sklearn,pandas, epyyaml. - Criar vetores de características a partir do seu conjunto de dados.
- Divida seu conjunto de dados usando
KFolddesklearn.model_selection. - Treine o modelo YOLO em cada divisão.
Para um guia completo, consulte a seção Divisão de Dataset K-Fold em nossa documentação.
Por que devo usar Ultralytics YOLO para detecção de objetos?
O YOLO da Ultralytics 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, como detecção, segmentação e classificação. Além disso, integra-se perfeitamente com ferramentas como o HUB da Ultralytics para treinamento e implantação de modelos sem código. Para mais detalhes, explore os benefícios e recursos em nossa página do YOLO da Ultralytics.
Como posso garantir que minhas anotações estejam no formato correto para Ultralytics YOLO?
Suas anotações devem seguir o formato de detecção YOLO. Cada arquivo de anotação deve listar a classe do objeto, juntamente com as coordenadas de sua caixa delimitadora na imagem. O formato YOLO garante o processamento de dados simplificado e padronizado para treinar modelos de detecção de objetos. Para obter mais informações sobre a formatação correta das anotações, visite o guia de formato de detecção YOLO.
Posso usar Validação Cruzada K-Fold com conjuntos de dados personalizados que não sejam de Detecção de Frutas?
Sim, você pode 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. Substitua os caminhos do conjunto de dados e os rótulos de classe pelos específicos do seu conjunto de dados personalizado. Essa flexibilidade garante que qualquer projeto de detecção de objetos possa se beneficiar da avaliação robusta do modelo usando a Validação Cruzada K-Fold. Para um exemplo prático, revise nossa seção Generating Feature Vectors (Geração de Vetores de Características).