مواصفات التكميم TensorFlow Lite 8 بت

يوضح المستند التالي مواصفات نظام التكميم 8 بت الخاص بـ TensorFlow Lite. يهدف هذا إلى مساعدة مطوري الأجهزة في توفير دعم الأجهزة للاستدلال باستخدام نماذج TensorFlow Lite الكمية.

ملخص المواصفات

نحن نقدم مواصفات، ولا يمكننا تقديم بعض الضمانات بشأن السلوك إلا في حالة اتباع المواصفات. نحن ندرك أيضًا أن الأجهزة المختلفة قد يكون لها تفضيلات وقيود قد تسبب انحرافات طفيفة عند تنفيذ المواصفات مما يؤدي إلى عمليات تنفيذ غير دقيقة. في حين أن ذلك قد يكون مقبولاً في معظم الحالات (وسوف نقدم مجموعة من الاختبارات التي تشمل، على حد علمنا، التفاوتات المسموح بها لكل عملية والتي جمعناها من عدة نماذج)، وطبيعة التعلم الآلي (والتعلم العميق في أكثر أنواع التعلم شيوعًا) الحالة) يجعل من المستحيل تقديم أي ضمانات صارمة.

تقريب 8 بتات قيم الفاصلة العائمة باستخدام الصيغة التالية.

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

يتم تمثيل كل محور (المعروف أيضًا باسم كل قناة في Conv ops) أو أوزان كل موتر بواسطة القيم التكميلية int8 two في النطاق [-127, 127] مع نقطة صفر تساوي 0. يتم تمثيل عمليات التنشيط/المدخلات لكل موتر بواسطة القيم التكميلية لـ int8 two في النطاق [-128, 127] ، مع نقطة صفر في النطاق [-128, 127] .

هناك استثناءات أخرى لعمليات معينة موثقة أدناه.

عدد صحيح موقّع مقابل عدد صحيح غير موقّع

سوف يقوم تكميم TensorFlow Lite في المقام الأول بإعطاء الأولوية للأدوات والنوى لتكميم int8 لـ 8 بت. وذلك من أجل تسهيل التكميم المتماثل الذي يتم تمثيله بنقطة صفر تساوي 0. بالإضافة إلى ذلك، تحتوي العديد من الواجهات الخلفية على تحسينات إضافية لتراكم int8xint8 .

لكل محور مقابل لكل موتر

ويعني تكميم كل موتر أنه سيكون هناك مقياس واحد و/أو نقطة صفر لكل موتر كامل. يعني التكميم لكل محور أنه سيكون هناك مقياس واحد و/أو zero_point لكل شريحة في quantized_dimension . يحدد البعد الكمي بعد شكل Tensor الذي تتوافق معه المقاييس ونقاط الصفر. على سبيل المثال، موتر t ، مع dims=[4, 3, 2, 1] مع معلمات التكميم: scale=[1.0, 2.0, 3.0] , zero_point=[1, 2, 3] , quantization_dimension=1 سيتم تكميمها عبر البعد الثاني لـ 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

في كثير من الأحيان، quantized_dimension هو output_channel لأوزان التلافيف، ولكن من الناحية النظرية يمكن أن يكون البعد الذي يتوافق مع كل منتج نقطي في تنفيذ النواة، مما يسمح بمزيد من دقة التكميم دون آثار على الأداء. هذا له تحسينات كبيرة على الدقة.

يتمتع TFLite بدعم لكل محور لعدد متزايد من العمليات. في وقت إعداد هذا المستند، كان الدعم موجودًا لـ Conv2d وDepthwiseConv2d.

متماثل مقابل غير متماثل

عمليات التنشيط غير متماثلة: يمكن أن يكون لها نقطة الصفر في أي مكان ضمن نطاق int8 الموقع [-128, 127] . العديد من عمليات التنشيط غير متماثلة بطبيعتها، ونقطة الصفر هي وسيلة غير مكلفة نسبيًا للحصول بشكل فعال على قدر ثنائي إضافي من الدقة. نظرًا لأن عمليات التنشيط يتم ضربها فقط بأوزان ثابتة، فيمكن تحسين قيمة نقطة الصفر الثابتة بشكل كبير.

الأوزان متماثلة: تُجبر على أن تكون نقطة الصفر تساوي 0. ويتم ضرب قيم الوزن بقيم الإدخال الديناميكي وقيم التنشيط. وهذا يعني أن هناك تكلفة وقت تشغيل لا يمكن تجنبها تتمثل في ضرب نقطة الصفر للوزن مع قيمة التنشيط. ومن خلال فرض أن نقطة الصفر هي 0 يمكننا تجنب هذه التكلفة.

شرح العمليات الحسابية: هذا مشابه للقسم 2.3 في arXiv:1712.05877 ، باستثناء الاختلاف الذي نسمح به لقيم المقياس أن تكون لكل محور. وهذا يمكن تعميمه بسهولة كما يلي:

\(A\) عبارة عن مصفوفة \(m \times n\) للتنشيط الكمي.
\(B\) عبارة عن مصفوفة \(n \times p\) للأوزان الكمية.
فكر في ضرب الصف \(j\)من \(A\)، \(a_j\) في العمود \(k\)من\(B\)، \(b_k\)، وكلاهما بطول \(n\). قيم الأعداد الصحيحة الكمية وقيم النقاط الصفرية هي \(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

مراجع

أرخايف:1712.05877