Poniższy dokument przedstawia specyfikację 8-bitowego schematu kwantyzacji TensorFlow Lite. Ma to na celu pomóc twórcom sprzętu w zapewnieniu sprzętowej obsługi wnioskowania ze skwantowanymi modelami TensorFlow Lite.
Podsumowanie specyfikacji
Dostarczamy specyfikację i możemy zapewnić pewne gwarancje dotyczące zachowania tylko wtedy, gdy specyfikacja będzie przestrzegana. Rozumiemy również, że inny sprzęt może mieć preferencje i ograniczenia, które mogą powodować niewielkie odchylenia podczas wdrażania specyfikacji, co skutkuje implementacjami, które nie są dokładne bitowo. Chociaż może to być akceptowalne w większości przypadków (i zapewnimy zestaw testów, które zgodnie z naszą najlepszą wiedzą obejmują tolerancje operacji, które zebraliśmy z kilku modeli), charakter uczenia maszynowego (i głębokiego uczenia się w najpowszechniejszych przypadku) uniemożliwia udzielenie jakichkolwiek twardych gwarancji.
Kwantyzacja 8-bitowa przybliża wartości zmiennoprzecinkowe za pomocą następującego wzoru.
\[real\_value = (int8\_value - zero\_point) \times scale\]
Wagi na oś (inaczej na kanał w Conv ops) lub wagi na tensor są reprezentowane przez wartości uzupełnienia do dwóch int8
w zakresie [-127, 127]
z punktem zerowym równym 0. Aktywacje/wejścia na tensor są reprezentowane przez int8
wartości uzupełnienia do dwóch w zakresie [-128, 127]
, z punktem zerowym w zakresie [-128, 127]
.
Istnieją inne wyjątki dla określonych operacji, które opisano poniżej.
Liczba całkowita ze znakiem vs liczba całkowita bez znaku
Kwantyzacja TensorFlow Lite będzie przede wszystkim priorytetem dla narzędzi i jąder do kwantyzacji int8
dla 8-bitów. Ma to na celu wygodę symetrycznej kwantyzacji reprezentowanej przez punkt zerowy równy 0. Dodatkowo wiele backendów ma dodatkowe optymalizacje dla akumulacji int8xint8
.
Na oś vs na tensor
Kwantyzacja na tensor oznacza, że na cały tensor będzie przypadać jedna skala i/lub punkt zerowy. Kwantyzacja na osi oznacza, że będzie jedna skala i/lub zero_point
na wycinek w quantized_dimension
. Skwantowany wymiar określa wymiar kształtu tensora, któremu odpowiadają skale i punkty zerowe. Na przykład tensor t
z dims=[4, 3, 2, 1]
z parametrami kwantyzacji: scale=[1.0, 2.0, 3.0]
, zero_point=[1, 2, 3]
, quantization_dimension=1
będzie kwantowany w poprzek drugi wymiar t
:
t[:, 0, :, :] will have scale[0]=1.0, zero_point[0]=1
t[:, 1, :, :] will have scale[1]=2.0, zero_point[1]=2
t[:, 2, :, :] will have scale[2]=3.0, zero_point[2]=3
Często quantized_dimension
jest kanałem output_channel
wag splotów, ale teoretycznie może to być wymiar odpowiadający każdemu iloczynowi skalarnemu w implementacji jądra, umożliwiając większą szczegółowość kwantyzacji bez wpływu na wydajność. Zapewnia to znaczną poprawę dokładności.
TFLite obsługuje każdą oś dla rosnącej liczby operacji. W momencie tworzenia tego dokumentu dostępna była obsługa Conv2d i DepthwiseConv2d.
Symetryczny kontra asymetryczny
Aktywacje są asymetryczne: mogą mieć punkt zerowy w dowolnym miejscu w zakresie int8
ze znakiem [-128, 127]
. Wiele aktywacji ma charakter asymetryczny, a punkt zerowy jest stosunkowo niedrogim sposobem na skuteczne uzyskanie dodatkowej binarnej precyzji. Ponieważ aktywacje są mnożone tylko przez stałe wagi, stałą wartość punktu zerowego można dość mocno zoptymalizować.
Wagi są symetryczne: punkt zerowy musi być równy 0. Wartości wag są mnożone przez dynamiczne wartości wejściowe i aktywacyjne. Oznacza to, że istnieje nieunikniony koszt w czasie działania związany z pomnożeniem punktu zerowego ciężaru przez wartość aktywacji. Wymuszając, że punkt zerowy wynosi 0, możemy uniknąć tego kosztu.
Wyjaśnienie matematyki: jest to podobne do sekcji 2.3 w arXiv:1712.05877 , z tą różnicą, że pozwalamy, aby wartości skali były przypisane do osi. Można to łatwo uogólnić w następujący sposób:
\(A\) jest \(m \times n\) macierz skwantowanych aktywacji.
\(B\) jest \(n \times p\) macierz skwantowanych wag.
Rozważ pomnożenie \(j\)rząd \(A\), \(a_j\) przez \(k\)kolumna\(B\), \(b_k\), obie długości \(n\). Skwantowane wartości całkowite i wartości punktów zerowych to \(q_a\), \(z_a\) I \(q_b\), \(z_b\) odpowiednio.
\[a_j \cdot b_k = \sum_{i=0}^{n} a_{j}^{(i)} b_{k}^{(i)} = \sum_{i=0}^{n} (q_{a}^{(i)} - z_a) (q_{b}^{(i)} - z_b) = \sum_{i=0}^{n} q_{a}^{(i)} q_{b}^{(i)} - \sum_{i=0}^{n} q_{a}^{(i)} z_b - \sum_{i=0}^{n} q_{b}^{(i)} z_a + \sum_{i=0}^{n} z_a z_b\]