7.8. Vstup/výstup tenzorů

Engine přijímá na vstupní straně jediný tenzor a na výstupní straně produkuje jeden či více. Tenzory jsou objekty ndarray s tvarem, dtype a slovníkem deskriptorů, které představila kapitola o numpy. Jejich tvary a dtype pocházejí ze souboru modelu a jsou hlášeny přes input_shape / output_shape a input_dtype / output_dtype.

7.8.1. Kvantizace

Většina sítí, které kamera spouští, pracuje s kvantizovanými celočíselnými tenzory – int8 nebo uint8 – aby se vešly do rozpočtu RAM a výpočetního výkonu kamery. Kvantizovaný tenzor nese celočíselné hodnoty, jež reprezentují reálně hodnotová čísla pomocí měřítka a nulového bodu na úrovni tenzoru:

\[\text{real} = \text{scale} \times (q - \text{zero_point})\]
\[q = \mathrm{round}(\text{real} / \text{scale}) + \text{zero_point}\]

Měřítko a nulový bod pocházejí z kalibrace modelu v době trénování a jsou uloženy v souboru modelu. Jsou vystaveny jako input_scale, input_zero_point, output_scale a output_zero_point – každý seznam s jedním záznamem na každý vstupní nebo výstupní tenzor.

ml.utils.quantize() a ml.utils.dequantize() aplikují vzorce vůči zadanému výstupnímu indexu:

import ml.utils

real_tensor = ml.utils.dequantize(model, q_tensor, index=0)
q_tensor    = ml.utils.quantize(model, real_tensor, index=0)

Obě funkce vracejí hodnotu beze změny, když je výstupní dtype na daném indexu už float, takže je volání bezpečné bez ohledu na stav kvantizace modelu.

7.8.2. Co skript vidí na výstupní straně

To, co predict() vrací, závisí na tom, zda je registrován post-processor.

Bez post-processoru jsou surové celočíselné výstupy enginu automaticky dekvantovány na float a vráceny jako seznam objektů ndarray typu float. Skript přijímá reálně hodnotová čísla připravená ke čtení. To je správná cesta pro klasifikační sítě, jejichž jediný výstupní tenzor je už seznam skóre spolehlivosti na každou třídu, který aplikace prochází – není potřeba žádný dekódovací krok. Je to také snadná cesta k rychlému rozběhnutí neznámého modelu nebo k ad hoc prozkoumání z REPL.

Je-li registrován post-processor (přes postprocess= v konstruktoru nebo callback= ve volání predict), surové kvantizované tenzory se předají přímo volatelnému objektu post-processoru. Post-processor přijímá surové kvantizované tenzory a je zodpovědný za jakoukoli dekvantizaci, kterou potřebuje.

Toto rozdělení je výkonnostní volba. Automatická dekvantizace alokuje pro každý výstup nový tenzor float a projde každý prvek. Post-processor, který z každého tenzoru potřebuje jen pár hodnot – prahuje skóre spolehlivosti a poté dekóduje rámečky pro ty, co projdou – ušetří cenu dekvantizace zbytku. Dekodéry rámečků dodávané pod ml.postprocessing všechny volí tuto cestu a ml.utils.threshold() je vytvořena přesně pro tento případ: přijme kvantizovaný tenzor skóre a vrátí indexy, jejichž dekvantované hodnoty projdou reálně hodnotovým prahem, aniž by dekvantovala celý tenzor.