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 ไม่มีฟังก์ชันการทำงานสำหรับการเรียกใช้โมเดลในระบบคลาวด์
ดูตัวอย่างวิธีใช้ NNAPI ได้จากตัวอย่าง Android Neural Networks API
ทําความเข้าใจรันไทม์ Neural Networks API
NNAPI มีชื่อโดยไลบรารีแมชชีนเลิร์นนิง เฟรมเวิร์ก และเครื่องมือ ที่ช่วยให้นักพัฒนาแอปฝึกโมเดลนอกอุปกรณ์และทำให้ใช้งานได้ใน Android อุปกรณ์ โดยทั่วไปแล้ว แอปจะไม่ใช้ NNAPI โดยตรง แต่จะใช้เฟรมเวิร์กแมชชีนเลิร์นนิงในระดับที่สูงขึ้นแทน เฟรมเวิร์กเหล่านี้อาจใช้ NNAPI เพื่อดำเนินการอนุมานที่เร่งด้วยฮาร์ดแวร์ในอุปกรณ์ที่รองรับ
อิงตามข้อกำหนดของแอปและความสามารถของฮาร์ดแวร์ใน Android รันไทม์เครือข่ายระบบประสาทเทียมของ Android สามารถกระจาย ภาระงานด้านการคำนวณของตัวประมวลผลในอุปกรณ์ที่มีอยู่ รวมถึงหน่วยประมวลผลเฉพาะ ฮาร์ดแวร์เครือข่ายระบบประสาท หน่วยประมวลผลกราฟิก (GPU) และสัญญาณดิจิทัล โปรเซสเซอร์ (DSP)
รันไทม์ของ NNAPI สำหรับอุปกรณ์ Android ที่ไม่มีไดรเวอร์ของผู้ให้บริการเฉพาะ ดำเนินการตามคำขอบน CPU
รูปที่ 1 แสดงสถาปัตยกรรมระบบระดับสูงสำหรับ NNAPI

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

เนื้อหาที่เหลือของส่วนนี้จะอธิบายขั้นตอนในการตั้งค่าโมเดล 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
ทำงานได้ตามที่คาดไว้ โดยใช้การกำหนดอุปกรณ์เพื่อระบุตัวเร่ง
หากต้องการอนุญาตให้รันไทม์ของ 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 คืออาร์เรย์ N มิติ NNAPI รองรับ tensor ที่มีจุดลอยตัว 16 บิต, จุดลอยตัว 32 บิต, 8 บิต Quantized, 16 บิตที่ควอนไตซ์, จำนวนเต็ม 32 บิต และ 8 บิต ค่าบูลีน
ตัวอย่างเช่น รูปที่ 3 แสดงโมเดลที่มีการดำเนินการ 2 อย่าง ได้แก่ การเพิ่มตามด้วยคูณ โมเดลจะรับ Tensor อินพุตและสร้าง Tensor เอาต์พุต 1 รายการ

โมเดลด้านบนมีโอเปอเรนด์ 7 รายการ ตัวถูกดำเนินการเหล่านี้จะระบุโดยปริยายโดย ดัชนีของลำดับที่เพิ่มลงในโมเดล ตัวถูกดำเนินการแรก ที่ถูกเพิ่มจะมีดัชนีเป็น 0 ดัชนีที่สองเป็น 1 เป็นต้น ออบเจ็กต์ 1, 2, 3 และ 5 เป็นตัวดำเนินการแบบคงที่
ลำดับที่คุณเพิ่มตัวถูกดำเนินการไม่สำคัญ ตัวอย่างเช่น โมเดล ตัวถูกดำเนินการของเอาต์พุตอาจเป็นตัวถูกเพิ่มลงในตัวแรก ส่วนสำคัญคือการใช้ ค่าดัชนีถูกต้องเมื่ออ้างถึงตัวถูกดำเนินการ
ตัวดำเนินการมีหลายประเภท ซึ่งจะระบุเมื่อมีการเพิ่มลงในโมเดล
คุณใช้ตัวถูกดำเนินการเป็นทั้งอินพุตและเอาต์พุตของโมเดลไม่ได้
ตัวถูกดำเนินการทั้งหมดต้องเป็นอินพุตโมเดล ค่าคงที่ หรือตัวถูกดำเนินการเอาต์พุตของ หนึ่งการดำเนินการเท่านั้น
ดูข้อมูลเพิ่มเติมเกี่ยวกับการใช้โอเปอแรนด์ได้ที่ ข้อมูลเพิ่มเติมเกี่ยวกับตัวถูกดำเนินการ
การทำงาน
การดำเนินการจะระบุการคำนวณที่จะดำเนินการ การดำเนินการแต่ละรายการประกอบด้วย ขององค์ประกอบเหล่านี้
- ประเภทการดำเนินการ (เช่น บวก คูณ Convolution)
- รายการดัชนีของออพพีเรนตที่การดำเนินการใช้สำหรับอินพุต และ
- รายการดัชนีของตัวถูกดำเนินการที่การดำเนินการใช้สำหรับเอาต์พุต
ลำดับในรายการเหล่านี้มีความสำคัญ โปรดดู เอกสารอ้างอิง NNAPI API สำหรับอินพุตที่คาดไว้ และเอาต์พุตของการดำเนินการแต่ละประเภท
คุณต้องเพิ่มตัวถูกดำเนินการที่การดำเนินการใช้หรือสร้างในโมเดล ก่อนเพิ่มการดำเนินการ
ลำดับที่คุณเพิ่มการดำเนินการนั้นไม่สำคัญ NNAPI อาศัย ทรัพยากร Dependency ที่กำหนดโดยกราฟการคำนวณของตัวถูกดำเนินการและการดำเนินการกับ กำหนดลำดับการดำเนินการ
การดำเนินการที่ NNAPI รองรับจะสรุปไว้ในตารางด้านล่าง
ปัญหาที่ทราบใน API ระดับ 28: เมื่อส่ง ANEURALNETWORKS_TENSOR_QUANT8_ASYMM
เทอร์เซอร์ไปยังการดำเนินการ ANEURALNETWORKS_PAD
ซึ่งพร้อมใช้งานใน Android 9 (API ระดับ 28) ขึ้นไป เอาต์พุตจาก NNAPI อาจไม่ตรงกับเอาต์พุตจากเฟรมเวิร์กแมชชีนเลิร์นนิงระดับสูงขึ้น เช่น TensorFlow Lite คุณ
ควรที่จะผ่านเท่านั้น
ANEURALNETWORKS_TENSOR_FLOAT32
ปัญหาได้รับการแก้ไขแล้วใน Android 10 (API ระดับ 29) ขึ้นไป
สร้างโมเดล
ในตัวอย่างต่อไปนี้ เราจะสร้างโมเดลการดำเนินการ 2 รายการที่แสดงในรูปที่ 3
ทําตามขั้นตอนต่อไปนี้เพื่อสร้างโมเดล
เรียกใช้
ANeuralNetworksModel_create()
เพื่อกำหนดโมเดลที่ว่างเปล่าANeuralNetworksModel* model = NULL; ANeuralNetworksModel_create(&model);
เพิ่มตัวถูกดำเนินการลงในโมเดลโดยการเรียกใช้
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สำหรับตัวถูกดำเนินการที่มีค่าคงที่ เช่น น้ำหนักและความลำเอียงที่ ที่ได้รับจากกระบวนการฝึกอบรม ให้ใช้
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));สำหรับแต่ละการดำเนินการในกราฟมีทิศทางที่คุณต้องการคำนวณ ให้ใส่ข้อมูลโค้ด ไปยังโมเดลของคุณโดยเรียก
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);ระบุตัวดำเนินการที่โมเดลควรถือว่าเป็นอินพุตและเอาต์พุตโดยเรียกใช้ฟังก์ชัน
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);
(ไม่บังคับ) ระบุว่าจะอนุญาตให้คำนวณ
ANEURALNETWORKS_TENSOR_FLOAT32
ด้วยช่วงหรือความแม่นยำที่ต่ำเท่ากับรูปแบบเลขทศนิยม 16 บิตของ IEEE 754 หรือไม่โดยเรียกใช้ANeuralNetworksModel_relaxComputationFloat32toFloat16()
โทรหา
ANeuralNetworksModel_finish()
เพื่อกําหนดค่าโมเดลให้เสร็จสมบูรณ์ หากไม่มีข้อผิดพลาด ฟังก์ชันนี้จะแสดงผลรหัสANEURALNETWORKS_NO_ERROR
ANeuralNetworksModel_finish(model);
เมื่อสร้างโมเดลแล้ว คุณสามารถคอมไพล์โมเดลได้ไม่จำกัดจำนวนครั้งและสั่งการแต่ละโมเดล คอมไพล์ได้ไม่จำกัดจำนวนครั้ง
การควบคุมโฟลว์
ในการรวมขั้นตอนการควบคุมไว้ในโมเดล NNAPI ให้ทำดังนี้
สร้างกราฟย่อยการดําเนินการที่เกี่ยวข้อง (กราฟย่อย
then
และelse
สำหรับคำสั่งIF
, กราฟย่อยcondition
และbody
สำหรับลูปWHILE
) เป็นโมเดลANeuralNetworksModel*
แบบสแตนด์อโลน ดังนี้ANeuralNetworksModel* thenModel = makeThenModel(); ANeuralNetworksModel* elseModel = makeElseModel();
สร้างโอเปอเรนด์ที่อ้างอิงโมเดลเหล่านั้นภายในโมเดลที่มีโฟลว์การควบคุม
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);
เพิ่มการดำเนินการของโฟลว์การควบคุม
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);
การรวบรวม
ขั้นตอนคอมไพล์จะกําหนดว่าโมเดลจะทํางานบนโปรเซสเซอร์ใด และขอให้ไดรเวอร์ที่เกี่ยวข้องเตรียมพร้อมสําหรับการดําเนินการ การดำเนินการนี้อาจ รวมการสร้างรหัสของเครื่องสำหรับโปรเซสเซอร์โมเดลของคุณโดยเฉพาะ จะทำงานต่อ
หากต้องการคอมไพล์โมเดล ให้ทําตามขั้นตอนต่อไปนี้
เรียกใช้ฟังก์ชัน
ANeuralNetworksCompilation_create()
เพื่อสร้างอินสแตนซ์การคอมไพล์ใหม่// Compile the model ANeuralNetworksCompilation* compilation; ANeuralNetworksCompilation_create(model, &compilation);
นอกจากนี้ คุณยังใช้การกำหนดอุปกรณ์เพื่อ เลือกอุปกรณ์ที่จะเรียกใช้
คุณเลือกที่จะกำหนดวิธีใช้พลังงานแบตเตอรี่และความเร็วในการดำเนินการของรันไทม์ได้ คุณสามารถทำได้โดยการโทร
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
: แนะนำให้เพิ่มอัตราการรับส่งสูงสุดของเฟรมต่อเนื่อง เช่น เมื่อประมวลผลเฟรมต่อเนื่องที่มาจากกล้อง
คุณสามารถเลือกตั้งค่าการแคชการรวบรวมได้โดยการเรียกใช้
ANeuralNetworksCompilation_setCaching
// Set up compilation caching ANeuralNetworksCompilation_setCaching(compilation, cacheDir, token);
ใช้
getCodeCacheDir()
สําหรับcacheDir
token
ที่ระบุต้องไม่ซ้ำกันสำหรับแต่ละโมเดลภายในแอปพลิเคชันสรุปคําจํากัดความการคอมไพล์โดยเรียกใช้
ANeuralNetworksCompilation_finish()
หากไม่มีข้อผิดพลาด ฟังก์ชันนี้จะแสดงรหัสผลลัพธ์ของANEURALNETWORKS_NO_ERROR
ANeuralNetworksCompilation_finish(compilation);
การค้นหาและการกําหนดอุปกรณ์
ในอุปกรณ์ Android ที่ใช้ Android 10 (API ระดับ 29) ขึ้นไป NNAPI มีฟังก์ชันที่ช่วยให้ไลบรารีและแอปเฟรมเวิร์กแมชชีนเลิร์นนิงรับข้อมูลเกี่ยวกับอุปกรณ์ที่ใช้ได้และระบุอุปกรณ์ที่จะใช้สำหรับการดำเนินการ การให้ข้อมูลเกี่ยวกับอุปกรณ์ที่มีอยู่ช่วยให้แอป เวอร์ชันจริงของไดรเวอร์ที่พบในอุปกรณ์เพื่อหลีกเลี่ยงที่ทราบ การทำงานร่วมกันไม่ได้ โดยทำให้แอปสามารถระบุได้ว่าจะใช้อุปกรณ์ใด ใช้งานส่วนต่างๆ ของโมเดล แอปสามารถเพิ่มประสิทธิภาพสำหรับ Android อุปกรณ์ที่นำไปใช้งาน
การค้นหาอุปกรณ์
ใช้
ANeuralNetworks_getDeviceCount
เพื่อดูจำนวนอุปกรณ์ที่ใช้ได้ สําหรับอุปกรณ์แต่ละเครื่อง ให้ใช้
ANeuralNetworks_getDevice
เพื่อตั้งค่าอินสแตนซ์ ANeuralNetworksDevice
เป็นข้อมูลอ้างอิงถึงอุปกรณ์นั้น
เมื่อคุณมีข้อมูลอ้างอิงอุปกรณ์แล้ว คุณสามารถดูข้อมูลเพิ่มเติมเกี่ยวกับอุปกรณ์นั้นโดยใช้ฟังก์ชันต่อไปนี้
ANeuralNetworksDevice_getFeatureLevel
ANeuralNetworksDevice_getName
ANeuralNetworksDevice_getType
ANeuralNetworksDevice_getVersion
การกำหนดอุปกรณ์
ใช้
ANeuralNetworksModel_getSupportedOperationsForDevices
เพื่อค้นหาการดำเนินการของโมเดลที่เรียกใช้ในอุปกรณ์ที่เจาะจงได้
หากต้องการควบคุมตัวเร่งที่ใช้สำหรับการดำเนินการ ให้เรียกใช้ ANeuralNetworksCompilation_createForDevices
แทน ANeuralNetworksCompilation_create
ใช้ออบเจ็กต์ ANeuralNetworksCompilation
ที่ได้มาตามปกติ
ฟังก์ชันจะแสดงข้อผิดพลาดหากโมเดลที่ระบุมีการดำเนินการที่
ไม่รองรับในอุปกรณ์ที่เลือก
หากระบุอุปกรณ์หลายเครื่อง รันไทม์จะทำหน้าที่กระจายข้อมูล การทำงานในอุปกรณ์ต่างๆ
การใช้งาน NNAPI CPU จะแสดงด้วย ANeuralNetworksDevice
ที่มีชื่อ nnapi-reference
และประเภท ANEURALNETWORKS_DEVICE_TYPE_CPU
เช่นเดียวกับอุปกรณ์อื่นๆ เมื่อโทร
ANeuralNetworksCompilation_createForDevices
, การใช้งาน CPU ไม่ได้
ซึ่งใช้สำหรับจัดการกรณีความล้มเหลวในการคอมไพล์โมเดลและการดำเนินการ
แอปพลิเคชันมีหน้าที่รับผิดชอบในการแบ่งพาร์ติชันโมเดลเป็นโมเดลย่อยที่
สามารถทำงานในอุปกรณ์ที่ระบุ แอปพลิเคชันที่ไม่จำเป็นต้องทำด้วยตนเอง
ควรจะยังคงเรียกการแบ่งพาร์ติชัน
ANeuralNetworksCompilation_create
ให้ใช้อุปกรณ์ที่มีอยู่ทั้งหมด (รวมถึง CPU) เพื่อเร่งความเร็ว
โมเดล หากอุปกรณ์ที่คุณระบุรองรับโมเดลได้ไม่สมบูรณ์
โดยใช้ ANeuralNetworksCompilation_createForDevices
ANEURALNETWORKS_BAD_DATA
การแบ่งพาร์ติชันโมเดล
เมื่อมีอุปกรณ์หลายเครื่องสำหรับโมเดลนี้ รันไทม์ของ NNAPI
กระจายงานไปยังทุกอุปกรณ์ เช่น หากมีการจัดเตรียมอุปกรณ์ให้กับ ANeuralNetworksCompilation_createForDevices
มากกว่า 1 เครื่อง ระบบจะพิจารณาอุปกรณ์ที่ระบุทั้งหมดเมื่อจัดสรรงาน โปรดทราบว่าหากอุปกรณ์ 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 รายการที่แอปของคุณจัดสรรไว้
หากต้องการเรียกใช้โมเดลที่คอมไพล์แล้ว ให้ทําตามขั้นตอนต่อไปนี้
เรียกใช้
ANeuralNetworksExecution_create()
เพื่อสร้างอินสแตนซ์การดำเนินการใหม่// Run the compiled model against a set of inputs ANeuralNetworksExecution* run1 = NULL; ANeuralNetworksExecution_create(compilation, &run1);
ระบุตําแหน่งที่แอปอ่านค่าอินพุตสําหรับการคํานวณ แอปของคุณอ่านค่าอินพุตได้จากบัฟเฟอร์ผู้ใช้หรือพื้นที่หน่วยความจำที่จัดสรรโดยเรียกใช้
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));
ระบุตำแหน่งที่แอปเขียนค่าเอาต์พุต แอปของคุณสามารถเขียนค่าเอาต์พุตไปยัง บัฟเฟอร์ผู้ใช้หรือพื้นที่หน่วยความจำที่จัดสรรไว้ โดยการเรียกใช้
ANeuralNetworksExecution_setOutput()
หรือANeuralNetworksExecution_setOutputFromMemory()
ตามลำดับ// Set the output float32 myOutput[3][4]; ANeuralNetworksExecution_setOutput(run1, 0, NULL, myOutput, sizeof(myOutput));
กำหนดเวลาการดำเนินการเพื่อเริ่มต้น โดยเรียกใช้
ANeuralNetworksExecution_startCompute()
หากไม่มีข้อผิดพลาด ฟังก์ชันนี้จะแสดงรหัสผลลัพธ์ของANEURALNETWORKS_NO_ERROR
// Starts the work. The work proceeds asynchronously ANeuralNetworksEvent* run1_end = NULL; ANeuralNetworksExecution_startCompute(run1, &run1_end);
เรียกใช้ฟังก์ชัน
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);
หรือคุณจะใช้ชุดอินพุตอื่นกับโมเดลที่คอมไพล์ได้โดย โดยใช้อินสแตนซ์การคอมไพล์เดียวกันเพื่อสร้าง
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_compute
เพื่อเรียกใช้รันไทม์แบบซิงค์แทนการเรียกใช้ ANeuralNetworksExecution_startCompute
เพื่อเรียกใช้รันไทม์แบบไม่พร้อมกัน การโทรไปที่ ANeuralNetworksExecution_compute
จะไม่ใช้ ANeuralNetworksEvent
และไม่ได้จับคู่กับการโทรไปที่ ANeuralNetworksEvent_wait
การดำเนินการแบบทันที
ในอุปกรณ์ Android ที่ใช้ Android 10 (API ระดับ 29) ขึ้นไป NNAPI จะรองรับการดำเนินการแบบต่อเนื่องผ่านออบเจ็กต์ ANeuralNetworksBurst
การดำเนินการแบบทันทีเป็นลำดับการดำเนินการในคอมไพล์เดียวกัน
ที่เกิดขึ้นต่อเนื่องกันอย่างรวดเร็ว เช่น เฟรมที่ทำงานบนเฟรมกล้อง
บันทึกเสียงหรือตัวอย่างเสียงต่อเนื่อง การใช้ออบเจ็กต์ ANeuralNetworksBurst
อาจทําให้การดำเนินการเร็วขึ้น เนื่องจากจะบอกให้ตัวเร่งการทํางานทราบว่าอาจนําทรัพยากรมาใช้ซ้ำระหว่างการดําเนินการ และตัวเร่งการทํางานควรอยู่ในสถานะประสิทธิภาพสูงตลอดระยะเวลาของการทำงาน
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()
เมื่อใช้วิธีการนี้ การดำเนินการจะรอให้ส่งสัญญาณเหตุการณ์ที่เกี่ยวข้องทั้งหมดก่อนเริ่มการประเมิน เมื่อการดำเนินการได้
เสร็จสมบูรณ์ และเอาต์พุตพร้อมใช้งานแล้ว เหตุการณ์ที่ส่งกลับคือ
ได้รับสัญญาณ
เหตุการณ์อาจได้รับการสนับสนุนจากSync 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
และเป็น
ประเภทเดียวที่เลือก
ผู้ประมวลผลข้อมูลที่สนับสนุนการดำเนินการเหล่านั้น หรือเป็นผู้ประมวลผลข้อมูลที่กล่าวอ้างว่าดีที่สุด
ประสิทธิภาพสำหรับการดำเนินการเหล่านั้น ระบบจะเลือกเป็นข้อมูลหลัก (ไม่ใช่วิดีโอสำรอง)
ผู้ดำเนินการ
ใช้ ANeuralNetworksCompilation_createForDevices
ในขณะที่ยกเว้น nnapi-reference
ออกจากรายการอุปกรณ์เพื่อให้แน่ใจว่าไม่มีการดำเนินการของ CPU
เริ่มตั้งแต่ Android P คุณจะปิดใช้วิดีโอสำรองในเวลาดำเนินการได้ที่
บิลด์ DEBUG โดยการตั้งค่าพร็อพเพอร์ตี้ debug.nn.partition
เป็น 2
โดเมนความทรงจำ
ใน Android 11 ขึ้นไป NNAPI รองรับโดเมนหน่วยความจำที่มีอินเทอร์เฟซตัวจัดสรรสำหรับหน่วยความจำแบบทึบ ซึ่งช่วยให้แอปพลิเคชันสามารถส่งหน่วยความจำแบบอุปกรณ์ไปยังการดำเนินการต่างๆ ได้ เพื่อไม่ให้ NNAPI คัดลอกหรือเปลี่ยนรูปแบบข้อมูลโดยไม่จำเป็นเมื่อดำเนินการติดต่อกันในไดรเวอร์เดียวกัน
ฟีเจอร์โดเมนหน่วยความจำมีไว้สำหรับ Tensor ที่ส่วนใหญ่เป็นฟีเจอร์ภายใน ผู้ขับรถและไม่จําเป็นต้องเข้าถึงฝั่งไคลเอ็นต์บ่อยๆ ตัวอย่างเทนเซอร์ดังกล่าว ได้แก่ เทนเซอร์สถานะในโมเดลลำดับ สำหรับเทนเซอร์ที่ต้องเข้าถึง CPU บ่อยครั้งฝั่งไคลเอ็นต์ ให้ใช้พูลหน่วยความจำที่ใช้ร่วมกันแทน
หากต้องการจัดสรรหน่วยความจำที่คลุมเครือ ให้ทำตามขั้นตอนต่อไปนี้
เรียกใช้
ANeuralNetworksMemoryDesc_create()
เพื่อสร้างข้อบ่งชี้หน่วยความจำใหม่:// Create a memory descriptor ANeuralNetworksMemoryDesc* desc; ANeuralNetworksMemoryDesc_create(&desc);
ระบุบทบาทอินพุตและเอาต์พุตที่ต้องการทั้งหมดด้วยการเรียกใช้
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);
(ไม่บังคับ) ระบุขนาดหน่วยความจำโดยการเรียกใช้
ANeuralNetworksMemoryDesc_setDimensions()
// Specify the memory dimensions uint32_t dims[] = {3, 4}; ANeuralNetworksMemoryDesc_setDimensions(desc, 2, dims);
กำหนดคำจำกัดความของข้อบ่งชี้ให้เสร็จโดยเรียกใช้
ANeuralNetworksMemoryDesc_finish()
ANeuralNetworksMemoryDesc_finish(desc);
จัดสรรความทรงจำได้มากเท่าที่ต้องการโดยการส่งข้อบ่งชี้ไปยัง
ANeuralNetworksMemory_createFromDesc()
// Allocate two opaque memories with the descriptor ANeuralNetworksMemory* opaqueMem; ANeuralNetworksMemory_createFromDesc(desc, &opaqueMem);
ปล่อยตัวระบุหน่วยความจำเมื่อไม่ต้องการแล้ว
ANeuralNetworksMemoryDesc_free(desc);
ไคลเอ็นต์จะใช้ออบเจ็กต์ ANeuralNetworksMemory
ที่สร้างขึ้นได้เฉพาะกับ
ANeuralNetworksExecution_setInputFromMemory()
หรือ
ANeuralNetworksExecution_setOutputFromMemory()
ตามบทบาท
ที่ระบุในออบเจ็กต์ ANeuralNetworksMemoryDesc
ต้องตั้งค่าอาร์กิวเมนต์ offset และ length เป็น 0 ซึ่งบ่งบอกว่ามีการใช้หน่วยความจําทั้งหมด นอกจากนี้ ไคลเอ็นต์ยังอาจตั้งค่าหรือดึงข้อมูลเนื้อหาของหน่วยความจําอย่างชัดเจนได้โดยใช้ ANeuralNetworksMemory_copy()
คุณสามารถสร้างความทรงจำแบบทึบแสงด้วยบทบาทของมิติข้อมูลหรืออันดับที่ไม่ได้ระบุ
ในกรณีดังกล่าว การสร้างหน่วยความจำอาจล้มเหลวโดยมี
ANEURALNETWORKS_OP_FAILED
หากไม่รองรับโดยเครือข่ายพื้นฐาน
คนขับ ขอแนะนำให้ไคลเอ็นต์ใช้ตรรกะสำรองโดยการจัดสรร
บัฟเฟอร์ขนาดใหญ่เพียงพอที่ขับเคลื่อนโดย Ashmem หรือ BLOB-mode AHardwareBuffer
เมื่อ NNAPI ไม่ต้องการเข้าถึงออบเจ็กต์หน่วยความจำที่ทึบแสงอีกต่อไป ให้เพิ่มพื้นที่ว่าง
อินสแตนซ์ ANeuralNetworksMemory
ที่เกี่ยวข้อง:
ANeuralNetworksMemory_free(opaqueMem);
วัดประสิทธิภาพ
คุณสามารถประเมินประสิทธิภาพของแอปได้โดยวัดเวลาดำเนินการหรือโดยการสร้างโปรไฟล์
เวลาดำเนินการ
หากต้องการระบุเวลาดำเนินการทั้งหมดผ่านรันไทม์ ให้ใช้ API การเรียกใช้แบบซิงค์และวัดเวลาที่ใช้ในการเรียกใช้ เมื่อคุณ
ต้องการกำหนดเวลาทั้งหมดในการดำเนินการผ่านซอฟต์แวร์ในระดับที่ต่ำลง
คุณสามารถใช้
ANeuralNetworksExecution_setMeasureTiming
และ
ANeuralNetworksExecution_getDuration
เพื่อรับ:
- เวลาที่ใช้ในการดำเนินการบนตัวเร่ง (ไม่ใช่ในไดรเวอร์ที่ทำงานบนโปรเซสเซอร์โฮสต์)
- เวลาดำเนินการในไดรเวอร์ ซึ่งรวมถึงเวลาใน Accelerator
เวลาดำเนินการในไดรเวอร์ไม่รวมโอเวอร์เฮด เช่น เวลารันไทม์ และ IPC ที่จำเป็นสำหรับรันไทม์ในการสื่อสารกับไดรเวอร์
API เหล่านี้จะวัดระยะเวลาระหว่างเหตุการณ์งานที่ส่งและงานที่เสร็จสมบูรณ์ ไม่ใช่เวลาที่ไดรเวอร์หรือตัวเร่งใช้เพื่อทำการอนุมาน ซึ่งอาจถูกขัดจังหวะด้วยการสลับบริบท
ตัวอย่างเช่น หากการอนุมาน 1 เริ่มขึ้น จากนั้นไดรเวอร์จะหยุดทํางานเพื่อทำการอนุมาน 2 จากนั้นจึงกลับมาทํางานต่อและทำการอนุมาน 1 ให้เสร็จสมบูรณ์ เวลาดำเนินการสำหรับการอนุมาน 1 จะรวมเวลาที่หยุดทํางานเพื่อทำการอนุมาน 2
ข้อมูลการกําหนดเวลานี้อาจมีประโยชน์สําหรับการติดตั้งใช้งานเวอร์ชันที่ใช้งานจริงของแอปพลิเคชันเพื่อรวบรวมข้อมูลการวัดและส่งข้อมูลทางไกลสําหรับการใช้งานแบบออฟไลน์ คุณสามารถใช้ข้อมูลเวลาเพื่อ แก้ไขแอปเพื่อให้มีประสิทธิภาพสูงขึ้น
เมื่อใช้ฟังก์ชันนี้ โปรดคำนึงถึงสิ่งต่อไปนี้
- การรวบรวมข้อมูลเวลาอาจมีต้นทุนด้านประสิทธิภาพ
- มีเพียงไดรเวอร์เท่านั้นที่คำนวณเวลาที่ใช้กับตนเองหรือในโปรแกรมเร่งความเร็วได้ โดยไม่รวมเวลาที่ใช้ในรันไทม์ NNAPI และใน IPC
- คุณจะใช้ API เหล่านี้ได้เฉพาะกับ
ANeuralNetworksExecution
ที่ สร้างด้วยANeuralNetworksCompilation_createForDevices
กับnumDevices = 1
- ผู้ใช้ไม่จำเป็นต้องขับรถเพื่อรายงานข้อมูลเวลา
ทำโปรไฟล์แอปพลิเคชันด้วย Systrace ของ Android
ตั้งแต่ Android 10 เป็นต้นไป NNAPI จะสร้างเหตุการณ์ systrace โดยอัตโนมัติซึ่งคุณใช้เพื่อโปรไฟล์แอปพลิเคชันได้
แหล่งที่มาของ NNAPI มาพร้อมกับยูทิลิตี parse_systrace
เพื่อประมวลผลเหตุการณ์ systrace ที่แอปพลิเคชันสร้างขึ้น และสร้างมุมมองตารางที่แสดงเวลาที่ใช้ในแต่ละระยะของวงจรโมเดล (การสร้างอินสแตนซ์ การเตรียม การคอมไพล์ การดำเนินการ และการสิ้นสุด) และเลเยอร์ต่างๆ ของแอปพลิเคชัน เลเยอร์ที่แอปพลิเคชันของคุณแยกออกเป็นดังนี้
Application
: รหัสแอปพลิเคชันหลักRuntime
: รันไทม์ของ NNAPIIPC
: การสื่อสารระหว่างกระบวนการระหว่างรันไทม์ NNAPI กับโค้ดไดรเวอร์Driver
: กระบวนการของโปรแกรมเร่ง
สร้างข้อมูลการวิเคราะห์โปรไฟล์
สมมติว่าคุณตรวจสอบซอร์สทรี AOSP ที่ $ANDROID_BUILD_TOP และตัวอย่างการแยกประเภทรูปภาพด้วย TFLite เป็นแอปพลิเคชันเป้าหมาย คุณสามารถสร้างข้อมูลการโปรไฟล์ NNAPI ได้โดยทำตามขั้นตอนต่อไปนี้
- เริ่ม 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 ของแอป
ซึ่งจะทำให้คอนโซลเชลล์หนึ่งไม่ว่าง อย่าเรียกใช้คำสั่งในเบื้องหลังเนื่องจากจะรอให้ enter
สิ้นสุดการทำงานแบบอินเทอร์แอกทีฟ
- หลังจากเริ่มเครื่องมือรวบรวม Systrace แล้ว ให้เริ่มแอปและทำการทดสอบการเปรียบเทียบประสิทธิภาพ
ในกรณีของเรา คุณสามารถเริ่มแอปการจัดประเภทรูปภาพจาก Android Studio หรือจาก UI โทรศัพท์ทดสอบโดยตรงหากได้ติดตั้งแอปแล้ว หากต้องการสร้างข้อมูล NNAPI บางส่วน คุณต้องกำหนดค่าแอปให้ใช้ NNAPI ภายในวันที่ เลือก NNAPI เป็นอุปกรณ์เป้าหมายในกล่องโต้ตอบการกำหนดค่าแอป
เมื่อการทดสอบเสร็จสิ้นแล้ว ให้สิ้นสุดการติดตามระบบโดยกด
enter
ในเทอร์มินัลคอนโซลที่ทำงานมาตั้งแต่ขั้นตอนที่ 1เรียกใช้ยูทิลิตี
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 ทำงานตามฟังก์ชันการทำงานของ systrace ในตัวของ Android คุณสามารถเพิ่มการติดตามสําหรับการดำเนินการที่เฉพาะเจาะจงในแอปได้โดยใช้ systrace API (สําหรับ Java สําหรับแอปพลิเคชันเนทีฟ ) ที่มีชื่อเหตุการณ์ที่กําหนดเอง
หากต้องการเชื่อมโยงเหตุการณ์ที่กำหนดเองกับขั้นตอนต่างๆ ของวงจรแอปพลิเคชัน แทรกสตริงใดสตริงหนึ่งต่อไปนี้ไว้ข้างหน้าชื่อเหตุการณ์
[NN_LA_PI]
: เหตุการณ์ระดับแอปสําหรับการเริ่มต้น[NN_LA_PP]
: เหตุการณ์ระดับแอปพลิเคชันสําหรับการเตรียม[NN_LA_PC]
: เหตุการณ์ระดับแอปพลิเคชันสำหรับการคอมไพล์[NN_LA_PE]
: เหตุการณ์ระดับแอปพลิเคชันสําหรับการดําเนินการ
ต่อไปนี้คือตัวอย่างวิธีแก้ไขโค้ดตัวอย่างการจัดประเภทรูปภาพของ TFLite โดยเพิ่มส่วน runInferenceModel
สำหรับระยะ Execution
และเลเยอร์ Application
ที่มีส่วนอื่นๆ อีก preprocessBitmap
ซึ่งจะไม่ได้รับการพิจารณาในการติดตาม NNAPI ส่วนrunInferenceModel
จะเป็น
ส่วนหนึ่งของเหตุการณ์ 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 ListrecognizeImage(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()
ตั้งกำหนดเวลา
แอปพลิเคชันสามารถกำหนดกำหนดเวลาสำหรับทั้งการคอมไพล์โมเดลและการอนุมานได้
- หากต้องการตั้งค่าการหมดเวลาการคอมไพล์ ให้เรียกใช้
ANeuralNetworksCompilation_setTimeout()
ก่อนเรียกใช้ANeuralNetworksCompilation_finish()
- หากต้องการตั้งค่าการหมดเวลาการอนุมาน ให้เรียกใช้
ANeuralNetworksExecution_setTimeout()
ก่อนเริ่มการคอมไพล์
ข้อมูลเพิ่มเติมเกี่ยวกับโอเปอเรนด์
ส่วนต่อไปนี้ครอบคลุมหัวข้อขั้นสูงเกี่ยวกับการใช้ตัวถูกดำเนินการ
Tensor ที่แปลงค่าเป็นจำนวนเต็ม
เทนเซอร์ที่แปลงเป็นจำนวนเต็มเป็นวิธีที่กะทัดรัดในการแสดงอาร์เรย์ n มิติของค่าทศนิยม
NNAPI รองรับ Tensor แบบไม่สมมาตรแบบ 8 บิต สำหรับ Tensor เหล่านี้ ของแต่ละเซลล์จะแสดงด้วยจำนวนเต็ม 8 บิต เทนเซอร์จะเชื่อมโยงกับค่าสเกลและค่าจุดศูนย์ ส่วนนี้ใช้เพื่อแปลงค่า 8 บิต จำนวนเต็มในค่าทศนิยมที่แสดง
สูตรคือ
(cellValue - zeroPoint) * scale
โดยที่ค่า zeroPoint เป็นจำนวนเต็ม 32 บิต และ scale เป็นค่าตัวเลขทศนิยม 32 บิต
เมื่อเปรียบเทียบกับ Tensor ของค่าจุดลอยตัว 32 บิต Tensor ที่ควอนไซส์ 8 บิต ข้อดี 2 ข้อ ได้แก่
- แอปพลิเคชันของคุณจะมีขนาดเล็กลง เนื่องจากน้ำหนักที่ผ่านการฝึกมีขนาดเล็กกว่าเทนเซอร์ 32 บิต 1 ใน 4
- การคํานวณมักจะทําได้เร็วขึ้น เนื่องจากจำนวนที่น้อยกว่า ของข้อมูลที่ต้องดึงจากหน่วยความจำและประสิทธิภาพของหน่วยประมวลผล เช่น DSP ในการคำนวณจำนวนเต็ม
แม้ว่าจะสามารถแปลงโมเดลจำนวนทศนิยมเป็นโมเดลที่เล็กลงได้ แสดงให้เห็นว่าการได้รับผลลัพธ์ที่ดีขึ้นจากการฝึกตัวแปร โมเดลโดยตรง ผลที่ได้คือ เครือข่ายประสาทจะเรียนรู้เพื่อชดเชยความละเอียดที่เพิ่มขึ้นของแต่ละค่า ระบบจะกำหนดค่าสเกลและค่าจุดเริ่มต้นของแต่ละเทนเซอร์ที่แปลงค่าเป็นจำนวนเต็มระหว่างกระบวนการฝึก
ใน NNAPI คุณจะกําหนดประเภท Tensor ที่แปลงค่าเป็นจำนวนเต็มได้โดยการตั้งค่าช่องประเภทของรูปแบบข้อมูล ANeuralNetworksOperandType
เป็น ANEURALNETWORKS_TENSOR_QUANT8_ASYMM
คุณยังระบุสเกลและค่า ZeroPoint ของ tensor ในข้อมูลนั้นได้ด้วย
ใหม่
นอกจาก Tensor จำนวน 8 บิตแบบไม่สมมาตรแล้ว NNAPI ยังรองรับสิ่งต่อไปนี้ด้วย
ANEURALNETWORKS_TENSOR_QUANT8_SYMM_PER_CHANNEL
ซึ่งคุณใช้เพื่อแสดงน้ำหนักให้กับการดำเนินการCONV/DEPTHWISE_CONV/TRANSPOSED_CONV
ได้ANEURALNETWORKS_TENSOR_QUANT16_ASYMM
ซึ่งคุณใช้สำหรับสถานะภายในของQUANTIZED_16BIT_LSTM
ได้ANEURALNETWORKS_TENSOR_QUANT8_SYMM
ซึ่งอาจเป็นอินพุตสำหรับANEURALNETWORKS_DEQUANTIZE
ออบเจ็กต์ที่ไม่บังคับ
การดำเนินการบางอย่าง เช่น
ANEURALNETWORKS_LSH_PROJECTION
,
ใช้ตัวถูกดำเนินการที่ไม่บังคับ หากต้องการระบุว่าในโมเดลไม่มีตัวดำเนินการที่ไม่บังคับ ให้เรียกใช้ฟังก์ชัน ANeuralNetworksModel_setOperandValue()
โดยส่ง NULL
สำหรับบัฟเฟอร์และ 0 สำหรับความยาว
ถ้าการตัดสินว่าตัวถูกดำเนินการมีหรือไม่แตกต่างกันในแต่ละรายการ
คุณจะระบุว่าตัวถูกละเว้นถูกละเว้นด้วยการใช้ฟังก์ชัน
ANeuralNetworksExecution_setInput()
หรือ
ANeuralNetworksExecution_setOutput()
ฟังก์ชัน โดยส่ง NULL
สำหรับบัฟเฟอร์และ 0 สำหรับความยาว
เทนเซอร์ที่มีลําดับชั้นที่ไม่รู้จัก
Android 9 (API ระดับ 28) ได้เปิดตัวตัวดำเนินการโมเดลของมิติข้อมูลที่ไม่ทราบ แต่ทราบลําดับ (จํานวนมิติข้อมูล) เปิดตัว Android 10 (API ระดับ 29) 10 อันดับของอันดับที่ไม่รู้จักดังที่แสดงใน ANeuralNetworksOperandType
การเปรียบเทียบ NNAPI
การเปรียบเทียบ NNAPI มีอยู่ใน AOSP ใน platform/test/mlts/benchmark
(แอปการเปรียบเทียบ) และ platform/test/mlts/models
(โมเดลและชุดข้อมูล)
เกณฑ์เปรียบเทียบนี้จะประเมินเวลาในการตอบสนองและความแม่นยำ แล้วเปรียบเทียบไดรเวอร์คนเดียวกัน ใช้ Tensorflow Lite ที่ทำงานบน CPU สำหรับรุ่นเดียวกันและ ชุดข้อมูล
หากต้องการใช้การเปรียบเทียบ ให้ทําดังนี้
เชื่อมต่ออุปกรณ์ Android เป้าหมายกับคอมพิวเตอร์ เปิดหน้าต่างเทอร์มินัล และตรวจสอบว่าเข้าถึงอุปกรณ์ผ่าน adb ได้
หากมีอุปกรณ์ Android มากกว่า 1 เครื่องเชื่อมต่ออยู่ ให้ส่งออกอุปกรณ์เป้าหมาย ตัวแปรสภาพแวดล้อม
ANDROID_SERIAL
ไปที่ไดเรกทอรีแหล่งที่มาระดับบนสุดของ Android
เรียกใช้คำสั่งต่อไปนี้
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
: การดำเนินการโดยใช้การติดตั้งใช้งาน NNAPI CPUmanager
: ข้อมูลที่เกี่ยวข้องกับส่วนขยาย 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
- ExecutionBuilder
- ExecutionBurstController
- เซิร์ฟเวอร์ ExecutionBurst
- ExecutionPlan
- ฟีโบนักชีไดรเวอร์
- GraphDump
- IndexedShapeWrapper
- ผู้เฝ้าดู Ion
- ผู้จัดการ
- หน่วยความจำ
- ยูทิลิตีหน่วยความจำ
- MetaModel
- ModelArgumentInfo
- ModelBuilder
- NeuralNetworks
- โอเปอเรเตอร์การแก้ไข
- การทำงาน
- ยูทิลิตีการดำเนินการ
- PackageInfo
- TokenHasher
- เครื่องมือจัดการประเภท
- Utils
- ตรวจสอบความถูกต้องฮาล
- อินเทอร์เฟซที่มีเวอร์ชัน
หากต้องการควบคุมระดับของข้อความบันทึกที่แสดงโดย 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
เพื่อสร้างข้อมูลบันทึกแบบละเอียด