Google I/O'yu ayarladığınız için teşekkür ederiz. İsteğe bağlı olarak tüm oturumları görüntüleyin İsteğe bağlı olarak izleyin

TensorFlow Lite 8 bit nicemleme özelliği

Aşağıdaki belge, TensorFlow Lite'ın 8 bit nicemleme şemasının belirtimini özetlemektedir. Bu, donanım geliştiricilerine nicelleştirilmiş TensorFlow Lite modelleriyle çıkarım için donanım desteği sağlamada yardımcı olmayı amaçlamaktadır.

Spesifikasyon özeti

Bir spesifikasyon sağlıyoruz ve ancak spesifikasyona uyulursa davranışla ilgili bazı garantiler verebiliriz. Ayrıca, farklı donanımların, özellikleri uygularken küçük sapmalara neden olabilecek ve bit kesin olmayan uygulamalarla sonuçlanan tercihleri ​​ve kısıtlamaları olabileceğini anlıyoruz. Çoğu durumda bu kabul edilebilir olsa da (ve bilgimiz dahilinde, çeşitli modellerden topladığımız işlem başına toleransları içeren bir dizi test sağlayacağız), makine öğreniminin doğası (ve en yaygın olarak derin öğrenme) durum) herhangi bir kesin garanti vermeyi imkansız hale getirir.

8 bit niceleme, aşağıdaki formülü kullanarak kayan nokta değerlerine yaklaşır.

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

Ortalama ekseni (diğer adıyla kanal başına Dönüşüm ops) veya başına tensör ağırlıkları ile temsil edilmektedir int8 aralığında ikinin tümleyici değerleri [-127, 127] sıfır noktası 0 başına tensör aktivasyonları için eşit / girdileri ile temsil edilmektedir int8 aralığında ikinin tümleyici değerleri [-128, 127] aralığı içinde bir sıfır noktası, [-128, 127] .

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

İşaretli tamsayı ve işaretsiz tamsayı

TensorFlow Lite nicemleme olacak öncelikle öncelik vermektedir takım ve için çekirdekleri int8 8-bit nicelenmesinin. Simetrik nicemleme kolaylık için ek optimizasyonunuz 0 Ayrıca birçok arka ucu için eşit sıfır noktası ile temsil edilen bilgi için bkz int8xint8 birikimi.

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

Tensör başına niceleme, tüm tensör başına bir ölçek ve/veya sıfır noktası olacağı anlamına gelir. Ortalama eksenli bir ölçek ve / veya olacağı nicemleme aracı zero_point dilim başına quantized_dimension . Nicelenmiş boyut, ölçeklerin ve sıfır noktalarının karşılık geldiği Tensör şeklinin boyutunu belirtir. Örneğin, bir tensör için t ile dims=[4, 3, 2, 1] niceleme parametreleri içeren: scale=[1.0, 2.0, 3.0] , zero_point=[1, 2, 3] , quantization_dimension=1 arasında kuantize edilecektir ikinci boyut 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

Çoğu zaman, quantized_dimension olan output_channel konvolüsyonlar ağırlıklarının fakat teorik olarak çekirdek uygulanmasında her nokta ürüne karşılık gelir, performans üzerindeki etkileri olmadan daha fazla niceleme ayrıntı sağlayan bu boyut olabilir. Bu, doğrulukta büyük iyileştirmelere sahiptir.

TFLite, artan sayıda işlem için eksen başına desteğe sahiptir. Bu belgenin hazırlandığı tarihte Conv2d ve DepthwiseConv2d için destek mevcuttur.

Simetrik ve asimetrik

Etkinleştirmeler asimetrik: onlar imzalı içindeki sıfır noktası hiçbir yerinde olabilir int8 aralık [-128, 127] . Birçok etkinleştirme doğası gereği asimetriktir ve sıfır noktası, fazladan bir ikili hassasiyete etkili bir şekilde ulaşmanın nispeten ucuz bir yoludur. Aktivasyonlar yalnızca sabit ağırlıklarla çarpıldığından, sabit sıfır noktası değeri oldukça yoğun şekilde optimize edilebilir.

Ağırlıklar simetriktir: sıfır noktası 0'a eşit olmaya zorlanır. Ağırlık değerleri dinamik giriş ve aktivasyon değerleri ile çarpılır. Bu, ağırlığın sıfır noktasını etkinleştirme değeriyle çarpmanın kaçınılmaz bir çalışma zamanı maliyeti olduğu anlamına gelir. Sıfır noktasının 0 olduğunu zorunlu kılarak bu maliyeti önleyebiliriz.

Matematik açıklanması: Bu bölüm 2.3 benzerdir 1712,05877: arXiv ölçek değerlerini başına eksenine edilmesine olanak vermesi fark dışında. Bu, aşağıdaki gibi kolayca genellenir:

\(A\) a, \(m \times n\) nicelenmiş etkinleştirme matrisi.
\(B\) a, \(n \times p\) nicelenmiş ağırlıkları matrisi.
Çarparak düşünün \(j\)inci satır \(A\), \(a_j\) ile \(k\)inci sütun\(B\), \(b_k\), uzunluk hem \(n\). Nicelenmiş tam sayı değerleri ve değerler sıfır noktalarıdır \(q_a\), \(z_a\) ve \(q_b\), \(z_b\) sırasıyla.

\[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)}\) bu giriş değerine ve ağırlık değerinin nokta ürününü gerçekleştirmek beri terimi kaçınılmazdır.

\(\sum_{i=0}^{n} q_{b}^{(i)} z_a\) ve \(\sum_{i=0}^{n} z_a z_b\) koşulları önceden hesaplanabilir ve böylece çıkarım çağırma başına aynı kalır ve sabitler oluşur.

\(\sum_{i=0}^{n} q_{a}^{(i)} z_b\) süreli aktivasyonu her çıkarım değiştirir beri her çıkarım bilgisayarlı gerekmektedir. Ağırlıkları simetrik olmaya zorlayarak bu terimin maliyetini kaldırabiliriz.

int8 nicelenmiş operatör özellikleri

Aşağıda int8 tflite çekirdeklerimiz için niceleme gereksinimlerini açıklıyoruz:

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-tensor
    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