7.12. Jälkikäsittelijät

Tunnistusverkko ei tuota laatikoita. Se tuottaa yhden tai useamman tensorin, joiden asettelu riippuu arkkitehtuurista, jota vasten malli on koulutettu – 2-ulotteisen ehdokasennusteiden tensorin YOLO-perheen tunnistimelle, parin (boxes, scores)-tensoreita MediaPipe-tunnistimelle, litteän listan avainpisteiden koordinaatteja asentoverkolle. Sovellus ei voi lukea mitään näistä suoraan; se mitä se haluaa – listan laatikoita, listan avainpisteitä, luokkakohtaisen erittelyn – on dekoodattava raakatensorista.

Tämä dekooderi on jälkikäsittelijä. ml.postprocessing-moduuli ryhmittelee ne lähde-ekosysteemin mukaan.

7.12.1. Darknet

ml.postprocessing.darknet dekoodaa alkuperäisen YOLO-aikakauden malleja. YOLO v2 esitteli ruudukon ja ankkurin ideat, jotka useimmat myöhemmät tunnistimet perivät jossain muodossa, joten v2-asettelu on selkein lähtökohta.

YOLO v2 aloittaa jakamalla syötekuvan karkeaan ruudukkoon – 13-kertaa-13-asetteluun kanonisella 416-pikselin syötteellä, pienemmäksi pienemmissä malleissa – ja kouluttaa verkon niin, että jokainen ruudukon solu vastaa minkä tahansa kohteen tunnistamisesta, jonka keskipiste osuu sen sisään. Ulostulotensorin spatiaalinen asettelu peilaa syötteen asettelua: yksi sijainti ulostulossa kutakin kuvan solua kohti.

Kussakin ruudukon solussa verkko ei ennusta laatikkoa tyhjästä. Se valitsee useista ennalta valituista referenssimuodoista, joita kutsutaan ankkureiksi – kiinteistä (width, height)-pareista, jotka on johdettu offline-tilassa klusteroimalla koulutusjoukon laatikkokoot niin, että ne kattavat tyypilliset kohteet, joita mallin odotetaan näkevän. Verkon tehtävänä kussakin solussa on ennustaa jokaiselle ankkurille pieni siirtymä laatikon keskipisteeseen solun sisällä, skaala ankkurin leveydelle ja korkeudelle, objectness-pisteytys (todennäköisyys, että jotain on siellä) sekä luokkakohtainen todennäköisyysvektori. 13-kertaa-13-ruudukko oletusarvoisilla 5 ankkurilla ja 20 luokalla tuottaa siis 13 * 13 * 5 * (4 + 1 + 20) = 21,125 lukua päättelyä kohti.

YoloV2 dekoodaa tämän asettelun: se käy solut läpi, soveltaa kunkin ankkurin siirtymät ja skaalat absoluuttisten laatikkokoordinaattien palauttamiseksi, yhdistää objectness-arvon luokkatodennäköisyyteen luokkakohtaiseksi pisteytykseksi, kynnystää ja työntää säilyneet NMS:lle. Luokka ottaa anchors=-konstruktoriargumentin, kun malli on koulutettu mukautettua ankkuritaulukkoa vasten, ja muuten turvautuu sisäänrakennettuun oletukseen. Tietyille luokkajoukoille viritetyt variantit toimitetaan samassa alimoduulissa.

7.12.2. Ultralytics

ml.postprocessing.ultralytics dekoodaa uudemmat YOLO-sukupolvet. YoloV8 lukee sarakejärjestyksessä olevan ulostulon, jossa jokainen sarake on yksi ankkuriennuste, joka sisältää laatikon koordinaatit ja luokkakohtaisen pisteytysvektorin – objectness-kanava, jota aiemmat YOLO-ulostulot kantoivat, on pudotettu pois v8:ssa, ja luokkapisteytykset seisovat yksinään. YOLOv8:n läpikäynti käy dekoodauksen läpi tensori tensorilta. Vanhemmat Ultralytics-aikakauden versiot toimitetaan samassa alimoduulissa malleille, jotka on koulutettu niiden asetteluja vasten.

7.12.3. MediaPipe

ml.postprocessing.mediapipe dekoodaa Googlen kevyen laitteella toimivan perheen. BlazeFace on kasvotunnistin, joka käsitellään dokumentissa hello-blazeface: nopea ankkuripohjainen tunnistin, joka tuottaa laatikot ja kuusi maamerkkikoordinaattia kasvoja kohti, palautettuna (box, score, keypoints)-monikoina, joissa maamerkit on liitetty kuhunkin laatikkoon eikä erillisenä ulostulolistana. Saman perheen käsientunnistus-, maamerkki- ja asentomallit toimitetaan sen rinnalla ja noudattavat samaa liitettyjen avainpisteiden palautusmuotoa.

7.12.4. Sellaisen valitseminen

Oikean jälkikäsittelijän määrää arkkitehtuuri, jota vasten malli on koulutettu, ei se, mitä sovellus haluaa. YOLOv8 .tflite dekoodautuu oikein vain YoloV8-luokan kautta; BlazeFace .tflite vain BlazeFace-luokan kautta. Jälkikäsittelijän valitseminen on osa mallin valitsemista. Kun mallin arkkitehtuuria ei edusta mikään mukana toimitettu jälkikäsittelijä, oman kirjoittaminen on suoraviivaista.

Luokitteluverkot ovat poikkeus. Niiden yksittäinen ulostulotensori on jo se, mitä sovellus haluaa – lista luokkakohtaisia pisteytyksiä – eikä jälkikäsittelijää tarvita. Mallin lataaminen ilman postprocess=-argumenttia ja ennustustuloksen lukeminen litteänä ndarray-taulukkona on oikea polku, kuten tensorin I/O käsitteli.