7.15. Scrierea propriului post-procesor#

Când catalogul nu acoperă un model – o rețea de cercetare a cărei dispunere de ieșire este personalizată, o modificare a unei arhitecturi existente, un tensor a cărui interpretare semantică este specifică aplicației – aplicația își furnizează propriul post-procesor. Protocolul este simplu: un obiect apelabil care preia (model, inputs, outputs) și returnează orice se așteaptă aplicația de la predict().

O clasă cu __call__ este forma convențională:

class MyPostprocessor:
    def __init__(self, threshold=0.5):
        self.threshold = threshold

    def __call__(self, model, inputs, outputs):
        ...
        return result

O funcție simplă funcționează și ea – motorul verifică doar că obiectul este apelabil.

7.15.1. Conectarea acestuia#

Două puncte de atașare. Argumentul cu cuvânt-cheie postprocess= de pe constructor leagă obiectul apelabil pentru fiecare apel predict() de pe model:

model = ml.Model("/rom/my_model.tflite",
                 postprocess=MyPostprocessor())

Pentru a suprascrie legarea pentru un singur apel – schimbând decodoarele fără a reîncărca modelul – transmite callback= direct lui predict:

result = model.predict([img], callback=MyOtherPostprocessor())

Semnătura obiectului apelabil este aceeași în oricare caz.

7.15.2. Ce primește obiectul apelabil#

  • model – instanța Model, utilă pentru parametrii de cuantizare (output_scale, output_zero_point, output_dtype) și dimensiunile de intrare (input_shape).

  • inputs – lista de intrări pe care aplicația le-a transmis lui predict(). Primul element este de obicei instanța legată Normalization; atributul său roi este ceea ce așteaptă NMS pentru remaparea casetelor înapoi în imaginea originală.

  • outputs – tensorii de ieșire bruți sub forma unei liste de obiecte ndarray, în tipul lor de date nativ. Ieșirile în virgulă mobilă sosesc așa cum sunt; ieșirile întregi sosesc cuantizate.

7.15.3. Aritmetică cuantizată#

Decodoarele livrate apelează toate aceiași asistenți din ml.utils, iar unul personalizat dorește de obicei același tipar: quantize() ridică un prag în virgulă mobilă în spațiul cuantizat al modelului, threshold() filtrează fără a dezcuantiza întregul tensor, iar dequantize() rulează o singură dată asupra supraviețuitorilor. sigmoid() și logit() sunt disponibile pentru rețele ale căror canale de ieșire sunt logit-uri pre-sigmoid (detectoarele MediaPipe sunt cazul canonic).

Pentru modele cu ieșiri în virgulă mobilă – capete de regresie, modele cu un strat final de dezcuantizare integrat – asistenții de cuantizare trec mai departe nemodificați, astfel încât același cod de post-procesor funcționează față de oricare tip de date fără tratare specială.

7.15.4. Valoarea returnată#

Orice returnează obiectul apelabil este ceea ce returnează predict(). Pentru decodoarele care emit casete, convenția este să se transmită candidații printr-un NMS și să se returneze listele sale pe clase – forma de apel pe care suprimarea non-maximelor o documentează și pe care parcurgerea pas cu pas a YOLOv8 o construiește în context. Pentru orice altceva, returnează orice consideră aplicația convenabil: un singur ndarray, un șir de etichetă, un tuplu (class, score, embedding), un dicționar.