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

Сегментация экземпляров

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

Определение

Сегментация экземпляров — это детекция плюс форма. Каждый экземпляр объекта по-прежнему получает рамку, класс и оценку, а вдобавок — бинарную маску, которая покрывает принадлежащие ему пиксели. Маски могут перекрываться, а пиксели, не принадлежащие ни одному объекту, остаются без назначения — именно это отличает задачу от семантической сегментации и паноптической сегментации.

segment — канонический ключ задачи, а суффикс -seg в имени файла чекпойнта выбирает её, поэтому при загрузке опубликованных весов task= не нужен.

predict() заполняет result.masks рядом с result.boxes. .data — это стек масок (N, H, W) размером с исходное изображение, построчно выровненный с рамками, так что маска i относится к рамке i. .xy превращает каждую маску в её наибольший внешний контур — массив пикселей (P, 2), а .xyn даёт тот же контур в нормализованном виде.

Модели

Обучать и предсказывать маски умеют четыре семейства: RF-DETR, EdgeCrafter, D-FINE и RTMDet. Для RF-DETR нужна своя дополнительная зависимость, pip install "libreyolo[rfdetr]"; остальные три работают на базовом пакете.

Mask R-CNN предсказывает, валидирует и экспортирует маски, но его train() выбрасывает NotImplementedError.

EoMT предсказывает и валидирует маски и тоже не поддерживает обучение, а его экспорт ограничен ещё сильнее: export() принимает только семантическую задачу и выбрасывает NotImplementedError для segment и panoptic, потому что контракт среды выполнения для query-масок, который нужен этим двум, пока не определён. Используйте EoMT для масок экземпляров в Python, а не через экспортированный граф.

Отдельная группа сегментирует по промпту, а не по списку классов: клик, рамка или фраза указывают на объект, и модель возвращает его маску. Так работают SAM, SAM 2, SAM 3, MobileSAM, EdgeTAM и PicoSAM3, а также SenseNova-Vision, у которого сегментация идёт по описанию (referring): модель принимает фразу, называющую один объект. Они загружаются через собственную фабрику и дополнительные зависимости, а точный вызов приведён на странице каждой модели.

Предсказание

Веса скачиваются с Hugging Face при первом запуске и кэшируются локально.

Python
from libreyolo import LibreYOLO, SAMPLE_IMAGE # Суффикс -seg в имени файла выбирает голову масок, поэтому# аргумент task не нужен.model = LibreYOLO("LibreDFINEn-seg.pt")result = model(SAMPLE_IMAGE, save=True) print(result.masks.data.shape)   # (N, H, W), по одной маске на детекциюprint(result.boxes.xyxy.shape)   # (N, 4), те же N строк
CLI
libreyolo predict model=LibreDFINEn-seg.pt save=True \  source=https://raw.githubusercontent.com/LibreYOLO/libreyolo/release/libreyolo/assets/parkour.jpg
Контуры масок
from libreyolo import LibreYOLO, SAMPLE_IMAGE model = LibreYOLO("LibreDFINEn-seg.pt")result = model(SAMPLE_IMAGE) # .xy — список контуров (P, 2) в пикселях, .xyn — те же, но нормализованные.for name, contour in zip(result.boxes.cls, result.masks.xy):    print(result.names[int(name)], contour.shape)
Другое семейство, тот же вызов
from libreyolo import LibreYOLO, SAMPLE_IMAGE model = LibreYOLO("LibreRTMDets-seg.pt")result = model(SAMPLE_IMAGE) print(result.masks.data.shape)

conf и max_det формируют вывод так же, как в детекции, а маски фильтруются вместе с рамками, которым принадлежат. Про источники, стриминг и обработку результатов — в разделе предсказание.

Формат датасета

Структура та же, что и в детекции: один файл разметки .txt на изображение; путь к нему получается, если заменить images на labels в пути к изображению и сменить расширение.

dataset/
  data.yaml
  images/
    train/000001.jpg
    val/000101.jpg
  labels/
    train/000001.txt
    val/000101.txt

Меняется сама строка. Сегмент — это индекс класса, за которым идёт плоский список координат полигона:

<class_id> <x1> <y1> ... <xN> <yN>

Точек должно быть не меньше трёх, то есть количество координат после индекса класса чётное и не меньше шести, а полигон не должен быть вырожденным. Координаты — числа с плавающей точкой в [0, 1] относительно ширины и высоты исходного изображения. Строка детекции из пяти полей тоже принимается в датасете сегментации и читается как прямоугольный сегмент — благодаря этому датасет только с рамками загружается без отдельного прохода конвертации.

YAML — тот же, что и в детекции:

yaml
path: dataset
train: images/train
val: images/val
names:
  0: person
  1: bicycle

Нативный COCO JSON тоже работает: добавьте раздел annotations, который сопоставляет имя сплита с JSON-файлом, а путь сплита задаёт корневой каталог изображений.

Обучение

Python
from libreyolo import LibreYOLO # Обучение продолжается с опубликованных весов сегментации, с головой масок.# data должен указывать на датасет, в разметке которого есть полигоны.model = LibreYOLO("LibreDFINEn-seg.pt")model.train(data="my-dataset.yaml", epochs=50, imgsz=640, batch=8, lr0=2e-4)
CLI
libreyolo train model=LibreDFINEn-seg.pt data=my-dataset.yaml \  epochs=50 imgsz=640 batch=8 lr0=2e-4
Из весов детекции
# В весах детекции нет головы масок, поэтому это явный перенос:# голова стартует необученной. Разрешает его именно явно# указанный task=segment.libreyolo train model=LibreDFINEn.pt data=my-dataset.yaml \  task=segment epochs=50 imgsz=640

По умолчанию обучение продолжается с опубликованного чекпойнта -seg. Стартовать с весов детекции тоже можно, но это осознанный перенос: в таких весах нет головы масок, поэтому она стартует необученной, а разрешает такую замену именно task=segment. Про датасеты, аугментацию, обучение на нескольких GPU и логгеры — в разделе обучение.

Валидация

val() возвращает обычный словарь с ключами metrics/. Рамки и маски оцениваются отдельно, обе — по протоколу COCO, и основными считаются числа по маскам.

Python
from libreyolo import LibreYOLO model = LibreYOLO("LibreDFINEn-seg.pt")metrics = model.val(data="my-dataset.yaml") print(metrics["metrics/mAP50-95"])       # маскиprint(metrics["metrics/mAP50-95(M)"])    # маски, явноprint(metrics["metrics/mAP50-95(B)"])    # рамки
CLI
libreyolo val model=LibreDFINEn-seg.pt data=my-dataset.yaml

Ключи без суффикса содержат результаты по маскам: metrics/mAP50-95, metrics/mAP50, metrics/mAP75, затем metrics/mAP_small, metrics/mAP_medium и metrics/mAP_large по площади объекта, а также metrics/AR1, metrics/AR10, metrics/AR100, metrics/AR_small, metrics/AR_medium, metrics/AR_large для средней полноты. В metrics/AR_max_det и metrics/max_det записан лимит числа детекций, с которым шёл запуск.

Четыре величины публикуются ещё и с явным суффиксом — (M) для маски и (B) для рамки, — чтобы сравнение не зависело от того, какое число семейство решило считать основным: metrics/mAP50-95(M) и metrics/mAP50-95(B), metrics/mAP50(M) и metrics/mAP50(B), metrics/precision(M) и metrics/precision(B), metrics/recall(M) и metrics/recall(B). Ключей metrics/precision и metrics/recall без суффикса в этой задаче нет.

Ключи precision и recall читайте внимательно. Они оставлены для обратной совместимости и служат псевдонимами, а не рабочей точкой: в metrics/precision(M) лежит то же значение, что и в metrics/mAP50-95(M), а в metrics/recall(M) — то же, что и AR по маскам при 100 детекциях; с (B) для рамок всё устроено так же. График по паре таких ключей покажет одно и то же число дважды.

Экспорт

Python
from libreyolo import LibreYOLO model = LibreYOLO("LibreDFINEn-seg.pt")model.export(format="onnx", imgsz=640)
CLI
libreyolo export model=LibreDFINEn-seg.pt format=onnx imgsz=640
Использование экспортированного файла
from libreyolo import LibreYOLO, SAMPLE_IMAGE # Фабрика выбирает загрузчик по суффиксу файла, поэтому экспортированный# артефакт загружается как чекпойнт и возвращает тот же объект Results.model = LibreYOLO("LibreDFINEn-seg.onnx")result = model(SAMPLE_IMAGE) print(result.masks.data.shape)

Экспортированный артефакт загружается обратно через LibreYOLO() по суффиксу файла, поэтому файл .onnx или .engine ведёт себя как чекпойнт и возвращает тот же Results. Покрытие форматов для сегментации уже, чем для детекции у того же семейства. Матрица на странице каждой модели генерируется из проверенного набора и называет причину, по которой цель недоступна. Про форматы, их дополнительные зависимости и ограничения — в разделе экспорт и развёртывание.

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