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

Импорт существующих весов

LibreYOLO портирует свои семейства моделей из upstream-проектов, поэтому опубликованные ими чекпойнты уже почти загружаются. Не хватает им метаданных. Автоконвертация добавляет их при загрузке.

Точка входа
LibreYOLO("path/to/upstream.pth")
Записывается рядом с исходником как
<source>-<Prefix><size>[-task].pt
Скрипты конвертации
weights/ в репозитории

Эта страница — о чекпойнтах из других проектов. Если вы переносите собственный код со старой версии LibreYOLO, см. переход на 1.5.0.

Что происходит при загрузке чужого файла

LibreYOLO() сначала загружает любой файл весов по ограниченному пути, который читает только веса. Если в результате есть полные метаданные LibreYOLO, он используется напрямую. Если нет, файл уходит в автоконвертер, прежде чем будет предпринято что-то ещё. Если ограниченная загрузка сразу завершается ошибкой — так бывает, когда внутрь чекпойнта через pickle записан сторонний объект, — автоконвертер запускается с загрузчиком, который такие объекты нейтрализует.

Автоконвертация делает четыре вещи. Она распаковывает словарь тензоров из того формата, который использовал upstream-проект. Она спрашивает каждое зарегистрированное семейство, распознаёт ли оно получившиеся ключи, и переименовывает их там, где именование в upstream отличается от порта LibreYOLO. Она упаковывает победителя в чекпойнт, соответствующий схеме метаданных v1.0, считывая размер, задачу и число классов из самих тензоров. Затем записывает результат рядом с исходным файлом и загружает уже его.

Python
from libreyolo import LibreYOLO # Подставьте путь к чекпойнту, который у вас уже есть. Распознанная# структура upstream-чекпойнта конвертируется на лету, записывается# рядом с исходником и затем загружается.model = LibreYOLO("path/to/upstream-checkpoint.pth") # Число классов и имена берутся из тензоров и из собственных# метаданных файла, поэтому дообученная модель сохраняет свой# набор меток вместо набора COCO.print(model.family, model.size, model.task, model.nb_classes)print(model.names)
CLI
libreyolo predict model=path/to/upstream-checkpoint.pth \  source=https://raw.githubusercontent.com/LibreYOLO/libreyolo/release/libreyolo/assets/parkour.jpg
Проверка результата
# Сконвертированный файл соответствует той же схеме, что и опубликованный.libreyolo metadata path=path/to/upstream-checkpoint-LibreYOLO9t.pt

Конвертация не проходит незаметно. Для каждого сконвертированного файла в лог пишутся семейство, имя исходника, имя результата и итоговое число классов, так что по логу запуска видно, что именно было загружено.

Структуры, которые он распаковывает

Upstream-чекпойнты хранят веса в нескольких привычных местах, и конвертер перебирает их по порядку, пока в одном не окажутся тензоры: EMA-блок в ema.module или плоский ema, ema_state_dict со срезанным префиксом module., затем params_ema, params, ema_net, net, model, state_dict и, наконец, сам объект. Перебор нескольких мест, а не только первого, означает, что блок ema с одними счётчиками не заслонит настоящие веса под ним.

Префиксы-обёртки тоже снимаются: module. от распределённого обучения, _orig_mod. от скомпилированной модели и вложенность model.model., которую добавляют некоторые перевыложенные копии.

Что он читает и откуда

Размер, задача и число классов берутся из тензоров, а не из имени файла — поэтому дообученный чекпойнт конвертируется со своим числом классов, а не со значением по умолчанию для архитектуры. Имена классов берутся из собственных метаданных чекпойнта, когда они есть, из блока args или hyper_parameters, если имена лежат там, и обрезаются до обнаруженного числа классов, чтобы дообученная модель, сохранившая базовый набор меток, не тащила индексы, которых в её голове больше нет.

Плотные задачи обрабатываются явно, а не получают выдуманные метки. Чекпойнт оценки глубины получает один класс с именем depth, чекпойнт восстановления — один класс с именем image. Чекпойнт оценки позы обязан дать число ключевых точек — из тензоров или от семейства; если ни то ни другое его не даёт, конвертация отклоняется, вместо того чтобы записать неполный файл.

У RF-DETR свой распознаватель: определение размера требует чекпойнта целиком, а голова этой модели даёт 91 выход там, где в LibreYOLO принято соглашение COCO о 80 классах. Чекпойнт приводится к 80 классам, если в нём ровно 80 имён, или заявлено число классов 80, или датасетом указан COCO, или метаданных о классах и датасете нет вовсе. Настоящая 90-классовая модель, опознанная по именам, по явно указанному числу классов, отличному от 80, или по подсказке о датасете, отличном от COCO, сохраняется как есть.

Куда попадает сконвертированный файл

Результат записывается рядом с исходником и называется по нему:

<source stem>-<FilenamePrefix><size>[-<task suffix>].pt

Поэтому детектор YOLOv9 размера t, сохранённый как upstream-checkpoint.pth, превращается в upstream-checkpoint-LibreYOLO9t.pt. Имя по исходнику, а не по семейству, означает, что два дообученных чекпойнта одного семейства и размера в одном каталоге не перезапишут друг друга и ни один из них не столкнётся с официальным чекпойнтом. Файл перезаписывается при каждой загрузке, поэтому никогда не устаревает относительно своего исходника. Если каталог доступен только для чтения, сконвертированный файл уходит в новый приватный временный каталог, а в логе сказано, куда именно.

Дальше это обычный чекпойнт LibreYOLO: он загружается по пути с метаданными, а libreyolo metadata сообщает, что он валиден.

Случаи, требующие ручного вмешательства

Два семейства остаются за пределами общего распознавателя. Семейство gaze исключено полностью: оно предназначено только для инференса, а на его опубликованные веса наложены ограничения на перераспространение. RF-DETR исключён потому, что у него есть отдельный распознаватель, описанный выше, — он и берёт эту модель на себя.

Сырые upstream-чекпойнты PIDNet отклоняются с ошибкой, которая указывает на weights/convert_pidnet_weights.py. Этот скрипт записывает семантические метаданные Cityscapes, которых чекпойнту не хватает.

У D-FINE и DEIM одинаковые ключи архитектуры, поэтому по одним тензорам их не различить. Когда на файл претендуют оба и среди претендентов нет соседнего семейства с отличительным маркером, решает имя файла: имя вида dfine_hgnetv2_n_coco.pth или deim_hgnetv2_n_coco.pth снимает вопрос, а имя, которое ничего не говорит, приводит к отказу с этим объяснением, а не к догадке. Прямое создание LibreDFINE или LibreDEIM тоже решает вопрос.

Когда на один файл законно претендуют несколько семейств, подкласс побеждает базовый класс, который он уточняет, а остальное решает порядок в реестре, потому что этот порядок отражает, насколько специфична проверка каждого семейства. Имя файла учитывается только в ничьей между D-FINE и DEIM, поэтому имя никогда не поставит широкое совпадение выше точного.

Скрипты конвертации

В репозитории под weights/ лежат скрипты конвертации для каждого семейства и общие вспомогательные функции для повторяющейся рутины. Это путь для файла, который отклонён на этапе загрузки, для подготовки чекпойнта заранее, а не в момент загрузки, и для семейств, метаданные которых приходится задавать, а не выводить из тензоров.

Эти скрипты — часть репозитория, а не установленного пакета, поэтому, чтобы воспользоваться одним из них, репозиторий нужно клонировать:

bash
git clone https://github.com/LibreYOLO/libreyolo.git
cd libreyolo
python weights/convert_pidnet_weights.py --help

Каждый скрипт записывает чекпойнт, соответствующий схеме v1.0, — ту же планку берёт автоконвертация, и ей же соответствуют опубликованные веса. Что входит в эту схему, описано в разделе чекпойнты и веса.

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