Существуют множество готовых решений, позволяющих запускать модели «из коробки», и YOLO не исключение. Встроенные механизмы автоматически подбирают параметры обучения модели, что удобно для быстрых экспериментов и прототипов. Но инженерный интерес рано или поздно берёт своё. Хочется попробовать разные версии, разобраться в тонкостях работы модели и понять, почему модель ведёт себя именно так, а не иначе.
С одной стороны, кажется, зачем что-то менять, если уже есть «оптимальное решение»? А с другой исследовательский азарт: «А что, если попробовать так?» или «Почему это работает именно так?».
На практике выясняется, что подбор гиперпараметров задача не такая уж простая. Важно учитывать версии библиотек, совместимость кода и особенности расчёта метрик, которые могут отличаться от релиза к релизу.
В статье я делюсь собственным опытом экспериментов с разными версиями YOLO на личном датасете.
Изначально я планировал сделать эксперимент и по результату написать статью для Хабра, потому что можно получить быструю и честную обратную связь. Но по мере анализа результатов эксперимент неожиданно перерос в полноценную научную работу, которая в итоге будет продаваться за 700 рублей за просмотр и, разумеется, не мне =). Хороший пример того, как из простого интереса иногда вырастает что-то большее.
YOLO (You Only Look Once) - это семейство моделей (обнаружения объектов и сегментации изображений), сочетающих высокую скорость и достойную точность. В моём случае задачей являлось обнаружение компонентов на изображениях печатных плат.
Практика показывает, что, если вы работаете с нестандартным датасетом, небольшим количеством данных или объектами, сложными даже для человека, автоматические настройки оказываются далеко не всегда оптимальными. Кроме того, разные версии YOLO обучаются по-разному и по-разному реагируют на одни и те же параметры. Это не очевидно, пока не попробуешь всё руками.
Эксперимент был построен с целью систематического сравнения влияния гиперпараметров (optimizer, batch size, epoch) на метрики качества (mAP50, mAP50-95, Precision, Recall) моделей YOLO разных поколений (YOLOv8, YOLOv10, YOLO11, YOLO12).
Используемый датасет - это расширенная версия набора изображений, описанного ранее в статье Как я собрал и подготовил датасет дефектов печатных плат для обучения моделей YOLO. Он дополнен аугментациями и увеличенным количеством изображений.
Для понимания структуры датасета достаточно посмотреть на распределение объектов по классам (Рисунок 1. Распределение объектов всего датасета).
Это не «идеальный» синтетический датасет, а данные с реальным распределением, шумом и перекосами.
Эксперимент проводился на Python 3.13.7 с использованием ultralytics 8.3.229 и PyTorch 2.8.0+cu128, на NVIDIA GeForce RTX 5090 с включённой AMP (Automatic Mixed Precision), что позволило ускорить процесс и снизить потребление видеопамяти. Благо малый размер модели позволял разместить на 1 GPU и лишал меня проблем с тензорным параллелизмом в случае обучения на 2 GPU.
В эксперименте варьировались архитектуры моделей: yolov8s, yolov8s-worldv2*, yolov10s, yolo11s, yolo12s и гиперпараметры обучения:
Optimizer: SGD, Adam, AdamW, RMSProp, NAdam, RAdam, auto**
Batch size: 4, 8, 16
Epochs: 50, 100, 200
* В модели YOLO-World предусмотрена возможность использовать текстовые описания классов. В данном эксперименте я этого не делал, классы задавались стандартными именами без дополнительных промптов. Целью работы было сравнить поведение оптимизаторов и настроек обучения.
**Optimizer со значением auto подразумевает автоматический подбор оптимизатора.
Итого 5х7х3х3=315 эксперимента, общей продолжительностью обучения 69 часов 48 минут.
Для каждого запуска выполнялись шаги:
Инициализация модели.
Обучение с логированием всех процессов.
Валидация и извлечение метрик.
Сохранение весов и результатов в JSON/CSV.
Очистка GPU-памяти (torch.cuda.empty_cache()).
При разработке кода я сознательно не использовал кэширование, чтобы случайно не переиспользовать результаты предыдущих запусков.
Код содержал блок try-except, чтобы ошибка в одном эксперименте не останавливала весь процесс. Параметры и текст ошибки сохранялись, а при повторном запуске уже выполненные конфигурации автоматически пропускались.
На первый взгляд может возникнуть вопрос: «Какой же это эксперимент, если тут просто перебор гиперпараметров?»
Перед экспериментом у меня, как и у многих, были довольно стандартные ожидания:
Чем больше batch size тем быстрее обучение, но хуже метрики.
Больше эпох всегда лучше.
SGD закрывает большинство задач.
Новая версия модели всегда лучше старой.
Именно проверка этих «очевидных» предположений и была основной мотивацией.
Почему я считаю это полноценным экспериментом:
Используется личный размеченный датасет с реальным распределением.
Данные содержат специфику реального мира (имитация печатных плат).
Инженерный подход предполагает натурный эксперимент, а не только теорию.
Грамотная настройка модели важна не только ради высокой метрики. Она экономит нервы и часы отладки. Когда на основном этапе обучения что-то внезапно идёт не так (а это обязательно случится), хочется быть уверенным в принятых решениях и быстро находить слабые места.
Нет ничего хуже, чем безуспешно разглядывать загадочный сбой обучения, не понимая, где может прятаться ошибка.
Результаты обучения сохраняются в файл results.json и summary.csv, но для большей уверенности, а так же для построения определенных графиков этого будет не достаточно, и я брал данные из подкатегорий каждого эксперимента (например, /{путь до папки с экспериментом}/YOLO_Experiment/yolov10s_e200_b16_SGD) из файлов results.csv который содержит промежуточный результаты по эпохам и данные файла args.yaml содержащий параметры обученной модели.
Для наглядности я выделил 3 лучших (TOP), 3 средних (MID) и 3 худших (BOTTOM) результата которые отображены в таблицах в зависимости от метрики. Это компромисс между полнотой и читаемостью особенно для тех, кто хочет быстро понять, «что лучше», и для тех, кто только начинает копаться в гиперпараметрах.
Скрытый текст|
model |
epochs |
batch |
optimizer |
epoch_best |
group |
mAP50-95 |
|
yolo12s.pt |
200 |
8 |
SGD |
125 |
TOP |
0.66863 |
|
yolo12s.pt |
200 |
16 |
auto |
126 |
TOP |
0.66836 |
|
yolo11s.pt |
200 |
16 |
auto |
149 |
TOP |
0.66390 |
|
yolov8s-worldv2.pt |
100 |
8 |
RAdam |
100 |
MID |
0.61476 |
|
yolov8s-worldv2.pt |
200 |
8 |
Adam |
173 |
MID |
0.61433 |
|
yolo11s.pt |
100 |
4 |
RAdam |
88 |
MID |
0.61432 |
|
yolov10s.pt |
50 |
4 |
RMSprop |
1 |
BOTTOM |
0.00000 |
|
yolov8s-worldv2.pt |
50 |
8 |
RMSprop |
1 |
BOTTOM |
0.00000 |
|
yolov8s-worldv2.pt |
200 |
16 |
RMSprop |
1 |
BOTTOM |
0.00000 |
|
model |
epochs |
batch |
optimizer |
epoch_best |
group |
mAP50 |
|
yolov8s.pt |
200 |
8 |
SGD |
196 |
TOP |
0.92137 |
|
yolo12s.pt |
200 |
8 |
SGD |
125 |
TOP |
0.92099 |
|
yolo12s.pt |
200 |
16 |
auto |
126 |
TOP |
0.92064 |
|
yolo11s.pt |
100 |
16 |
Adam |
97 |
MID |
0.88909 |
|
yolov10s.pt |
200 |
8 |
NAdam |
185 |
MID |
0.88860 |
|
yolov8s-worldv2.pt |
100 |
16 |
Adam |
100 |
MID |
0.88847 |
|
yolov8s-worldv2.pt |
50 |
16 |
RMSprop |
1 |
BOTTOM |
0.00000 |
|
yolov8s-worldv2.pt |
50 |
8 |
RMSprop |
1 |
BOTTOM |
0.00000 |
|
yolov8s-worldv2.pt |
100 |
16 |
RMSprop |
1 |
BOTTOM |
0.00000 |
|
model |
epochs |
batch |
optimizer |
epoch_best |
group |
Precision |
|
yolo12s.pt |
100 |
16 |
SGD |
90 |
TOP |
0.94162 |
|
yolov8s.pt |
200 |
16 |
SGD |
199 |
TOP |
0.94119 |
|
yolov8s.pt |
200 |
8 |
SGD |
196 |
TOP |
0.93878 |
|
yolov8s-worldv2.pt |
200 |
4 |
NAdam |
183 |
MID |
0.89457 |
|
yolo11s.pt |
100 |
16 |
NAdam |
83 |
MID |
0.89456 |
|
yolo12s.pt |
100 |
16 |
Adam |
98 |
MID |
0.89415 |
|
yolov8s-worldv2.pt |
50 |
16 |
RMSprop |
1 |
BOTTOM |
0.00000 |
|
yolov8s-worldv2.pt |
50 |
8 |
RMSprop |
1 |
BOTTOM |
0.00000 |
|
yolov8s-worldv2.pt |
200 |
16 |
RMSprop |
1 |
BOTTOM |
0.00000 |
|
model |
epochs |
batch |
optimizer |
epoch_best |
group |
Recall |
|
yolo12s.pt |
100 |
4 |
auto |
67 |
TOP |
0.87137 |
|
yolo12s.pt |
200 |
4 |
SGD |
176 |
TOP |
0.86943 |
|
yolov8s.pt |
200 |
8 |
auto |
136 |
TOP |
0.86862 |
|
yolo12s.pt |
50 |
8 |
RAdam |
50 |
MID |
0.82459 |
|
yolo12s.pt |
200 |
8 |
AdamW |
185 |
MID |
0.82442 |
|
yolo11s.pt |
50 |
4 |
RAdam |
41 |
MID |
0.82429 |
|
yolov8s-worldv2.pt |
200 |
4 |
RMSprop |
1 |
BOTTOM |
0.00000 |
|
yolov8s-worldv2.pt |
50 |
8 |
RMSprop |
1 |
BOTTOM |
0.00000 |
|
yolov8s-worldv2.pt |
200 |
16 |
RMSprop |
1 |
BOTTOM |
0.00000 |
Все варианты сравнивались между собой, и на основе этого был собран набор «победителей» по разным критериям:
|
Criterion |
Model |
Optimizer |
Epochs |
Batch |
epoch_best |
Metric_value |
Train_time_min |
Model_size_MB |
|
mAP50-95 |
yolo12s.pt |
SGD |
200 |
8 |
125 |
0.66863 |
23.94 |
18.09 |
|
mAP50 |
yolov8s.pt |
SGD |
200 |
8 |
196 |
0.92137 |
16.46 |
21.50 |
|
Precision |
yolo12s.pt |
SGD |
100 |
16 |
90 |
0.94162 |
10.15 |
18.07 |
|
Recall |
yolo12s.pt |
auto |
100 |
4 |
67 |
0.87137 |
19.34 |
18.07 |
|
Fastest Training |
yolov8s.pt |
SGD |
50 |
16 |
45 |
3.41 |
3.41 |
21.49 |
|
Smallest Model |
yolov10s.pt |
RAdam |
50 |
4 |
48 |
15.78 |
9.52 |
15.78 |
RMSprop был исключён из финальной таблицы, так как показал наихудшие результаты и нестабильность в процессе обучения
Для понимания поведения моделей одного взгляда на таблицы недостаточно. Куда информативнее графики, но как уместить полученный «зоопарк экспериментов»? Этот вопрос не стоял, и стал очевидный в момент получения результатов обучения.
На графиках проиллюстрировано 3 вида эпох (50, 100, 200) и отчетливо видна незначительная разница в количестве эпох для достижения пика качества на SGD и auto.
SGD и auto стабильно показывают лучшие результаты по mAP50-95. RAdam замыкает тройку победителей. Adam-подобные оптимизаторы более устойчивы, но в среднем уступают. RMSProp показал сильную нестабильность.
Усреднение кривых обучения моделей с разными настройками может быть методологически некорректным, так как скрывает индивидуальную динамику. Разные оптимизаторы, batch size и версии моделей обучаются с разной скоростью и разной стабильностью. Среднее значение скрывает колебания и создаёт «идеализированную» кривую, которой в реальности не существует. Такие графики выглядят красиво, но ломают логику эксперимента.
Да, можно использовать среднее ± стандартное отклонение или доверительные интервалы, которые покажут вариабельность. Но даже такие графики стоит трактовать осторожно.
Нужно строго определиться с методом визуализации. Критически важно, учитывать каждый эксперимент отдельно, без бездумного усреднения. Тем не менее, я дополнительно привёл усреднённые графики - не как источник истины, а как иллюстрацию общей тенденции. При интерпретации таких графиков я опираюсь на полный набор индивидуальных кривых.
Для большинства графиков я использовал mAP50 и mAP50–95. На практике именно они лучше всего показывают, что реально происходит с моделью в процессе обучения.
Precision и Recall сильно зависят от порога IoU (Intersection over Union) при определении true positive. При разных запусках модель может давать немного разные предсказанные bounding boxes, что при фиксированном пороге IoU приводит к скачкам этих метрик. mAP усредняет результаты по разным порогам, поэтому более стабилен.
Нужно задать вопрос, например «Как происходит начало обучения?»
На графике показано, как разные оптимизаторы разгоняют обучение на старте (первые 20 эпох). Видно, что SGD и auto быстрее выходят на рабочие значения mAP и делают это достаточно стабильно. Adam-подобные оптимизаторы стартуют мягче, прирост идёт более плавно. RMSProp, наоборот, показывает высокую нестабильность уже на раннем этапе у части запусков качество практически не растёт. Я думаю, тут и кроется основная ошибка, не подходящий learning rate.
«Какой оптимизатор лучше?»
Здесь сравниваются распределения mAP50-95 для разных оптимизаторов по всем моделям YOLO. Boxplot хорошо показывает медиану и разброс. У SGD и auto медианы выше остальных, а разброс умеренный - это означает, что они чаще дают хороший результат. Adam, AdamW и RAdam в среднем немного уступают, но ведут себя более предсказуемо. RMSProp заметно отстаёт и демонстрирует сильную нестабильность.
«На какой эпохе достигается максимум mAP?»
Этот график показывает, как распределяется эпоха достижения максимума mAP50-95. Это важно для понимания, есть ли смысл обучать модель дольше. В моём случае пик чаще всего достигался в районе 80–120 эпох. Это означает, что для быстрого прототипирования можно ограничиться 100 эпохами, а 200 эпох имеет смысл только при необходимости выжать последние доли процента mAP50-95.
«Как ведёт себя оптимизатор на разных batch?»
На графике видно, как качество меняется при разных сочетаниях оптимизатора и batch size. В целом размер batch size влияет слабее, чем тип оптимизатора. Batch 8 и 16 чаще дают более стабильные результаты, batch size 4 иногда ведёт к большему разбросу. При этом у SGD и auto высокие значения mAP50-95 сохраняются практически на всех размерах batch size.
После аккуратной агрегации результатов можно строить более общие графики.
Выбор оптимизатора системно влияет на результат и этот эффект повторяется на разных моделях YOLO.
На этом графике показан компромисс между качеством модели и временем обучения. Видно, что самые быстрые конфигурации дают заметно более низкий mAP. Лучшие по качеству модели обучаются дольше, но разница во времени между «середняками» и «лидерами» уже не такая большая. Максимальное качество требует больше времени, но экономия времени почти всегда означает потерю mAP.
Результаты оказались полезнее, чем я ожидал. Было проверено ряд интуитивных предположений, которые ставил изначально:
Во-первых, версия YOLO действительно влияет на результат, но не так сильно, как обычно думают. Да, YOLO12s показала лучший абсолютный mAP50–95 (0.6686), однако медианные значения у YOLOv8, YOLO11 и YOLO12 оказались практически одинаковыми. Это значит, что новая версия не гарантирует автоматического прироста качества, без настройки она легко может обучаться нестабильно. В реальности архитектурные отличия уступают по значимости гиперпараметрам обучения. Поэтому стратегия «просто обновиться на новую YOLO» работает далеко не всегда.
Во-вторых, оптимизатор оказался, пожалуй, самым критичным фактором. По средним и медианным значениям mAP50–95 стабильно лидировали auto и SGD. Когда нужна максимальная точность, то разумно начинать с auto или SGD, а если важнее стабильность и предсказуемость, то Adam-семейство (Adam, AdamW и RAdam) безопаснее. А вот RMSProp на моём датасете вёл себя крайне нестабильно (в ряде запусков метрики обнулялись уже в первой эпохе). Скорее всего, это сочетание дефолтных параметров с не подходящим learning rate и структурой данных. Я оставил эти результаты в статье ровно потому, что они хорошо демонстрируют, что выбор оптимизатора способен радикально изменить итог.
В-третьих, влияние batch size оказалось заметно слабее, чем ожидалось. Разница между batch size 4, 8 и 16 по медианным значениям mAP не выглядит принципиальной. Тем не менее, большие batch size (8–16) чаще давали стабильное обучение, а вот batch=4 иногда приводил к большему разбросу. В итоге я пришёл к простому выводу, что размер batch size - это инструмент тонкой настройки, чем рычаг, радикально влияющий на качество.
В-четвёртых, число эпох действительно влияет на качество, но только до определённого момента. Увеличение обучения с 50 до 200 эпох в среднем улучшает результат, и большинство лучших конфигураций действительно обучались долго. При этом пик качества в среднем приходился примерно на 90-ю эпоху. Дальше начинается борьба за десятые доли процента, а риск переобучения только растёт. Поэтому 200 эпох имеют смысл, но лишь при осознанном контроле метрик, а не по принципу «пусть крутится».
Если подытожить, то получится довольно простой итог. Гиперпараметры оказывают на качество не меньший эффект, чем выбор версии YOLO. Оптимизатор - это ключевой элемент. Auto и SGD дают самые высокие результаты, но требуют контроля, маленькие batch size чаще нестабильны, а больше эпох не всегда лучше.
Практический рецепт для похожих задач, выглядит так: YOLOv8 или YOLO12, оптимизатор SGD или auto, batch size 8 или16, число эпох 100 или 150 с обязательным контролем переобучения после примерно 80-й. AdamW или RAdam логично использовать там, где данные шумные или есть сильный дисбаланс классов они ведут себя спокойнее.
По результатам эксперимента я понял, что усреднённые кривые обучения и «магические» графики легко вводят в заблуждение. Чем больше экспериментов и целевых метрик, тем сложнее свести всё к одной аккуратной картинке.
В какой-то момент становится ясно, что смотреть нужно не на отдельные графики, а на всё сразу с разбросами, провалами и странными выбросами.
Именно поэтому даже при наличии AutoML ручной эксперимент по-прежнему остаётся лучшим способом разобраться в поведении модели на своём датасете.
Если модель «не едет», это не всегда значит, что нужно обновляться на новую версию - иногда достаточно изменить оптимизатор. Даже самая новая YOLO может проиграть более старым версиям если обучать её «на автопилоте». А вот аккуратная работа с гиперпараметрами иногда даёт больший прирост, чем смена архитектуры.
Источник


