Гиперпараметры
Каждый аргумент обучения — поле датакласса TrainConfig. Базовый класс задаёт само поле и его значение по умолчанию; каждое семейство моделей наследуется от него и переопределяет те значения, которые меняет его опубликованный рецепт.
Задание аргументов
train() принимает именованные аргументы, а CLI — те же имена в форме
key=value.
from libreyolo import LibreYOLO model = LibreYOLO("LibreYOLO9s.pt")results = model.train( data="my-dataset.yaml", epochs=100, batch=16, imgsz=640, lr0=0.01,) print(results["best_mAP50_95"])libreyolo train model=LibreYOLO9s.pt data=my-dataset.yaml \ epochs=100 batch=16 imgsz=640 lr0=0.01Оба пути ведут в одно и то же место. Аргументы передаются в
TrainConfig.from_kwargs(), который собирает датакласс конфигурации семейства.
Опечатка не вызывает ошибку
from_kwargs() отбрасывает любой ключ, которого нет среди полей конфигурации, и
выдаёт UserWarning с его именем. Обучение после этого стартует со значением по
умолчанию:
# UserWarning: Unknown training config keys (ignored): ['learning_rate']
model.train(data="my-dataset.yaml", learning_rate=0.001)Ничего не падает, запуск доходит до конца, а скорость обучения так и не стала той, которую запросил вызывающий код. Читайте предупреждения на первой эпохе нового рецепта. CLI строже, потому что проверяет имена флагов до сборки конфигурации, так что флаг CLI с опечаткой отклоняется сразу.
Значения по умолчанию свои у каждого семейства
TrainConfig задаёт поле и базовое значение по умолчанию. Каждое семейство
наследуется от него и переопределяет то, что меняет его опубликованный рецепт,
поэтому у вопроса «какая скорость обучения по умолчанию» нет одного правильного
ответа.
Базовые значения по умолчанию — optimizer="sgd", lr0=0.01, momentum=0.937,
weight_decay=5e-4, scheduler="yoloxwarmcos", epochs=300, batch=16,
imgsz=640 и amp=True. Три примера того, как далеко семейство от них уходит:
| Поле | База | YOLOv9 | D-FINE | YOLO-NAS |
|---|---|---|---|---|
optimizer | sgd | sgd | adamw | adamw |
lr0 | 0.01 | 0.01 | 2e-4 | 5e-4 |
weight_decay | 5e-4 | 5e-4 | 1e-4 | 1e-5 |
scheduler | yoloxwarmcos | linear | flat_cosine | cos |
epochs | 300 | 300 | 132 | 300 |
amp | True | True | False | False |
D-FINE и DEIM поставляются с amp=False, потому что декодер D-FINE ограничивает
активации значением 65504 — это наибольшее конечное значение float16. У YOLO-NAS
и FOMO он по умолчанию тоже выключен. Флаг --amp в CLI по умолчанию равен
True для каждого семейства, поэтому он считается заданным пользователем и
переопределяет значение семейства; не трогайте его, если не собираетесь его
менять.
Чтобы прочитать настоящие значения по умолчанию семейства, а не гадать:
from dataclasses import fields from libreyolo import LibreYOLO9from libreyolo.training.config import TrainConfig family_cfg = LibreYOLO9.TRAIN_CONFIG()base_cfg = TrainConfig() for f in fields(family_cfg): family_value = getattr(family_cfg, f.name) base_value = getattr(base_cfg, f.name, None) if not hasattr(base_cfg, f.name) or family_value != base_value: print(f"{f.name}: {family_value}")# Печатает значения по умолчанию для train, val и predict, включая переопределения семейств.libreyolo cfgРазмер батча
batch — это глобальный батч. При обучении на нескольких GPU каждый ранг
загружает batch // world_size, поэтому переданное число — это число
изображений на шаг оптимизатора независимо от того, сколько GPU задействовано.
См. Обучение на нескольких GPU.
batch=-1 включает autobatch. Модель прогоняется в режиме обучения с настоящим
обратным проходом на степенях двойки, по кривой потребления памяти строится
прямая, и берётся наибольшая степень двойки строго ниже экстраполированного
значения, которая укладывается в 60 процентов всей VRAM.
from libreyolo import LibreYOLO model = LibreYOLO("LibreYOLO9s.pt") # batch=-1 замеряет память GPU и превращается в конкретную степень двойки.model.train(data="my-dataset.yaml", batch=-1, imgsz=640)libreyolo train model=LibreYOLO9s.pt data=my-dataset.yaml batch=-1Замер именно в режиме обучения и с обратным проходом — это принципиально: замер в режиме инференса не учитывает сохранённые активации и тензоры градиентов, а для глубокой CNN они в несколько раз превышают объём, нужный для инференса. RF-DETR снижает целевую долю до 45 процентов, потому что синтетический обратный проход при замере всё равно недооценивает, во что обходятся его функция потерь и вспомогательные слои декодера.
Autobatch работает только с CUDA. На CPU или MPS он пишет в лог одну строку и оставляет батч по умолчанию.
Накопление градиентов
nbs задаёт номинальный, он же эффективный, размер батча. На один шаг
оптимизатора накапливается round(nbs / batch) микробатчей.
from libreyolo import LibreYOLO model = LibreYOLO("LibreYOLO9s.pt") # 4 микробатча по 16 на шаг оптимизатора, эффективный батч 64.model.train(data="my-dataset.yaml", batch=16, nbs=64)Если оставить None — значение по умолчанию, — накопление выключено и обучение
идёт как обычно.
Скорость обучения и расписание
lr0 — начальная скорость обучения, а optimizer принимает sgd, adam и
adamw. momentum — это момент SGD или beta1 у Adam, weight_decay —
L2-слагаемое, а nesterov относится к SGD.
Форму расписания задают scheduler, warmup_epochs, warmup_lr_start и
min_lr_ratio. no_aug_epochs задаёт, сколько последних эпох идёт без сильной
аугментации, и несколько расписаний используют его ещё и для формы своего
хвоста, так что это не только настройка аугментации. Что каждое семейство делает
с аугментационной половиной этого параметра, описано на странице
Аугментации.
Некоторые семейства добавляют свои настройки скорости обучения.
backbone_lr_mult масштабирует группу бэкбона относительно головы,
clip_max_norm задаёт обрезку градиентов, а SegFormer использует
head_lr_mult, чтобы его декодирующая голова обучалась со скоростью в десять раз
выше, чем у бэкбона. Эти поля живут в подклассе конфигурации семейства, а не в базовом.
EMA
ema=True держит экспоненциальное скользящее среднее весов рядом с обученными.
По умолчанию оно включено везде, кроме FOMO.
ema_decay — целевой коэффициент затухания. Затухание нарастает, а не
начинается сразу с целевого значения: фактическая величина на обновлении n
равна ema_decay * (1 - exp(-n / tau)), где tau по умолчанию 2000, поэтому
ранние обновления точнее следуют за моделью, а поздние её сглаживают. Значения по
умолчанию у семейств идут от 0.997 у YOLO-NAS pose через 0.9998 у YOLOX до
0.9999 у YOLOv9 и линейки DETR.
Валидируются именно веса EMA, и они же лежат в best.pt и last.pt. Исходные
обученные веса тоже сохраняются, под ключом train_model, поэтому возобновление
продолжает обученную траекторию, а не среднее.
Точность вычислений
amp=True выполняет прямой проход под CUDA autocast. amp_dtype выбирает
float16 (по умолчанию) или bfloat16; написания fp16 и bf16 тоже
принимаются.
Float16 нуждается в динамическом масштабировании функции потерь и получает
работающий GradScaler. Bfloat16 с его более широким диапазоном экспоненты в
этом не нуждается, поэтому его scaler создаётся, но остаётся выключенным, а путь
оптимизатора при этом не меняется. Запрос bfloat16 на устройстве с CUDA без поддержки bfloat16 приводит к
ошибке на этапе настройки, а не к тихой деградации.
Вывод, чекпойнты и остановка
Запуски пишутся в project/name. project везде по умолчанию равен
runs/train, а вот name — одно из полей, переопределяемых на уровне
семейства: базовое значение по умолчанию — exp, тогда как YOLOv9 использует
yolo9_exp, а D-FINE — dfine_exp. При exist_ok=False, значении по
умолчанию, к существующему каталогу добавляется числовой суффикс, вместо того
чтобы перезаписать его.
save_period пишет дополнительный weights/epoch_<N>.pt каждые N эпох —
вдобавок к weights/last.pt после каждой эпохи и weights/best.pt всякий раз,
когда отслеживаемая метрика улучшается. eval_interval задаёт, как часто
запускается валидация, а patience останавливает запуск после указанного числа
эпох без улучшения; 0 отключает раннюю остановку.
cache ускоряет повторные эпохи, держа декодированные изображения в RAM (True
или "ram") либо в виде файлов .npy рядом с исходниками ("disk"). Чтение из
кэша побайтово совпадает с обычным. Если работают воркеры загрузчика данных, из
двух вариантов безопаснее "disk".
Возобновление
resume=True продолжает прерванный запуск. Чекпойнт нужно загрузить заранее,
потому что resume берёт его из модели, а не из отдельного аргумента.
from libreyolo import LibreYOLO # Загрузить чекпойнт прерванного запуска, затем попросить продолжить.model = LibreYOLO("runs/train/exp/weights/last.pt")model.train(data="my-dataset.yaml", epochs=100, resume=True)libreyolo train model=runs/train/exp/weights/last.pt \ data=my-dataset.yaml epochs=100 resume=trueВозобновление восстанавливает обученные веса, состояние оптимизатора, веса EMA и
счётчик обновлений, отслеживание лучшей метрики, масштаб GradScaler, а также
состояния генераторов случайных чисел PyTorch, CUDA и NumPy. Оно стартует с
эпохи чекпойнта плюс один и прокручивает расписание до этой точки.
Двух вещей оно не сделает. resume=True нельзя сочетать с pretrained — это
приводит к ошибке. И если ключ лучшей метрики в чекпойнте отличается от ключа
текущего запуска, отслеживание лучшей метрики сбрасывается в ноль с
предупреждением, вместо того чтобы сравнивать величины, которые означают разное.
Рецепты в файле
cfg= загружает YAML-словарь с именами полей TrainConfig и подкладывает его
под явные именованные аргументы, так что kwarg всегда побеждает файл.
from libreyolo import LibreYOLO # Ключи в yaml — имена полей TrainConfig. Явные kwargs побеждают.model = LibreYOLO("LibreYOLO9s.pt")model.train(data="my-dataset.yaml", cfg="my-recipe.yaml", epochs=50)size и num_classes из файла вырезаются, потому что они уже принадлежат
экземпляру модели. Флага --cfg в CLI нет; путь к файлу — это аргумент Python.
Смотрите также
- Датасеты — что принимает
data=. - Аугментации — настройки аугментации и то, какие семейства их учитывают.
- Заморозка слоёв и LoRA — обучение части весов.
- Валидация и метрики — что сообщает запуск.