Детекция точек
Детекция точек возвращает по одной координате x, y на объект вместо ограничивающей рамки. LibreYOLO предоставляет её как задачу point, и в предсказании на каждый объект приходится одна строка с x, y, классом и уверенностью.
Определение
Задача point находит каждый объект одной координатой x, y и классом — без
ширины, высоты и маски. Поскольку предсказание — это плоский список объектов,
число строк равно числу объектов, и именно поэтому это задача подсчёта.
Предсказание заполняет result.points — объект Points, который оборачивает
массив (N, 4) со строками x, y, class, confidence в пикселях исходного
изображения. .xy возвращает координаты, .xyn — те же координаты, делённые
на размер изображения, .cls — индексы классов, а .conf — оценки
уверенности; len() возвращает число точек. result.boxes остаётся пустым,
поэтому iou и max_det применять не к чему.
Модели
Задачу point решают три семейства, и они не взаимозаменяемы.
FOMO — вариант с фиксированным словарём: сеточный классификатор, который размечает каждую ячейку сетки низкого разрешения как фон или как центр объекта. Это единственное точечное семейство, которое LibreYOLO умеет обучать, и единственное, которое экспортируется.
LocateAnything принимает текст вместо индекса
класса, поэтому словарь — это любая фраза, которую вы напишете. Модели нужен
extra vlm, она создаётся как LibreLocateAnything, а не через фабрику
LibreYOLO(), и её веса ограничены некоммерческим использованием. Точные
условия и две дополнительные лицензии, которые объединяет чекпойнт, — на её
странице.
SenseNova-Vision решает point тем же
чекпойнтом генерации по промпту, которым решает ещё шесть задач; он загружается
через LibreVLM("sensenova-vision", task="point"). Ему нужен extra
sensenova, и каждое предсказание — это проход генерации по модели на 7B
параметров, так что задержка на изображение будет заметно выше, чем у
специализированного детектора. Его веса некоммерческие; лицензия — на его
странице.
Предсказание
Веса LibreFOMO — единственное исключение из автоматической загрузки на этом
сайте. LibreYOLO("LibreFOMOs-point.pt") ищет этот файл на диске и вместо
скачивания выбрасывает ValueError с его именем. Сначала скачайте чекпойнт из
организации LibreYOLO на Hugging Face и
загрузите его по локальному пути — или обучите свой.
from libreyolo import LibreYOLO, SAMPLE_IMAGE # Веса LibreFOMO автоматически не скачиваются. Сначала возьмите# чекпойнт с https://huggingface.co/LibreYOLO и загрузите его по# локальному пути.model = LibreYOLO("./LibreFOMOs-point.pt")result = model(SAMPLE_IMAGE, save=True) points = result.pointsprint(len(points)) # число объектовprint(points.xy) # центры (N, 2) в пикселях исходного изображенияprint(points.cls, points.conf)from collections import Counter from libreyolo import LibreYOLO, SAMPLE_IMAGE model = LibreYOLO("./LibreFOMOs-point.pt")result = model(SAMPLE_IMAGE) points = result.points.numpy()print(points.xyn) # те же центры в [0, 1]print(Counter(points.cls.astype(int).tolist()))Имя файла должно нести суффикс задачи -point, иначе загрузчик его не
распознает. predict(..., nms_radius=1) задаёт, на сколько ячеек сетки должны
отстоять друг от друга две детекции FOMO, чтобы уцелели обе. Про источники,
стриминг и работу с результатами — в разделе предсказание.
Формат датасета
У point нет собственного формата разметки. Точечные семейства читают
стандартную раскладку YOLO для детекции и выводят один центр из каждой строки с
рамкой, так что cx cy — это точка, а w h только решают, валидна ли строка.
dataset/
data.yaml
images/
train/scene.jpg
val/scene.jpg
labels/
train/scene.txt
val/scene.txtВ каждом файле разметки — по одной строке на объект, с нормализованными координатами:
<class_id> <cx> <cy> <w> <h>path: dataset
train: images/train
val: images/val
nc: 1
names: {0: seedling}Отсутствующий или пустой файл разметки означает, что объектов нет. Полный контракт — в разделе форматы датасетов.
Обучение
FOMO — единственное точечное семейство, для которого реализовано обучение.
train() у LocateAnything и у SenseNova-Vision выбрасывает
NotImplementedError; дообучайте их в исходных проектах и загружайте результат.
from libreyolo import LibreYOLO model = LibreYOLO("./LibreFOMOs-point.pt")model.train(data="my-dataset.yaml", epochs=40, batch=32, lr0=3e-4)from libreyolo import LibreYOLO, SAMPLE_IMAGE model = LibreYOLO("./LibreFOMOs-point.pt")results = model.train(data="my-dataset.yaml", epochs=40) # train() загружает лучший чекпойнт обратно в тот же объект, поэтому# после возврата из вызова модель предсказывает обученными весами.print(results["best_checkpoint"])print(model(SAMPLE_IMAGE).points.xy)imgsz для FOMO выбирается не свободно: по умолчанию берётся родное разрешение
загруженного чекпойнта, а другое значение приводит к ValueError с указанием
ожидаемого размера. Про датасеты, логгеры и обучение на нескольких GPU — в
разделе обучение, а значения по умолчанию для этого семейства —
на странице FOMO.
Валидация
val() сопоставляет предсказанные точки с точками эталонной разметки (ground
truth) один к одному венгерским алгоритмом, перебирая пороги расстояния. Порог
— это евклидово расстояние в нормализованных координатах изображения, а перебор
по умолчанию — десять значений от 0.01 до 0.10.
from libreyolo import LibreYOLO model = LibreYOLO("./LibreFOMOs-point.pt")metrics = model.val(data="my-dataset.yaml") print(metrics["metrics/precision"], metrics["metrics/recall"])print(metrics["metrics/f1"])print(metrics["metrics/mAP@[0.01:0.10]"]) # fitnessprint(metrics["metrics/MLE"]) # средняя ошибка локализацииprint(metrics["metrics/MAE"], metrics["metrics/RMSE"]) # ошибка подсчётаfrom libreyolo import LibreYOLO model = LibreYOLO("./LibreFOMOs-point.pt") # Границы перебора входят в текст ключа, поэтому свой набор порогов# переименовывает ключи mAP, которые он создаёт.metrics = model.val(data="my-dataset.yaml", dist_thresholds=[0.02, 0.05]) print(metrics["metrics/mAP@0.02"])print(metrics["metrics/mAP@[0.02:0.05]"])metrics/precision, metrics/recall и metrics/f1 усредняются по классам
(макро) на самом строгом пороге перебора — по умолчанию 0.01.
metrics/mAP@0.01 — это AP на том же пороге, а metrics/mAP@[0.01:0.10] —
среднее по всему перебору. Это же среднее служит и fitness — числом, по
которому выбирается лучший чекпойнт. Оба ключа mAP строятся из
используемых порогов, поэтому передача dist_thresholds= их переименовывает.
metrics/MLE — среднее расстояние между сопоставленными парами на самом
строгом пороге, в тех же нормализованных единицах. metrics/MAE и
metrics/RMSE — метрики подсчёта, а не локализации: они измеряют разницу между
числом предсказанных точек и числом точек эталонной разметки на каждом
изображении.
Поверх этого FOMO добавляет вторую группу — на уровне сетки. Она перебирает
уверенность и nms_radius и публикует комбинацию с лучшим F1 как
metrics/grid_F1, metrics/grid_precision, metrics/grid_recall,
metrics/grid_mean_distance, metrics/grid_TP, metrics/grid_FP и
metrics/grid_FN, а давшие её настройки — под decode/threshold и
decode/nms_radius.
Экспорт
FOMO экспортируется через общий путь экспорта, а экспортированный артефакт
загружается обратно через LibreYOLO() по суффиксу файла, так что файл .onnx
или .engine ведёт себя как чекпойнт и возвращает тот же Results.
from libreyolo import LibreYOLO model = LibreYOLO("./LibreFOMOs-point.pt")model.export(format="onnx")from libreyolo import LibreYOLO, SAMPLE_IMAGE # Фабрика выбирает загрузчик по суффиксу файла, поэтому# экспортированный артефакт загружается как обычный чекпойнт и# возвращает тот же объект Results.model = LibreYOLO("./LibreFOMOs-point.onnx")result = model(SAMPLE_IMAGE) print(result.points.xy)Поддержка по форматам — на странице FOMO и в полной
матрице экспорта. LocateAnything и
SenseNova-Vision не экспортируются: export() выбрасывает исключение в обоих
случаях, потому что у генеративной модели нет трассируемого графа детекции.