API ансамблів
LibreEnsemble запускає кілька детекторів на тому самому зображенні та зливає їхні виявлення в один Results. Злиття відбувається після власного постоброблення кожного учасника, тому учасники зберігають власні розмір вхідних даних, нормалізацію та придушення.
LibreEnsemble
LibreEnsemble(
members,
*,
weights=None,
fusion="wbf",
fusion_iou=0.55,
min_votes=1,
)| Аргумент | Типове значення | Значення |
|---|---|---|
members | Два або більше детекторів | |
weights | None | Коефіцієнти довіри для кожного учасника; за відсутності всі дорівнюють 1.0 |
fusion | "wbf" | "wbf", "wbf_seeded", "nms" або викликаний об'єкт |
fusion_iou | 0.55 | Поріг IoU для кластеризації під час злиття |
min_votes | 1 | Залишати лише рамки, підтверджені щонайменше такою кількістю учасників |
Учасником може бути шлях до ваг, визначений через фабрику LibreYOLO(), уже
створена модель, експортований бекенд або ExternalDetector. Кожен учасник має
бути моделлю завдання detect.
from libreyolo import LibreEnsemble, SAMPLE_IMAGE ens = LibreEnsemble(["LibreYOLO9t.pt", "LibreYOLO9s.pt"]) # Джерело з одним зображенням повертає один Results, а не список.result = ens(SAMPLE_IMAGE, conf=0.25) print(result.boxes.xyxy)print(result.speed)from libreyolo import LibreEnsemble, SAMPLE_IMAGE ens = LibreEnsemble( ["LibreYOLO9t.pt", "LibreYOLO9s.pt"], weights=[1.0, 2.0], fusion="wbf", fusion_iou=0.55, min_votes=2,)result = ens(SAMPLE_IMAGE, conf=[0.25, 0.4])print(len(result))Під час створення відхиляються: менше двох учасників, список weights
неправильної довжини, недодатна вага, значення min_votes, що не є додатним
цілим числом, і min_votes, більше за кількість учасників. fusion="nms" із
min_votes > 1 також спричиняє помилку, оскільки NMS відкидає належність до
кластера й не може підраховувати голоси.
weights масштабує довіру до кожного учасника. Більша вага наближає злиті
координати й оцінки до цього учасника. За домовленістю вони задаються
пропорційно до валідаційного mAP.
Простори класів
Учасники з однаковим names проходять без змін. В іншому разі простори класів
об'єднуються за назвою, ідентифікатори класів учасників перетворюються через
таблиці відповідності, а Results.names після злиття є об'єднанням. Злиття
поєднує рамки лише в межах одного об'єднаного класу, тому клас, відомий лише
одному учаснику, проходить без злиття. Невідповідність спричиняє попередження
під час створення.
min_votes обмежується окремо для кожного класу кількістю учасників, простори
міток яких містять цей клас, тому консенсус залишається змістовним для частково
спільних словників.
Виклик ансамблю
ens(
source=None,
*,
conf=0.25,
iou=0.45,
imgsz=None,
device=None,
classes=None,
max_det=300,
augment=False,
save=False,
output_path=None,
color_format="auto",
batch=1,
stream=False,
stream_buffer=False,
vid_stride=1,
show=False,
**kwargs,
)predict є псевдонімом __call__. Повертається звичайний Results, де
speed розділяє витрати за учасниками й додає запис fusion. Джерело з одним
зображенням повертає один такий об'єкт, список або каталог повертає список, а
stream=True повертає генератор.
conf, iou та device транслюються на кожного учасника й також приймають по
одному значенню на учасника, тому conf=[0.25, 0.4] задає учаснику 0 поріг
0.25, а учаснику 1 поріг 0.4. imgsz транслюється, коли є цілим числом або
кортежем, і застосовується окремо до учасників лише як список. Тому
imgsz=(480, 640) задає один прямокутний розмір для всіх, а
imgsz=[480, 640] задає 480 для учасника 0 і 640 для учасника 1. Кожен елемент
має бути дійсним для сімейства відповідного учасника.
augment транслюється на учасників, які підтримують аугментацію під час
тестування, а експортовані бекенди його ігнорують. classes приймає
ідентифікатори класів об'єднання, а max_det застосовується до злитого
результату, тому учасники працюють із запасом, а ансамбль один раз обрізає
результат. batch приймається для узгодженості API; зображення обробляються
послідовно.
val() і export() спричиняють NotImplementedError. Валідуйте й експортуйте
учасників окремо.
ExternalDetector
ExternalDetector(fn: Callable, names: dict[int, str])Адаптує будь-який викликаний детектор до учасника. fn приймає зображення PIL
і повертає (boxes, scores, labels), де рамки задано як xyxy у пікселях
початкового зображення, а мітки є ідентифікаторами класів, дійсними в names.
Працюють тензори, масиви та вкладені списки. LibreYOLO нічого не імпортує із
зовнішнього коду.
Адаптер перевіряє повернене значення: воно має бути 3-кортежем, рамки повинні
мати форму (N, 4), три масиви повинні мати однакову довжину, а кожен
ідентифікатор класу має бути в names. Виявлення з conf або нижче
відкидаються перед злиттям.
Операції злиття
Примітиви злиття є окремими операціями torch у libreyolo.ops. Вони не
залежать від моделі й можуть імпортуватися окремо, тому їх експортовано окремо
від ансамблю.
import torchfrom libreyolo.ops import weighted_boxes_fusion boxes = torch.tensor([[10.0, 10.0, 50.0, 50.0], [12.0, 11.0, 51.0, 49.0]])scores = torch.tensor([0.9, 0.8])labels = torch.tensor([0, 0])model_ids = torch.tensor([0, 1]) fused = weighted_boxes_fusion( boxes, scores, labels, model_ids, num_models=2, iou_thr=0.55)print(fused)Усі три приймають ті самі позиційні аргументи boxes, scores, labels, model_ids і повертають (boxes, scores, labels).
| Операція | Ключ реєстру | Поведінка |
|---|---|---|
weighted_boxes_fusion | wbf | Послідовне зважене злиття рамок із точним дотриманням статті |
wbf_seeded | wbf_seeded | Паралельний однопрохідний варіант того самого зведення |
nms_fusion | nms | Об'єднання всіх даних із застосуванням NMS з урахуванням класів |
FUSIONS зіставляє три ключі реєстру з викликаними об'єктами, а
LibreEnsemble шукає там значення fusion=.
weighted_boxes_fusion(
boxes, scores, labels, model_ids,
*,
weights=None,
num_models=None,
iou_thr=0.55,
skip_box_thr=0.0,
conf_type="avg",
min_votes=1,
models_per_label=None,
label_weights=None,
)wbf_seeded має ідентичну сигнатуру. nms_fusion приймає ті самі аргументи,
крім conf_type, і спричиняє ValueError, коли min_votes > 1.
У weighted_boxes_fusion виявлення розглядаються в порядку спадання
впевненості, масштабованої за вагою. Кожне виявлення або приєднується до
наявного кластера, з поточною злитою рамкою якого має найбільше перекриття, за
IoU вище iou_thr і тієї самої мітки, або починає новий кластер. Злита рамка
кластера є середнім координат його учасників, зваженим за впевненістю, а його
оцінка є зваженим середнім або максимумом їхньої впевненості, масштабованим так,
щоб рамки, підтверджені меншою кількістю моделей, мали нижчі оцінки.
wbf_seeded вибирає початкові елементи кластерів через NMS з урахуванням класів
за iou_thr, призначає кожне виявлення початковому елементу тієї самої мітки з
найбільшим IoU, а потім так само зводить кожен кластер. Форми кластерів не
змінюються посеред проходу, тому вся операція є тензорною математикою з
фіксованою формою. Два варіанти збігаються, коли кластери однозначні, і можуть
трохи відрізнятися в ланцюжках перекривних кластерів.
nms_fusion без змін залишає рамку з найвищою впевненістю в кожній групі
перекриття. weights окремих моделей масштабує впевненість лише для ранжування
під час придушення, а рамки, що залишилися, зберігають початкові оцінки.
Власне злиття
fusion= також приймає викликаний об'єкт із тією самою сигнатурою, що й
операції вище. Його назва записується в ens.fusion або як "custom", коли
назви немає. Повернене значення перевіряється: воно має бути трійкою
(boxes, scores, labels) з узгодженими формами.