Validação cruzada K-Fold com Ultralytics#
Introdução#
Este guia completo ilustra a implementação da validação cruzada K-Fold em conjuntos de dados de deteção de objetos no ecossistema Ultralytics. Vamos usar o formato de deteção YOLO e bibliotecas Python importantes, como sklearn, pandas e PyYAML, para orientar-te pela configuração necessária, pelo processo de geração de vetores de características e pela execução de uma divisão K-Fold do conjunto de dados.
Quer o teu projeto envolva o conjunto de dados Fruit Detection ou uma fonte de dados personalizada, este tutorial pretende ajudar-te a compreender e aplicar a validação cruzada K-Fold para reforçar a fiabilidade e a robustez dos teus modelos de aprendizagem automática. Embora usemos k=5 folds neste tutorial, lembra-te de que o número ideal de folds pode variar consoante o teu conjunto de dados e as características específicas do teu projeto. A validação cruzada K-Fold é mais útil quando o conjunto de dados é pequeno, ruidoso ou muito variável; para conjuntos de dados grandes e diversificados, normalmente basta uma divisão train/val/test bem concebida.
Vamos começar.
Configuração#
-
As tuas anotações devem estar no formato de deteção YOLO.
-
Este guia pressupõe que os ficheiros de anotação estão disponíveis localmente.
-
Para a nossa demonstração, usamos o conjunto de dados Fruit Detection.
- Este conjunto de dados contém um total de 8479 imagens.
- Inclui 6 rótulos de classe, cujas contagens totais de instâncias são apresentadas abaixo.
| Rótulo da classe | Contagem de instâncias |
|---|---|
| Maçã | 7049 |
| Uvas | 7202 |
| Ananás | 1613 |
| Laranja | 15549 |
| Banana | 3536 |
| Melancia | 1976 |
-
Os pacotes Python necessários incluem:
ultralyticssklearnpandaspyyaml
-
Este tutorial usa
k=5folds. No entanto, deves determinar o melhor número de folds para o teu conjunto de dados específico.
-
Cria um novo ambiente virtual Python (
venv) para o teu projeto e ativa-o. Usapip(ou o gestor de pacotes da tua preferência) 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:
-
Confirma que as tuas anotações estão no formato de deteção YOLO.
- Neste tutorial, todos os ficheiros de anotação encontram-se no diretório
Fruit-Detection/labels.
- Neste tutorial, todos os ficheiros de anotação encontram-se no diretório
Gerar vetores de características para um conjunto de dados de deteçã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 conjunto de dados 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, lê o conteúdo do ficheiro YAML do conjunto de dados e extrai 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) -
Conta as instâncias de cada classe presente nos ficheiros 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()) -
Segue-se uma amostra da vista 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 usam caminhos absolutos para as imagens, e as colunas correspondem aos índices dos rótulos de classe. Os rótulos em falta permanecem como linhas de fundo compostas apenas por zeros. Esta estrutura de dados permite aplicar a validação cruzada K-Fold a um conjunto de dados de deteção de objetos.
Divisão K-Fold do conjunto de dados#
-
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=McomoM, um número inteiro à tua escolha, podes obter resultados reproduzíveis.
- Definir
from sklearn.model_selection import KFold ksplit = 5 kf = KFold(n_splits=ksplit, shuffle=True, random_state=20) # definir random_state para obter resultados reproduzíveis 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 apresentar estes resultados com mais clareza.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 proporção das classes presentes em
valem relação às 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 as proporções de todas as classes sejam razoavelmente semelhantes em cada divisão e entre classes. No entanto, isso dependerá das características específicas do teu conjunto de dados.
-
Escreve listas de imagens e um ficheiro YAML do conjunto de dados para cada divisão. As listas de texto evitam copiar o conjunto de dados
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, )
Guardar registos (opcional)#
Se quiseres, podes guardar os registos da divisão K-Fold e os DataFrames de distribuição dos rótulos como ficheiros CSV para consulta 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, carrega o modelo YOLO.
from ultralytics import YOLO weights_path = "path/to/weights.pt" # usa yolo26n.pt para um modelo pequeno model = YOLO(weights_path, task="detect") -
Em seguida, percorre os 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, esse diretório é 'runs/detect/train#', em que # é 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 dividir automaticamente o conjunto de dados:
from ultralytics.data.split import autosplit # Dividir automaticamente o conjunto de dados em 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 da validação cruzada K-Fold para treinar o modelo YOLO de deteção de objetos. Aprendemos a dividir o conjunto de treino e validação em K partições e a usar a tabela de proporções gerada para inspecionar o equilíbrio entre classes após a divisão aleatória.
Também explorámos o procedimento para criar DataFrames de relatório que permitem visualizar as divisões dos dados e as distribuições dos rótulos entre essas divisões, dando-nos uma visão clara da estrutura dos conjuntos de treino e validação.
Opcionalmente, guardámos os nossos registos para consulta futura, o que pode ser especialmente útil em projetos de grande escala ou ao investigar problemas de desempenho do modelo.
Por fim, implementámos o treino efetivo do modelo usando cada divisão num ciclo e guardámos os resultados do treino 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 dados disponíveis e ajuda a garantir que o desempenho do modelo é fiável e consistente em diferentes subconjuntos de dados. O resultado é um modelo mais generalizável e fiável, com menor probabilidade de sobreajustar a padrões de dados específicos.
Lembra-te de que, embora tenhamos usado YOLO neste guia, estes passos são, na sua maioria, aplicáveis a outros modelos de aprendizagem automática. Compreender estes passos permite-te aplicar a validação cruzada de forma eficaz nos teus próprios projetos de aprendizagem automática.
Perguntas frequentes#
A validação cruzada K-Fold é uma técnica que divide o conjunto de dados em «k» subconjuntos (folds) para avaliar o desempenho do modelo com maior fiabilidade. Cada fold serve tanto como dados de validação como de treino. No contexto da deteção de objetos, usar a validação cruzada K-Fold ajuda a garantir que o desempenho do teu modelo Ultralytics YOLO é robusto e generalizável entre diferentes divisões dos dados, aumentando a sua fiabilidade. Para obter instruções detalhadas sobre como configurar a validação cruzada K-Fold com Ultralytics YOLO, consulta Validação cruzada K-Fold com Ultralytics.
Para implementar a validação cruzada K-Fold com Ultralytics YOLO, segue estes passos:
- Confirma que as anotações estão no formato de deteção YOLO.
- Usa bibliotecas Python como
sklearn,pandasepyyaml. - Cria vetores de características a partir do teu conjunto de dados.
- Divide o teu conjunto de dados usando
KFolddesklearn.model_selection. - Treina o modelo YOLO em cada divisão.
Para um guia completo, consulta a secção Divisão K-Fold do conjunto de dados na nossa documentação.
O fluxo de trabalho deste guia destina-se ao formato de deteção YOLO, mas a mesma abordagem adapta-se a todas as tarefas YOLO — a tarefa altera a forma como compões os folds, não se a validação cruzada é útil:
Tarefa Conceção dos folds detectDivide ao nível da imagem, equilibrando a distribuição de objetos e classes entre os folds. Mantém imagens relacionadas (do mesmo paciente, sequência de vídeo, câmara ou local) no mesmo fold. segmentUsa a mesma estratégia ao nível da imagem que na deteção, preservando também a cobertura de máscaras e classes em cada fold. classifyPrefere folds estratificados para manter equilibradas as frequências das classes entre treino e validação. poseDivide por indivíduo ou sequência, para que a mesma pessoa ou animal nunca apareça nos dois lados de um fold. obbDivide ao nível da imagem, mantendo juntos os mosaicos ou recortes da mesma cena — algo especialmente importante para imagens aéreas. Independentemente da tarefa, mantém amostras quase duplicadas e relacionadas fora de folds opostos: esse tipo de fuga de dados infla as métricas de validação muito para além do desempenho que o modelo terá em produção.
Ultralytics YOLO oferece deteção de objetos em tempo real de última geração, com elevada precisão e eficiência. É versátil e compatível com várias tarefas de visão computacional, como deteção, segmentação de instâncias, segmentação semântica e classificação. Além disso, integra-se facilmente com ferramentas como a Ultralytics Platform para treinar e implementar modelos sem código. Para mais informações, explora as vantagens e funcionalidades na nossa página Ultralytics YOLO.
As tuas anotações devem seguir o formato de deteção YOLO. Cada ficheiro de anotação deve indicar a classe do objeto e as coordenadas da respetiva caixa delimitadora na imagem. O formato YOLO garante um processamento de dados simplificado e padronizado para treinar modelos de deteção de objetos. Para mais informações sobre a formatação correta das anotações, consulta o guia do formato de deteçã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 deteçã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 permite que qualquer projeto de deteção de objetos beneficie de uma avaliação robusta do modelo com validação cruzada K-Fold. Para um exemplo prático, consulta a secção Gerar vetores de características.