7.8. I/O dei tensori¶
Il motore accetta un singolo tensore sul lato input e ne produce uno o più sul lato output. I tensori sono oggetti ndarray con la forma, il dtype e il vocabolario di descrittori introdotti nel capitolo su numpy. Le loro forme e i loro dtype provengono dal file del modello e sono riportati tramite input_shape / output_shape e input_dtype / output_dtype.
7.8.1. Quantizzazione¶
La maggior parte delle reti che la camera esegue opera su tensori interi quantizzati – int8 o uint8 – per rientrare nella RAM e nel budget di calcolo della camera. Un tensore quantizzato contiene valori interi che rappresentano numeri a valori reali attraverso una scala e uno zero point per tensore:
La scala e lo zero point provengono dalla calibrazione al tempo dell’addestramento del modello e sono memorizzati nel file del modello. Sono esposti come input_scale, input_zero_point, output_scale e output_zero_point – ognuno un elenco con una voce per ogni tensore di input o di output.
ml.utils.quantize() e ml.utils.dequantize() applicano le formule rispetto a un indice di output specificato:
import ml.utils
real_tensor = ml.utils.dequantize(model, q_tensor, index=0)
q_tensor = ml.utils.quantize(model, real_tensor, index=0)
Entrambe le funzioni restituiscono il valore invariato quando il dtype di output all’indice indicato è già float, quindi la chiamata è sicura indipendentemente dallo stato di quantizzazione del modello.
7.8.2. Cosa vede lo script sul lato output¶
Ciò che predict() restituisce dipende dal fatto che sia registrato o meno un post-processor.
Senza post-processor, gli output interi grezzi del motore vengono dequantizzati automaticamente in float e restituiti come elenco di oggetti ndarray float. Lo script riceve numeri a valori reali pronti per essere letti. Questo è il percorso corretto per le reti di classificazione, il cui singolo tensore di output è già un elenco di punteggi di confidenza per classe su cui l’applicazione itera – nessuna fase di decodifica necessaria. È anche il percorso più semplice per mettere rapidamente in esecuzione un modello sconosciuto o per un’ispezione estemporanea dal REPL.
Con un post-processor registrato (tramite postprocess= sul costruttore o callback= sulla chiamata a predict), i tensori quantizzati grezzi vengono passati direttamente all’oggetto invocabile del post-processor. Il post-processor riceve i tensori quantizzati grezzi ed è responsabile di qualunque dequantizzazione gli serva.
La suddivisione è una scelta di prestazioni. La dequantizzazione automatica alloca un nuovo tensore float per ogni output e percorre ogni elemento. Un post-processor che necessita solo di pochi valori da ogni tensore – applicare una soglia ai punteggi di confidenza e poi decodificare i box per i sopravvissuti – evita il costo di dequantizzare il resto. I decodificatori di box forniti in ml.postprocessing seguono tutti questa strada, e ml.utils.threshold() è costruito esattamente per questo caso: prende un tensore di punteggi quantizzato e restituisce gli indici i cui valori dequantizzati superano una soglia a valore reale, senza dequantizzare l’intero tensore.