TensorFlow Lite 8-বিট কোয়ান্টাইজেশন স্পেসিফিকেশন

নিম্নলিখিত নথিতে TensorFlow Lite-এর 8-বিট কোয়ান্টাইজেশন স্কিমের স্পেসিফিকেশনের রূপরেখা দেওয়া হয়েছে। এটি হার্ডওয়্যার ডেভেলপারদের কোয়ান্টাইজড টেনসরফ্লো লাইট মডেলের অনুমানের জন্য হার্ডওয়্যার সমর্থন প্রদানে সহায়তা করার উদ্দেশ্যে।

স্পেসিফিকেশন সারাংশ

আমরা একটি স্পেসিফিকেশন প্রদান করছি, এবং আমরা শুধুমাত্র আচরণের কিছু গ্যারান্টি দিতে পারি যদি স্পেসিফিকেশন অনুসরণ করা হয়। আমরা এটাও বুঝি যে বিভিন্ন হার্ডওয়্যারের পছন্দ এবং বিধিনিষেধ থাকতে পারে যা স্পেক প্রয়োগ করার সময় সামান্য বিচ্যুতি ঘটাতে পারে যার ফলস্বরূপ বাস্তবায়নগুলি বিট-সঠিক নয়। যদিও এটি বেশিরভাগ ক্ষেত্রেই গ্রহণযোগ্য হতে পারে (এবং আমরা পরীক্ষাগুলির একটি স্যুট প্রদান করব যা আমাদের সর্বোত্তম জ্ঞানের মধ্যে রয়েছে প্রতি-অপারেশন সহনশীলতা যা আমরা বিভিন্ন মডেল থেকে সংগ্রহ করেছি), মেশিন লার্নিংয়ের প্রকৃতি (এবং সবচেয়ে সাধারণ ক্ষেত্রে গভীর শিক্ষা) ক্ষেত্রে) কোনো কঠিন গ্যারান্টি প্রদান করা অসম্ভব করে তোলে।

8-বিট কোয়ান্টাইজেশন নিম্নলিখিত সূত্র ব্যবহার করে ভাসমান বিন্দু মান আনুমানিক।

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

প্রতি-অক্ষ (ওরফে প্রতি-চ্যানেল কনভ অপস) বা প্রতি-টেনসর ওজনগুলিকে int8 দুই-এর পরিপূরক মান দ্বারা উপস্থাপিত করা হয় [-127, 127] পরিসরে শূন্য-বিন্দু 0 এর সমান। প্রতি-টেনসর অ্যাক্টিভেশন/ইনপুটগুলি দ্বারা প্রতিনিধিত্ব করা হয় পরিসরে int8 দুই এর পরিপূরক মান [-128, 127] , পরিসরে একটি শূন্য-বিন্দু সহ [-128, 127]

নিচে নথিভুক্ত করা নির্দিষ্ট অপারেশনের জন্য অন্যান্য ব্যতিক্রম আছে।

স্বাক্ষরিত পূর্ণসংখ্যা বনাম স্বাক্ষরবিহীন পূর্ণসংখ্যা

TensorFlow Lite কোয়ান্টাইজেশন প্রাথমিকভাবে 8-বিটের জন্য int8 কোয়ান্টাইজেশনের জন্য টুলিং এবং কার্নেলকে অগ্রাধিকার দেবে। এটি 0-এর সমান শূন্য-পয়েন্ট দ্বারা উপস্থাপিত প্রতিসম কোয়ান্টাইজেশনের সুবিধার জন্য। উপরন্তু অনেক ব্যাকএন্ডে int8xint8 সঞ্চয়ের জন্য অতিরিক্ত অপ্টিমাইজেশন রয়েছে।

প্রতি-অক্ষ বনাম প্রতি-টেনসর

প্রতি-টেনসর কোয়ান্টাইজেশনের অর্থ হল প্রতি টেনসরে একটি স্কেল এবং/অথবা শূন্য-পয়েন্ট থাকবে। প্রতি-অক্ষের পরিমাপকরণের অর্থ হল quantized_dimension এ প্রতি স্লাইসে একটি স্কেল এবং/অথবা zero_point থাকবে। পরিমাপকৃত মাত্রা টেনসরের আকৃতির মাত্রা নির্দিষ্ট করে যা দাঁড়িপাল্লা এবং শূন্য-পয়েন্টগুলির সাথে সামঞ্জস্যপূর্ণ। উদাহরণস্বরূপ, একটি টেনসর 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 প্রয়োগ করে আমরা এই খরচ এড়াতে পারি।

গণিতের ব্যাখ্যা: এটি arXiv:1712.05877- এর অধ্যায় 2.3-এর অনুরূপ, এই পার্থক্য ব্যতীত যে আমরা স্কেলের মানগুলিকে প্রতি-অক্ষে হতে দিই। এটি সহজেই সাধারণীকরণ করে, নিম্নরূপ:

\(A\) হল কোয়ান্টাইজড অ্যাক্টিভেশনের একটি \(m \times n\) ম্যাট্রিক্স।
\(B\) হল কোয়ান্টাইজড ওজনের একটি \(n \times p\) ম্যাট্রিক্স।
l10n- \(A\) \(j\)তম সারি , \(a_j\) l10n\(B\)এর \(k\)তম কলাম দ্বারা \(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

তথ্যসূত্র

arXiv:1712.05877