Посмотреть как Markdown

Заморозка слоёв

Заморозка удерживает выбранные веса неизменными, пока обучается остальная модель. Селекторы адресуют собственные упорядоченные группы заморозки семейства или имена его модулей, а не сырые номера слоёв из YAML-графа.

Заморозить что-нибудь

freeze — необязательный параметр, по умолчанию ничего не замораживается.

Python
from libreyolo import LibreYOLO model = LibreYOLO("LibreYOLO9s.pt") # Первые 10 групп — это весь бэкбон YOLOv9.model.train(data="my-dataset.yaml", epochs=50, freeze=10)
CLI
libreyolo train model=LibreYOLO9s.pt data=my-dataset.yaml \  epochs=50 freeze=10
По имени
from 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.

Область применения

Это статическая заморозка, которая определяется при запуске. Разморозка по расписанию и постепенная заморозка в интерфейс не входят.

Смотрите также

Проверено с LibreYOLO v1.5.0.