7.3. Hello BlazeFace¶
BlazeFace je neuronová síť pro detekci obličejů z kolekce MediaPipe od Googlu. Jediné volání inference vrátí ohraničující obdélník kolem každého detekovaného obličeje spolu se šesti obličejovými body – pravé oko, levé oko, nos, ústa, pravé ucho, levé ucho. Každá OpenMV Cam, která se dodává s podporou neuronových sítí, nese ve flash paměti model blazeface_front_128.tflite, takže spuštění kompletního detektoru obličejů zabere pár řádků Pythonu.
7.3.1. Celý skript¶
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))
To je celý detektor obličejů. Nic víc v něm není; skript zachytí snímek, předá jej modelu, projde vrácený seznam detekcí a vykreslí ohraničující obdélník každého obličeje plus jeho šest bodů zpět do snímku. Náhled v IDE zobrazuje rámečky a body v reálném čase.
7.3.2. Co dělá každý řádek¶
První tři řádky importují moduly, které skript potřebuje. csi je rozhraní senzoru kamery; ml je modul strojového učení, o kterém je zbytek této kapitoly; BlazeFace je post-procesor, který surové výstupní tenzory BlazeFace převádí na seznam ohraničujících rámečků a bodů, přes který skript iteruje.
Dalších pět řádků konfiguruje senzor. Kamera se resetuje do známého stavu, nastaví se na barvu RGB565, nastaví se na rozlišení VGA a poté se vyřízne okno na čtverec 400 na 400. Na okně záleží: BlazeFace byla trénována na čtvercových výřezech a poskytnutí čtvercového vstupu sladí očekávaný poměr stran sítě s tím, co vidí v zachyceném snímku.
Řádek načítání modelu otevírá soubor modelu:
model = ml.Model("/rom/blazeface_front_128.tflite",
postprocess=BlazeFace(threshold=0.4))
ml.Model přečte soubor na zadané cestě – /rom/ je souborový systém umístěný ve flash paměti, popsaný později – a vrátí objekt modelu, proti kterému bude skript spouštět inference. Klíčové slovo postprocess= registruje post-procesor BlazeFace; bez něj by predict vrátil surové výstupní tenzory sítě a aplikace by je musela dekódovat ručně. S ním predict vrací dekódovaný výsledek přímo. Argument threshold=0.4 na post-procesoru nastavuje minimální spolehlivost, kterou musí síť ohlásit, než je detekce ponechána; nižší hodnoty zachytí slabší obličeje za cenu více falešně pozitivních detekcí.
Zbývající čtyři řádky tvoří hlavní smyčku. Každý její průchod zachytí jeden snímek a zeptá se modelu, co vidí:
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() přijímá seznam vstupů (zde jeden zachycený obraz) a vrací seznam n-tic detekcí. Každá n-tice obsahuje ohraničující obdélník (x, y, w, h), spolehlivost score mezi nulou a jedničkou a ndarray o rozměru (6, 2) souřadnic bodů – pravé oko, levé oko, nos, ústa, pravé ucho a levé ucho v tomto pořadí. Volání kreslení používá draw_rectangle() – stejnou primitivu, kterou končil každý klasický detektor v kapitole o obrazu – k obrysu obličeje. ml.utils.draw_keypoints() je malý pomocník z ml utilit, který každý klíčový bod označí křížkem na jeho pozici (x, y).
7.3.3. Co skript neříká¶
Skript představuje sedm spustitelných řádků inferenční práce za importy a nastavením senzoru, ale uvnitř těchto sedmi řádků se odehrává velké množství aritmetiky. Zachycený snímek 400 na 400 v RGB565 se před dosažením sítě stane kvantovaným 8bitovým tenzorem 128 na 128; síť provede stovky operací proti desítkám tisíc vah; výsledné tenzory spolehlivostí a posunů rámečků se před návratem predict stanou seřazeným seznamem nepřekrývajících se ohraničujících rámečků s připojenými body. Každou z těchto transformací může aplikace řídit, pokud to potřebuje, a několik z nich je nutné vyladit pro jakýkoli nestandardní model.
Následující čtyři podkapitoly tyto transformace rozebírají. V pořadí:
Modul ml – co
ml.Modelzpřístupňuje po načtení modelu a kde soubor modelu na kameře vlastně žije.Inferenční řetězec – čtyři fáze každého volání
predict().Inferenční enginy – cesty CPU a NPU, které provádějí aritmetiku sítě.
Dekódování výstupu – post-procesory, které převádějí surové výstupní tenzory na detekce, přes které tento skript iteroval.
Na konci kapitoly dokáže čtenář napsat ekvivalentní skript pro model, který se s kamerou nedodával, dekódovat tenzor, jehož post-procesor zatím neexistuje, a uvažovat o tom, proč určitý model běží na jedné kameře při 30 FPS a na jiné při 3 FPS.