LiteRT 8비트 양자화 사양

다음 문서에서는 LiteRT의 8비트 양자화 스키마입니다. 이는 하드웨어 개발자가 양자화된 LiteRT 모델을 사용한 추론을 위한 하드웨어 지원

사양 요약

Google은 사양을 제공하고 있으며 제품 또는 서비스에 대해 일부 보증만 제공할 수 있습니다. 동작의 영향을 받습니다. 또한 다른 하드웨어로 인해 특정 광고나 판매 의도가 있는 광고와의 비트가 정확하지 않은 구현을 초래하는 사양을 구현합니다. 그러나 대부분의 경우 허용될 수 있지만 테스트에는 우리가 알고 있는 한 머신러닝의 특성, 딥 러닝의 특성, 절대적인 보장을 제공하는 것이 불가능합니다.

8비트 양자화는 다음을 사용하여 부동 소수점 값을 근사화합니다. 공식을 사용할 수 있습니다.

\[real\_value = (int8\_value - zero\_point) \times scale\]

축당 (전환 작업에서는 채널별) 또는 텐서당 가중치는 다음과 같이 표현됩니다. int8 [-127, 127] 범위에서 2의 보수 값(0점 같음) 0으로 설정합니다. 텐서별 활성화/입력은 int8 2의 보수로 표현 [-128, 127] 범위의 값([-128, 127] 범위의 0점)

특정 작업에 대한 다른 예외는 아래에 설명되어 있습니다.

부호 있는 정수와 부호 없는 정수 비교

LiteRT 양자화는 주로 이러한 하드웨어를 대상으로 하는 도구와 커널에 8비트에 대한 int8 양자화 이는 대칭 이동의 편의를 위한 것입니다. 0과 같은 0점으로 표현되는 양자화입니다. 또한 많은 백엔드에는 int8xint8 축적을 위한 추가 최적화가 있습니다.

축 및 텐서당 비교

텐서별 양자화는 각 특성마다 하나의 척도 또는 제로포인트가 전체 텐서에 해당합니다. 축당 양자화는 하나의 스케일 및/또는 quantized_dimension의 슬라이스당 zero_point입니다. 양자화 차원은 는 텐서의 배율 및 0점인 텐서 도형의 차원을 지정합니다. 나타냅니다. 예를 들어 dims=[4, 3, 2, 1]가 있는 t 텐서 양자화 매개변수: scale=[1.0, 2.0, 3.0], zero_point=[1, 2, 3], quantization_dimension=1t의 두 번째 차원에서 양자화됩니다.

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

종종 quantized_dimension는 다음 가중치의 output_channel입니다. 컨볼루션이지만 이론적으로는 각 컨볼루션에 해당하는 차원이 될 수 있습니다. 커널 구현의 dot-product를 사용하여 더 많은 양자화 세분성을 허용 성능을 향상할 수 있습니다 이렇게 하면 정확성이 크게 향상됩니다.

TFLite는 증가하는 작업 수를 위한 축당 지원을 제공합니다. 이 문서에서는 Conv2d 및 DepthwayConv2d가 지원됩니다.

대칭 대 비대칭

활성화는 비대칭입니다. 활성화 지점은 부호 있는 int8 범위 [-128, 127]. 많은 활성화는 본질적으로 비대칭이며 제로 포인트는 추가 값을 효과적으로 얻을 수 있는 상대적으로 저렴한 방법입니다. 정밀도가 매우 높습니다. 활성화 함수가 상수로만 곱하기 때문에 상수인 0점 값은 상당히 많이 최적화될 수 있습니다.

가중치는 대칭적입니다. 즉, 0이 0이 되도록 강제됩니다. 가중치 값은 곱하기만 하면 됩니다. 이것은 가중치의 0점을 활성화 값 0을 0으로 적용하면 이 비용을 피할 수 있습니다.

계산에 대한 설명: 이 내용은 arXiv:1712.05877 배율 값을 축당으로 설정할 수 있습니다. 이것은 쉽게 일반화됩니다. 다음과 같습니다.

$A$ 는 양자화된 활성화 함수의 $m \times n$ 행렬입니다.
$B$ 는 양자화된 가중치의 $n \times p$ 행렬입니다.
$A$의 $j$번째 행, $a_j$에 두 단어 모두 길이가 $n$인 $B$, $b_k$입니다. 양자화된 정수 값과 0포인트 값은 각각 $q_a$, $z_a$, $q_b$, $z_b$ 입니다.

\[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\]

와 함께 실패합니다.

\(\sum_{i=0}^{n} q_{a}^{(i)} q_{b}^{(i)}\) 용어는 내적을 구합니다.

\(\sum_{i=0}^{n} q_{b}^{(i)} z_a\) 및 \(\sum_{i=0}^{n} z_a z_b\) 약관 추론 호출마다 동일하게 유지되는 상수로 구성되므로 사전에 계산되어야 합니다.

추론할 때마다 \(\sum_{i=0}^{n} q_{a}^{(i)} z_b\) 항을 계산해야 함 활성화가 모든 추론을 변경하기 때문입니다. 가중치를 적용하여 대칭적으로 이 항의 비용을 제거할 수 있습니다.

int8 양자화 연산자 사양

아래에서는 int8 tflite 커널의 양자화 요구사항을 설명합니다.

ADD
  Input 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
  Input 1:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
  Output 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor

AVERAGE_POOL_2D
  Input 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
  Output 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
  restriction: Input and outputs must all have same scale/zero_point

CONCATENATION
  Input ...:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
  Output 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
  restriction: Input and outputs must all have same scale/zero_point

CONV_2D
  Input 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
  Input 1 (Weight):
    data_type  : int8
    range      : [-127, 127]
    granularity: per-axis (dim = 0)
    restriction: zero_point = 0
  Input 2 (Bias):
    data_type  : int32
    range      : [int32_min, int32_max]
    granularity: per-axis
    restriction: (scale, zero_point) = (input0_scale * input1_scale[...], 0)
  Output 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor

DEPTHWISE_CONV_2D
  Input 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
  Input 1 (Weight):
    data_type  : int8
    range      : [-127, 127]
    granularity: per-axis (dim = 3)
    restriction: zero_point = 0
  Input 2 (Bias):
    data_type  : int32
    range      : [int32_min, int32_max]
    granularity: per-axis
    restriction: (scale, zero_point) = (input0_scale * input1_scale[...], 0)
  Output 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor

FULLY_CONNECTED
  Input 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
  Input 1 (Weight):
    data_type  : int8
    range      : [-127, 127]
    granularity: per-axis (dim = 0)
    restriction: zero_point = 0
  Input 2 (Bias):
    data_type  : int32
    range      : [int32_min, int32_max]
    granularity: per-tensor
    restriction: (scale, zero_point) = (input0_scale * input1_scale[...], 0)
  Output 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor

L2_NORMALIZATION
  Input 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
  Output 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
    restriction: (scale, zero_point) = (1.0 / 128.0, 0)

LOGISTIC
  Input 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
  Output 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
    restriction: (scale, zero_point) = (1.0 / 256.0, -128)

MAX_POOL_2D
  Input 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
  Output 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
  restriction: Input and outputs must all have same scale/zero_point

MUL
  Input 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
  Input 1:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
  Output 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor

RESHAPE
  Input 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
  Output 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
  restriction: Input and outputs must all have same scale/zero_point

RESIZE_BILINEAR
  Input 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
  Output 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
  restriction: Input and outputs must all have same scale/zero_point

SOFTMAX
  Input 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
  Output 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
    restriction: (scale, zero_point) = (1.0 / 256.0, -128)

SPACE_TO_DEPTH
  Input 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
  Output 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
  restriction: Input and outputs must all have same scale/zero_point

TANH
  Input 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
  Output 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
    restriction: (scale, zero_point) = (1.0 / 128.0, 0)

PAD
  Input 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
  Output 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
  restriction: Input and outputs must all have same scale/zero_point

GATHER
  Input 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
  Output 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
  restriction: Input and outputs must all have same scale/zero_point

BATCH_TO_SPACE_ND
  Input 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
  Output 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
  restriction: Input and outputs must all have same scale/zero_point

SPACE_TO_BATCH_ND
  Input 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
  Output 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
  restriction: Input and outputs must all have same scale/zero_point

TRANSPOSE
  Input 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
  Output 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
  restriction: Input and outputs must all have same scale/zero_point

MEAN
  Input 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
  Output 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor

SUB
  Input 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
  Input 1:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
  Output 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor

SUM
  Input 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
  Output 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor

SQUEEZE
  Input 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
  Output 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
  restriction: Input and outputs must all have same scale/zero_point

LOG_SOFTMAX
  Input 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
  Output 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
    restriction: (scale, zero_point) = (16.0 / 256.0, 127)

MAXIMUM
  Input 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
  Output 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
  restriction: Input and outputs must all have same scale/zero_point

ARG_MAX
  Input 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor

MINIMUM
  Input 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
  Output 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
  restriction: Input and outputs must all have same scale/zero_point

LESS
  Input 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
  Input 1:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor

PADV2
  Input 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
  Output 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
  restriction: Input and outputs must all have same scale/zero_point

GREATER
  Input 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
  Input 1:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor

GREATER_EQUAL
  Input 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
  Input 1:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor

LESS_EQUAL
  Input 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
  Input 1:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor

SLICE
  Input 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
  Output 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
  restriction: Input and outputs must all have same scale/zero_point

EQUAL
  Input 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
  Input 1:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor

NOT_EQUAL
  Input 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
  Input 1:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor

SHAPE
  Input 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor

QUANTIZE (Requantization)
  Input 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor
  Output 0:
    data_type  : int8
    range      : [-128, 127]
    granularity: per-tensor

참조

arXiv:1712.05877