K-voudige kruisvalidatie met Ultralytics
Inleiding
Deze uitgebreide handleiding illustreert de implementatie van K-Fold Cross Validation voor objectdetectie datasets binnen het Ultralytics ecosysteem. We maken gebruik van het YOLO detectieformaat en de belangrijkste Python bibliotheken zoals sklearn, pandas en PyYaml om je door de noodzakelijke instellingen, het proces van het genereren van kenmerkvectoren en de uitvoering van een K-Fold dataset splitsing te leiden.
Of je project nu de Fruit Detection dataset of een aangepaste databron bevat, deze tutorial helpt je bij het begrijpen en toepassen van K-Fold Cross Validation om de betrouwbaarheid en robuustheid van je machine learning modellen te versterken. Terwijl we k=5
Houd er rekening mee dat het optimale aantal vouwen voor deze tutorial kan variëren, afhankelijk van je dataset en de specifieke kenmerken van je project.
Zonder verder oponthoud, laten we erin duiken!
Setup
-
Je annotaties moeten het formaatYOLO detectie hebben.
-
Deze handleiding gaat ervan uit dat annotatiebestanden lokaal beschikbaar zijn.
-
Voor onze demonstratie gebruiken we de Fruit Detection dataset.
- Deze dataset bevat in totaal 8479 afbeeldingen.
- Het bevat 6 klassenlabels, elk met zijn totale aantal instanties hieronder vermeld.
Klasse-etiket | Aantal instanties |
---|---|
Appel | 7049 |
Druiven | 7202 |
Ananas | 1613 |
Oranje | 15549 |
Banaan | 3536 |
Watermeloen | 1976 |
-
Noodzakelijke Python pakketten zijn onder andere:
ultralytics
sklearn
pandas
pyyaml
-
Deze tutorial werkt met
k=5
vouwen. Je moet echter het beste aantal vouwen bepalen voor je specifieke dataset. -
Start een nieuwe Python virtuele omgeving (
venv
) voor je project en activeer het. Gebruikpip
(of de pakketbeheerder van je voorkeur) om te installeren:- De Ultralytics bibliotheek:
pip install -U ultralytics
. Je kunt ook de officiële repo. - Scikit-learn, pandas en PyYAML:
pip install -U scikit-learn pandas pyyaml
.
- De Ultralytics bibliotheek:
-
Controleer of je annotaties het formaatYOLO detectie hebben.
- Voor deze tutorial zijn alle annotatiebestanden te vinden in de
Fruit-Detection/labels
map.
- Voor deze tutorial zijn alle annotatiebestanden te vinden in de
Genereren van objectvectoren voor objectdetectiedataset
-
Begin met het maken van een nieuw Python bestand en importeer de benodigde bibliotheken.
-
Ga verder met het ophalen van alle labelbestanden voor je dataset.
-
Lees nu de inhoud van het YAML-bestand van de dataset en extraheer de indices van de klassenlabels.
-
Een lege
pandas
Dataframe. -
Tel de instanties van elke klasse-label in de annotatiebestanden.
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`
-
Het volgende is een voorbeeldweergave van het bevolkte DataFrame:
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
De rijen indexeren de labelbestanden, die elk corresponderen met een afbeelding in je dataset, en de kolommen corresponderen met je klasse-label indices. Elke rij vertegenwoordigt een pseudo-kenmerkvector, met de telling van elk klasse-label aanwezig in je dataset. Deze gegevensstructuur maakt het mogelijk om K-Fold kruisvalidatie toe te passen op een dataset voor objectdetectie.
K-voudige dataset opsplitsing
-
Nu zullen we de
KFold
klasse vansklearn.model_selection
omk
splitsingen van de dataset.- Belangrijk:
- Instellen
shuffle=True
zorgt voor een willekeurige verdeling van klassen in je splitsingen. - Door
random_state=M
waarbijM
een gekozen geheel getal is, kun je herhaalbare resultaten krijgen.
- Instellen
- Belangrijk:
-
De dataset is nu opgesplitst in
k
vouwen, elk met een lijst vantrain
enval
indexen. We zullen een DataFrame maken om deze resultaten duidelijker weer te geven. -
Nu berekenen we de verdeling van klassenlabels voor elke vouw als een verhouding van de klassen die aanwezig zijn in
val
aan de aanwezigen intrain
.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
Het ideale scenario is dat alle klassenratio's redelijk gelijk zijn voor elke splitsing en tussen klassen. Dit is echter afhankelijk van de specifieke kenmerken van je dataset.
-
Vervolgens maken we de mappen en dataset YAML-bestanden aan voor elke splitsing.
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)
-
Kopieer tenslotte de afbeeldingen en labels naar de respectievelijke map ('train' of 'val') voor elke splitsing.
- OPMERKING: De tijd die nodig is voor dit deel van de code hangt af van de grootte van je dataset en je systeemhardware.
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)
Records opslaan (optioneel)
Optioneel kun je de records van de K-Fold split en label distributie DataFrames opslaan als CSV-bestanden voor toekomstig gebruik.
folds_df.to_csv(save_path / "kfold_datasplit.csv")
fold_lbl_distrb.to_csv(save_path / "kfold_label_distribution.csv")
Train YOLO met behulp van K-voudige gegevenssplitsingen
-
Laad eerst het model YOLO .
-
Doorloop vervolgens de YAML-bestanden van de dataset om de training uit te voeren. De resultaten worden opgeslagen in een map gespecificeerd door de
project
enname
argumenten. Standaard is deze map 'exp/runs#' waarbij # een gehele index is.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
Conclusie
In deze handleiding hebben we het proces onderzocht van het gebruik van K-voudige kruisvalidatie voor het trainen van het YOLO objectdetectiemodel. We hebben geleerd hoe we onze dataset in K partities kunnen verdelen, waarbij we zorgen voor een evenwichtige klassenverdeling over de verschillende vouwen.
We onderzochten ook de procedure voor het maken van rapport DataFrames om de datasplitsingen en labelverdelingen over deze splitsingen te visualiseren, waardoor we een duidelijk inzicht kregen in de structuur van onze trainings- en validatiesets.
Optioneel sloegen we onze records op voor toekomstig gebruik, wat vooral handig kan zijn bij grootschalige projecten of bij het oplossen van problemen met modelprestaties.
Tot slot implementeerden we de eigenlijke modeltraining met elke splitsing in een lus, waarbij we onze trainingsresultaten opsloegen voor verdere analyse en vergelijking.
Deze techniek van K-voudige kruisvalidatie is een robuuste manier om het beste uit je beschikbare gegevens te halen en het helpt om ervoor te zorgen dat de prestaties van je model betrouwbaar en consistent zijn over verschillende subsets van gegevens. Dit resulteert in een meer generaliseerbaar en betrouwbaar model dat minder snel te veel past bij specifieke gegevenspatronen.
Onthoud dat we in deze gids weliswaar YOLO hebben gebruikt, maar dat deze stappen meestal ook toepasbaar zijn op andere modellen voor machinaal leren. Als je deze stappen begrijpt, kun je cross-validation effectief toepassen in je eigen machine learning projecten. Veel plezier met coderen!