LiteRT 8 bit miktar belirleme spesifikasyonu

Aşağıdaki dokümanda, LiteRT'in 8 bit sürümü için spesifikasyonlar nicelikleme şemasıdır. Burada amaç, donanım geliştiricilerinin nicel LiteRT modelleriyle çıkarım için donanım desteği.

Spesifikasyon özeti

Bir spesifikasyon sağlıyoruz ve bunun için yalnızca bazı garantiler verebiliyoruz. bir davranış sergileyeceğinden emin olun. Ayrıca farklı donanımların küçük sapmalara neden olabilecek tercihlere ve kısıtlamalara uygulanmasına yol açan teknikler de vardır. Çoğu durumda bu kabul edilebilir bir uygulamadır (ve size yardımcı olacak ve bu testler, uyguladığımız işlem başına toleransları çeşitli modellerden toplanan verileri içeren, makine öğreniminin (ve derin öğrenme) ) somut garantiler verilmesini imkansız hale getirir.

8 bitlik niceleme, aşağıdakini kullanarak kayan nokta değerlerini tahmin eder: formülünü kullanabilirsiniz.

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

Eksen başına (Dönş. işlemlerinde kanal başına) veya tensör başına ağırlıklar int8 [-127, 127] aralığındaki ikinin tamamlayıcı değerleri (sıfır noktasına eşit) 0 olarak ayarladı. Tensör başına etkinleştirme/girişler, int8 ikinin tamamlayıcısı ile gösterilir. [-128, 127] aralığında sıfır noktasına sahip, [-128, 127] aralığında bir değer.

Belirli işlemler için, aşağıda belgelenen başka istisnalar da vardır.

İmzalı tam sayı ile imzasız tam sayı karşılaştırması

LiteRT nicelemesi, öncelikli olarak araç ve çekirdeklere 8 bit için int8 nicelemesi. Bu, simetrik kullanım kolaylığı 0'a eşit sıfır noktasıyla temsil edilen nicelemedir. Ayrıca birçok arka uçlarda int8xint8 toplama için ek optimizasyonlar var.

Eksen başına ve tensör başına

Tensör başına miktar verme, her seferinde bir ölçek ve/veya sıfır nokta olacağı anlamına gelir. düşünebilirsiniz. Eksen başına nicelik, tek bir ölçek ve/veya quantized_dimension içindeki dilim başına zero_point. Ölçülen boyut Ölçeklendirildiği Tensor şeklinin boyutunu belirtir ve anlamına gelir. Örneğin, t tensörü ve dims=[4, 3, 2, 1] içeren niceleme parametreleri: scale=[1.0, 2.0, 3.0], zero_point=[1, 2, 3], quantization_dimension=1, t öğesinin ikinci boyutunda ölçülecektir:

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

Genellikle quantized_dimension, ağırlıkların output_channel kadarıdır ancak teoride her bir döngüye karşılık gelen çekirdek uygulamasında nokta çarpımı, daha fazla miktar belirleme ayrıntı düzeyi performansı etkilemeyecek. Bu yaklaşımda doğrulukta büyük artışlar söz konusudur.

TFLite, artan işlem sayısı için eksen başına destek sunar. Şu tarihte: bu dokümanda Conv2d ve DepthwardConv2d için destek devam etmektedir.

Simetrik ve asimetrik

Etkinleştirmeler asimetriktir: imzalı int8 aralığı [-128, 127]. Birçok asimetrik doğası gereği asimetriktir sıfır noktasının, ek bir maliyete neden olmak için etkili bir şekilde ikili hassasiyetten oluşur. Etkinleştirmeler sadece sabit sayılarla çarpıldığı için sabit sıfır noktalı değer oldukça yüksek oranda optimize edilebilir.

Ağırlıklar simetriktir: sıfır noktası 0'a eşit olmaya zorlanır. Ağırlık değerleri: ve aktivasyon değerleriyle çarpılır. Bunun anlamı şudur: ağırlığın sıfır noktasını etkinleştirme değeri. Sıfır noktasının 0 olmasını zorunlu kılarak bu maliyeti önleyebiliriz.

Matematik açıklaması: Bu, Bölüm 2.3'e benzerdir arXiv:1712.05877 (fark hariç) her eksen için ayrı ayrı ayarlanmasına izin veririz. Bu, açıklamanın şöyle olur:

$A$, nicel etkinleştirmelere ait $m \times n$ tutarında bir matristir.
. $B$, nicel ağırlıklara ilişkin $n \times p$ matristir.
. $A$için $j$. satırı, $a_j$ ile $k$. sütunu arasında $B$, $b_k$, her ikisi de $n$ uzunluğunda. Ölçülen tam sayı değerleri ve sıfır puan değerleri sırasıyla $q_a$, $z_a$ ve $q_b$ ve $z_b$ şeklindedir.

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

ile başarısız oluyor

Elbette \(\sum_{i=0}^{n} q_{a}^{(i)} q_{b}^{(i)}\) terim kaçınılmazdır, çünkü giriş değerinin ve ağırlık değerinin nokta çarpımını uygulayabilirsiniz.

\(\sum_{i=0}^{n} q_{b}^{(i)} z_a\) ve \(\sum_{i=0}^{n} z_a z_b\) terimler çıkarım çağrısı başına aynı kalan sabit değerlerden oluşur ve bu nedenle, olması gerekir.

\(\sum_{i=0}^{n} q_{a}^{(i)} z_b\) teriminin her çıkarımda hesaplanması gerekir çünkü etkinleştirme işlemi her çıkarımı değiştiriyor. Belirlenecek ağırlıkları zorunlu kılarak simetrik olduğundan bu terimin maliyetini kaldırabiliriz.

int8 ölçülebilir operatör özellikleri

Aşağıda, int8 tflite çekirdeklerimiz için miktar belirleme gereksinimlerini açıklanmaktadır:

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

Referanslar

arXiv:1712.05877