مشخصات کمی سازی 8 بیتی TensorFlow Lite

سند زیر مشخصات مربوط به طرح کوانتاسیون 8 بیتی TensorFlow Lite را مشخص می کند. این هدف برای کمک به توسعه دهندگان سخت افزار در ارائه پشتیبانی سخت افزاری برای استنتاج با مدل های کمی شده TensorFlow Lite است.

خلاصه مشخصات

ما در حال ارائه مشخصات هستیم و تنها در صورت رعایت مشخصات می توانیم برخی از تضمینات مربوط به رفتار را ارائه دهیم. ما همچنین می فهمیم که ممکن است سخت افزارهای مختلف ترجیحات و محدودیت هایی داشته باشند که ممکن است هنگام اجرای مشخصات منجر به پیاده سازی هایی شود که دقیق دقیق نیستند ، انحراف جزئی ایجاد کند. در حالی که این ممکن است در بیشتر موارد قابل قبول باشد (و ما مجموعه ای از تست ها را ارائه خواهیم داد که در حد دانش ما شامل تحمل های عملیاتی است که از چندین مدل جمع آوری کرده ایم) ، ماهیت یادگیری ماشین (و یادگیری عمیق در رایج ترین مورد) ارائه هرگونه ضمانت سخت را غیرممکن می کند.

کمی سازی 8 بیتی مقادیر نقطه شناور را با استفاده از فرمول زیر تقریب می زند.

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

وزن هر محور (با نام مستعار در هر کانال در گزینه های Conv) یا هر تنسور با مقادیر مکمل int8 two در محدوده [-127, 127] با نقطه صفر برابر 0. نشان داده می شود. فعال سازی ها / ورودی های تانسور توسط مقادیر مکمل int8 two در محدوده [-128, 127] ، با یک نقطه صفر در محدوده [-128, 127] .

استثناهای دیگری نیز برای عملیات خاص وجود دارد که در زیر مستند شده است.

عدد صحیح امضا شده در مقابل عدد صحیح بدون امضا

کمی سازی TensorFlow Lite در درجه اول ابزار و هسته ها را برای int8 برای 8 بیتی در اولویت قرار می دهد. این برای سهولت تعیین مقدار متقارن است که با نقطه صفر برابر با 0 نشان داده می شود. بعلاوه بسیاری از int8xint8 بهینه سازی های اضافی برای تجمع int8xint8 .

در هر محور در مقابل هر تنسور

مقداردهی به ازای هر تنسور به معنای وجود یک مقیاس و / یا نقطه صفر برای کل سنسور است. میانگین پستها در طول محور یعنی تدریج که وجود خواهد داشت یک مقیاس و / یا zero_point در هر تکه quantized_dimension . بعد كوانتيزه شده بعد شكل تنسور را مشخص مي كند كه مقياس ها و نقاط صفر با آن مطابقت دارند. به عنوان مثال، یک تانسور 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

غالباً ، output_channel quantized_dimension output_channel وزن پیچیدگی ها است ، اما از لحاظ تئوری می تواند ابعادی باشد که با هر نقطه-محصول در اجرای هسته مطابقت دارد ، و اجازه می دهد دانه بندی کوانتیزاسیون بیشتر بدون پیامدهای عملکردی باشد. این پیشرفت های زیادی در دقت دارد.

TFLite دارای پشتیبانی از هر محور برای تعداد فزاینده ای از عملیات است. در زمان تهیه این سند ، پشتیبانی از Conv2d و DepthwiseConv2d وجود دارد.

متقارن در مقابل نامتقارن

فعال سازی ها نامتقارن هستند: آنها می توانند نقطه صفر خود را در هر جایی از محدوده int8 امضا شده int8 باشند [-128, 127] . بسیاری از فعال سازی ها از نظر ماهیت نامتقارن هستند و نقطه صفر یک روش نسبتاً ارزان برای دستیابی م effectivelyثر به کمی دودویی اضافی است. از آنجا که فعال سازی ها فقط در وزن های ثابت ضرب می شوند ، مقدار ثابت نقطه صفر را می توان کاملاً بهینه کرد.

وزن ها متقارن هستند: مجبور می شوند نقطه صفر برابر با 0 داشته باشند. مقادیر وزن در مقادیر ورودی و فعال سازی دینامیکی ضرب می شوند. این بدان معناست که هزینه زمان اجتناب ناپذیر ضرب نقطه صفر وزن با مقدار فعال سازی وجود دارد. با اجرای این که نقطه صفر 0 است ، می توانیم از این هزینه جلوگیری کنیم.

توضیح ریاضی: این مشابه بخش 2.3 در arXiv است: 1712.05877 ، به غیر از این تفاوت که اجازه می دهیم مقادیر مقیاس در هر محور باشد. این به آسانی تعمیم می یابد ، به شرح زیر است:

$ A $ ماتریس $ m \ times n $ از فعالیتهای کوانتیزه شده است.
$ B $ یک ماتریس $ n \ sa p $ از وزنهای کوانتیزه شده است.
ضرب در ردیف $ j $ th $ A $، $ a_j $ را در ستون $ k $ th $ $ 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-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

منابع

arXiv: 1712.05877