API โครงข่ายระบบประสาทเทียม

API โครงข่ายระบบประสาทเทียมของ Android (NNAPI) คือ Android C API ที่ออกแบบมาเพื่อการเรียกใช้ การดำเนินงานด้านการคำนวณอย่างหนักสำหรับแมชชีนเลิร์นนิงในอุปกรณ์ Android NNAPI ได้รับการออกแบบมาเพื่อมอบฟังก์ชันชั้นฐานสำหรับระดับที่สูงกว่า เฟรมเวิร์กแมชชีนเลิร์นนิง เช่น TensorFlow Lite และ Caffe2 ที่สร้างและฝึกโครงข่ายประสาท API พร้อมใช้งาน ในอุปกรณ์ Android ทั้งหมดที่ใช้ Android 8.1 (API ระดับ 27) ขึ้นไป

NNAPI รองรับการแทรกกรอบโดยการใช้ข้อมูลจากอุปกรณ์ Android กับอุปกรณ์ โมเดลที่นักพัฒนาซอฟต์แวร์กำหนดและได้รับการฝึกแล้ว ตัวอย่างของการกำหนดกรอบ ได้แก่ การแยกประเภท การคาดการณ์พฤติกรรมของผู้ใช้ และเลือกคำตอบที่เหมาะสมให้กับ คำค้นหา

การละเมิดในอุปกรณ์มีประโยชน์หลายประการดังนี้

  • เวลาในการตอบสนอง: คุณไม่จำเป็นต้องส่งคำขอผ่านการเชื่อมต่อเครือข่าย และ รอการตอบกลับ ตัวอย่างเช่น สิ่งนี้อาจมีความสำคัญสำหรับแอปพลิเคชันวิดีโอ ซึ่งประมวลผลเฟรมต่อเนื่อง ที่มาจากกล้อง
  • ความพร้อมใช้งาน: แอปพลิเคชันจะทำงานแม้อยู่นอกการครอบคลุมเครือข่าย
  • ความเร็ว: ฮาร์ดแวร์ใหม่ที่ใช้สำหรับการประมวลผลโครงข่ายระบบประสาทเทียมโดยเฉพาะ ให้การคำนวณที่รวดเร็วกว่า CPU สำหรับการใช้งานทั่วไปเพียงอย่างเดียว
  • ความเป็นส่วนตัว: จะไม่มีการส่งข้อมูลออกจากอุปกรณ์ Android
  • ต้นทุน: ไม่ต้องมีเซิร์ฟเวอร์ฟาร์มเมื่อคำนวณทั้งหมด อุปกรณ์ Android

แต่ก็มีข้อดีและข้อเสียต่างๆ ที่นักพัฒนาแอปควรคำนึงถึงดังนี้

  • การใช้งานระบบ: การประเมินโครงข่ายประสาทเกี่ยวข้องกับ ซึ่งอาจเพิ่มการใช้พลังงานแบตเตอรี่ คุณควรพิจารณา การตรวจสอบประสิทธิภาพแบตเตอรี่ถ้าสิ่งนี้เป็นข้อกังวลสำหรับแอปของคุณ โดยเฉพาะอย่างยิ่ง สำหรับการคำนวณเป็นเวลานาน
  • ขนาดแอปพลิเคชัน: ให้ความสำคัญกับขนาดของโมเดล โมเดลอาจ ใช้พื้นที่ว่างหลายเมกะไบต์ การรวมโมเดลขนาดใหญ่ไว้ใน APK จะส่งผลกระทบต่อผู้ใช้อย่างไม่เหมาะสม คุณอาจต้องลองดาวน์โหลด หลังการติดตั้งแอป การใช้โมเดลที่เล็กลง หรือการเรียกใช้ การคำนวณในระบบคลาวด์ NNAPI ไม่มีฟังก์ชันสำหรับการเรียกใช้ โมเดลต่างๆ ในระบบคลาวด์

โปรดดู ตัวอย่าง API โครงข่ายระบบประสาทเทียมของ Android เพื่อดูตัวอย่างวิธีใช้ NNAPI

ทำความเข้าใจรันไทม์ของ Neural Networks API

NNAPI มีชื่อโดยไลบรารีแมชชีนเลิร์นนิง เฟรมเวิร์ก และเครื่องมือ ที่ช่วยให้นักพัฒนาแอปฝึกโมเดลนอกอุปกรณ์และทำให้ใช้งานได้ใน Android อุปกรณ์ โดยทั่วไปแอปจะไม่ใช้ NNAPI โดยตรง แต่จะใช้ ใช้เฟรมเวิร์กแมชชีนเลิร์นนิง ในระดับสูงกว่า เฟรมเวิร์กเหล่านี้สามารถใช้ NNAPI สำหรับดำเนินการอนุมานการเร่งฮาร์ดแวร์ในอุปกรณ์ที่รองรับ

อิงตามข้อกำหนดของแอปและความสามารถของฮาร์ดแวร์ใน Android รันไทม์เครือข่ายระบบประสาทเทียมของ Android สามารถกระจาย ภาระงานการคำนวณของตัวประมวลผลในอุปกรณ์ที่พร้อมใช้งาน รวมถึงหน่วยประมวลผลเฉพาะ ฮาร์ดแวร์เครือข่ายระบบประสาท หน่วยประมวลผลกราฟิก (GPU) และสัญญาณดิจิทัล โปรเซสเซอร์ (DSP)

รันไทม์ของ NNAPI สำหรับอุปกรณ์ Android ที่ไม่มีไดรเวอร์ของผู้ให้บริการเฉพาะ ดำเนินการตามคำขอบน CPU

รูปที่ 1 แสดงสถาปัตยกรรมระบบระดับสูงสำหรับ NNAPI

วันที่
รูปที่ 1 สถาปัตยกรรมระบบสำหรับ API โครงข่ายระบบประสาทเทียมของ Android

โมเดลการเขียนโปรแกรม API เครือข่ายระบบประสาท

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

NNAPI ใช้นามธรรมหลักๆ 4 แบบดังนี้

  • โมเดล: กราฟการคำนวณของการดำเนินการทางคณิตศาสตร์และค่าคงที่ คุณค่าที่ได้เรียนรู้ผ่านกระบวนการฝึกอบรม การดำเนินการเหล่านี้เจาะจงสำหรับ โครงข่ายประสาท ซึ่งประกอบด้วย 2 มิติ (2 มิติ) Convolution โลจิสติกส์ (sigmoid) การเปิดใช้งาน เส้นตรง (ReLU) และอื่นๆ การสร้างโมเดลเป็นการดำเนินการแบบซิงโครนัส เมื่อสร้างเรียบร้อยแล้ว ก็สามารถนำกลับมาใช้ซ้ำในชุดข้อความและการรวบรวมได้ ใน NNAPI โมเดลจะแสดงเป็น ANeuralNetworksModel อินสแตนซ์
  • การคอมไพล์: แสดงการกำหนดค่าสำหรับการคอมไพล์โมเดล NNAPI ลงใน ระดับต่ำลงมา การสร้างการคอมไพล์เป็นการดำเนินการแบบซิงโครนัส ครั้งเดียว สำเร็จ สามารถนำมาใช้ซ้ำในเทรดและการดำเนินการต่างๆ ได้ ใน NNAPI คอมไพล์แต่ละรายการจะแสดงเป็น ANeuralNetworksCompilation อินสแตนซ์
  • หน่วยความจำ: หมายถึงหน่วยความจำที่ใช้ร่วมกัน ไฟล์ที่แมปจากหน่วยความจำ และหน่วยความจำที่คล้ายกัน บัฟเฟอร์ การใช้บัฟเฟอร์หน่วยความจำทำให้รันไทม์ NNAPI โอนข้อมูลไปยังไดรเวอร์ได้ ได้อย่างมีประสิทธิภาพมากขึ้น โดยทั่วไปแล้วแอปจะสร้างบัฟเฟอร์หน่วยความจำที่ใช้ร่วมกัน 1 ส่วนซึ่ง มี Tensor ทุกรายการที่ต้องใช้ในการกำหนดโมเดล คุณยังใช้หน่วยความจำได้ เพื่อจัดเก็บอินพุตและเอาต์พุตสำหรับอินสแตนซ์การดำเนินการ ใน NNAPI บัฟเฟอร์หน่วยความจำแต่ละภาพจะแสดงเป็น ANeuralNetworksMemory อินสแตนซ์
  • การดำเนินการ: อินเทอร์เฟซสำหรับการใช้โมเดล NNAPI กับชุดอินพุตและ รวบรวมผลลัพธ์ การดำเนินการอาจทำแบบซิงโครนัสหรืออะซิงโครนัสก็ได้

    สำหรับการดำเนินการแบบไม่พร้อมกัน เทรดหลายรายการ จะรอในการดำเนินการเดียวกันได้ เมื่อการดำเนินการนี้เสร็จสมบูรณ์ เทรดทั้งหมดจะ เผยแพร่แล้ว

    ใน NNAPI การดำเนินการแต่ละรายการจะแสดงเป็น ANeuralNetworksExecution อินสแตนซ์

รูปที่ 2 แสดงขั้นตอนการเขียนโปรแกรมพื้นฐาน

วันที่
รูปที่ 2 ขั้นตอนการเขียนโปรแกรมสำหรับ API โครงข่ายระบบประสาทเทียมของ Android

เนื้อหาที่เหลือของส่วนนี้จะอธิบายขั้นตอนในการตั้งค่าโมเดล NNAPI ดำเนินการคำนวณ คอมไพล์โมเดล และเรียกใช้โมเดลที่คอมไพล์

ให้สิทธิ์เข้าถึงข้อมูลการฝึก

ระบบอาจเก็บข้อมูลน้ำหนักและน้ำหนักที่ฝึกแล้วไว้ในไฟล์ หากต้องการจัดเตรียม รันไทม์ NNAPI ที่มีการเข้าถึงข้อมูลนี้อย่างมีประสิทธิภาพ ANeuralNetworksMemory โดยการเรียกฟังก์ชัน ANeuralNetworksMemory_createFromFd() และส่งไปในข้อบ่งชี้ไฟล์ของไฟล์ข้อมูลที่เปิดอยู่ และคุณยัง ระบุแฟล็กการป้องกันหน่วยความจำและออฟเซ็ตที่มีพื้นที่หน่วยความจำที่แชร์ เริ่มต้นในไฟล์

// Create a memory buffer from the file that contains the trained data
ANeuralNetworksMemory* mem1 = NULL;
int fd = open("training_data", O_RDONLY);
ANeuralNetworksMemory_createFromFd(file_size, PROT_READ, fd, 0, &mem1);

แม้ว่าในตัวอย่างนี้ เราจะใช้ ANeuralNetworksMemory สำหรับน้ำหนักทั้งหมดของเรา ก็อาจจะใช้ ANeuralNetworksMemoryอินสแตนซ์สำหรับหลายไฟล์

ใช้บัฟเฟอร์ของฮาร์ดแวร์เนทีฟ

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

หากต้องการอนุญาตให้รันไทม์ของ NNAPI เข้าถึงออบเจ็กต์ AHardwareBuffer ให้สร้าง ANeuralNetworksMemory โดยการเรียกฟังก์ชัน ฟังก์ชัน ANeuralNetworksMemory_createFromAHardwareBuffer และการส่งในฟังก์ชัน ออบเจ็กต์ AHardwareBuffer ดังที่แสดงในตัวอย่างโค้ดต่อไปนี้

// Configure and create AHardwareBuffer object
AHardwareBuffer_Desc desc = ...
AHardwareBuffer* ahwb = nullptr;
AHardwareBuffer_allocate(&desc, &ahwb);

// Create ANeuralNetworksMemory from AHardwareBuffer
ANeuralNetworksMemory* mem2 = NULL;
ANeuralNetworksMemory_createFromAHardwareBuffer(ahwb, &mem2);

เมื่อ NNAPI ไม่ต้องการเข้าถึงออบเจ็กต์ AHardwareBuffer อีกต่อไป ให้เพิ่มพื้นที่ว่าง อินสแตนซ์ ANeuralNetworksMemory ที่เกี่ยวข้อง:

ANeuralNetworksMemory_free(mem2);

หมายเหตุ:

  • คุณสามารถใช้ AHardwareBuffer เท่านั้นสำหรับบัฟเฟอร์ทั้งหมด คุณไม่สามารถใช้กับ พารามิเตอร์ ARect
  • รันไทม์ของ NNAPI จะไม่ล้างออก เพื่อบัฟเฟอร์ คุณต้องตรวจสอบว่าบัฟเฟอร์อินพุตและเอาต์พุต ก่อนกำหนดเวลาการดำเนินการ
  • ไม่มีการสนับสนุนสำหรับ Sync Fence Descriptor
  • สำหรับ AHardwareBuffer ที่มี รูปแบบเฉพาะผู้ให้บริการและบิตการใช้งาน จะขึ้นอยู่กับการใช้งานของผู้ให้บริการ เพื่อดูว่าลูกค้าหรือคนขับเป็นผู้รับผิดชอบในการล้าง แคช

รุ่น

โมเดลคือหน่วยพื้นฐานของการคำนวณใน NNAPI แต่ละโมเดลได้รับการกำหนดไว้ โดยตัวถูกดำเนินการและการดำเนินการอย่างน้อย 1 รายการ

ตัวถูกดำเนินการ

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

มีตัวถูกดำเนินการ 2 ประเภทที่สามารถเพิ่มลงในโมเดล NNAPI ได้แก่ สเกลาร์ และ tensors

สเกลาร์แสดงถึงค่าเดียว NNAPI รองรับค่าสเกลาร์ในบูลีน จุดลอยตัว 16 บิต, จุดลอยตัว 32 บิต, จำนวนเต็ม 32 บิต และไม่มีเครื่องหมาย รูปแบบจำนวนเต็ม 32 บิต

การดำเนินการส่วนใหญ่ใน NNAPI เกี่ยวข้องกับ Tensor Tensor คืออาร์เรย์ N มิติ NNAPI รองรับ tensor ที่มีจุดลอยตัว 16 บิต, จุดลอยตัว 32 บิต, 8 บิต Quantized, 16 บิตที่ควอนไตซ์, จำนวนเต็ม 32 บิต และ 8 บิต ค่าบูลีน

ตัวอย่างเช่น รูปที่ 3 หมายถึงโมเดลที่มีการดำเนินการ 2 อย่าง ได้แก่ การบวก ตามด้วยการคูณ โมเดลจะใช้ Tensor อินพุตและสร้าง 1 รายการ Tensor เอาต์พุต

วันที่
รูปที่ 3 ตัวอย่างตัวถูกดำเนินการสำหรับโมเดล NNAPI

โมเดลด้านบนมีตัวถูกดำเนินการ 7 ตัว ตัวถูกดำเนินการเหล่านี้จะระบุโดยปริยายโดย ดัชนีของลำดับที่เพิ่มลงในโมเดล ตัวถูกดำเนินการแรก ที่ถูกเพิ่มจะมีดัชนีเป็น 0 ดัชนีที่สองเป็น 1 เป็นต้น ตัวต่อตัว 1, 2, 3 และ 5 คือตัวถูกดำเนินการคงที่

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

ตัวดำเนินการมีหลายประเภท ซึ่งจะระบุเมื่อมีการเพิ่มลงในโมเดล

คุณใช้ตัวถูกดำเนินการเป็นทั้งอินพุตและเอาต์พุตของโมเดลไม่ได้

ตัวถูกดำเนินการทั้งหมดต้องเป็นอินพุตโมเดล ค่าคงที่ หรือตัวถูกดำเนินการเอาต์พุตของ หนึ่งการดำเนินการเท่านั้น

ดูข้อมูลเพิ่มเติมเกี่ยวกับการใช้ตัวถูกดำเนินการได้ที่ ข้อมูลเพิ่มเติมเกี่ยวกับตัวถูกดำเนินการ

การทำงาน

การดำเนินการจะระบุการคำนวณที่จะดำเนินการ การดำเนินการแต่ละรายการประกอบด้วย ขององค์ประกอบเหล่านี้

  • ประเภทการดำเนินการ (เช่น การบวก การคูณ Convolution)
  • รายการดัชนีของตัวถูกดำเนินการที่การดำเนินการใช้สำหรับอินพุต และ
  • รายการดัชนีของตัวถูกดำเนินการที่การดำเนินการใช้สำหรับเอาต์พุต

ลำดับในรายการเหล่านี้มีความสำคัญ โปรดดู เอกสารอ้างอิง NNAPI API สำหรับอินพุตที่คาดไว้ และเอาต์พุตของการดำเนินการแต่ละประเภท

คุณต้องเพิ่มตัวถูกดำเนินการที่การดำเนินการใช้หรือสร้างในโมเดล ก่อนเพิ่มการดำเนินการ

ลำดับที่คุณเพิ่มการดำเนินการไม่มีผล NNAPI อาศัย ทรัพยากร Dependency ที่กำหนดโดยกราฟการคำนวณของตัวถูกดำเนินการและการดำเนินการกับ กำหนดลำดับการดำเนินการ

การดำเนินการที่ NNAPI รองรับจะสรุปไว้ในตารางด้านล่าง

หมวดหมู่ การทำงาน
การดำเนินการทางคณิตศาสตร์ที่คำนึงถึงองค์ประกอบ
การจัดการ Tensor
การดำเนินการกับอิมเมจ
การดำเนินการค้นหา
การดำเนินการทำให้เป็นเวอร์ชันมาตรฐาน
การดำเนินการคอนโวลูชัน
การดำเนินการพูล
การดำเนินการเปิดใช้งาน
การดำเนินการอื่นๆ

ปัญหาที่ทราบใน API ระดับ 28: เมื่อส่ง ANEURALNETWORKS_TENSOR_QUANT8_ASYMM Tensor ไปยัง ANEURALNETWORKS_PAD ซึ่งพร้อมใช้งานใน Android 9 (API ระดับ 28) ขึ้นไป เอาต์พุตจาก NNAPI อาจไม่ตรงกับผลลัพธ์จากแมชชีนเลิร์นนิงในระดับที่สูงกว่า เช่น เฟรมเวิร์ก TensorFlow Lite คุณ ควรที่จะผ่านเท่านั้น ANEURALNETWORKS_TENSOR_FLOAT32 ปัญหาได้รับการแก้ไขแล้วใน Android 10 (API ระดับ 29) ขึ้นไป

สร้างโมเดล

ในตัวอย่างต่อไปนี้ เราสร้างโมเดลการดำเนินการ 2 แบบที่พบใน รูปที่ 3

หากต้องการสร้างโมเดล ให้ทำตามขั้นตอนต่อไปนี้

  1. เรียกใช้ ANeuralNetworksModel_create() เพื่อกำหนดโมเดลที่ว่างเปล่า

    ANeuralNetworksModel* model = NULL;
    ANeuralNetworksModel_create(&model);
    
  2. เพิ่มตัวถูกดำเนินการลงในโมเดลโดยการเรียกใช้ ANeuralNetworks_addOperand() ประเภทข้อมูลจะกำหนดโดยใช้ ANeuralNetworksOperandType Google Analytics 4

    // In our example, all our tensors are matrices of dimension [3][4]
    ANeuralNetworksOperandType tensor3x4Type;
    tensor3x4Type.type = ANEURALNETWORKS_TENSOR_FLOAT32;
    tensor3x4Type.scale = 0.f;    // These fields are used for quantized tensors
    tensor3x4Type.zeroPoint = 0;  // These fields are used for quantized tensors
    tensor3x4Type.dimensionCount = 2;
    uint32_t dims[2] = {3, 4};
    tensor3x4Type.dimensions = dims;

    // We also specify operands that are activation function specifiers ANeuralNetworksOperandType activationType; activationType.type = ANEURALNETWORKS_INT32; activationType.scale = 0.f; activationType.zeroPoint = 0; activationType.dimensionCount = 0; activationType.dimensions = NULL;

    // Now we add the seven operands, in the same order defined in the diagram ANeuralNetworksModel_addOperand(model, &tensor3x4Type); // operand 0 ANeuralNetworksModel_addOperand(model, &tensor3x4Type); // operand 1 ANeuralNetworksModel_addOperand(model, &activationType); // operand 2 ANeuralNetworksModel_addOperand(model, &tensor3x4Type); // operand 3 ANeuralNetworksModel_addOperand(model, &tensor3x4Type); // operand 4 ANeuralNetworksModel_addOperand(model, &activationType); // operand 5 ANeuralNetworksModel_addOperand(model, &tensor3x4Type); // operand 6
  3. สำหรับตัวถูกดำเนินการที่มีค่าคงที่ เช่น น้ำหนักและความลำเอียงที่ ที่ได้รับจากกระบวนการฝึกอบรม ให้ใช้ ANeuralNetworksModel_setOperandValue() และ ANeuralNetworksModel_setOperandValueFromMemory()

    ในตัวอย่างต่อไปนี้ เรากำหนดค่าคงที่จากไฟล์ข้อมูลการฝึก ที่สอดคล้องกับบัฟเฟอร์หน่วยความจำที่เราสร้างขึ้นในให้การเข้าถึง ข้อมูลการฝึกอบรม

    // In our example, operands 1 and 3 are constant tensors whose values were
    // established during the training process
    const int sizeOfTensor = 3 * 4 * 4;    // The formula for size calculation is dim0 * dim1 * elementSize
    ANeuralNetworksModel_setOperandValueFromMemory(model, 1, mem1, 0, sizeOfTensor);
    ANeuralNetworksModel_setOperandValueFromMemory(model, 3, mem1, sizeOfTensor, sizeOfTensor);

    // We set the values of the activation operands, in our example operands 2 and 5 int32_t noneValue = ANEURALNETWORKS_FUSED_NONE; ANeuralNetworksModel_setOperandValue(model, 2, &noneValue, sizeof(noneValue)); ANeuralNetworksModel_setOperandValue(model, 5, &noneValue, sizeof(noneValue));
  4. สำหรับแต่ละการดำเนินการในกราฟมีทิศทางที่คุณต้องการคำนวณ ให้ใส่ฟิลด์ ไปยังโมเดลของคุณโดยเรียก ANeuralNetworksModel_addOperation()

    แอปจะต้องระบุข้อมูลต่อไปนี้เป็นพารามิเตอร์ในการเรียกนี้

    • ประเภทการดำเนินการ
    • จำนวนค่าอินพุต
    • อาร์เรย์ของดัชนีสำหรับตัวถูกดำเนินการของอินพุต
    • จำนวนค่าเอาต์พุต
    • อาร์เรย์ของดัชนีสำหรับตัวถูกดำเนินการของเอาต์พุต

    โปรดทราบว่าไม่สามารถใช้ตัวถูกดำเนินการได้ทั้งสำหรับอินพุตและเอาต์พุตของ

    // We have two operations in our example
    // The first consumes operands 1, 0, 2, and produces operand 4
    uint32_t addInputIndexes[3] = {1, 0, 2};
    uint32_t addOutputIndexes[1] = {4};
    ANeuralNetworksModel_addOperation(model, ANEURALNETWORKS_ADD, 3, addInputIndexes, 1, addOutputIndexes);

    // The second consumes operands 3, 4, 5, and produces operand 6 uint32_t multInputIndexes[3] = {3, 4, 5}; uint32_t multOutputIndexes[1] = {6}; ANeuralNetworksModel_addOperation(model, ANEURALNETWORKS_MUL, 3, multInputIndexes, 1, multOutputIndexes);
  5. ระบุตัวถูกดำเนินการที่โมเดลควรถือเป็นอินพุตและเอาต์พุตโดย กำลังเรียก ANeuralNetworksModel_identifyInputsAndOutputs()

    // Our model has one input (0) and one output (6)
    uint32_t modelInputIndexes[1] = {0};
    uint32_t modelOutputIndexes[1] = {6};
    ANeuralNetworksModel_identifyInputsAndOutputs(model, 1, modelInputIndexes, 1 modelOutputIndexes);
    
  6. (ไม่บังคับ) ระบุว่า ANEURALNETWORKS_TENSOR_FLOAT32 ได้รับอนุญาตให้คำนวณด้วยช่วงหรือความแม่นยำต่ำเท่ากับ รูปแบบจุดลอยตัว 16 บิต IEEE 754 ด้วยการเรียก ANeuralNetworksModel_relaxComputationFloat32toFloat16()

  7. โทร ANeuralNetworksModel_finish() เพื่อสรุปการกำหนดโมเดลของคุณ หากไม่มีข้อผิดพลาด แสดงผลรหัสผลลัพธ์ของ ANEURALNETWORKS_NO_ERROR

    ANeuralNetworksModel_finish(model);
    

เมื่อสร้างโมเดลแล้ว คุณสามารถคอมไพล์โมเดลได้ไม่จำกัดจำนวนครั้งและสั่งการแต่ละโมเดล คอมไพล์ได้ไม่จำกัดจำนวนครั้ง

ควบคุมโฟลว์

ในการรวมขั้นตอนการควบคุมไว้ในโมเดล NNAPI ให้ทำดังนี้

  1. สร้างกราฟย่อยการดำเนินการที่เกี่ยวข้อง (then และ else กราฟย่อย สำหรับคำสั่ง IF, condition และ body กราฟย่อยสำหรับ WHILE วนซ้ำ) เป็นโมเดล ANeuralNetworksModel* แบบสแตนด์อโลน

    ANeuralNetworksModel* thenModel = makeThenModel();
    ANeuralNetworksModel* elseModel = makeElseModel();
    
  2. สร้างตัวถูกดำเนินการที่อ้างอิงถึงโมเดลเหล่านั้นภายในโมเดลที่มีส่วน ควบคุมโฟลว์:

    ANeuralNetworksOperandType modelType = {
        .type = ANEURALNETWORKS_MODEL,
    };
    ANeuralNetworksModel_addOperand(model, &modelType);  // kThenOperandIndex
    ANeuralNetworksModel_addOperand(model, &modelType);  // kElseOperandIndex
    ANeuralNetworksModel_setOperandValueFromModel(model, kThenOperandIndex, &thenModel);
    ANeuralNetworksModel_setOperandValueFromModel(model, kElseOperandIndex, &elseModel);
    
  3. เพิ่มการดำเนินการขั้นตอนการควบคุมดังนี้

    uint32_t inputs[] = {kConditionOperandIndex,
                         kThenOperandIndex,
                         kElseOperandIndex,
                         kInput1, kInput2, kInput3};
    uint32_t outputs[] = {kOutput1, kOutput2};
    ANeuralNetworksModel_addOperation(model, ANEURALNETWORKS_IF,
                                      std::size(inputs), inputs,
                                      std::size(output), outputs);
    

การรวบรวม

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

หากต้องการคอมไพล์โมเดล ให้ทำตามขั้นตอนต่อไปนี้

  1. เรียกใช้ ANeuralNetworksCompilation_create() เพื่อสร้างอินสแตนซ์การคอมไพล์ใหม่

    // Compile the model
    ANeuralNetworksCompilation* compilation;
    ANeuralNetworksCompilation_create(model, &compilation);
    

    นอกจากนี้ คุณยังใช้การกำหนดอุปกรณ์เพื่อ เลือกอุปกรณ์ที่จะเรียกใช้

  2. คุณเลือกควบคุมการเปลี่ยนรันไทม์ระหว่างพลังงานแบตเตอรี่ได้ และการใช้งานได้อย่างรวดเร็ว คุณสามารถทำได้โดยการโทร ANeuralNetworksCompilation_setPreference()

    // Ask to optimize for low power consumption
    ANeuralNetworksCompilation_setPreference(compilation, ANEURALNETWORKS_PREFER_LOW_POWER);
    

    ค่ากำหนดที่คุณสามารถระบุได้มีดังนี้

    • ANEURALNETWORKS_PREFER_LOW_POWER: ควรเรียกใช้ในลักษณะที่ช่วยลดการใช้แบตเตอรี่ให้เหลือน้อยที่สุด ช่วยได้มาก สำหรับการรวบรวมที่มีการดำเนินการบ่อยครั้ง
    • ANEURALNETWORKS_PREFER_FAST_SINGLE_ANSWER: หากต้องการให้ระบบแสดงคำตอบข้อเดียวโดยเร็วที่สุด แม้ว่าจะเป็นสาเหตุก็ตาม ใช้พลังงานมากขึ้น โดยตัวเลือกนี้คือค่าเริ่มต้น
    • ANEURALNETWORKS_PREFER_SUSTAINED_SPEED: เพิ่มประสิทธิภาพอัตราการส่งข้อมูลของเฟรมต่อเนื่อง เช่น เมื่อ ประมวลผลเฟรมต่อเนื่องที่มาจากกล้อง
  3. คุณสามารถเลือกตั้งค่าการแคชการรวบรวมได้โดยการเรียกใช้ ANeuralNetworksCompilation_setCaching

    // Set up compilation caching
    ANeuralNetworksCompilation_setCaching(compilation, cacheDir, token);
    

    ใช้ getCodeCacheDir() สำหรับ cacheDir token ที่ระบุต้องไม่ซ้ำกันสำหรับแต่ละโมเดลภายใน แอปพลิเคชัน

  4. สรุปคำจำกัดความของการรวบรวมคลิปโดยการเรียกใช้ ANeuralNetworksCompilation_finish() หากไม่มีข้อผิดพลาด ฟังก์ชันนี้จะแสดงรหัสผลลัพธ์ของ ANEURALNETWORKS_NO_ERROR

    ANeuralNetworksCompilation_finish(compilation);
    

การค้นหาและการกำหนดอุปกรณ์

NNAPI มีให้บริการสำหรับอุปกรณ์ Android ที่ใช้ Android 10 (API ระดับ 29) ขึ้นไป ฟังก์ชันที่ช่วยให้ไลบรารีและแอปของเฟรมเวิร์กแมชชีนเลิร์นนิงได้รับ ข้อมูลเกี่ยวกับอุปกรณ์ที่ใช้ได้และระบุอุปกรณ์ที่จะใช้ การให้ข้อมูลเกี่ยวกับอุปกรณ์ที่มีอยู่ช่วยให้แอป เวอร์ชันจริงของไดรเวอร์ที่พบในอุปกรณ์เพื่อหลีกเลี่ยงที่ทราบ ไม่เข้ากัน โดยทำให้แอปสามารถระบุได้ว่าจะใช้อุปกรณ์ใด ใช้งานส่วนต่างๆ ของโมเดล แอปสามารถเพิ่มประสิทธิภาพสำหรับ Android อุปกรณ์ที่นำไปใช้งาน

การค้นหาอุปกรณ์

ใช้ ANeuralNetworks_getDeviceCount เพื่อดูจำนวนอุปกรณ์ที่ใช้ได้ สำหรับแต่ละอุปกรณ์ ให้ใช้ ANeuralNetworks_getDevice เพื่อตั้งค่าอินสแตนซ์ ANeuralNetworksDevice เป็นการอ้างอิงไปยังอุปกรณ์นั้น

เมื่อมีข้อมูลอ้างอิงอุปกรณ์แล้ว คุณก็สามารถดูข้อมูลเพิ่มเติมเกี่ยวกับ อุปกรณ์นั้นโดยใช้ฟังก์ชันต่อไปนี้

การกำหนดอุปกรณ์

ใช้ ANeuralNetworksModel_getSupportedOperationsForDevices เพื่อค้นหาการดำเนินการของโมเดลที่เรียกใช้ในอุปกรณ์ที่เจาะจงได้

หากต้องการควบคุม Accelerator ที่จะใช้ในการดำเนินการ ให้เรียกใช้ ANeuralNetworksCompilation_createForDevices แทน ANeuralNetworksCompilation_create ใช้ออบเจ็กต์ ANeuralNetworksCompilation ที่ได้มาตามปกติ ฟังก์ชันจะแสดงข้อผิดพลาดหากโมเดลที่ระบุมีการดำเนินการที่ ไม่รองรับในอุปกรณ์ที่เลือก

หากระบุอุปกรณ์หลายเครื่อง รันไทม์จะทำหน้าที่กระจายข้อมูล การทำงานในอุปกรณ์ต่างๆ

เช่นเดียวกับอุปกรณ์อื่นๆ การใช้งาน CPU NNAPI จะแสดงด้วยองค์ประกอบ ANeuralNetworksDevice ที่ชื่อ nnapi-reference และเป็นประเภท ANEURALNETWORKS_DEVICE_TYPE_CPU เมื่อโทร ANeuralNetworksCompilation_createForDevices, การใช้งาน CPU ไม่ได้ ซึ่งใช้สำหรับจัดการกรณีความล้มเหลวในการคอมไพล์โมเดลและการดำเนินการ

แอปพลิเคชันมีหน้าที่รับผิดชอบในการแบ่งพาร์ติชันโมเดลเป็นโมเดลย่อยที่ สามารถทำงานในอุปกรณ์ที่ระบุ แอปพลิเคชันที่ไม่จำเป็นต้องทำด้วยตนเอง ควรจะยังคงเรียกการแบ่งพาร์ติชัน ANeuralNetworksCompilation_create ให้ใช้อุปกรณ์ที่มีอยู่ทั้งหมด (รวมถึง CPU) เพื่อเร่งความเร็ว โมเดล หากอุปกรณ์ที่คุณระบุรองรับโมเดลได้ไม่สมบูรณ์ โดยใช้ ANeuralNetworksCompilation_createForDevices ANEURALNETWORKS_BAD_DATA

การแบ่งพาร์ติชันโมเดล

เมื่อมีอุปกรณ์หลายเครื่องสำหรับโมเดลนี้ รันไทม์ของ NNAPI กระจายงานไปยังทุกอุปกรณ์ ตัวอย่างเช่น หากมีอุปกรณ์มากกว่า 1 เครื่อง ให้กับ ANeuralNetworksCompilation_createForDevices ทุกค่าที่ระบุ จะได้รับการพิจารณาเมื่อจัดสรรงาน โปรดทราบว่าหากอุปกรณ์ CPU ไม่อยู่ในรายชื่อนี้ ระบบจะปิดการดำเนินการของ CPU เมื่อใช้ ANeuralNetworksCompilation_create จะมีการพิจารณาอุปกรณ์ที่ใช้ได้ทั้งหมด รวมถึง CPU ด้วย

การกระจายนี้ทำได้โดยการเลือกจากรายการอุปกรณ์ที่พร้อมใช้งาน การดำเนินการในโมเดล อุปกรณ์ที่สนับสนุนการทำงาน และ การประกาศประสิทธิภาพที่ดีที่สุด กล่าวคือ เวลาที่มีการดำเนินการรวดเร็วที่สุด หรือ ใช้พลังงานต่ำสุด โดยขึ้นอยู่กับค่ากำหนดการดำเนินการที่ระบุโดย ไคลเอ็นต์ อัลกอริทึมการแบ่งพาร์ติชันนี้ไม่นับว่าเป็นไปได้ ความไร้ประสิทธิภาพอันเกิดจาก IO ระหว่างโปรเซสเซอร์ต่างๆ การระบุโปรเซสเซอร์หลายรายการ (อย่างชัดเจนเมื่อใช้ ANeuralNetworksCompilation_createForDevices หรือโดยนัยโดยใช้ ANeuralNetworksCompilation_create) คุณจำเป็นต้องสร้างโปรไฟล์ผลลัพธ์ แอปพลิเคชัน

หากต้องการทำความเข้าใจวิธีที่ NNAPI แบ่งพาร์ติชันโมเดล ให้ดูที่ บันทึก Android สำหรับข้อความ (ที่ระดับ INFO ที่มีแท็ก ExecutionPlan):

ModelBuilder::findBestDeviceForEachOperation(op-name): device-index

op-name คือชื่อที่สื่อความหมายของการดำเนินการในกราฟ และ device-index คือดัชนีของอุปกรณ์ที่ต้องการในรายการอุปกรณ์ รายการนี้เป็นอินพุตที่ป้อนให้กับ ANeuralNetworksCompilation_createForDevices หรือถ้าใช้ ANeuralNetworksCompilation_createForDevices ให้แสดงรายการอุปกรณ์ แสดงผลเมื่อทำซ้ำในอุปกรณ์ทั้งหมดที่ใช้ ANeuralNetworks_getDeviceCount และ ANeuralNetworks_getDevice

ข้อความ (ที่ระดับ INFO ที่มีแท็ก ExecutionPlan):

ModelBuilder::partitionTheWork: only one best device: device-name

ข้อความนี้แสดงว่ามีการเร่งกราฟทั้งกราฟในอุปกรณ์แล้ว device-name

การลงมือปฏิบัติ

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

ในการใช้งานโมเดลที่คอมไพล์แล้ว ให้ทำตามขั้นตอนต่อไปนี้

  1. เรียกใช้ ANeuralNetworksExecution_create() เพื่อสร้างอินสแตนซ์การดำเนินการใหม่

    // Run the compiled model against a set of inputs
    ANeuralNetworksExecution* run1 = NULL;
    ANeuralNetworksExecution_create(compilation, &run1);
    
  2. ระบุตำแหน่งที่แอปอ่านค่าอินพุตสำหรับการคำนวณ แอปของคุณ อ่านค่าอินพุตจากบัฟเฟอร์ผู้ใช้หรือพื้นที่หน่วยความจำที่จัดสรรได้ โดยการโทร ANeuralNetworksExecution_setInput() หรือ ANeuralNetworksExecution_setInputFromMemory() ตามลำดับ

    // Set the single input to our sample model. Since it is small, we won't use a memory buffer
    float32 myInput[3][4] = { ...the data... };
    ANeuralNetworksExecution_setInput(run1, 0, NULL, myInput, sizeof(myInput));
    
  3. ระบุตำแหน่งที่แอปเขียนค่าเอาต์พุต แอปของคุณสามารถเขียนค่าเอาต์พุตไปยัง บัฟเฟอร์ผู้ใช้หรือพื้นที่หน่วยความจำที่จัดสรรไว้ โดยการเรียกใช้ ANeuralNetworksExecution_setOutput() หรือ ANeuralNetworksExecution_setOutputFromMemory() ตามลำดับ

    // Set the output
    float32 myOutput[3][4];
    ANeuralNetworksExecution_setOutput(run1, 0, NULL, myOutput, sizeof(myOutput));
    
  4. กำหนดเวลาการดำเนินการเพื่อเริ่มต้น โดยเรียกใช้ ANeuralNetworksExecution_startCompute() หากไม่มีข้อผิดพลาด ฟังก์ชันนี้จะแสดงรหัสผลลัพธ์ของ ANEURALNETWORKS_NO_ERROR

    // Starts the work. The work proceeds asynchronously
    ANeuralNetworksEvent* run1_end = NULL;
    ANeuralNetworksExecution_startCompute(run1, &run1_end);
    
  5. โทรหา ANeuralNetworksEvent_wait() เพื่อรอให้การดำเนินการเสร็จสิ้น หากการดำเนินการคือ สำเร็จ ฟังก์ชันนี้ส่งคืนรหัสผลลัพธ์ของ ANEURALNETWORKS_NO_ERROR ระบบสามารถดําเนินการรอในชุดข้อความอื่นที่ไม่ใช่เทรดที่เริ่มต้นการดําเนินการ

    // For our example, we have no other work to do and will just wait for the completion
    ANeuralNetworksEvent_wait(run1_end);
    ANeuralNetworksEvent_free(run1_end);
    ANeuralNetworksExecution_free(run1);
    
  6. หรือคุณจะใช้ชุดอินพุตอื่นกับโมเดลที่คอมไพล์ได้โดย โดยใช้อินสแตนซ์การคอมไพล์เดียวกันเพื่อสร้าง ANeuralNetworksExecution อินสแตนซ์

    // Apply the compiled model to a different set of inputs
    ANeuralNetworksExecution* run2;
    ANeuralNetworksExecution_create(compilation, &run2);
    ANeuralNetworksExecution_setInput(run2, ...);
    ANeuralNetworksExecution_setOutput(run2, ...);
    ANeuralNetworksEvent* run2_end = NULL;
    ANeuralNetworksExecution_startCompute(run2, &run2_end);
    ANeuralNetworksEvent_wait(run2_end);
    ANeuralNetworksEvent_free(run2_end);
    ANeuralNetworksExecution_free(run2);
    

การดำเนินการแบบซิงโครนัส

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

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

การดำเนินการแบบทันที

NNAPI รองรับภาพถ่ายอัจฉริยะในอุปกรณ์ Android ที่ใช้ Android 10 (API ระดับ 29) ขึ้นไป ที่ดำเนินการผ่าน ANeuralNetworksBurst ออบเจ็กต์ การดำเนินการแบบทันทีเป็นลำดับการดำเนินการในคอมไพล์เดียวกัน ที่เกิดขึ้นต่อเนื่องกันอย่างรวดเร็ว เช่น เฟรมที่ทำงานบนเฟรมกล้อง บันทึกเสียงหรือตัวอย่างเสียงต่อเนื่อง การใช้ออบเจ็กต์ ANeuralNetworksBurst รายการอาจส่งผล ส่งผลให้ดำเนินการได้รวดเร็ว เนื่องจากจะบ่งชี้ถึงตัวเร่งความเร็วว่าทรัพยากรต่างๆ มาใช้ซ้ำได้ระหว่างการดำเนินการ และ Accelerator ควรคงอยู่ สถานะประสิทธิภาพสูงในช่วงที่ถ่ายภาพอัจฉริยะ

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

// Create burst object to be reused across a sequence of executions
ANeuralNetworksBurst* burst = NULL;
ANeuralNetworksBurst_create(compilation, &burst);

การดำเนินการแบบต่อเนื่องจะเป็นแบบพร้อมกัน อย่างไรก็ตาม แทนที่จะใช้ ANeuralNetworksExecution_compute ในการอนุมานแต่ละรายการ คุณจะต้องจับคู่ ANeuralNetworksExecution วัตถุที่มี ANeuralNetworksBurst เดียวกันในการเรียกฟังก์ชัน ANeuralNetworksExecution_burstCompute

// Create and configure first execution object
// ...

// Execute using the burst object
ANeuralNetworksExecution_burstCompute(execution1, burst);

// Use results of first execution and free the execution object
// ...

// Create and configure second execution object
// ...

// Execute using the same burst object
ANeuralNetworksExecution_burstCompute(execution2, burst);

// Use results of second execution and free the execution object
// ...

ทำให้ออบเจ็กต์ ANeuralNetworksBurst เป็นอิสระด้วย ANeuralNetworksBurst_free เมื่อไม่จำเป็นต้องใช้แล้ว

// Cleanup
ANeuralNetworksBurst_free(burst);

คิวคำสั่งแบบไม่พร้อมกันและการดำเนินการแบบ Fenced

ใน Android 11 ขึ้นไป NNAPI รองรับวิธีกำหนดเวลาเพิ่มเติม การดำเนินการแบบอะซิงโครนัสผ่าน ANeuralNetworksExecution_startComputeWithDependencies() เมื่อคุณใช้วิธีนี้ การดำเนินการจะรอข้อมูลต่อไปนี้ทั้งหมด ที่จะส่งสัญญาณก่อนเริ่มการประเมิน เมื่อการดำเนินการได้ เสร็จสมบูรณ์ และเอาต์พุตพร้อมใช้งานแล้ว เหตุการณ์ที่ส่งกลับคือ ได้รับสัญญาณ

กิจกรรมอาจมีการสนับสนุนโดย ซิงค์ Fence คุณ ต้องเรียก ANeuralNetworksEvent_wait() เพื่อรอเหตุการณ์และกู้คืนทรัพยากรที่การดำเนินการใช้ไป คุณ สามารถนำเข้าขอบเขตการซิงค์ไปยังออบเจ็กต์เหตุการณ์ได้โดยใช้ ANeuralNetworksEvent_createFromSyncFenceFd() และคุณสามารถส่งออกขอบเขตการซิงค์จากออบเจ็กต์เหตุการณ์ได้โดยใช้ ANeuralNetworksEvent_getSyncFenceFd()

เอาต์พุตที่มีขนาดแบบไดนามิก

เพื่อรองรับโมเดลที่ขนาดของเอาต์พุตขึ้นอยู่กับอินพุต ซึ่งก็คือข้อมูลที่ไม่สามารถระบุขนาดได้ในการดำเนินการโมเดล เวลา—ใช้ ANeuralNetworksExecution_getOutputOperandRank และ ANeuralNetworksExecution_getOutputOperandDimensions

ตัวอย่างโค้ดต่อไปนี้แสดงวิธีดำเนินการ

// Get the rank of the output
uint32_t myOutputRank = 0;
ANeuralNetworksExecution_getOutputOperandRank(run1, 0, &myOutputRank);

// Get the dimensions of the output
std::vector<uint32_t> myOutputDimensions(myOutputRank);
ANeuralNetworksExecution_getOutputOperandDimensions(run1, 0, myOutputDimensions.data());

ทำความสะอาดข้อมูล

ขั้นตอนการล้างข้อมูลจะช่วยจัดการกับการปลดทรัพยากรภายในที่ใช้สำหรับ การคำนวณ

// Cleanup
ANeuralNetworksCompilation_free(compilation);
ANeuralNetworksModel_free(model);
ANeuralNetworksMemory_free(mem1);

การจัดการข้อผิดพลาดและ CPU สำรอง

ถ้าเกิดข้อผิดพลาดระหว่างการแบ่งพาร์ติชัน ถ้าไดรเวอร์ไม่สามารถคอมไพล์ (ส่วนของ a) หรือหากไดรเวอร์ไม่สามารถดำเนินการกับโมเดลที่คอมไพล์แล้ว NNAPI อาจกลับไปใช้ CPU ของตนเองมากกว่า 1 รายการ

หากไคลเอ็นต์ NNAPI มีการดำเนินการเวอร์ชันที่เพิ่มประสิทธิภาพ (เช่น เช่น TFLite) การปิดใช้งานตัวเลือก CPU สำรองและ จัดการความล้มเหลวด้วยการดำเนินการเพิ่มประสิทธิภาพของไคลเอ็นต์

ใน Android 10 หากทำการคอมไพล์โดยใช้ ANeuralNetworksCompilation_createForDevices จากนั้นระบบจะปิดใช้ CPU สำรอง

ใน Android P การดำเนินการ NNAPI จะกลับไปที่ CPU หากการดำเนินการในไดรเวอร์ล้มเหลว เหตุการณ์เช่นนี้จะเป็นจริงใน Android 10 เช่นกันเมื่อ ANeuralNetworksCompilation_create กว่า ANeuralNetworksCompilation_createForDevices

การดำเนินการครั้งแรกจะย้อนกลับสำหรับพาร์ติชันเดี่ยวดังกล่าว และหากยังคง ไม่สำเร็จ ระบบจะลองใช้โมเดลทั้งโมเดลบน CPU อีกครั้ง

หากการแบ่งพาร์ติชันหรือการคอมไพล์ล้มเหลว ระบบจะลองใช้ทั้งโมเดลบน CPU

แต่อาจมีบางกรณีที่ CPU ไม่รองรับการดำเนินการบางอย่าง การรวบรวมหรือดำเนินการจะล้มเหลวแทนที่จะย้อนกลับ

แม้ว่าจะปิดใช้การสำรอง CPU ไปแล้ว แต่อาจมีการดำเนินการต่างๆ ในโมเดล ที่กำหนดไว้บน CPU หาก CPU อยู่ในรายการโปรเซสเซอร์ที่ให้มา เป็น ANeuralNetworksCompilation_createForDevices และเป็น ประเภทเดียวที่เลือก ผู้ประมวลผลข้อมูลที่สนับสนุนการดำเนินการเหล่านั้น หรือเป็นผู้ประมวลผลข้อมูลที่กล่าวอ้างว่าดีที่สุด ประสิทธิภาพสำหรับการดำเนินการเหล่านั้น ระบบจะเลือกเป็นข้อมูลหลัก (ไม่ใช่วิดีโอสำรอง) ผู้ดำเนินการ

หากต้องการตรวจสอบว่าไม่มีการดำเนินการของ CPU ให้ใช้ ANeuralNetworksCompilation_createForDevices ขณะที่ยกเว้น nnapi-reference ในรายการอุปกรณ์ เริ่มตั้งแต่ Android P คุณจะปิดใช้วิดีโอสำรองในเวลาดำเนินการได้ที่ บิลด์ DEBUG โดยการตั้งค่าพร็อพเพอร์ตี้ debug.nn.partition เป็น 2

โดเมนของหน่วยความจำ

ใน Android 11 ขึ้นไป NNAPI รองรับโดเมนหน่วยความจำที่มีตัวจัดสรร สำหรับความทรงจำที่ไม่ชัดเจน ซึ่งช่วยให้แอปพลิเคชันส่งผ่านการเชื่อมต่อเฉพาะอุปกรณ์ได้ หน่วยความจำในการดำเนินการต่างๆ เพื่อให้ NNAPI ไม่คัดลอกหรือเปลี่ยนรูปแบบข้อมูล โดยไม่จำเป็นเมื่อมีการดำเนินการติดต่อกันบนไดรเวอร์เดียวกัน

ฟีเจอร์โดเมนหน่วยความจำมีไว้สำหรับ Tensor ที่ส่วนใหญ่เป็นฟีเจอร์ภายใน ผู้ขับรถและไม่จําเป็นต้องเข้าถึงฝั่งไคลเอ็นต์บ่อยๆ ตัวอย่างของ Tensor ดังกล่าวรวมถึง Tensor สถานะในโมเดลลำดับ สำหรับ Tensor ที่ต้องการ การเข้าถึง CPU บ่อยครั้งในฝั่งไคลเอ็นต์ โปรดใช้พูลหน่วยความจำที่ใช้ร่วมกันแทน

หากต้องการจัดสรรหน่วยความจำที่คลุมเครือ ให้ทำตามขั้นตอนต่อไปนี้

  1. เรียกใช้ ANeuralNetworksMemoryDesc_create() เพื่อสร้างข้อบ่งชี้หน่วยความจำใหม่:

    // Create a memory descriptor
    ANeuralNetworksMemoryDesc* desc;
    ANeuralNetworksMemoryDesc_create(&desc);
    
  2. ระบุบทบาทอินพุตและเอาต์พุตที่ต้องการทั้งหมดด้วยการเรียกใช้ ANeuralNetworksMemoryDesc_addInputRole() และ ANeuralNetworksMemoryDesc_addOutputRole()

    // Specify that the memory may be used as the first input and the first output
    // of the compilation
    ANeuralNetworksMemoryDesc_addInputRole(desc, compilation, 0, 1.0f);
    ANeuralNetworksMemoryDesc_addOutputRole(desc, compilation, 0, 1.0f);
    
  3. (ไม่บังคับ) ระบุขนาดหน่วยความจำโดยการเรียกใช้ ANeuralNetworksMemoryDesc_setDimensions()

    // Specify the memory dimensions
    uint32_t dims[] = {3, 4};
    ANeuralNetworksMemoryDesc_setDimensions(desc, 2, dims);
    
  4. สรุปคำจำกัดความข้อบ่งชี้โดยการเรียก ANeuralNetworksMemoryDesc_finish()

    ANeuralNetworksMemoryDesc_finish(desc);
    
  5. จัดสรรความทรงจำได้มากเท่าที่ต้องการโดยการส่งข้อบ่งชี้ไปยัง ANeuralNetworksMemory_createFromDesc()

    // Allocate two opaque memories with the descriptor
    ANeuralNetworksMemory* opaqueMem;
    ANeuralNetworksMemory_createFromDesc(desc, &opaqueMem);
    
  6. เพิ่มพื้นที่ว่างในข้อบ่งชี้หน่วยความจำเมื่อไม่ต้องการใช้งานแล้ว

    ANeuralNetworksMemoryDesc_free(desc);
    

ไคลเอ็นต์จะใช้ออบเจ็กต์ ANeuralNetworksMemory ที่สร้างขึ้นได้เฉพาะกับ ANeuralNetworksExecution_setInputFromMemory()หรือ ANeuralNetworksExecution_setOutputFromMemory()ตามบทบาท ที่ระบุในออบเจ็กต์ ANeuralNetworksMemoryDesc ออฟเซ็ตและความยาว อาร์กิวเมนต์ต้องตั้งค่าเป็น 0 แสดงว่าใช้หน่วยความจำทั้งหมด ลูกค้า อาจตั้งค่าหรือแยกเนื้อหาของหน่วยความจำอย่างชัดเจนโดยใช้ ANeuralNetworksMemory_copy()

คุณสามารถสร้างความทรงจำแบบทึบแสงด้วยบทบาทของมิติข้อมูลหรืออันดับที่ไม่ได้ระบุ ในกรณีดังกล่าว การสร้างหน่วยความจำอาจล้มเหลวโดยมี ANEURALNETWORKS_OP_FAILED หากไม่รองรับโดยเครือข่ายพื้นฐาน คนขับ ขอแนะนำให้ไคลเอ็นต์ใช้ตรรกะสำรองโดยการจัดสรร บัฟเฟอร์ขนาดใหญ่เพียงพอที่ขับเคลื่อนโดย Ashmem หรือ BLOB-mode AHardwareBuffer

เมื่อ NNAPI ไม่ต้องการเข้าถึงออบเจ็กต์หน่วยความจำที่ทึบแสงอีกต่อไป ให้เพิ่มพื้นที่ว่าง อินสแตนซ์ ANeuralNetworksMemory ที่เกี่ยวข้อง:

ANeuralNetworksMemory_free(opaqueMem);

วัดประสิทธิภาพ

คุณสามารถประเมินประสิทธิภาพของแอปได้โดยการวัดเวลาดำเนินการหรือตาม การสร้างโปรไฟล์

เวลาดำเนินการ

หากต้องการกำหนดเวลาดำเนินการทั้งหมดผ่านรันไทม์ ให้ใช้ API การดำเนินการแบบซิงโครนัสและวัดเวลาที่เรียกใช้ เมื่อคุณ ต้องการกำหนดเวลาทั้งหมดในการดำเนินการผ่านซอฟต์แวร์ในระดับที่ต่ำลง คุณสามารถใช้ ANeuralNetworksExecution_setMeasureTiming และ ANeuralNetworksExecution_getDuration เพื่อรับ:

  • เวลาในการดำเนินการใน Accelerator (ไม่ใช่ในไดรเวอร์ ซึ่งทำงานบนโฮสต์ ผู้ประมวลผลข้อมูล)
  • เวลาดำเนินการในคนขับ รวมถึงเวลาบน Accelerator

เวลาดำเนินการในไดรเวอร์ไม่รวมโอเวอร์เฮด เช่น เวลารันไทม์ และ IPC ที่จำเป็นสำหรับรันไทม์ในการสื่อสารกับไดรเวอร์

API เหล่านี้จะวัดระยะเวลาระหว่างงานที่ส่งและทำงานที่ทำเสร็จแล้ว กิจกรรม แทนที่จะเป็นเวลาที่คนขับรถหรือพนักงานเร่งทุ่มเทเวลาให้กับการจัดกิจกรรม ของการอนุมาน ซึ่งอาจถูกขัดจังหวะโดยการเปลี่ยนบริบท

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

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

เมื่อใช้ฟังก์ชันนี้ โปรดคำนึงถึงสิ่งต่อไปนี้

  • การรวบรวมข้อมูลเวลาอาจมีต้นทุนด้านประสิทธิภาพ
  • มีเพียงคนขับเท่านั้นที่สามารถคำนวณเวลาที่ใช้ในตัวเองหรือบน Accelerator ไม่รวมเวลาที่ใช้ในรันไทม์ของ NNAPI และใน IPC
  • คุณจะใช้ API เหล่านี้ได้เฉพาะกับ ANeuralNetworksExecution ที่ สร้างด้วย ANeuralNetworksCompilation_createForDevices กับ numDevices = 1
  • ผู้ใช้ไม่จำเป็นต้องขับรถเพื่อรายงานข้อมูลเวลา

สร้างโปรไฟล์แอปพลิเคชันของคุณด้วย Android Systrace

NNAPI จะสร้างโดยอัตโนมัติสำหรับ Android 10 ตั้งแต่ Android 10 systrace ที่ คุณสามารถใช้โปรไฟล์ของแอปพลิเคชันได้

แหล่งที่มา NNAPI มาพร้อมกับยูทิลิตี parse_systrace สำหรับการประมวลผล เหตุการณ์ systrace ที่สร้างขึ้นโดยแอปพลิเคชันและสร้างมุมมองตารางที่แสดง เวลาที่ใช้ในวงจรต่างๆ ของโมเดล (Instantiation, การเตรียมความพร้อม การดำเนินการคอมไพล์ และการสิ้นสุด) และชั้นต่างๆ ของ แอปพลิเคชัน เลเยอร์ที่แบ่งแอปพลิเคชันของคุณมีดังนี้

  • Application: รหัสแอปพลิเคชันหลัก
  • Runtime: รันไทม์ของ NNAPI
  • IPC: การสื่อสารระหว่างกระบวนการระหว่างรันไทม์ของ NNAPI และไดรเวอร์ รหัส
  • Driver: กระบวนการของไดรเวอร์ Accelerator

สร้างข้อมูลการวิเคราะห์โปรไฟล์

สมมติว่าคุณได้ดูแผนผังแหล่งที่มา AOSP ที่ $ANDROID_BUILD_TOP และ โดยใช้ตัวอย่างการจัดประเภทรูปภาพ TFLite เป็นแอปพลิเคชันเป้าหมาย คุณสามารถสร้างข้อมูลการทำโปรไฟล์ NNAPI ด้วยฟังก์ชัน ขั้นตอนต่อไปนี้

  1. เริ่ม Android systrace ด้วยคำสั่งต่อไปนี้
$ANDROID_BUILD_TOP/external/chromium-trace/systrace.py  -o trace.html -a org.tensorflow.lite.examples.classification nnapi hal freq sched idle load binder_driver

พารามิเตอร์ -o trace.html ระบุว่าการติดตามจะ ซึ่งเขียนใน trace.html เมื่อทำโปรไฟล์แอปพลิเคชันของตัวเอง คุณจำเป็นจะต้อง แทนที่ org.tensorflow.lite.examples.classification ด้วยชื่อกระบวนการ ที่ระบุในไฟล์ Manifest ของแอป

การดำเนินการนี้จะทำให้คอนโซล Shell ของคุณไม่ว่าง โปรดอย่าเรียกใช้คำสั่งใน เพราะเป็นการโต้ตอบที่รอให้ enter สิ้นสุด

  1. หลังจากที่เริ่มใช้งานตัวรวบรวม Systrace แล้ว ให้เริ่มแอปและเรียกใช้ เปรียบเทียบ

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

  1. เมื่อการทดสอบเสร็จสิ้น ให้สิ้นสุด Sytrace โดยกด enter เปิด เทอร์มินัลคอนโซลจะทำงานตั้งแต่ขั้นตอนที่ 1

  2. เรียกใช้ยูทิลิตี systrace_parser เพื่อสร้างสถิติสะสม:

$ANDROID_BUILD_TOP/frameworks/ml/nn/tools/systrace_parser/parse_systrace.py --total-times trace.html

โปรแกรมแยกวิเคราะห์จะยอมรับพารามิเตอร์ต่อไปนี้ - --total-times: แสดงเวลาทั้งหมดที่ใช้ในเลเยอร์ รวมทั้งเวลา ใช้เวลารอการดำเนินการสำหรับการเรียกไปยังเลเยอร์ที่สำคัญ - --print-detail: พิมพ์เหตุการณ์ทั้งหมดที่รวบรวมจาก systrace - --per-execution: พิมพ์เฉพาะการดำเนินการและเฟสย่อย (เป็นจำนวนครั้งต่อการดำเนินการ) แทนที่จะเป็นสถิติสำหรับทุกระยะ - --json: สร้างเอาต์พุตในรูปแบบ JSON

ตัวอย่างเอาต์พุตจะแสดงที่ด้านล่าง

===========================================================================================================================================
NNAPI timing summary (total time, ms wall-clock)                                                      Execution
                                                           ----------------------------------------------------
              Initialization   Preparation   Compilation           I/O       Compute      Results     Ex. total   Termination        Total
              --------------   -----------   -----------   -----------  ------------  -----------   -----------   -----------   ----------
Application              n/a         19.06       1789.25           n/a           n/a         6.70         21.37           n/a      1831.17*
Runtime                    -         18.60       1787.48          2.93         11.37         0.12         14.42          1.32      1821.81
IPC                     1.77             -       1781.36          0.02          8.86            -          8.88             -      1792.01
Driver                  1.04             -       1779.21           n/a           n/a          n/a          7.70             -      1787.95

Total                   1.77*        19.06*      1789.25*         2.93*        11.74*        6.70*        21.37*         1.32*     1831.17*
===========================================================================================================================================
* This total ignores missing (n/a) values and thus is not necessarily consistent with the rest of the numbers

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

เพิ่มสถิติสำหรับโค้ดแอปพลิเคชันของคุณไปยังเอาต์พุต systrace_parser

แอปพลิเคชัน parse_systrace จะขึ้นอยู่กับ Android systrace ในตัว คุณเพิ่มการติดตามสำหรับการทำงานที่เฉพาะเจาะจงในแอปได้โดยใช้ API ของ Systrace (สำหรับ Java สำหรับแอปพลิเคชันที่มาพร้อมเครื่อง ) พร้อมชื่อเหตุการณ์ที่กำหนดเอง

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

  • [NN_LA_PI]: เหตุการณ์ระดับแอปพลิเคชันสำหรับการเริ่มต้น
  • [NN_LA_PP]: เหตุการณ์ระดับแอปพลิเคชันสำหรับการเตรียมพร้อม
  • [NN_LA_PC]: เหตุการณ์ระดับแอปพลิเคชันสำหรับการคอมไพล์
  • [NN_LA_PE]: เหตุการณ์ระดับแอปพลิเคชันสำหรับการดำเนินการ

ด้านล่างนี้เป็นตัวอย่างวิธีที่คุณสามารถปรับเปลี่ยนตัวอย่างการจัดประเภทรูปภาพ TFLite โดยเพิ่มส่วน runInferenceModel สำหรับระยะ Execution และส่วน Application เลเยอร์ที่มีส่วนอื่นๆ อีก preprocessBitmap ที่ จะไม่ได้รับการพิจารณาในการติดตาม NNAPI ส่วนrunInferenceModelจะเป็น ส่วนหนึ่งของเหตุการณ์ Systrace ที่ประมวลผลโดยโปรแกรมแยกวิเคราะห์ systrace ของ nnapi

Kotlin

/** Runs inference and returns the classification results. */
fun recognizeImage(bitmap: Bitmap): List {
   // This section won’t appear in the NNAPI systrace analysis
   Trace.beginSection("preprocessBitmap")
   convertBitmapToByteBuffer(bitmap)
   Trace.endSection()

   // Run the inference call.
   // Add this method in to NNAPI systrace analysis.
   Trace.beginSection("[NN_LA_PE]runInferenceModel")
   long startTime = SystemClock.uptimeMillis()
   runInference()
   long endTime = SystemClock.uptimeMillis()
   Trace.endSection()
    ...
   return recognitions
}

Java

/** Runs inference and returns the classification results. */
public List recognizeImage(final Bitmap bitmap) {

 // This section won’t appear in the NNAPI systrace analysis
 Trace.beginSection("preprocessBitmap");
 convertBitmapToByteBuffer(bitmap);
 Trace.endSection();

 // Run the inference call.
 // Add this method in to NNAPI systrace analysis.
 Trace.beginSection("[NN_LA_PE]runInferenceModel");
 long startTime = SystemClock.uptimeMillis();
 runInference();
 long endTime = SystemClock.uptimeMillis();
 Trace.endSection();
  ...
 Trace.endSection();
 return recognitions;
}

คุณภาพของการบริการ

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

กำหนดลำดับความสำคัญของภาระงาน

หากต้องการตั้งค่าลำดับความสำคัญของภาระงาน NNAPI โปรดเรียกใช้ ANeuralNetworksCompilation_setPriority() ก่อนที่จะโทรหา ANeuralNetworksCompilation_finish()

ตั้งกำหนดเวลา

แอปพลิเคชันสามารถกำหนดกำหนดเวลาสำหรับทั้งการคอมไพล์โมเดลและการอนุมานได้

ข้อมูลเพิ่มเติมเกี่ยวกับตัวถูกดำเนินการ

ส่วนต่อไปนี้ครอบคลุมหัวข้อขั้นสูงเกี่ยวกับการใช้ตัวถูกดำเนินการ

Tensor ที่ปรับให้เล็กลง

Tensor ควอนไทล์คือวิธีกะทัดรัดที่ใช้แสดงอาร์เรย์ n มิติของ ค่าทศนิยม

NNAPI รองรับ Tensor แบบไม่สมมาตรแบบ 8 บิต สำหรับ Tensor เหล่านี้ ของแต่ละเซลล์จะแสดงด้วยจำนวนเต็ม 8 บิต เชื่อมโยงกับ tensor คือสเกลและค่าคะแนนเป็น 0 ส่วนนี้ใช้เพื่อแปลงค่า 8 บิต จำนวนเต็มในค่าทศนิยมที่แสดง

สูตรคือ

(cellValue - zeroPoint) * scale

โดยค่า ZeroPoint เป็นจำนวนเต็ม 32 บิต และค่าสเกล 32 บิตแบบลอย คะแนนเต็ม

เมื่อเปรียบเทียบกับ Tensor ของค่าจุดลอยตัว 32 บิต Tensor ที่ควอนไซส์ 8 บิต ข้อดี 2 ข้อ ได้แก่

  • แอปพลิเคชันมีขนาดเล็กลง เนื่องจากน้ำหนักที่ฝึกแล้วใช้เวลา 1 ใน 4 ของขนาด Tensor 32 บิต
  • การคำนวณมักดำเนินการได้เร็วขึ้น เนื่องจากจำนวนที่น้อยกว่า ของข้อมูลที่ต้องดึงจากหน่วยความจำและประสิทธิภาพของหน่วยประมวลผล เช่น DSP ในการคำนวณจำนวนเต็ม

แม้ว่าจะสามารถแปลงโมเดลจำนวนทศนิยมเป็นโมเดลที่เล็กลงได้ แสดงให้เห็นว่าการได้รับผลลัพธ์ที่ดีขึ้นจากการฝึกตัวแปร โมเดลโดยตรง โครงข่ายประสาทจะเรียนรู้ที่จะชดเชย รายละเอียดที่เพิ่มขึ้นของแต่ละค่า สำหรับแต่ละ Tensor ที่ปรับขนาดแล้ว ขนาด และ ระบบจะกำหนดค่า ZeroPoint ในระหว่างขั้นตอนการฝึก

ใน NNAPI คุณจะกำหนดประเภท Tensor ให้เล็กลงได้โดยตั้งค่าช่องประเภทของพารามิเตอร์ ANeuralNetworksOperandType เพื่อ ANEURALNETWORKS_TENSOR_QUANT8_ASYMM คุณยังระบุสเกลและค่า ZeroPoint ของ tensor ในข้อมูลนั้นได้ด้วย ใหม่

นอกจาก Tensor จำนวน 8 บิตแบบไม่สมมาตรแล้ว NNAPI ยังรองรับสิ่งต่อไปนี้ด้วย

ตัวถูกดำเนินการที่ไม่บังคับ

การดำเนินการบางอย่าง เช่น ANEURALNETWORKS_LSH_PROJECTION ใช้ตัวถูกดำเนินการที่ไม่บังคับ เพื่อระบุในโมเดลว่าตัวถูกดำเนินการที่ไม่บังคับคือ ละเว้น ให้เรียกเมธอด ANeuralNetworksModel_setOperandValue() โดยส่ง NULL สำหรับบัฟเฟอร์และ 0 สำหรับความยาว

ถ้าการตัดสินว่าตัวถูกดำเนินการมีหรือไม่แตกต่างกันในแต่ละรายการ คุณจะระบุว่าตัวถูกละเว้นถูกละเว้นด้วยการใช้ฟังก์ชัน ANeuralNetworksExecution_setInput() หรือ ANeuralNetworksExecution_setOutput() ฟังก์ชัน โดยส่ง NULL สำหรับบัฟเฟอร์และ 0 สำหรับความยาว

Tensor ของอันดับที่ไม่รู้จัก

Android 9 (API ระดับ 28) เปิดตัวตัวถูกดำเนินการโมเดลของมิติข้อมูลที่ไม่รู้จัก แต่ อันดับที่ทราบ (จำนวนมิติข้อมูล) เปิดตัว Android 10 (API ระดับ 29) 10 อันดับของอันดับที่ไม่รู้จักดังที่แสดงใน ANeuralNetworksOperandType

การเปรียบเทียบ NNAPI

การเปรียบเทียบ NNAPI มีให้บริการบน AOSP ในplatform/test/mlts/benchmark (แอปเปรียบเทียบ) และ platform/test/mlts/models (โมเดลและชุดข้อมูล)

เกณฑ์เปรียบเทียบนี้จะประเมินเวลาในการตอบสนองและความแม่นยำ แล้วเปรียบเทียบไดรเวอร์คนเดียวกัน ใช้ Tensorflow Lite ที่ทำงานบน CPU สำหรับรุ่นเดียวกันและ ชุดข้อมูล

ในการใช้การเปรียบเทียบ ให้ทำดังนี้

  1. เชื่อมต่ออุปกรณ์ Android เป้าหมายกับคอมพิวเตอร์ เปิดหน้าต่างเทอร์มินัล และ ตรวจสอบว่าอุปกรณ์เข้าถึงได้ผ่าน adb

  2. หากมีอุปกรณ์ Android มากกว่า 1 เครื่องเชื่อมต่ออยู่ ให้ส่งออกอุปกรณ์เป้าหมาย ตัวแปรสภาพแวดล้อม ANDROID_SERIAL

  3. ไปที่ไดเรกทอรีแหล่งที่มาระดับบนสุดของ Android

  4. เรียกใช้คำสั่งต่อไปนี้

    lunch aosp_arm-userdebug # Or aosp_arm64-userdebug if available
    ./test/mlts/benchmark/build_and_run_benchmark.sh
    

    เมื่อสิ้นสุดการทำงานเปรียบเทียบ ผลลัพธ์จะแสดงเป็นหน้า HTML ผ่านไปยัง xdg-open

บันทึกของ NNAPI

NNAPI จะสร้างข้อมูลการวินิจฉัยที่เป็นประโยชน์ในบันทึกของระบบ หากต้องการวิเคราะห์บันทึก ให้ใช้ logcat ยูทิลิตี

เปิดใช้การบันทึก NNAPI แบบละเอียดสำหรับเฟสหรือคอมโพเนนต์เฉพาะโดยการตั้งค่า คุณสมบัติ debug.nn.vlog (โดยใช้ adb shell) ในรายการค่าต่อไปนี้ คั่นด้วยการเว้นวรรค เครื่องหมายโคลอน หรือคอมมา

  • model: การสร้างแบบจำลอง
  • compilation: การสร้างแผนการดำเนินการโมเดลและคอมไพล์
  • execution: การดำเนินการโมเดล
  • cpuexe: การดำเนินการโดยใช้การใช้งาน CPU ของ NNAPI
  • manager: ข้อมูลที่เกี่ยวข้องกับส่วนขยาย NNAPI, อินเทอร์เฟซและความสามารถที่มีให้บริการ
  • all หรือ 1: องค์ประกอบด้านบนทั้งหมด

ตัวอย่างเช่น หากต้องการเปิดการบันทึกแบบละเอียด ให้ใช้คำสั่ง adb shell setprop debug.nn.vlog all หากต้องการปิดใช้การบันทึกแบบละเอียด ให้ใช้คำสั่ง adb shell setprop debug.nn.vlog '""'

เมื่อเปิดใช้ การบันทึกแบบละเอียดจะสร้างรายการบันทึกที่ระดับ INFO ด้วยแท็กที่ตั้งชื่อเฟสหรือคอมโพเนนต์

นอกเหนือจากข้อความที่มีการควบคุม debug.nn.vlog แล้ว คอมโพเนนต์ NNAPI API ยัง รายการบันทึกอื่นๆ ในหลายระดับ โดยแต่ละรายการจะใช้แท็กบันทึกเฉพาะ

หากต้องการดูรายการคอมโพเนนต์ ให้ค้นหาโครงสร้างแหล่งที่มาโดยใช้องค์ประกอบ นิพจน์ต่อไปนี้

grep -R 'define LOG_TAG' | awk -F '"' '{print $2}' | sort -u | egrep -v "Sample|FileTag|test"

ปัจจุบันนิพจน์นี้ส่งคืนแท็กต่อไปนี้

  • สร้างภาพถ่ายอัจฉริยะ
  • Callback
  • CompilationBuilder
  • CpuExecutor
  • คำสั่งสร้างการดำเนินการ
  • ExecutionBurstController
  • เซิร์ฟเวอร์ ExecutionBurst
  • แผนดำเนินการ
  • ฟีโบนักชีไดรเวอร์
  • กราฟ Dump
  • IndexedShapeWrapper
  • ผู้เฝ้าดู Ion
  • ผู้จัดการ
  • หน่วยความจำ
  • ยูทิลิตีหน่วยความจำ
  • โมเดลเมตา
  • ข้อมูลอาร์กิวเมนต์ของโมเดล
  • เครื่องมือสร้างโมเดล
  • เครือข่ายระบบประสาท
  • โอเปอเรเตอร์การแก้ไข
  • การทำงาน
  • ยูทิลิตีการดำเนินการ
  • ข้อมูลแพ็กเกจ
  • TokenHasher
  • เครื่องมือจัดการประเภท
  • ประโยชน์ใช้สอย
  • ตรวจสอบความถูกต้องฮาล
  • อินเทอร์เฟซที่มีเวอร์ชัน

หากต้องการควบคุมระดับของข้อความบันทึกที่แสดงโดย logcat ให้ใช้ ตัวแปรสภาพแวดล้อม ANDROID_LOG_TAGS

หากต้องการแสดงข้อความบันทึก NNAPI ทั้งชุดและปิดใช้งานข้อความอื่นๆ ให้ตั้งค่า ANDROID_LOG_TAGS เป็น ดังต่อไปนี้

BurstBuilder:V Callbacks:V CompilationBuilder:V CpuExecutor:V ExecutionBuilder:V ExecutionBurstController:V ExecutionBurstServer:V ExecutionPlan:V FibonacciDriver:V GraphDump:V IndexedShapeWrapper:V IonWatcher:V Manager:V MemoryUtils:V Memory:V MetaModel:V ModelArgumentInfo:V ModelBuilder:V NeuralNetworks:V OperationResolver:V OperationsUtils:V Operations:V PackageInfo:V TokenHasher:V TypeManager:V Utils:V ValidateHal:V VersionedInterfaces:V *:S.

คุณตั้งค่า ANDROID_LOG_TAGS ได้โดยใช้คำสั่งต่อไปนี้

export ANDROID_LOG_TAGS=$(grep -R 'define LOG_TAG' | awk -F '"' '{ print $2 ":V" }' | sort -u | egrep -v "Sample|FileTag|test" | xargs echo -n; echo ' *:S')

โปรดทราบว่านี่เป็นเพียงตัวกรองที่ใช้กับ logcat เท่านั้น คุณยังต้อง ตั้งค่าพร็อพเพอร์ตี้ debug.nn.vlog เป็น all เพื่อสร้างข้อมูลบันทึกแบบละเอียด