Заморозка слоёв
Заморозка удерживает выбранные веса неизменными, пока обучается остальная модель. Селекторы адресуют собственные упорядоченные группы заморозки семейства или имена его модулей, а не сырые номера слоёв из YAML-графа.
Заморозить что-нибудь
freeze — необязательный параметр, по умолчанию ничего не замораживается.
from libreyolo import LibreYOLO model = LibreYOLO("LibreYOLO9s.pt") # Первые 10 групп — это весь бэкбон YOLOv9.model.train(data="my-dataset.yaml", epochs=50, freeze=10)libreyolo train model=LibreYOLO9s.pt data=my-dataset.yaml \ epochs=50 freeze=10from libreyolo import LibreYOLO model = LibreYOLO("LibreRFDETRs.pt")model.train(data="my-dataset.yaml", epochs=50, freeze="backbone")from libreyolo import LibreYOLO model = LibreYOLO("LibreYOLO9s.pt")model.train(data="my-dataset.yaml", freeze=["backbone", "neck"])Заморозка выполняется после сборки модели и после любой перестройки головы под новое число классов, но до создания оптимизатора, поэтому оптимизатор всегда получает только обучаемые параметры.
Каким может быть селектор
| Значение | Что означает |
|---|---|
None, False, "", "none" | Обучать все параметры |
10 или "10" | Заморозить первые десять групп заморозки семейства |
[0, 3, 7] | Заморозить эти группы, индексация с нуля |
"backbone" | Заморозить подходящую группу, модуль или префикс имени параметра |
["backbone", "neck"] | Заморозить каждый перечисленный селектор |
["backbone", 3] | Смешанные списки работают |
Строка сначала разбирается, а уже потом интерпретируется, поэтому CLI и
YAML-конфиг принимают те же формы, что и Python. freeze="[0, 3, 'head']"
разбирается как литеральный список, freeze="backbone,neck" разбивается по
запятой, а строка из одних цифр трактуется как количество.
freeze=True отклоняется как неоднозначное значение.
Селекторы по имени сопоставляются с именем группы заморозки, именем модуля или
префиксом имени параметра, причём работают glob-символы *, ? и [. Ведущий
model. трактуется гибко, поэтому и backbone, и model.backbone сработают
независимо от того, какое написание семейство использует внутри.
Группы задаёт семейство
Целое число адресует собственный упорядоченный список групп заморозки семейства, а не позицию в общем графе. Семейства LibreYOLO — это не одна общая последовательная модель с индексами из YAML, поэтому сырой номер слоя у каждого из них означал бы своё.
YOLOv9 упорядочивает группы от входа: десять стадий бэкбона, затем шесть стадий
neck, затем голова. Поэтому freeze=10 — это ровно бэкбон. Поверх этого
backbone, neck и head работают как стабильные селекторы по имени.
Группы RF-DETR — это backbone.encoder, backbone.projector, decoder,
queries, transformer.encoder_output и head. Здесь имена подходят лучше,
потому что компоненты трансформера не сводятся к числу слоёв. backbone по
префиксу совпадает с обеими группами бэкбона.
Семейства, которые не определяют семантические группы, берут консервативный вариант по умолчанию: каждый прямой потомок модели, у которого есть хотя бы один параметр, в порядке объявления. Обычно это короткий список, так что большое целое число не найдёт достаточно групп:
freeze index 10 is out of range for 3 available freeze groups.Чтобы увидеть настоящий список, а не гадать:
from libreyolo import LibreYOLO9from libreyolo.models.yolo9.trainer import YOLO9Trainer model = LibreYOLO9("LibreYOLO9s.pt", size="s")trainer = YOLO9Trainer(model=model.model, wrapper_model=model, size="s") for index, (name, _module) in enumerate(trainer.get_freeze_groups()): print(index, name)Ошибки не молчат
Любой способ ошибиться здесь приводит к исключению, а не к обучению чего-то, о чём вы не просили.
Селектор, который ни с чем не совпал, вызывает исключение и называет промахнувшиеся селекторы:
freeze selector(s) matched no parameters: 'backbon'Заморозка, после которой не осталось бы обучаемых параметров, вызывает исключение — и в момент заморозки, и ещё раз при создании оптимизатора:
freeze would leave no trainable parameters. Use a smaller freeze value or
target a narrower module.Именно так ведёт себя freeze="all", ведь all совпадает с каждым параметром.
Когда заморозка проходит успешно, произошедшее записывается одной строкой:
Layer freezing: selectors=[10], tensors=124, params=2103776, trainable=1863456/3967232Замороженный BatchNorm перестаёт обновляться
Замороженный параметр всё равно лежит внутри модуля, чья скользящая статистика
продолжала бы меняться. Каждый модуль типа BatchNorm, чьи параметры попали в
замороженное множество, переключается в режим eval, и тренер применяет это заново
после вызова model.train() в каждой эпохе, так что статистика остаётся
зафиксированной на весь запуск.
По умолчанию это включено, и именно поэтому заморозка бэкбона действительно его замораживает.
Совмещение с LoRA
freeze и lora=True работают вместе. В RF-DETR, DEIM и ConvNeXt параметры
адаптеров остаются обучаемыми, даже когда их родительская группа заморожена, — это
и есть нужное сочетание: замороженный бэкбон с адаптерами, которые учатся поверх
него. См. Дообучение с LoRA.
Область применения
Это статическая заморозка, которая определяется при запуске. Разморозка по расписанию и постепенная заморозка в интерфейс не входят.
Смотрите также
- Гиперпараметры — про остальные аргументы
train(). - Дистилляция — другой способ перенести знания большой модели в запуск обучения.