7.7. Normalizace

ml.Model.predict() přijímá seznam vstupů, protože některé sítě mají více než jeden vstupní tenzor, ale seznam nemá jak vnitřně nést argumenty specifické pro jednotlivé vstupy – neexistuje místo pro kwarg ve smyslu „ořízni tento vstup na (x, y, w, h), ale ostatní vstupy ponech beze změny“. ml.preprocessing.Normalization je obal, který tuto mezeru vyplňuje. Instance Normalization drží parametry pro jeden vstup; skript předá zabalený vstup v seznamu pro predict, kdykoli potřebuje cokoli jiného než výchozí hodnoty.

Nejběžnějším důvodem, proč po ní sáhnout, je oříznout konkrétní oblast zachyceného snímku do sítě namísto celého obrazu.

7.7.1. Parametry

Normalization(scale=(0.0, 1.0),
              mean=(0.0, 0.0, 0.0),
              stdev=(1.0, 1.0, 1.0),
              roi=None)
  • roi – obdélník (x, y, w, h) ve zdrojovém snímku k oříznutí před změnou velikosti. Výchozí hodnotou je celý snímek. Většina použití Normalization nastavuje pouze tento parametr.

  • scale – rozsah (min, max), který vstupní tenzory s pohyblivou řádovou čárkou očekávají po normalizaci. Rozsah pixelů 0..255 se do tohoto rozsahu mapuje lineárně. Běžné hodnoty jsou (0.0, 1.0) pro sítě trénované s ReLU a (-1.0, 1.0) pro symetricky normalizované sítě.

  • mean – průměr (R, G, B) na každý kanál odečtený od obrazu po aplikaci měřítka. Odpovídá statistikám kanálů, vůči nimž byla síť trénována – kanonickým příkladem je (0.485, 0.456, 0.406) pro sítě odvozené z ImageNet. Sítě ve stupních šedi redukují průměr na hodnotu jasu pomocí standardního 0.299*R + 0.587*G + 0.114*B.

  • stdev – směrodatná odchylka (R, G, B) na každý kanál, kterou se obraz dělí po odečtení průměru, opět odpovídající trénovacím statistikám sítě. Pro sítě ve stupních šedi se redukuje na jas stejným způsobem.

7.7.2. Kdy na parametrech záleží

scale, mean a stdev se ignorují, když je input_dtype sítě int8 nebo uint8. U sítí s celočíselným vstupem se bajty oříznutého obrazu zapisují přímo do tenzoru a o převod z celého čísla na reálné se starají vlastní input_scale a input_zero_point sítě. Tyto tři parametry mají význam jen tehdy, když síť očekává vstup s pohyblivou řádovou čárkou.

roi se čte v každém případě – řídí, která část zdrojového snímku se dostane do sítě, bez ohledu na vstupní dtype.

7.7.3. ROI a změna velikosti

ROI se bilineárně škáluje ze svých zdrojových rozměrů na vstupní rozměry sítě. Obraz se vycentruje v cíli a škálování cíl vyplní – nezachovává poměr stran. Nečtvercová ROI předaná čtvercovému vstupu sítě vyjde vodorovně nebo svisle roztažená.

Zda na roztažení záleží, závisí na síti. Modely detekce obličejů a orientačních bodů jako rodina MediaPipe (BlazeFace, FaceLandmarks, HandLandmarks, MoveNet) byly trénovány vůči čtvercovým výřezům a rychle degradují, když je poměr stran vstupu mimo; pro ty musí aplikace dodat čtvercovou ROI – buď zachycením ve čtvercovém framesize přes window(), nebo oříznutím parametrem roi=. Detektory objektů z rodiny YOLO jsou obvykle trénovány s augmentací zahrnující náhodná roztažení a přijímají nečtvercové ROI bez velké ztráty přesnosti; předat celý zachycený snímek přímo dovnitř je obvykle v pořádku.

Když vstupní rozměry sítě přesně odpovídají ROI, škálování se zhroutí na kopii, což je nejlevnější případ.

7.7.4. Přepsání výchozího nastavení

predict() automaticky zabalí každý vstup image.Image do Normalization() – s výše uvedenými výchozími parametry. Většina modelů dodávaných s kamerou byla trénována vůči rozsahům pixelů, jež výchozí hodnoty už pokrývají, takže běžným případem je předat obraz přímo:

result = model.predict([img])

Pro použití vlastní ROI – nejběžnější přepsání – vytvořte Normalization s nastavenou ROI a navažte na ni obraz:

from ml.preprocessing import Normalization

norm = Normalization(roi=(80, 60, 160, 120))
result = model.predict([norm(img)])

Chcete-li sladit statistiky kanálů z doby trénování sítě, nastavte parametry s pohyblivou řádovou čárkou:

norm = Normalization(scale=(0.0, 1.0),
                     mean=(0.485, 0.456, 0.406),
                     stdev=(0.229, 0.224, 0.225))

result = model.predict([norm(img)])

Volání instance Normalization na obrazu vrátí novou navázanou instanci, ze které engine naplní tenzor. Navázaná instance je to, co predict přijímá namísto surového obrazu, a protože jde o objekt specifický pro jeden vstup, síť s více vstupy může v témž seznamu pro predict mísit obrazy s různými ROI.

U sítí, které očekávají vstupy už vyprodukované aplikací v podobě tenzoru – buffer z periferie, ndarray vypočtený jinou pipeline, neobrazová číselná data – přeskočte Normalization úplně a předejte ndarray nebo volatelný objekt, který jej produkuje. predict() je propustí do enginu bez zabalení.