ช่วยปกป้อง Great Barrier Reef กับ TensorFlow บน Kaggle เข้าร่วมท้าทาย

ข้อกำหนดการควอนไทซ์ 8 บิตของ TensorFlow Lite

เอกสารต่อไปนี้จะสรุปข้อกำหนดสำหรับรูปแบบการจัดลำดับแบบ 8 บิตของ TensorFlow Lite มีจุดมุ่งหมายเพื่อช่วยนักพัฒนาฮาร์ดแวร์ในการให้การสนับสนุนฮาร์ดแวร์สำหรับการอนุมานด้วยโมเดล TensorFlow Lite เชิงปริมาณ

สรุปข้อมูลจำเพาะ

เรากำลังจัดเตรียมข้อกำหนด และเราสามารถให้การรับประกันเกี่ยวกับพฤติกรรมบางอย่างได้ก็ต่อเมื่อปฏิบัติตามข้อกำหนดเท่านั้น เรายังเข้าใจดีว่าฮาร์ดแวร์ที่แตกต่างกันอาจมีการกำหนดลักษณะและข้อจำกัดที่อาจทำให้เกิดการเบี่ยงเบนเล็กน้อยเมื่อใช้งานข้อมูลจำเพาะที่ส่งผลให้มีการใช้งานที่ไม่แน่นอนบิต ในขณะที่นั่นอาจเป็นที่ยอมรับได้ในกรณีส่วนใหญ่ (และเราจะจัดเตรียมชุดการทดสอบที่ความรู้ที่ดีที่สุดของเรารวมถึงความคลาดเคลื่อนต่อการทำงานที่เรารวบรวมจากแบบจำลองต่างๆ) ธรรมชาติของการเรียนรู้ด้วยเครื่อง (และการเรียนรู้เชิงลึกโดยทั่วไป กรณี) ทำให้ไม่สามารถให้การค้ำประกันใด ๆ ได้

การหาปริมาณ 8 บิตจะประมาณค่าจุดลอยตัวโดยใช้สูตรต่อไปนี้

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

ต่อแกน (aka ต่อช่องทางในการปฏิบัติการ Conv) หรือต่อเมตริกซ์น้ำหนักโดยมีตัวแทน int8 สองของค่าสมบูรณ์ในช่วง [-127, 127] กับจุดศูนย์เท่ากับ 0. การเปิดใช้งานต่อเมตริกซ์ / ปัจจัยการผลิตโดยมีตัวแทน int8 สองของค่าสมบูรณ์ในช่วง [-128, 127] มีจุดศูนย์ในช่วง [-128, 127]

มีข้อยกเว้นอื่นๆ สำหรับการดำเนินการเฉพาะที่ระบุไว้ด้านล่าง

จำนวนเต็มลงนาม vs จำนวนเต็มไม่ได้ลงนาม

TensorFlow Lite quantization จะจัดลำดับความสำคัญการขับรถเป็นหลักและเมล็ดสำหรับ int8 quantization สำหรับ 8 บิต นี่คือเพื่อความสะดวกของควอนสมมาตรถูกแทนด้วยจุดศูนย์เท่ากับ 0 แบ็กเอนด์จำนวนมากนอกจากนี้ยังมีการเพิ่มประสิทธิภาพเพิ่มเติมสำหรับ int8xint8 สะสม

ต่อแกนเทียบกับต่อเทนเซอร์

การหาปริมาณต่อเทนเซอร์หมายความว่าจะมีหนึ่งมาตราส่วนและ/หรือจุดศูนย์ต่อเมตริกซ์ทั้งหมด ต่อแกน quantization หมายถึงว่าจะมีหนึ่งขนาดและ / หรือ zero_point ต่อชิ้นใน quantized_dimension มิติข้อมูลเชิงปริมาณระบุขนาดของรูปร่างของเทนเซอร์ที่มาตราส่วนและจุดศูนย์สอดคล้องกัน ยกตัวอย่างเช่นเมตริกซ์ t กับ dims=[4, 3, 2, 1] กับ params quantization: scale=[1.0, 2.0, 3.0] , zero_point=[1, 2, 3] , quantization_dimension=1 จะได้รับการ quantized ข้าม มิติที่สองของ 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 ของน้ำหนักของ convolutions แต่ในทางทฤษฎีมันสามารถเป็นมิติที่สอดคล้องกับแต่ละจุดผลิตภัณฑ์ในการดำเนินเคอร์เนลที่ช่วยให้เมล็ด quantization มากขึ้นโดยไม่ผลกระทบต่อประสิทธิภาพการทำงาน มีการปรับปรุงความแม่นยำอย่างมาก

TFLite มีการรองรับแบบทีละแกนสำหรับการดำเนินการที่มีจำนวนเพิ่มขึ้นเรื่อยๆ ในช่วงเวลาของเอกสารนี้ มีการสนับสนุนสำหรับ Conv2d และ DepthwiseConv2d

สมมาตรกับอสมมาตร

การเปิดใช้งานมีความไม่สมมาตร: พวกเขาสามารถมีได้ทุกจุดศูนย์ของพวกเขาภายในลงนาม int8 ช่วง [-128, 127] การเปิดใช้งานจำนวนมากมีลักษณะไม่สมมาตรและจุดศูนย์เป็นวิธีที่ไม่แพงนักในการรับบิตไบนารีที่มีความแม่นยำเป็นพิเศษ เนื่องจากการเปิดใช้งานจะถูกคูณด้วยน้ำหนักคงที่เท่านั้น ค่าจุดศูนย์คงที่สามารถปรับให้เหมาะสมได้ค่อนข้างมาก

น้ำหนักมีความสมมาตร: บังคับให้มีจุดศูนย์เท่ากับ 0 ค่าน้ำหนักจะถูกคูณด้วยค่าอินพุตแบบไดนามิกและการเปิดใช้งาน ซึ่งหมายความว่ามีค่าใช้จ่ายรันไทม์ที่หลีกเลี่ยงไม่ได้ในการคูณจุดศูนย์ของน้ำหนักด้วยค่าการเปิดใช้งาน การบังคับให้จุดศูนย์เป็น 0 เราสามารถหลีกเลี่ยงค่าใช้จ่ายนี้ได้

คำอธิบายของคณิตศาสตร์: นี้จะคล้ายกับส่วน 2.3 ใน arXiv: 1712.05877 ยกเว้นสำหรับความแตกต่างที่เราอนุญาตให้ค่าขนาดที่จะต่อแกน นี้สรุปได้อย่างง่ายดายดังนี้:

\(A\) เป็น \(m \times n\) เมทริกซ์ของการเปิดใช้งานไท
\(B\) เป็น \(n \times 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