7.3. Hello BlazeFace

BlazeFace — це нейронна мережа для виявлення облич з колекції Google MediaPipe. Один виклик інференсу повертає обмежувальний прямокутник навколо кожного виявленого обличчя разом із шістьма лицьовими ключовими точками — праве око, ліве око, ніс, рот, праве вухо, ліве вухо. Кожна OpenMV Cam з підтримкою нейронних мереж постачається з моделлю blazeface_front_128.tflite у флеш-пам’яті, тому запуск наскрізного детектора облич займає кілька рядків Python.

7.3.1. Повний скрипт

import csi
import ml
from ml.postprocessing.mediapipe import BlazeFace

csi0 = csi.CSI()
csi0.reset()
csi0.pixformat(csi.RGB565)
csi0.framesize(csi.VGA)
csi0.window((400, 400))

model = ml.Model("/rom/blazeface_front_128.tflite",
                 postprocess=BlazeFace(threshold=0.4))

while True:
    img = csi0.snapshot()
    for (x, y, w, h), score, keypoints in model.predict([img]):
        img.draw_rectangle((x, y, w, h), color=(0, 255, 0))
        ml.utils.draw_keypoints(img, keypoints, color=(255, 0, 0))

Це і є весь детектор облич. Більше нічого немає; скрипт захоплює кадр, передає його моделі, обходить повернутий список виявлень і малює обмежувальний прямокутник кожного обличчя разом із шістьма ключовими точками назад у кадр. Попередній перегляд в IDE показує прямокутники та ключові точки в реальному часі.

7.3.2. Що робить кожен рядок

Перші три рядки імпортують необхідні модулі. csi — це інтерфейс датчика камери; ml — модуль машинного навчання, про який йдеться в цьому розділі; BlazeFace — постпроцесор, що перетворює вихідні тензори BlazeFace на список обмежувальних прямокутників і ключових точок, по яких ітерується скрипт.

Наступні п’ять рядків налаштовують датчик. Камера скидається до відомого стану, переводиться в режим кольору RGB565, встановлюється роздільна здатність VGA, а потім обрізається до квадрата 400 на 400 пікселів. Вікно важливе: BlazeFace навчена на квадратних вирізках, і квадратний вхід узгоджує очікуваний мережею аспектний коефіцієнт із тим, що вона бачить у захопленому кадрі.

Рядок завантаження моделі відкриває файл моделі:

model = ml.Model("/rom/blazeface_front_128.tflite",
                 postprocess=BlazeFace(threshold=0.4))

ml.Model читає файл за вказаним шляхом — /rom/ є файловою системою у флеш-пам’яті, що розглядається далі — і повертає об’єкт моделі, на якому скрипт виконуватиме інференс. Ключове слово postprocess= реєструє постпроцесор BlazeFace; без нього predict повертав би вихідні тензори мережі, і застосунок мав би декодувати їх вручну. З ним predict повертає вже декодований результат. Аргумент threshold=0.4 постпроцесора задає мінімальну впевненість, яку мережа повинна повідомити, щоб виявлення було збережено; нижчі значення вловлюють слабкіші обличчя ціною більшої кількості хибних спрацювань.

Решта чотирьох рядків утворюють основний цикл. Кожна ітерація захоплює один кадр і запитує модель, що вона бачить:

img = csi0.snapshot()
for (x, y, w, h), score, keypoints in model.predict([img]):
    img.draw_rectangle((x, y, w, h), color=(0, 255, 0))
    ml.utils.draw_keypoints(img, keypoints, color=(255, 0, 0))

predict() приймає список входів (тут — одне захоплене зображення) і повертає список кортежів виявлень. Кожен кортеж містить обмежувальний прямокутник (x, y, w, h), оцінку впевненості score від нуля до одиниці, а також ndarray розміром (6, 2) з координатами ключових точок — праве око, ліве око, ніс, рот, праве вухо і ліве вухо в цьому порядку. Виклик малювання використовує draw_rectangle() — той самий примітив, яким завершувалися всі класичні детектори в розділі про зображення — щоб окреслити обличчя. ml.utils.draw_keypoints() — невелика допоміжна функція з утиліт ml, яка позначає кожну ключову точку хрестиком у позиції (x, y).

7.3.3. Що скрипт не говорить

Скрипт містить сім виконуваних рядків інференс-роботи після імпортів і налаштування датчика, але за цими сімома рядками прихована велика кількість арифметики. Захоплений кадр 400 на 400 RGB565 перетворюється на квантований 8-бітний тензор 128 на 128 перед надходженням до мережі; мережа виконує сотні операцій над десятками тисяч ваг; отримані тензори оцінок впевненості та зміщень прямокутників перетворюються на ранжований список непересічних обмежувальних прямокутників із прикріпленими ключовими точками перед поверненням predict. Кожне з цих перетворень — те, що застосунок може контролювати за потреби, і деякі з них потребують налаштування для будь-якої нестандартної моделі.

Наступні чотири підрозділи детально розглядають ці перетворення. По порядку:

  • Модуль ml — що надає ml.Model після завантаження моделі та де насправді знаходиться файл моделі на камері.

  • Конвеєр інференсу — чотири стадії кожного виклику predict().

  • Рушії інференсу — шляхи виконання через CPU та NPU, які виконують арифметику мережі.

  • Декодування виходу — постпроцесори, що перетворюють вихідні тензори у виявлення, по яких ітерувався цей скрипт.

Після завершення розділу читач зможе написати еквівалентний скрипт для моделі, що не постачається з камерою, декодувати тензор для якого постпроцесора ще не існує, і зрозуміти, чому конкретна модель виконується на 30 кадрів/с на одній камері і на 3 кадри/с — на іншій.