การวัดปริมาณหลังการฝึกอบรม

การวัดปริมาณหลังการฝึกเป็นเทคนิค Conversion ที่สามารถลดขนาดโมเดลไปพร้อมๆ กับปรับปรุงเวลาในการตอบสนองของตัวเร่ง CPU และฮาร์ดแวร์ โดยลดความแม่นยำของโมเดลลงเล็กน้อย คุณทำให้โมเดล TensorFlow ที่ฝึกแล้วกลายเป็นปริมาณเมื่อแปลงโมเดลดังกล่าวเป็นรูปแบบ TensorFlow Lite โดยใช้ TensorFlow Lite Converter ได้

วิธีการเพิ่มประสิทธิภาพ

การวัดปริมาณหลังการฝึกมีให้เลือกหลายรายการ ต่อไปนี้คือตารางสรุปของตัวเลือกและประโยชน์ที่มี

เทคนิค ประโยชน์ ฮาร์ดแวร์
การวัดช่วงไดนามิก เล็กลง 4 เท่า เร่งความเร็วได้ 2-3 เท่า CPU
การแปลงจำนวนเต็ม แบบเต็มจำนวน เล็กลง 4 เท่า เร่งความเร็วได้มากกว่า 3 เท่า CPU, Edge TPU ไมโครคอนโทรลเลอร์
การวัดปริมาณ Float16 เล็กลง 2 เท่า, การเร่ง GPU CPU, GPU

แผนผังการตัดสินใจต่อไปนี้สามารถช่วยพิจารณาว่าวิธีใดในการวัดปริมาณหลังการฝึกที่ดีที่สุดสำหรับ Use Case ของคุณ

ตัวเลือกการเพิ่มประสิทธิภาพหลังการฝึกอบรม

ไม่มีการกำหนดปริมาณ

การแปลงเป็นโมเดล TFLite โดยไม่มีการแปลงปริมาณเป็นจุดเริ่มต้นที่แนะนำ การดำเนินการนี้จะสร้างโมเดล TFLite แบบลอย

import tensorflow as tf
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
tflite_quant_model = converter.convert()

เราขอแนะนำให้คุณดำเนินการนี้ในขั้นตอนเริ่มต้นเพื่อยืนยันว่าโอเปอเรเตอร์ของโมเดล TF เดิมเข้ากันได้กับ TFLite และยังใช้เป็นเกณฑ์พื้นฐานเพื่อแก้ไขข้อผิดพลาดในเชิงปริมาณที่เกิดจากวิธีการวัดปริมาณหลังการฝึกที่ตามมา เช่น หากโมเดล TFLite ที่แปลงค่าเป็นจำนวนผลลัพธ์ให้ได้ผลลัพธ์ที่ไม่คาดคิด ขณะที่โมเดล TFLite แบบลอยมีความถูกต้อง เราสามารถจำกัดปัญหาให้แคบลงเฉพาะข้อผิดพลาดที่เกิดจากโอเปอเรเตอร์ TFLite เวอร์ชันเชิงปริมาณ

การวัดช่วงไดนามิก

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

import tensorflow as tf
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
tflite_quant_model = converter.convert()

เพื่อลดเวลาในการตอบสนองระหว่างการอนุมาน โอเปอเรเตอร์ "dynamic-range" จะวัดปริมาณการเปิดใช้งานแบบไดนามิกโดยอิงจากช่วงเป็น 8 บิต และดำเนินการคำนวณด้วยน้ำหนักและการเปิดใช้งานแบบ 8 บิต การเพิ่มประสิทธิภาพนี้ให้เวลาในการตอบสนองที่ใกล้เคียงกับการอนุมานแบบจุดคงที่โดยสมบูรณ์ อย่างไรก็ตาม ระบบจะยังคงจัดเก็บเอาต์พุตโดยใช้จุดทศนิยม ดังนั้นความเร็วของการดำเนินการในช่วงไดนามิกที่เพิ่มขึ้นจะน้อยกว่าการคำนวณแบบจุดคงที่เต็มรูปแบบ

การแปลงค่าจำนวนเต็มแบบเต็ม

คุณสามารถรับการปรับปรุงเวลาในการตอบสนองเพิ่มเติม ลดการใช้งานหน่วยความจำสูงสุด และความสามารถในการทำงานร่วมกับอุปกรณ์ฮาร์ดแวร์หรือ Accelerator แบบจำนวนเต็มเท่านั้น โดยตรวจสอบว่าคณิตศาสตร์ของโมเดลทั้งหมดเป็นตัวเลขจำนวนเต็ม

หากต้องการหาตัวเลขจำนวนเต็มแบบเต็ม คุณจะต้องปรับเทียบหรือประมาณช่วง เช่น (ต่ำสุด, สูงสุด) ของ Tensor จุดลอยตัวทั้งหมดในโมเดล ส่วน Tensor คงที่ เช่น น้ำหนักและอคติ ส่วน Tensor ตัวแปร เช่น อินพุตโมเดล จะไม่สามารถปรับเทียบการเปิดใช้งาน (เอาต์พุตของเลเยอร์ระดับกลาง) และเอาต์พุตโมเดลได้ เว้นแต่ว่าเราจะเรียกใช้รอบการอนุมาน 2-3 รอบ ด้วยเหตุนี้ ตัวแปลงจึงต้องการชุดข้อมูลตัวแทนเพื่อทำการปรับเทียบ ชุดข้อมูลนี้เป็นส่วนย่อยเล็กๆ (ประมาณ 100-500 ตัวอย่าง) ของข้อมูลการฝึกและการตรวจสอบ โปรดดูฟังก์ชัน representative_dataset() ด้านล่าง

จาก TensorFlow เวอร์ชัน 2.7 คุณจะระบุชุดข้อมูลตัวแทนผ่านลายเซ็นเป็นตัวอย่างต่อไปนี้ได้

def representative_dataset():
  for data in dataset:
    yield {
      "image": data.image,
      "bias": data.bias,
    }

หากมีลายเซ็นมากกว่า 1 รายการในโมเดล TensorFlow ที่ระบุ คุณระบุชุดข้อมูลหลายรายการได้โดยการระบุคีย์ลายเซ็น ดังนี้

def representative_dataset():
  # Feed data set for the "encode" signature.
  for data in encode_signature_dataset:
    yield (
      "encode", {
        "image": data.image,
        "bias": data.bias,
      }
    )

  # Feed data set for the "decode" signature.
  for data in decode_signature_dataset:
    yield (
      "decode", {
        "image": data.image,
        "hint": data.hint,
      },
    )

คุณสร้างชุดข้อมูลตัวแทนได้โดยการระบุรายการ Tensor อินพุต ดังนี้

def representative_dataset():
  for data in tf.data.Dataset.from_tensor_slices((images)).batch(1).take(100):
    yield [tf.dtypes.cast(data, tf.float32)]

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

สำหรับการทดสอบ คุณใช้ชุดข้อมูลจำลองได้ดังนี้

def representative_dataset():
    for _ in range(100):
      data = np.random.rand(1, 244, 244, 3)
      yield [data.astype(np.float32)]
 

จำนวนเต็มที่มีแบบลอยตัวสำรอง (โดยใช้อินพุต/เอาต์พุตแบบลอยเริ่มต้น)

หากต้องการคำนวณจำนวนเต็มแบบเต็มจำนวนของโมเดล แต่ใช้โอเปอเรเตอร์แบบลอยเมื่อไม่มีการใช้จำนวนเต็ม (เพื่อให้มั่นใจว่า Conversion จะเกิดขึ้นอย่างราบรื่น) ให้ทำตามขั้นตอนต่อไปนี้

import tensorflow as tf
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.representative_dataset = representative_dataset
tflite_quant_model = converter.convert()

จำนวนเต็มเท่านั้น

การสร้างโมเดลจำนวนเต็มเท่านั้นเป็นกรณีการใช้งานทั่วไปสำหรับ TensorFlow Lite สำหรับไมโครคอนโทรลเลอร์และ Coral Edge TPU

นอกจากนี้ เพื่อให้เข้ากันได้กับอุปกรณ์แบบจำนวนเต็มเท่านั้น (เช่น ไมโครคอนโทรลเลอร์ 8 บิต) และ Accelerator (เช่น Coral Edge TPU) คุณสามารถบังคับใช้การวัดจำนวนเต็มแบบเต็มจำนวนสำหรับการดำเนินการทั้งหมด รวมถึงอินพุตและเอาต์พุตโดยทำตามขั้นตอนต่อไปนี้

import tensorflow as tf
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.representative_dataset = representative_dataset
converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8]
converter.inference_input_type = tf.int8  # or tf.uint8
converter.inference_output_type = tf.int8  # or tf.uint8
tflite_quant_model = converter.convert()

การวัดปริมาณ Float16

คุณสามารถลดขนาดของโมเดลจุดลอยตัวได้โดยการกำหนดน้ำหนักเป็นเลขทศนิยม 16 ซึ่งเป็นมาตรฐาน IEEE สำหรับตัวเลขทศนิยม 16 บิต หากต้องการเปิดใช้การกำหนดน้ำหนักลอยตัว 16 ให้ทำตามขั้นตอนต่อไปนี้

import tensorflow as tf
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.target_spec.supported_types = [tf.float16]
tflite_quant_model = converter.convert()

ข้อดีของการวัดปริมาณด้วย Float 16 มีดังนี้

  • โมเดลลดขนาดลงสูงสุดครึ่งหนึ่ง (เนื่องจากน้ำหนักทั้งหมดกลายเป็นครึ่งหนึ่งของขนาดเดิม)
  • เพราะทำให้สูญเสียความแม่นยำน้อยที่สุด
  • โดยรองรับผู้รับมอบสิทธิ์บางราย (เช่น ผู้รับมอบสิทธิ์ GPU) ที่ทํางานกับข้อมูล Float 16 ได้โดยตรง ส่งผลให้ดำเนินการได้รวดเร็วกว่าการคำนวณ Float 32

ข้อเสียของการวัดปริมาณ Float 16 มีดังนี้

  • ซึ่งไม่ได้ลดเวลาในการตอบสนองมากเท่ากับการแปลงปริมาณเป็นการคำนวณจุดคงที่
  • โดยค่าเริ่มต้น โมเดล Floatized 16 จะ "แยกปริมาณ" ค่าน้ำหนักให้เป็น Float 32 เมื่อทำงานบน CPU (โปรดทราบว่าการมอบสิทธิ์ GPU จะไม่ทำการลดปริมาณนี้ เนื่องจากสามารถดำเนินการกับข้อมูล Float16 ได้)

จำนวนเต็มเท่านั้น: การเปิดใช้งาน 16 บิตที่มีน้ำหนัก 8 บิต (ทดลอง)

นี่คือรูปแบบการวัดปริมาณในการทดสอบ รูปแบบนี้คล้ายกับรูปแบบ "จำนวนเต็มเท่านั้น" แต่การเปิดใช้งานจะกำหนดปริมาณตามช่วงไปจนถึง 16 บิต การถ่วงน้ำหนักจะแสดงผลเป็นจำนวนเต็ม 8 บิตและการให้น้ำหนักพิเศษเป็นค่าจำนวนเต็ม 64 บิต ต่อไปจะเรียกว่า 16x8

ข้อดีหลักของการวัดขนาดนี้คือการปรับปรุงความแม่นยำได้อย่างมาก แต่จะเพิ่มขนาดโมเดลเล็กน้อยเท่านั้น

import tensorflow as tf
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
converter.representative_dataset = representative_dataset
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.target_spec.supported_ops = [tf.lite.OpsSet.EXPERIMENTAL_TFLITE_BUILTINS_ACTIVATIONS_INT16_WEIGHTS_INT8]
tflite_quant_model = converter.convert()

หากระบบไม่รองรับปริมาณ 16x8 สำหรับโอเปอเรเตอร์บางรายการในโมเดล โมเดลก็จะยังแปลงขนาดได้ แต่โอเปอเรเตอร์ที่ไม่รองรับจะลอยอยู่ คุณควรเพิ่มตัวเลือกต่อไปนี้ใน target_spec เพื่ออนุญาต

import tensorflow as tf
converter = tf.lite.TFLiteConverter.from_saved_model(saved_model_dir)
converter.representative_dataset = representative_dataset
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.target_spec.supported_ops = [tf.lite.OpsSet.EXPERIMENTAL_TFLITE_BUILTINS_ACTIVATIONS_INT16_WEIGHTS_INT8,
tf.lite.OpsSet.TFLITE_BUILTINS]
tflite_quant_model = converter.convert()

ตัวอย่างกรณีการใช้งานที่มีการปรับปรุงความแม่นยำตามรูปแบบการวัดปริมาณนี้

  • super-resolution,
  • การประมวลผลสัญญาณเสียง เช่น การตัดเสียงรบกวนและการบีมฟอร์ม
  • การตัดเสียงรบกวนของรูปภาพ
  • การสร้าง HDR ใหม่จากรูปภาพเดียว

ข้อเสียของการวัดขนาดนี้คือ

  • การอนุมานในปัจจุบันช้ากว่าจำนวนเต็มแบบเต็ม 8 บิตอย่างเห็นได้ชัดเนื่องจากไม่มีการใช้เคอร์เนลที่เพิ่มประสิทธิภาพ
  • ปัจจุบันยังใช้ไม่ได้กับตัวแทน TFLite ที่เร่งการแสดงผลด้วยฮาร์ดแวร์ที่มีอยู่

ดูบทแนะนำสำหรับโหมดการวัดปริมาณนี้ได้ที่นี่

ความถูกต้องของโมเดล

เนื่องจากการยกน้ำหนักเป็นการวัดปริมาณหลังการฝึก อาจทำให้ความแม่นยำลดลง โดยเฉพาะอย่างยิ่งสำหรับเครือข่ายขนาดเล็ก โมเดลที่แยกปริมาณทั้งหมดซึ่งฝึกล่วงหน้ามีให้บริการสำหรับเครือข่ายที่เฉพาะเจาะจงในโมเดล Kaggle การตรวจสอบความแม่นยำของโมเดลเชิงปริมาณเพื่อยืนยันว่าการลดลงของความแม่นยำนั้นอยู่ภายในขีดจำกัดที่ยอมรับได้ มีเครื่องมือในการประเมินความแม่นยำของโมเดล TensorFlow Lite

หรือหากความแม่นยำลดลงสูงเกินไป ให้ลองใช้การฝึกแบบรับรู้ปริมาณ อย่างไรก็ตาม การดำเนินการดังกล่าวต้องมีการปรับเปลี่ยนระหว่างการฝึกโมเดลเพื่อเพิ่มโหนดการวัดขนาดปลอม ในขณะที่เทคนิคการวัดปริมาณหลังการฝึกในหน้านี้ใช้โมเดลก่อนการฝึกที่มีอยู่

การนำเสนอสำหรับ Tensor ที่เล็กลง

การแปลงค่าเป็น 8 บิตจะประมาณค่าจำนวนทศนิยมโดยใช้สูตรต่อไปนี้

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

การนำเสนอประกอบด้วย 2 ส่วนหลักๆ ดังนี้

  • ต่อแกน (หรือที่เรียกว่าต่อแชแนล) หรือน้ำหนักต่อ tensor แสดงด้วยค่าประกอบของ int82 ในช่วง [-127, 127] โดยมีจุด 0 เท่ากับ 0

  • การเปิดใช้งาน/อินพุตต่อ Tensor แสดงด้วยค่าการเสริมของ int82 ในช่วง [-128, 127] โดยมีจุด 0 ในช่วง [-128, 127]

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