K-Fold Cross Validation с Ultralytics
Введение
Это исчерпывающее руководство иллюстрирует реализацию K-Fold Cross Validation для наборов данных обнаружения объектов в экосистеме Ultralytics. Мы используем формат обнаружения YOLO и ключевые библиотеки Python, такие как sklearn, pandas и PyYaml, чтобы провести тебя через необходимую настройку, процесс генерации векторов признаков и выполнение K-Fold разбиения набора данных.
Независимо от того, задействован ли в твоем проекте набор данных Fruit Detection или пользовательский источник данных, это руководство призвано помочь тебе понять и применить K-Fold Cross Validation для повышения надежности и прочности твоих моделей машинного обучения. Пока мы будем применять k=5
складки для этого руководства, имей в виду, что оптимальное количество складок может меняться в зависимости от набора данных и специфики твоего проекта.
Без лишних слов, давай погрузимся в игру!
Настройка
-
Твои аннотации должны быть в форматеYOLO detection.
-
В этом руководстве предполагается, что файлы аннотаций доступны локально.
-
Для демонстрации мы используем набор данных Fruit Detection.
- Этот набор данных содержит в общей сложности 8479 изображений.
- Он включает в себя 6 меток классов, для каждого из которых общее количество экземпляров указано ниже.
Ярлык класса | Количество экземпляров |
---|---|
Apple | 7049 |
Виноград | 7202 |
Ананас | 1613 |
Оранжевый | 15549 |
Банан | 3536 |
Арбуз | 1976 |
-
Необходимые пакеты Python включают в себя:
ultralytics
sklearn
pandas
pyyaml
-
Этот учебник работает с
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 и импортируй необходимые библиотеки.
-
Приступай к получению всех файлов с метками для твоего набора данных.
-
Теперь прочитай содержимое YAML-файла набора данных и извлеки из него индексы меток классов.
-
Инициализируй пустой
pandas
DataFrame. -
Подсчитай количество экземпляров каждого класса-метки, присутствующих в файлах аннотаций.
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`
-
Ниже приведен пример вида заполненного 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
это выбранное целое число, ты сможешь получить повторяющиеся результаты.
- Настройка
- Важно:
-
Теперь набор данных был разделен на
k
складки, каждая из которых имеет списокtrain
иval
Индексы. Для более наглядного отображения этих результатов мы построим DataFrame. -
Теперь мы вычислим распределение меток классов для каждой складки как отношение классов, присутствующих в
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-файлы наборов данных для каждого сплита.
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)
-
Наконец, скопируй изображения и метки в соответствующую директорию ("train" или "val") для каждого сплита.
- ПРИМЕЧАНИЕ: Время, необходимое для выполнения этой части кода, будет зависеть от размера твоего набора данных и аппаратного обеспечения системы.
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)
Сохраняй записи (необязательно)
По желанию ты можешь сохранить записи K-Fold split и распределения меток DataFrames в виде 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.
-
Далее пройдись итерацией по YAML-файлам набора данных, чтобы запустить обучение. Результаты будут сохранены в директорию, указанную параметром
project
иname
аргументы. По умолчанию эта директория - 'exp/runs#', где # - целочисленный индекс.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
Заключение
В этом руководстве мы рассмотрели процесс использования перекрестной валидации K-Fold для обучения модели обнаружения объектов YOLO. Мы узнали, как разбить наш набор данных на K разделов, обеспечив сбалансированное распределение классов по разным складкам.
Мы также изучили процедуру создания отчета DataFrames для визуализации разбиения данных и распределений меток по этим разбиениям, что дало нам четкое представление о структуре наших обучающих и проверочных наборов.
По желанию мы сохраняли свои записи для дальнейшего использования, что может быть особенно полезно в масштабных проектах или при устранении неполадок в работе модели.
Наконец, мы реализовали фактическое обучение модели, используя каждый сплит в цикле, сохраняя результаты обучения для дальнейшего анализа и сравнения.
Эта техника перекрестной валидации K-Fold - надежный способ извлечь максимум пользы из имеющихся у тебя данных, и она помогает обеспечить надежность и согласованность работы твоей модели в разных подмножествах данных. В результате получается более обобщенная и надежная модель, которая с меньшей вероятностью будет подстраиваться под конкретные шаблоны данных.
Помни, что хотя в этом руководстве мы использовали YOLO, эти шаги в основном можно перенести и на другие модели машинного обучения. Понимание этих шагов позволит тебе эффективно применять кросс-валидацию в своих собственных проектах по машинному обучению. Счастливого кодинга!