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.
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 Classe | Contagem de Instâncias |
|---|---|
| Apple | 7049 |
| Grapes | 7202 |
| Pineapple | 1613 |
| Orange | 15549 |
| Banana | 3536 |
| Watermelon | 1976 |
-
Os pacotes Python necessários incluem:
ultralyticssklearnpandaspyyaml
-
Este tutorial funciona com
k=5folds. No entanto, deves determinar o melhor número de folds para o teu conjunto de dados específico.
-
Inicia um novo ambiente virtual Python (
venv) para o teu projeto e ativa-o. Usapip(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.
- A biblioteca Ultralytics:
-
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.
- Para este tutorial, todos os ficheiros de anotação encontram-se no diretório
Gerando Vetores de Características para o Conjunto de Dados de Detecção de Objetos#
-
Começa por criar um novo ficheiro Python
example.pypara os passos abaixo. -
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] -
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()) -
Inicializa um DataFrame
pandasvazio.import pandas as pd labels_df = pd.DataFrame(0.0, columns=cls_idx, index=images) -
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()) -
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#
-
Agora vamos usar a classe
KFolddesklearn.model_selectionpara gerarkdivisões do conjunto de dados.- Importante:
- Definir
shuffle=Truegarante uma distribuição aleatória das classes nas tuas divisões. - Ao definir
random_state=M, ondeMé um número inteiro escolhido, podes obter resultados repetíveis.
- Definir
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)) - Importante:
-
O conjunto de dados foi agora dividido em
kfolds, cada um com uma lista de índicestraineval. 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" -
Agora vamos calcular a distribuição dos rótulos de classe para cada fold como um rácio entre as classes presentes em
vale as 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 classe sejam razoavelmente semelhantes para cada divisão e entre as classes. Isso, no entanto, estará sujeito às especificidades do seu conjunto de dados.
-
Escreve listas de imagens e um YAML de dataset para cada divisão. As listas de texto evitam copiar o dataset
kvezes.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#
-
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") -
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
projectename. 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 -
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:
- Verifica se as anotações estão no formato de detecção YOLO.
- Usa bibliotecas Python como
sklearn,pandasepyyaml. - Crie vetores de características a partir do seu conjunto de dados.
- Divide o teu conjunto de dados utilizando
KFolddesklearn.model_selection. - 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:
Tarefa Design 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.