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.