K-Fold кросс-валидация с Ultralytics#
Введение#
Это подробное руководство демонстрирует реализацию K-Fold кросс-валидации для наборов данных обнаружения объектов в экосистеме Ultralytics. Мы используем формат обнаружения YOLO и ключевые библиотеки Python, такие как sklearn, pandas и PyYAML, чтобы помочь тебе пройти необходимые этапы настройки, процесса генерации векторов признаков и выполнения разбиения набора данных на фолды.
Независимо от того, включает ли твой проект набор данных Fruit Detection или собственный источник данных, это руководство поможет тебе понять и применить перекрестную проверку методом K-Fold для повышения надежности и устойчивости твоих моделей машинного обучения. Хотя в этом руководстве мы используем k=5 фолдов, помни, что оптимальное количество фолдов может варьироваться в зависимости от твоего набора данных и специфики проекта. Перекрестная проверка методом K-Fold приносит наибольшую пользу, когда твой набор данных мал, зашумлен или сильно вариативен; для больших, разнообразных наборов данных обычно достаточно хорошо составленного разделения на обучающую, валидационную и тестовую выборки.
Давай начнем.
Настройка#
-
Твои аннотации должны быть представлены в формате обнаружения 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.
- В этом уроке все файлы аннотаций находятся в директории
Генерация векторов признаков для набора данных обнаружения объектов#
-
Начни с создания нового файла Python
example.pyдля выполнения шагов ниже. -
Загрузи настроенные изображения для обучения и валидации через владельца датасета в пакете, оставив тестовую выборку нетронутой.
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] -
Теперь прочитай содержимое YAML-файла набора данных и извлеки индексы меток классов.
classes = data["names"] cls_idx = sorted(classes.keys()) -
Инициализируй пустой DataFrame
pandas.import pandas as pd labels_df = pd.DataFrame(0.0, columns=cls_idx, index=images) -
Подсчитай экземпляры каждого класса-метки, присутствующего в файлах аннотаций.
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()) -
Ниже представлен пример заполненного 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-Fold Cross Validation к датасету для обнаружения объектов.
Разбиение набора данных методом K-Fold#
-
Теперь мы используем класс
KFoldизsklearn.model_selection, чтобы сгенерироватьkразбиений набора данных.- Важно:
- Установка
shuffle=Trueобеспечивает рандомизированное распределение классов по твоим фолдам. - Установив значение
random_state=M, гдеM— выбранное целое число, ты сможешь получать воспроизводимые результаты.
- Установка
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)) - Важно:
-
Набор данных теперь разделен на
kфолдов, каждый из которых содержит список индексовtrainиval. Мы создадим DataFrame, чтобы более наглядно отобразить эти результаты.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" -
Теперь мы рассчитаем распределение меток классов для каждого фолда как соотношение классов, присутствующих в
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-файл датасета для каждого разделения. Текстовые списки позволяют избежать копирования датасета
kраз.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, )
Сохранение записей (опционально)#
Опционально ты можешь сохранить записи о разбиении K-Fold и DataFrame распределения меток в виде CSV-файлов для дальнейшего использования.
folds_df.to_csv(save_path / "kfold_datasplit.csv")
fold_lbl_distrb.to_csv(save_path / "kfold_label_distribution.csv")Обучение YOLO с использованием K-Fold разбиений данных#
-
Сначала загрузи модель 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.split.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-Fold для обучения модели обнаружения объектов YOLO. Мы узнали, как разделить пул обучения и валидации на K частей и использовать созданную табличку соотношений для проверки баланса классов после случайного разделения.
Мы также рассмотрели процедуру создания отчетных DataFrame для визуализации разбиений данных и распределения меток по этим разбиениям, что дает нам четкое представление о структуре наших наборов для обучения и валидации.
Опционально мы сохранили наши записи для дальнейшего использования, что может быть особенно полезно в крупномасштабных проектах или при устранении неполадок в работе модели.
Наконец, мы реализовали само обучение модели, используя каждое разбиение в цикле, сохраняя результаты обучения для дальнейшего анализа и сравнения.
Этот метод K-Fold кросс-валидации — надежный способ получить максимум пользы от имеющихся данных и обеспечить стабильность и надежность работы модели на разных подмножествах данных. Это приводит к созданию более универсальной и надежной модели, которая менее склонна к переобучению под конкретные шаблоны данных.
Помни, что, хотя мы использовали YOLO в этом руководстве, эти шаги в основном применимы и к другим моделям машинного обучения. Понимание этих шагов позволит тебе эффективно применять кросс-валидацию в твоих собственных проектах по машинному обучению.
FAQ#
K-Fold кросс-валидация — это метод, при котором набор данных делится на 'k' подмножеств (фолдов) для более надежной оценки производительности модели. Каждый фолд служит одновременно тренировочными данными и данными валидации. В контексте обнаружения объектов использование K-Fold кросс-валидации помогает гарантировать, что производительность твоей модели Ultralytics YOLO является надежной и универсальной для различных разбиений данных, повышая ее стабильность. Подробные инструкции по настройке K-Fold кросс-валидации с помощью Ultralytics YOLO см. в разделе K-Fold кросс-валидация с Ultralytics.
Чтобы реализовать K-Fold кросс-валидацию с Ultralytics YOLO, тебе нужно выполнить следующие шаги:
- Убедись, что аннотации представлены в формате обнаружения YOLO.
- Используй библиотеки Python, такие как
sklearn,pandasиpyyaml. - Создай векторы признаков из твоего набора данных.
- Раздели свой набор данных с помощью
KFoldизsklearn.model_selection. - Обучи модель YOLO на каждом разбиении.
Подробное руководство см. в разделе Разбиение набора данных K-Fold в нашей документации.
Рабочий процесс в этом руководстве ориентирован на формат обнаружения YOLO, но тот же подход применим к любой задаче YOLO — задача меняет то, как ты формируешь фолды, а не то, помогает ли перекрестная проверка:
Задача Проектирование фолдов detectРазделяй на уровне изображений, балансируя распределение объектов и классов по фолдам. Держи связанные изображения (один и тот же пациент, видеопоследовательность, камера или объект) в пределах одного фолда. segmentИспользуй ту же стратегию на уровне изображений, что и для обнаружения, дополнительно сохраняя покрытие масок и классов в каждом фолде. classifyОтдавай предпочтение стратифицированным фолдам, чтобы частоты классов оставались сбалансированными между обучением и валидацией. poseРазделяй по субъекту или последовательности, чтобы один и тот же человек или животное никогда не появлялись по обе стороны фолда. obbРазделяй на уровне изображений, удерживая тайлы или фрагменты из одной сцены вместе — это особенно важно для аэрофотоснимков. Какова бы ни была задача, держи практически дублирующиеся и связанные сэмплы вне противоположных фолдов: такой вид утечки завышает показатели валидации далеко за пределы того, чего модель достигнет в продакшене.
Ultralytics YOLO предлагает передовое обнаружение объектов в реальном времени с высокой точностью и эффективностью. Она универсальна и поддерживает различные задачи компьютерного зрения, такие как обнаружение, сегментация экземпляров, семантическая сегментация и классификация. Кроме того, она легко интегрируется с такими инструментами, как Ultralytics Platform, для обучения и развертывания моделей без кода. Подробнее о преимуществах и функциях читай на нашей странице Ultralytics YOLO.
Твои аннотации должны соответствовать формату обнаружения YOLO. Каждый файл аннотаций должен содержать класс объекта вместе с координатами его ограничивающей рамки на изображении. Формат YOLO обеспечивает упорядоченную и стандартизированную обработку данных для обучения моделей обнаружения объектов. Дополнительную информацию о правильном форматировании аннотаций см. в руководстве по формату обнаружения YOLO.
Да, ты можешь использовать K-Fold кросс-валидацию с любым пользовательским набором данных, если аннотации представлены в формате обнаружения YOLO. Замени пути к набору данных и метки классов на те, которые относятся к твоему пользовательскому набору данных. Эта гибкость гарантирует, что любой проект по обнаружению объектов сможет выиграть от надежной оценки модели с помощью K-Fold кросс-валидации. Практический пример см. в нашем разделе Генерация векторов признаков.