7.12. Постпроцесори

Мережа виявлення не видає рамки. Вона видає один або кілька тензорів, розташування яких залежить від архітектури, на якій навчалася модель – двовимірний тензор кандидатних передбачень для детектора сімейства YOLO, пара тензорів (boxes, scores) для детектора MediaPipe, плаский список координат ключових точок для мережі оцінки поз. Застосунок не може читати жоден з них безпосередньо; те, що він хоче – список рамок, список ключових точок, розбивку за класами – необхідно декодувати з необробленого тензора.

Цей декодер називається постпроцесором. Модуль ml.postprocessing групує їх за екосистемою джерела.

7.12.1. Darknet

ml.postprocessing.darknet декодує моделі епохи оригінального YOLO. YOLO v2 ввів ідеї сітки та якорів, які більшість пізніших детекторів успадкували у тій чи іншій формі, тому розташування v2 є найзрозумілішою відправною точкою.

YOLO v2 починає з поділу вхідного зображення на грубу сітку – розмітка 13×13 для канонічного вхідного зображення 416 пікселів, менша для менших моделей – і навчає мережу так, щоб кожна клітинка сітки відповідала за виявлення будь-якого об’єкта, центр якого знаходиться всередині неї. Просторове розташування вихідного тензора відображає розташування вхідного: одна позиція у виході на кожну клітинку зображення.

У кожній клітинці сітки мережа не передбачає рамку з нічого. Вона вибирає серед кількох заздалегідь обраних еталонних форм, які називаються якорями – фіксованих пар (width, height), отриманих офлайн кластеризацією розмірів рамок у навчальному наборі, щоб вони охоплювали типові об’єкти, які модель має виявляти. Завдання мережі в кожній клітинці – передбачити для кожного якоря невеликий відступ центру рамки всередині клітинки, масштаб ширини і висоти якоря, оцінку об’єктності (ймовірність того, що там щось є), і вектор ймовірностей по класах. Сітка 13×13 зі стандартними 5 якорями та 20 класами тому видає 13 * 13 * 5 * (4 + 1 + 20) = 21,125 чисел на інференс.

YoloV2 декодує це розташування: він обходить клітинки, застосовує зміщення та масштаби кожного якоря для відновлення абсолютних координат рамки, поєднує об’єктність з ймовірністю класу для отримання оцінки по класах, застосовує порогування та надсилає відібрані значення до NMS. Клас приймає аргумент конструктора anchors=, коли модель навчалася проти власної таблиці якорів, і в іншому випадку повертається до вбудованого стандарту. Варіанти, налаштовані для конкретних наборів класів, постачаються в тому самому підмодулі.

7.12.2. Ultralytics

ml.postprocessing.ultralytics декодує новіші покоління YOLO. YoloV8 читає вивід у стовпцево-майорному форматі, де кожен стовпець є одним передбаченням якоря, що містить координати рамки та вектор оцінок по класах – канал об’єктності, який несли попередні виходи YOLO, у v8 вилучено, а оцінки класів стоять самостійно. Розбір YOLOv8 крок за кроком проходить через декодування тензора. Старіші версії епохи Ultralytics постачаються в тому самому підмодулі для моделей, навчених на відповідних розташуваннях.

7.12.3. MediaPipe

ml.postprocessing.mediapipe декодує легке сімейство Google для обробки на пристрої. BlazeFace — це детектор обличь, описаний у hello-blazeface: швидкий детектор на основі якорів, що видає рамки та шість координат орієнтирів на кожне обличчя, повернутих як кортежі (box, score, keypoints) з орієнтирами, прикріпленими до кожної рамки, а не як окремий вихідний список. Моделі виявлення рук, орієнтирів та поз з того самого сімейства постачаються разом і мають ту саму форму повернення з прикріпленими ключовими точками.

7.12.4. Вибір постпроцесора

Правильний постпроцесор визначається архітектурою, на якій навчалася модель, а не тим, що хоче застосунок. YOLOv8 .tflite правильно декодується лише через YoloV8; BlazeFace .tflite – лише через BlazeFace. Вибір постпроцесора є частиною вибору моделі. Коли архітектура моделі не представлена вбудованим постпроцесором, написання власного є простим.

Мережі класифікації є винятком. Їхній єдиний вихідний тензор вже є тим, що хоче застосунок – список оцінок по класах – і постпроцесор не потрібен. Завантаження моделі без postprocess= та читання результату передбачення як плаского ndarray є правильним шляхом, як описано у розділі тензорний ввід/вивід.