Kwantyzacja StableHLO

Typy kwantyzacji w StableHLO

Kwantyzacja to technika optymalizacji modeli uczenia maszynowego polegająca na przekształcaniu liczb zmiennoprzecinkowych (takich jak te używane w oryginalnych modelach) w liczby całkowite o mniejszej precyzji. Zmniejsza to zużycie pamięci i przyspiesza obliczenia, dzięki czemu modele są bardziej wydajne w przypadku wdrażania na urządzeniach o ograniczonych zasobach.

Kwantyzacja StableHLO jest zgodna ze specyfikacją kwantyzacji LiteRT i wykorzystuje jednolity schemat kwantyzacji z obsługą kwantyzacji na poziomie tensora i osi. Dziedziczy wyrażenie typu z dialektu Quant MLIR, co zapewnia standardowy sposób reprezentowania typów danych poddanych kwantyzacji.

Kwantyzacja jednolita mapuje wartości zmiennoprzecinkowe na liczby całkowite przy użyciu jednolitego rozmiaru kroku, co daje równomiernie rozmieszczone wartości skwantyzowane. Osiąga się to dzięki relacji afinicznej z użyciem 2 kluczowych parametrów kwantyzacji.

Kwantyzacja jednolita upraszcza reprezentację liczb zmiennoprzecinkowych przez mapowanie ich na równomiernie rozmieszczone liczby całkowite. Mapowanie to jest realizowane za pomocą transformacji afinicznej, która wykorzystuje 2 kluczowe parametry: skalępunkt zerowy. Skala określa rozmiar kroku między kolejnymi skwantowanymi wartościami. Mniejsza skala oznacza, że skwantowane wartości są bliżej siebie. Punkt zerowy określa wartość całkowitą, która reprezentuje zero w oryginalnej przestrzeni liczb zmiennoprzecinkowych.

Związek między pierwotną wartością zmiennoprzecinkową (real_value) a skwantowaną wartością całkowitą (quantized_value) w kwantyzacji równomiernej jest następujący:

real_value = scale * (quantized_value - zero_point)

Kwantyzacja na tensor

W kwantyzacji na tensor używa się jednej skali i jednego punktu zerowego dla wszystkich wartości w tensorze. Skwantowany typ na tensor jest wyrażany w StableHLO jako:

quant.uniform scale:zero_point>

Przykład: !quant.uniform<i8:f32, 0.01:50>

Jest to 8-bitowa liczba całkowita (i8) używana do przechowywania 32-bitowej liczby zmiennoprzecinkowej (f32) przy użyciu skali 0.01 i punktu zerowego 50.

Kwantyzacja na osi

Kwantyzacja na osi zapewnia bardziej precyzyjne podejście w porównaniu z kwantyzacją na tensorze. Kwantyzacja na osi przypisuje osobne skale i punkty zerowe do wycinków wzdłuż określonego wymiaru quantized_dimension tensora, zamiast używać jednej skali i jednego punktu zerowego dla całego tensora. Jest to szczególnie przydatne, gdy wartości znacznie różnią się w zależności od wymiarów, ponieważ pozwala lepiej zachować informacje i dokładność.

Rozważ tensor t o rozmiarach wymiarów [4, 3, 2]. Ten tensor kwantyzujemy wzdłuż drugiego wymiaru (quantized_dimension = 1). Oznacza to, że będziemy mieć 3 wycinki (ponieważ drugi wymiar ma rozmiar 3), z których każdy będzie miał własną skalę i punkt zerowy:

t[:, 0, :]: This slice gets scale[0] and zero_point[0].
t[:, 1, :]: This slice gets scale[1] and zero_point[1].
t[:, 2, :]: This slice gets scale[2] and zero_point[2].

W StableHLO typ skwantowany na osi jest wyrażany w ten sposób:

quant.uniform {scale0:zero_point0, scale1:zero_point1, ...}>

gdzie długość scale:zero_point odpowiada liczbie wycinków wzdłuż quantized_dimension tensora zawierającego.

Przykład: tensor<4x3x2x!quant.uniform<i8:f32:1, {0.2:20, 0.1:10, 0.3:30}>>

Przekształcenia kwantyzacji w StableHLO

StableHLO udostępnia kilka etapów kompilacji, które umożliwiają różne przekształcenia i optymalizacje związane z kwantyzacją, co daje Ci elastyczność w obsłudze skwantyzowanych modeli. Są to:

stablehlo-legalize-qdq-to-quantized-op

Ten etap łączy wspólny wzorzec w modelach skwantyzowanych: operację dekwantyzacji, po której następuje operacja zmiennoprzecinkowa, a na końcu operacja kwantyzacji, w jedną operację skwantyzowaną. Szczegóły

stablehlo-legalize-quantized-op-to-qdq

Ten karnet działa odwrotnie niż poprzedni. Rozkłada operację skwantowaną na równoważną sekwencję operacji odwrotnej kwantyzacji, operacji zmiennoprzecinkowej i kwantyzacji.Szczegóły

stablehlo-legalize-quant-to-math

Ten etap przekształca operacje StableHLO na typach poddanych kwantyzacji w odpowiednie operacje na typach całkowitych. W zasadzie implementuje arytmetykę kwantyzacji za pomocą standardowych operacji matematycznych. Ten rozkład jest przydatny w przypadku systemów, które nie obsługują kwantyzacji natywnie, ale mogą używać arytmetyki kwantyzacji do wyrażania semantyki modeli skwantyzowanych. Szczegóły

stablehlo-quant-legalize-to-tosa-rescale

StableHLO umożliwia legalizację operacji kwantyzowanych do ich odpowiednich reprezentacji w dialekcie TOSA. Legalizacja ta ułatwia zgodność i interoperacyjność między StableHLO a TOSA. Ten etap strategicznie przekształca skwantowane operacje StableHLO w połączenie operacji StableHLO i TOSA, przy czym dialekt TOSA jest używany głównie w przypadku operacji rescale. Operacja tosa.rescale odgrywa kluczową rolę w dostosowywaniu skali i punktu zerowego wartości skwantowanych, umożliwiając dokładne przedstawienie skwantowanych danych w ramach TOSA. Szczegóły

tosa-rescale-legalize-to-stablehlo

Ten etap przekształca operacje zmiany skali TOSA na operacje matematyczne StableHLO. Jednym z głównych przypadków użycia tego przekazywania jest umożliwienie interpreterowi StableHLO oceny programów zawierających operacje zmiany skali TOSA. Szczegóły

Ocena programów skwantyzowanych

Interpreter referencyjny StableHLO może wydajnie wykonywać programy zawierające operacje kwantyzowane. Aby to osiągnąć, najpierw przekształca program w równoważną reprezentację, używając tylko operacji na liczbach całkowitych. Proces ten obejmuje serię przejść kompilatora, które przekształcają program przed jego interpretacją.

W zasadzie interpreter wykorzystuje stablehlo-legalize-quant-to-math przekazywanie, aby przekształcić operacje skwantowane w odpowiednie implementacje arytmetyki liczb całkowitych. Ten etap wprowadza operacje transmisji CHLO do obsługi mnożenia/dzielenia skali i dodawania punktu zerowego. Aby zapewnić zgodność z interpreterem StableHLO, te operacje CHLO są następnie legalizowane do operacji StableHLO. Wprowadza to operacje związane z kształtem, które są następnie kanonizowane i optymalizowane za pomocą serii przebiegów kanonizacji.

Pełna sekwencja przebiegów w tym procesie obniżania wygląda tak:

stablehlo-legalize-quant-to-math
chlo-legalize-to-stablehlo
canonicalize
shape-legalize-to-stablehlo
stablehlo-canonicalize-dynamism

Skwantyzowane przypadki testowe

StableHLO udostępnia obszerny zestaw skwantyzowanych przypadków testowych, które pozwalają weryfikować poprawność i działanie skwantyzowanych operacji. Te przypadki testowe służą jako testy jednostkowe, które obejmują różne operacje StableHLO w scenariuszach kwantyzacji.

Typowy przykład skwantyzowanego przypadku testowego wygląda tak:

func.func @main() -> tensor<11xf32> {
    %operand_0 = stablehlo.constant dense<...> : tensor<11xf32>
    %operand_1 = stablehlo.constant dense<...> : tensor<11xf32>
    %golden = stablehlo.constant dense<...> : tensor<11xf32>

    %0 = stablehlo.uniform_quantize %operand_0 : (tensor<11xf32>) -> tensor<11x!quant.uniform<i8:f32, 0.3>>
    %1 = stablehlo.uniform_quantize %operand_1 : (tensor<11xf32>) -> tensor<11x!quant.uniform<i8:f32, 0.3>>

    %2 = stablehlo.add %1, %0 : tensor<11x!quant.uniform<i8:f32, 0.3>>

    %result = stablehlo.uniform_dequantize %2 : (tensor<11x!quant.uniform<i8:f32, 0.3>>) -> tensor<11xf32>

    %4 = stablehlo.custom_call @check.eq(%golden, %result) : (tensor<11xf32>, tensor<11xf32>) -> tensor<i1>

    return %3 : tensor<11xf32>
  }

Obejmuje to:

Te przypadki testowe są przydatne w przypadku:

  • Weryfikacja kwantyzacji StableHLO: sprawdzanie, czy zachowanie kwantyzacji operacji StableHLO jest zgodne z oczekiwanymi wynikami.
  • Weryfikacja krzyżowa: porównanie działania kwantyzacji StableHLO z innymi implementacjami lub platformami.
  • Debugowanie i rozwijanie: pomoc w rozwijaniu i debugowaniu nowych funkcji kwantyzacji lub optymalizacji.