K-кратная перекрестная проверка с Ultralytics
Введение
Это подробное руководство иллюстрирует реализацию K-кратной перекрестной проверки для наборов данных обнаружения объектов в экосистеме Ultralytics. Мы будем использовать формат обнаружения YOLO и ключевые библиотеки Python, такие как sklearn, pandas и PyYAML, чтобы провести тебя через необходимую настройку, процесс создания векторов признаков и выполнение K-кратного разбиения набора данных.
Независимо от того, используешь ли ты набор данных Fruit Detection или собственный источник данных, этот учебник поможет тебе понять и применить K-кратную перекрестную проверку для повышения надежности и устойчивости твоих моделей машинного обучения. Хотя в этом уроке мы применяем k=5 фолдов, помни, что оптимальное количество фолдов может варьироваться в зависимости от твоего набора данных и специфики проекта.
Давай приступим.
Настройка
-
Твои аннотации должны быть в формате обнаружения YOLO.
-
В этом руководстве предполагается, что файлы аннотаций доступны локально.
-
Для нашей демонстрации мы используем набор данных Fruit Detection.
- Этот набор данных содержит в общей сложности 8479 изображений.
- Он включает 6 меток классов, общее количество экземпляров для каждой из которых приведено ниже.
| Метка класса | Количество экземпляров |
|---|---|
| Apple | 7049 |
| Grapes | 7202 |
| Pineapple | 1613 |
| Orange | 15549 |
| Banana | 3536 |
| Watermelon | 1976 |
-
Необходимые пакеты Python включают:
ultralyticssklearnpandaspyyaml
-
В этом руководстве мы работаем с
k=5фолдами. Однако тебе следует определить оптимальное количество фолдов для твоего конкретного набора данных.
-
Создай новую виртуальную среду Python (
venv) для своего проекта и активируй её. Используйpip(или твой предпочтительный менеджер пакетов) для установки:- Библиотека Ultralytics:
pip install -U ultralytics. В качестве альтернативы ты можешь клонировать официальный репозиторий. - Scikit-learn, pandas и PyYAML:
pip install -U scikit-learn pandas pyyaml.
- Библиотека Ultralytics:
-
Убедись, что твои аннотации находятся в формате обнаружения YOLO.
- Для этого руководства все файлы аннотаций находятся в каталоге
Fruit-Detection/labels.
- Для этого руководства все файлы аннотаций находятся в каталоге
Создание векторов признаков для набора данных обнаружения объектов
-
Начни с создания нового файла
example.pyна языке Python для выполнения следующих шагов. -
Приступай к получению всех файлов меток для твоего набора данных.
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' -
Теперь прочитай содержимое YAML-файла набора данных и извлеки индексы меток классов.
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()) -
Инициализируй пустой
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) -
Подсчитай экземпляры каждой метки класса, присутствующие в файлах аннотаций.
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` -
Ниже представлен пример вида заполненного 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
Строки индексируют файлы меток, каждый из которых соответствует изображению в твоем наборе данных, а столбцы соответствуют индексам меток твоих классов. Каждая строка представляет собой псевдовектор признаков с количеством каждого класса, присутствующего в твоем наборе данных. Эта структура данных позволяет применять K-кратную перекрестную проверку к набору данных для обнаружения объектов.
K-кратное разбиение набора данных
-
Теперь мы будем использовать класс
KFoldизsklearn.model_selectionдля созданияkразбиений набора данных.- Важно:
- Установка
shuffle=Trueобеспечивает рандомизированное распределение классов в твоих разбиениях. - Установив
random_state=M, гдеM— выбранное целое число, ты сможешь получать воспроизводимые результаты.
- Установка
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)) - Важно:
-
Набор данных теперь разбит на
kфолдов, каждый из которых имеет список индексовtrainиval. Мы создадим DataFrame, чтобы нагляднее отобразить эти результаты.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" -
Теперь мы рассчитаем распределение меток классов для каждого фолда как соотношение классов, присутствующих в
val, к тем, что присутствуют в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Идеальный сценарий — когда все соотношения классов являются достаточно схожими для каждого разбиения и между классами. Однако это будет зависеть от специфики твоего набора данных.
-
Далее мы создаем каталоги и YAML-файлы наборов данных для каждого разбиения.
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, ) -
Наконец, скопируй изображения и метки в соответствующий каталог ('train' или 'val') для каждого разбиения.
- ПРИМЕЧАНИЕ: Время, необходимое для этой части кода, будет варьироваться в зависимости от размера твоего набора данных и аппаратного обеспечения твоей системы.
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)
Сохранение записей (необязательно)
При желании ты можешь сохранить записи K-кратного разбиения и DataFrame распределения меток в виде CSV-файлов для дальнейшего использования.
folds_df.to_csv(save_path / "kfold_datasplit.csv")
fold_lbl_distrb.to_csv(save_path / "kfold_label_distribution.csv")Обучение YOLO с использованием K-кратных разбиений данных
-
Сначала загрузи модель YOLO.
from ultralytics import YOLO weights_path = "path/to/weights.pt" # use yolo26n.pt for a small model model = YOLO(weights_path, task="detect") -
Далее, выполни итерацию по YAML-файлам наборов данных для запуска обучения. Результаты будут сохранены в каталоге, указанном аргументами
projectиname. По умолчанию этот каталог — 'runs/detect/train#', где # — целочисленный индекс.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 -
Ты также можешь использовать функцию Ultralytics data.utils.autosplit для автоматического разбиения набора данных:
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)
Заключение
В этом руководстве мы изучили процесс использования K-кратной перекрестной проверки для обучения модели обнаружения объектов YOLO. Мы узнали, как разбить наш набор данных на K разделов, обеспечивая сбалансированное распределение классов по разным фолдам.
Мы также рассмотрели процедуру создания отчетных DataFrame для визуализации разбиений данных и распределений меток по этим разбиениям, что дает нам четкое представление о структуре наших обучающих и валидационных наборов.
При желании мы сохранили наши записи для дальнейшего использования, что может быть особенно полезно в крупномасштабных проектах или при устранении неполадок производительности модели.
Наконец, мы реализовали фактическое обучение модели, используя каждое разбиение в цикле, сохраняя наши результаты обучения для дальнейшего анализа и сравнения.
Этот метод K-кратной перекрестной проверки — надежный способ максимально эффективно использовать доступные данные, он помогает обеспечить надежность и согласованность работы твоей модели на разных подмножествах данных. Это приводит к созданию более обобщаемой и надежной модели, которая с меньшей вероятностью будет переобучаться под конкретные закономерности данных.
Помни, что, хотя в этом руководстве мы использовали YOLO, эти шаги в основном применимы и к другим моделям машинного обучения. Понимание этих этапов позволит тебе эффективно применять перекрестную проверку в своих собственных проектах машинного обучения.
Часто задаваемые вопросы (FAQ)
Что такое K-кратная перекрестная проверка и почему она полезна при обнаружении объектов?
K-кратная перекрестная проверка — это метод, при котором набор данных делится на 'k' подмножеств (фолдов) для более надежной оценки производительности модели. Каждый фолд служит как обучающими, так и валидационными данными. В контексте обнаружения объектов использование K-кратной перекрестной проверки помогает убедиться, что производительность твоей модели Ultralytics YOLO является устойчивой и обобщаемой на разных разбиениях данных, что повышает её надежность. Подробные инструкции по настройке K-кратной перекрестной проверки с Ultralytics YOLO см. в разделе K-кратная перекрестная проверка с Ultralytics.
Как реализовать K-кратную перекрестную проверку с помощью Ultralytics YOLO?
Чтобы реализовать K-кратную перекрестную проверку с помощью Ultralytics YOLO, тебе необходимо выполнить следующие шаги:
- Убедись, что аннотации находятся в формате обнаружения YOLO.
- Используй библиотеки Python, такие как
sklearn,pandasиpyyaml. - Создай векторы признаков из своего набора данных.
- Разбей свой набор данных, используя
KFoldизsklearn.model_selection. - Обучи модель YOLO на каждом разбиении.
Полное руководство см. в разделе K-кратное разбиение набора данных в нашей документации.
Почему мне следует использовать Ultralytics YOLO для обнаружения объектов?
Ultralytics YOLO предлагает передовое обнаружение объектов в реальном времени с высокой точностью и эффективностью. Это универсальный инструмент, поддерживающий множество задач компьютерного зрения, таких как обнаружение, сегментация и классификация. Кроме того, он легко интегрируется с такими инструментами, как Ultralytics Platform для обучения и развертывания моделей без написания кода. Для получения дополнительной информации изучи преимущества и функции на нашей странице Ultralytics YOLO.
Как я могу убедиться, что мои аннотации имеют правильный формат для Ultralytics YOLO?
Твои аннотации должны соответствовать формату обнаружения YOLO. Каждый файл аннотации должен содержать класс объекта, а также координаты его ограничивающей рамки на изображении. Формат YOLO обеспечивает оптимизированную и стандартизированную обработку данных для обучения моделей обнаружения объектов. Для получения дополнительной информации о правильном форматировании аннотаций посети руководство по формату обнаружения YOLO.
Могу ли я использовать K-кратную перекрестную проверку с пользовательскими наборами данных, отличными от Fruit Detection?
Да, ты можешь использовать K-кратную перекрестную проверку с любым пользовательским набором данных, если аннотации представлены в формате обнаружения YOLO. Замени пути к набору данных и метки классов на те, что соответствуют твоему пользовательскому набору данных. Эта гибкость гарантирует, что любой проект по обнаружению объектов может извлечь выгоду из надежной оценки модели с помощью K-кратной перекрестной проверки. Практический пример можно найти в нашем разделе Создание векторов признаков.