7.6. Anatomie van predict

Model.predict(inputs, *, callback=None) is waar het geladen modelobject daadwerkelijk werk verricht. Tussen het binnenkomen van de invoer en het uitkomen van het resultaat draaien drie fasen achter elkaar: pre-process, engine dispatch, post-process. Twee van de drie nemen parameters die het script rechtstreeks aanstuurt; de engine in het midden wordt door de cam bepaald.

Een horizontale stroom van vijf verbonden vakken van links naar rechts. Het meest linkse is "Image input"; een pijl leidt naar "Pre-process" met ondertitel "Normalization"; een pijl leidt naar "Engine" met ondertitel "TFLM / STAI"; een pijl leidt naar "Post-process" met ondertitel "postprocess="; en een laatste pijl leidt naar "Result". De drie middelste fasen dragen een label eronder -- "user-controllable" onder Pre-process, "automatic" onder Engine, en "user-controllable" onder Post-process.

De drie fasen van predict(). Pre-process en post-process nemen parameters die het script aanstuurt; de engine in het midden ligt vast door de cam.

7.6.1. Pre-process

De pre-process-fase zet elke invoer om in de dichte tensor die het netwerk verwacht. De meest voorkomende invoer is een image.Image, vastgelegd in RGB565. De fase snijdt deze bij en schaalt deze naar de input_shape van het netwerk, converteert van RGB565 naar het kanaalformaat waarop het netwerk is getraind (RGB888 voor de meeste visienetwerken), past schaal en offset per kanaal toe en – wanneer het netwerk integer-invoer verwacht – kwantiseert in dezelfde doorgang naar de input_dtype van het model. Netwerken die voor float-invoer zijn getraind, slaan de kwantisatiestap over en ontvangen het schaal-en-offsetresultaat rechtstreeks.

De standaard ml.preprocessing.Normalization leest de invoer-dtype van het model en voert automatisch de juiste transformatie uit. Een handmatig afgestelde Normalization overschrijft de waarden voor schaal, gemiddelde en standaardafwijking voor modellen die zijn getraind tegen aangepaste kanaalstatistieken (de van ImageNet afgeleide gemiddelden en standaardafwijkingen zijn een veelvoorkomend geval). Een gewone callable overschrijft de fase volledig – handig wanneer de invoer helemaal geen afbeelding is of wanneer de applicatie de dichte tensor zelf al heeft geproduceerd.

7.6.2. Engine dispatch

De engine-fase voert het netwerk uit. Naar welke engine deze dispatcht, ligt vast door de cam: de H7 en RT1062 draaien TFLM (de TensorFlow Lite for Microcontrollers-interpreter, die waar ze bestaan ARM-geoptimaliseerde CMSIS-NN-kernels dispatcht); de AE3 draait dezelfde TFLM-interpreter met zijn Cortex-M55-fallback en de Ethos-U-NPU die elke operator afhandelt die de offline Vela-compiler voor de versneller heeft getagd; de N6 draait STAI, ST’s runtime voor de speciaal gebouwde NPU van de N6.

Het script kiest de engine niet. De engine die met de cam wordt meegeleverd, draait elk model dat de cam laadt.

7.6.3. Post-process

De post-process-fase zet de ruwe uitvoertensoren van het netwerk weer om in een bruikbaar resultaat. Het standaardgedrag is om elke uitvoertensor te dekwantiseren naar drijvende komma (of deze ongewijzigd door te geven voor netwerken met float-uitvoeren) en ze als een lijst van ndarray-objecten terug te geven. De meeste applicaties registreren een post-processor – een callable die de uitvoerindeling van het netwerk kent – om de tensoren te decoderen naar de resultaatvorm waarop de applicatie reageert: een lijst met begrenzingsvakken, een lijst met sleutelpunten, een lijst met klassen.

Het script stuurt deze fase op twee manieren aan. Het sleutelwoord postprocess= op de constructor registreert een post-processor die bij elke aanroep draait. Het sleutelwoord callback= op predict() overschrijft de geregistreerde post-processor voor slechts één aanroep – handig om tussen meerdere decoders te wisselen zonder het model opnieuw te laden. Beide vormen ontvangen (model, inputs, outputs) en geven terug wat de applicatie verwacht.

7.6.4. Wat het script aanstuurt

Pre-process en post-process zijn de twee handvatten van het script. De standaard pre-processor handelt de meeste visiemodellen af; de juiste post-processor voor een gegeven netwerkfamilie wordt gekozen uit de catalogus onder ml.postprocessing. De engine in het midden wordt door de build bepaald en draait op dezelfde manier, ongeacht wat het script vraagt.