واجهة برمجة تطبيقات الشبكات العصبية

واجهة برمجة تطبيقات Android Neral Networks API (NNAPI) هي واجهة برمجة تطبيقات تعمل بنظام التشغيل Android C تم تصميمها لتشغيل العمليات الحاسوبية المكثفة لتعلّم الآلة على أجهزة Android. صُممت NNAPI لتوفير طبقة أساسية من الوظائف للوصول إلى مستويات أعلى أطر التعلم الآلي، مثل TensorFlow Lite وCaffe2، التي تبني الشبكات العصبية وتدربها. تتوفر واجهة برمجة التطبيقات على جميع أجهزة Android التي تعمل بالإصدار 8.1 من نظام التشغيل Android (المستوى 27 من واجهة برمجة التطبيقات) أو الإصدارات الأحدث.

تدعم NNAPI التعويض من خلال تطبيق البيانات من أجهزة Android على مدربة، يحددها المطوّر. تتضمن أمثلة الاستقصاء تصنيف والصور والتنبؤ بسلوك المستخدم وتحديد الاستجابات المناسبة استعلام البحث.

هناك العديد من المزايا التي توفّرها تقنية الإبلاغ على الجهاز فقط:

  • وقت الاستجابة: لست بحاجة إلى إرسال طلب عبر اتصال بالشبكة انتظار الرد. على سبيل المثال، قد يكون ذلك مهمًا لتطبيقات الفيديو. تعمل على معالجة الإطارات المتتالية التي تأتي من الكاميرا.
  • مدى التوفّر: يتم تشغيل التطبيق حتى عندما يكون خارج تغطية الشبكة.
  • السرعة: جهاز جديد مخصص لمعالجة الشبكة العصبونية يوفر حسابًا أسرع بكثير من وحدة المعالجة المركزية للأغراض العامة فقط.
  • الخصوصية: لا يتم نقل البيانات خارج جهاز Android.
  • التكلفة: لا حاجة إلى مزرعة الخادم عند إجراء جميع العمليات الحسابية على جهاز Android.

هناك أيضًا حلول وسط يجب أن يأخذها المطوّر في الاعتبار:

  • استخدام النظام: يتضمّن تقييم الشبكات العصبونية الكثير من العملية الحسابية، مما قد يزيد من استخدام طاقة البطارية. أن تضع في اعتبارك مراقبة حالة البطارية إذا كانت هذه المشكلة تتعلّق بتطبيقك، خاصةً لإجراء عمليات حسابية طويلة الأمد.
  • حجم التطبيق: انتبه إلى حجم نماذجك. قد تسمح النماذج يشغل عدة ميغابايت من المساحة. في حال جمع نماذج كبيرة في حزمة APK في المستخدمين بلا داعٍ، ننصحك بتنزيل النماذج بعد تثبيت التطبيق، أو استخدام نماذج أصغر، أو تشغيل العمليات الحسابية في السحابة. لا توفر NNAPI وظائف لتشغيل النماذج في السحابة الإلكترونية.

يمكنك الاطّلاع على نموذج لواجهة برمجة تطبيقات الشبكات العصبية في Android للاطّلاع على مثال حول كيفية استخدام واجهة NNAPI

التعرّف على وقت تشغيل واجهة برمجة تطبيقات الشبكات العصبونية

من المفترض أن يتم طلب واجهة NNAPI من قبل مكتبات وأُطر وأدوات التعلم الآلي تتيح للمطوّرين تدريب نماذجهم خارج الأجهزة ونشرها على Android الأجهزة. لن تستخدم التطبيقات عادةً NNAPI مباشرةً، ولكن بدلاً من ذلك تستخدم أطر عمل عالية المستوى لتعلم الآلة. يمكن لأطر العمل هذه بدورها استخدام NNAPI لتنفيذ عمليات استنتاج سريعة للأجهزة على الأجهزة المتوافقة.

استنادًا إلى متطلبات التطبيق وإمكانات الأجهزة في نظام التشغيل Android جهازك، يمكن لوقت تشغيل الشبكة العصبونية في Android توزيع العمليات الحسابية على مستوى المعالجات المتاحة على الجهاز، بما في ذلك العمليات المخصّصة أجهزة الشبكة العصبونية ووحدات معالجة الرسومات (GPU) والإشارة الرقمية المعالجات (DSP).

بالنسبة إلى أجهزة Android التي تفتقر إلى برنامج تشغيل متخصص للمورّد، سيكون وقت تشغيل NNAPI وينفذ الطلبات على وحدة المعالجة المركزية.

يوضح الشكل 1 بنية النظام عالية المستوى لـ NNAPI.

الشكل 1. بنية النظام لواجهة برمجة تطبيقات Android Neral Networks

نموذج برمجة واجهة برمجة التطبيقات للشبكات العصبية

لإجراء العمليات الحسابية باستخدام NNAPI، يجب أولاً إنشاء ملف يحدد العمليات الحسابية المراد إجراؤها. يعد هذا الرسم البياني الحاسوبي مجتمعًا ببيانات الإدخال (على سبيل المثال، الأوزان والتحيزات التي تم تمريرها من التعلم الآلي)، يشكل نموذجًا لتقييم وقت تشغيل NNAPI.

تستخدم واجهة NNAPI أربعة تجريدات رئيسية:

  • النموذج: رسم بياني حسابي للعمليات الحسابية والثابت والقيم التي تم تعلمها من خلال عملية تدريبية. تتعلق هذه العمليات والشبكات العصبية. وتشمل الأبعاد ثنائية الأبعاد (ثنائي الأبعاد). الالتفاف الخدمات اللوجستية (الرقم السيني) والتفعيل المساواة بين نقاط الاتصال (ReLU) وغير ذلك. إن إنشاء نموذج هو عملية متزامنة. وبعد إنشائها بنجاح، يمكن إعادة استخدامها في سلاسل المحادثات وعمليات التجميع. في NNAPI، يتم تمثيل النموذج على أنه ANeuralNetworksModel مثال.
  • التجميع: يمثل إعدادًا لتجميع نموذج NNAPI في رمز المستوى الأدنى. يعد إنشاء التحويل البرمجي عملية متزامنة. مرة واحدة بنجاح، ويمكن إعادة استخدامه في سلاسل المحادثات وعمليات التنفيذ. ضِمن NNAPI، يتم تمثيل كل تجميع ANeuralNetworksCompilation مثال.
  • الذاكرة: تشير إلى الذاكرة المشتركة والملفات التي تم ربط الذاكرة بها والذاكرة المشابهة والموارد الاحتياطية. يتيح استخدام مخزن مؤقت للذاكرة نقل بيانات وقت تشغيل NNAPI إلى برامج التشغيل بكفاءة أكبر. ينشئ التطبيق عادةً مخزنًا مؤقتًا واحدًا للذاكرة يحتوي على كل متوتر مطلوب لتحديد أي نموذج. يمكنك أيضًا استخدام ميزة "الذاكرة" الموارد الاحتياطية لتخزين المدخلات والمخرجات لمثيل التنفيذ. في NNAPI، يتم تمثيل كل مخزن مؤقت للذاكرة ANeuralNetworksMemory مثال.
  • التنفيذ: واجهة لتطبيق نموذج NNAPI على مجموعة من الإدخالات وعلى وجمع النتائج. يمكن تنفيذ التنفيذ بشكلٍ متزامن أو غير متزامن.

    بالنسبة إلى التنفيذ غير المتزامن، يمكن استخدام سلاسل محادثات متعددة. يمكنك الانتظار عند التنفيذ ذاته. عند اكتمال عملية التنفيذ هذه، تتم مزامنة جميع سلاسل المحادثات. صدرت.

    في NNAPI، يتم تمثيل كل عملية تنفيذ على أنها ANeuralNetworksExecution مثال.

يوضح الشكل 2 تدفق البرمجة الأساسي.

الشكل 2. مسار البرمجة لواجهة برمجة تطبيقات الشبكات العصبية في 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 الوصول إلى AHardwareBuffer بدون أن يحتاج السائق إلى نسخ البيانات. لدى AHardwareBuffer العديد من بإعدادات مختلفة، وقد لا يدعم كل مسرِّع NNAPI جميع هذه التكوينات. بسبب هذا القيد، ارجع إلى القيود مدرجة في المستندات المرجعية التي تخصّ 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 المورد الاحتياطي. يجب التأكد من أنّ الموارد الاحتياطية للمدخلات والمخرجات قبل جدولة التنفيذ.
  • لا يوجد دعم واصفات ملف المزامنة.
  • لـ AHardwareBuffer مع التنسيقات الخاصة بالبائع ووحدات بت الاستخدام، فإن الأمر متروك لتنفيذ البائع لتحديد ما إذا كان العميل أو السائق مسؤولاً عن تنظيف البيانات ذاكرة التخزين المؤقت.

الطراز

النموذج هو الوحدة الأساسية للحساب في NNAPI. يتم تعريف كل نموذج بواسطة معامل واحد أو أكثر من العمليات والعمليات.

الجهات المعنيّة

المعاملات هي كائنات بيانات تستخدم في تعريف الرسم البياني. وتشمل هذه المدخلات ومخرجات النموذج، أي العقد الوسطى التي تحتوي على البيانات من عملية إلى أخرى، والثوابت التي تنتقل إلى هذه العمليات.

هناك نوعان من المعاملات التي يمكن إضافتها إلى نماذج NNAPI: الكميات القياسية Tinors.

يمثل العدد القياسي قيمة واحدة. تدعم NNAPI القيم العددية في القيم المنطقية نقطة عائمة 16 بت، ونقطة عائمة 32 بت، وعدد صحيح 32 بت، وغير موقَّعة تنسيقات الأعداد الصحيحة 32 بت

تتضمن معظم العمليات في NNAPI أدوات تنس. المتغيرات عبارة عن صفائف مكوّنة من n. NNAPI يتوافق مع أدوات وحدة العشرة مع النقطة العائمة 16 بت، ونقطة عائمة 32 بت، و8 بت quantity، وكمية 16 بت، وعدد صحيح 32 بت، و8 بت القيم المنطقية.

على سبيل المثال، يمثل الشكل 3 نموذجًا به عمليتين: إضافة متبوعة بالضرب. يستخدم النموذج متسّع إدخال وينتج واحدًا مترابط الناتج.

الشكل 3. مثال على معاملات نموذج NNAPI

يتضمن النموذج أعلاه سبعة معاملات. ويتم تحديد هذه المعاملات ضمنيًا عن طريق فهرس ترتيب إضافتها إلى النموذج. المعامل الأول المضافة تحتوي على فهرس 0 والفهرس الثاني 1، وهكذا. الجهات المعنيّة 1 و2 و3 و5 هي معاملات ثابتة.

لا يهم الترتيب الذي تضيف به المعاملات. على سبيل المثال، يعبِّر النموذج يمكن أن يكون معامل المخرجات هو أول تمت إضافته. الجزء المهم هو استخدام قيمة الفهرس الصحيحة عند الإشارة إلى المعامل.

وللمعاملين أنواع. ويتم تحديدها عند إضافتها إلى النموذج.

لا يمكن استخدام المعامل كإدخال وإخراج لنموذج.

يجب أن يكون كل معامل إما إدخال نموذج أو ثابتًا أو معامل إخراج عملية واحدة بالضبط.

لمزيد من المعلومات عن استخدام المعاملات، راجِع مزيد من المعلومات عن المعاملات

العمليات

تحدد العملية العمليات الحسابية المراد تنفيذها. تتكون كل عملية من هذه العناصر:

  • نوع عملية (على سبيل المثال، الجمع والضرب والالتفاف)،
  • قائمة فهارس المعاملات التي تستخدمها العملية للإدخال،
  • قائمة فهارس المعاملات التي تستخدمها العملية للمخرج.

الترتيب في هذه القوائم مهم؛ اطّلِع على مرجع واجهة برمجة التطبيقات NNAPI للإدخالات المتوقعة والمخرجات لكل نوع من أنواع العمليات.

يجب إضافة المعاملات التي تستهلكها العملية أو تنتجها إلى النموذج قبل إضافة العملية.

لا يهم ترتيب إضافة العمليات. تعتمد واجهة NNAPI على والتبعيات التي تم إنشاؤها بواسطة الرسم البياني للعمليات الحسابية والعمليات تحديد ترتيب تنفيذ العمليات.

يتم تلخيص العمليات التي تتوافق مع NNAPI في الجدول أدناه:

الفئة العمليات
العمليات الحسابية استنادًا إلى العناصر
معالجة الموتّر
عمليات الصور
عمليات البحث
عمليات التسوية
عمليات الالتفاف
عمليات التجميع
عمليات التفعيل
عمليات أخرى

مشكلة معروفة في المستوى 28 من واجهة برمجة التطبيقات: عند اجتياز ANEURALNETWORKS_TENSOR_QUANT8_ASYMM مقوّرات إلى ANEURALNETWORKS_PAD المتوفرة على نظام التشغيل Android 9 (المستوى 28 لواجهة برمجة التطبيقات) والإصدارات الأحدث، قد لا تتطابق ناتج NNAPI مع ناتج تعلُّم الآلة على مستوى أعلى وأطر العمل، مثل TensorFlow Lite إِنْتَ يجب أن يمرّ فقط ANEURALNETWORKS_TENSOR_FLOAT32 تم حلّ المشكلة في نظام التشغيل Android 10 (المستوى 29 من واجهة برمجة التطبيقات) والإصدارات الأحدث.

إنشاء نماذج

في المثال التالي، ننشئ نموذج العمليتين الموجود في الشكل 3.

لإنشاء النموذج، يُرجى اتّباع الخطوات التالية:

  1. عليك استدعاء ANeuralNetworksModel_create() لتحديد نموذج فارغ.

    ANeuralNetworksModel* model = NULL;
    ANeuralNetworksModel_create(&model);
    
  2. أضف المعاملات إلى نموذجك من خلال استدعاء ANeuralNetworks_addOperand() يتم تحديد أنواع البيانات لديها باستخدام ANeuralNetworksOperandType بنية البيانات.

    // 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);
    

اكتشاف الأجهزة وتعيينها

بالنسبة إلى أجهزة Android التي تعمل بالإصدار 10 (المستوى 29 من واجهة برمجة التطبيقات) والإصدارات الأحدث، توفّر NNAPI الوظائف التي تسمح لمكتبات وتطبيقات أطر التعلم الآلي بالحصول معلومات حول الأجهزة المتاحة وتحديد الأجهزة التي سيتم استخدامها والتنفيذ. يؤدي تقديم معلومات عن الأجهزة المتاحة إلى السماح للتطبيقات بالحصول على الإصدار الدقيق من برامج التشغيل الذي تم العثور عليه على الجهاز لتجنب معرفة وعدم التوافق. من خلال منح التطبيقات القدرة على تحديد الأجهزة التي تريد استخدامها تنفذ أقسامًا مختلفة من النموذج، ويمكن تحسين التطبيقات للتوافق مع أنظمة الجهاز الذي يتم استخدامها عليه.

رصد الأجهزة

استخدام ANeuralNetworks_getDeviceCount لمعرفة عدد الأجهزة المتاحة. لكل جهاز، استخدم ANeuralNetworks_getDevice لضبط مثيل ANeuralNetworksDevice على مرجع إلى ذلك الجهاز.

بمجرد أن يكون لديك مرجع جهاز، يمكنك معرفة معلومات إضافية حول هذا الجهاز باستخدام الدوال التالية:

تخصيص الجهاز

استخدام ANeuralNetworksModel_getSupportedOperationsForDevices لاكتشاف عمليات أحد النماذج التي يمكن تنفيذها على أجهزة معينة.

للتحكّم في مسرِّعات الأعمال التي تريد استخدامها في التنفيذ، اتصل 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، عند توفُّر أجهزة متعددة يوزع العمل عبر الأجهزة. على سبيل المثال، إذا تم تضمين أكثر من جهاز يتم تقديمها إلى ANeuralNetworksCompilation_createForDevices، كل التي سيتم مراعاتها عند تخصيص العمل. لاحظ أنه إذا لم يتم تثبيت وحدة المعالجة المركزية غير مدرج في القائمة، فسيتم إيقاف تنفيذ وحدة المعالجة المركزية (CPU). عند استخدام "ANeuralNetworksCompilation_create" مع مراعاة جميع الأجهزة المتاحة، بما فيها وحدة المعالجة المركزية.

ويتم التوزيع من خلال الاختيار من قائمة الأجهزة المتاحة لكل العمليات في النموذج، والجهاز الذي يتوافق مع العملية الإعلان عن أفضل أداء، أي أسرع وقت للتنفيذ أو أدنى استهلاك للطاقة، اعتمادًا على تفضيل التنفيذ المحدد بواسطة للعميل. ولا تراعي خوارزمية التقسيم هذه القيم المحتملة الذي يسببه أمر الإدراج (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

الرسالة (على مستوى المعلومات مع العلامة 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);
    
  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.

عمليات تنفيذ الصور المتسلسلة

على أجهزة Android التي تعمل بنظام التشغيل Android 10 (المستوى 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);

قوائم انتظار أوامر غير متزامنة وتنفيذ سياج

في نظام التشغيل Android 11 والإصدارات الأحدث، توفّر واجهة NNAPI طريقة إضافية لتحديد مواعيد التنفيذ غير المتزامن من خلال ANeuralNetworksExecution_startComputeWithDependencies() . عند استخدام هذه الطريقة، ينتظر التنفيذ كل مراحل الأحداث التي سيتم الإشارة إليها قبل بدء التقييم. بمجرد التنفيذ مكتملة والمخرجات جاهزة لاستهلاكها، يكون الحدث الذي تم إرجاعه مُشار إليها.

اعتمادًا على الأجهزة التي ستتولى عملية التنفيذ، قد يتم دعم الحدث من خلال حاجز المزامنة. إِنْتَ يجب الاتصال 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) الاحتياطية

إذا حدث خطأ أثناء التقسيم، أو إذا فشل برنامج التشغيل في تجميع (جزء من أ)، أو إذا فشل برنامج التشغيل في تنفيذ نموذج مجمّع، قد تعاود واجهة NNAPI تنفيذ وحدة المعالجة المركزية الخاصة بها العمليات التجارية.

إذا كان عميل NNAPI يحتوي على إصدارات محسنة من العملية (مثل على سبيل المثال، TFLite)، قد يكون من المفيد تعطيل الإجراء الاحتياطي لوحدة المعالجة المركزية التعامل مع حالات الفشل مع تنفيذ العملية المُحسَّنة للعميل.

في نظام Android 10، إذا تم التجميع باستخدام ANeuralNetworksCompilation_createForDevices، وسيتم إيقاف استخدام وحدة المعالجة المركزية (CPU) الاحتياطي.

في Android P، يعود تنفيذ NNAPI إلى وحدة المعالجة المركزية في حالة إخفاق التنفيذ على برنامج التشغيل. ينطبق ذلك أيضًا على Android 10 عند استخدام ANeuralNetworksCompilation_create بدلاً من ذلك استخدام أكثر من ANeuralNetworksCompilation_createForDevices.

يتم تنفيذ العملية الأولى مرة أخرى لهذا القسم الفردي، وما إذا كان لا يزال فإنه يعيد محاولة النموذج بأكمله على وحدة المعالجة المركزية (CPU).

إذا تعذّر التقسيم أو التجميع، ستتم تجربة النموذج بأكمله على وحدة المعالجة المركزية.

هناك حالات لا تتوفر فيها بعض العمليات على وحدة المعالجة المركزية، وفي مثل ستفشل مواقف أو تنفيذ المواقف بدلاً من التراجع.

حتى بعد تعطيل الرجوع إلى وحدة المعالجة المركزية (CPU)، قد تكون هناك عمليات في النموذج المجدولة على وحدة المعالجة المركزية. إذا كانت وحدة المعالجة المركزية (CPU) مُدرَجة في قائمة المعالِجات المُقدّمة إلى ANeuralNetworksCompilation_createForDevices، وهو إما المصدر الوحيد معالج يدعم تلك العمليات أو هو المعالج الذي يدّعي أنّ أفضل أداء هذه العمليات، فسيتم اختيارها كعملية أساسية (غير احتياطية) وتنفيذه.

لضمان عدم تنفيذ وحدة المعالجة المركزية (CPU)، استخدِم ANeuralNetworksCompilation_createForDevices. مع استبعاد nnapi-reference من قائمة الأجهزة. بدءًا من الإصدار Android P، يمكن إيقاف الإجراء الاحتياطي في وقت التنفيذ على تنشئ أداة "تصحيح الأخطاء" من خلال ضبط السمة debug.nn.partition على القيمة 2.

نطاقات الذاكرة

في نظام التشغيل Android 11 والإصدارات الأحدث، تتوافق واجهة NNAPI مع نطاقات الذاكرة التي توفّر أدوات التخصيص. وواجهات للذكريات المبهمة. يسمح هذا الإجراء للتطبيقات بتمريرها إلى الأجهزة الأصلية الذاكرة عبر عمليات التنفيذ، بحيث لا تنسخ NNAPI البيانات أو تحوّلها غير ضروري عند إجراء عمليات تنفيذ متتالية على برنامج التشغيل نفسه.

تم تصميم ميزة مجال الذاكرة لأجهزة Tens التي غالبًا ما تكون داخلية برنامج التشغيل ولا تحتاج إلى الدخول المتكرر إلى جانب العميل. أمثلة على وتشمل هذه العوامل متوترات الحالة في نماذج المتتابعة. لموتّرات تحتاج إلى الوصول المتكرر إلى وحدة المعالجة المركزية (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 أو وضع تخزين البيانات الثنائية الكبيرة AHardwareBuffer.

عندما لا تحتاج NNAPI إلى الوصول إلى كائن الذاكرة المعتم، فحرر مثيل ANeuralNetworksMemory المقابل:

ANeuralNetworksMemory_free(opaqueMem);

قياس الأداء

يمكنك تقييم أداء تطبيقك من خلال قياس وقت التنفيذ أو من خلال تحديد المواصفات الشخصية.

وقت التنفيذ

عندما تريد تحديد إجمالي وقت التنفيذ من خلال بيئة التشغيل، يمكنك استخدام واجهة برمجة التطبيقات للتنفيذ المتزامن وقياس الوقت الذي يستغرقه الاتصال. عندما تريد يريدون تحديد إجمالي وقت التنفيذ من خلال مستوى أقل من البرنامج المكدس، يمكنك استخدام ANeuralNetworksExecution_setMeasureTiming أو ANeuralNetworksExecution_getDuration للحصول على ما يلي:

  • مدة التنفيذ في مسرِّع (وليس في برنامج التشغيل الذي يعمل على المضيف) معالج البيانات).
  • مدة التنفيذ في برنامج التشغيل، بما في ذلك الوقت المستغرَق في مسرِّعة الأعمال.

تُستثنى وقت التنفيذ في برنامج التشغيل النفقات العامة، مثل وقت التشغيل. نفسه وIPC المطلوب لبيئة التشغيل للاتصال ببرنامج التشغيل.

تقيس واجهات برمجة التطبيقات هذه المدة بين العمل الذي تم إرساله والعمل المنجز. بدلاً من الوقت الذي يخصصه السائق أو مسرِّعة السرعة لتنفيذ الاستنتاج، وربما تقطعه بتبديل السياق.

على سبيل المثال، إذا بدأ الاستنتاج 1، حينئذٍ يتوقف السائق عن العمل لتنفيذ الاستنتاج 2، فإنه يستأنف ويُكمل الاستنتاج 1، وهو وقت تنفيذ سيشمل الاستنتاج 1 الوقت الذي توقّف فيه العمل لتنفيذ الاستنتاج 2.

قد تكون معلومات التوقيت هذه مفيدة لنشر إنتاج تطبيقًا لجمع بيانات القياس عن بُعد للاستخدام بلا اتصال بالإنترنت. يمكنك استخدام بيانات التوقيت تعديل التطبيق لرفع مستوى الأداء.

عند استخدام هذه الوظيفة، يجب مراعاة ما يلي:

  • قد تكون هناك تكلفة مرتبطة بجمع معلومات التوقيت.
  • يستطيع السائق فقط حساب الوقت الذي يقضيه بمفرده أو في مسرِّعة أعمال، باستثناء الوقت المستغرق في وقت تشغيل NNAPI وفي IPC.
  • لا يمكنك استخدام واجهات برمجة التطبيقات هذه إلا مع ANeuralNetworksExecution تم تم الإنشاء باستخدام ANeuralNetworksCompilation_createForDevices مع numDevices = 1.
  • لا يُطلب من السائقين الإبلاغ عن معلومات التوقيت.

إنشاء ملف شخصي على التطبيق باستخدام Android Systrace

بدءًا من الإصدار 10 من نظام التشغيل Android، تنشئ واجهة NNAPI تلقائيًا systrace التي التي يمكنك استخدامها لتحديد تطبيقك.

يأتي مصدر NNAPI مزوّدًا بأداة parse_systrace لمعالجة التي تم إنشاؤها بواسطة التطبيق وإنشاء عرض جدول يوضح الوقت المستغرَق في المراحل المختلفة لدورة حياة النموذج (المثيل المثيلي، الإعداد والتجميع والإنهاء) وطبقات مختلفة من التطبيقات. الطبقات التي ينقسم التطبيق فيها هي:

  • Application: رمز التطبيق الرئيسي
  • Runtime: وقت تشغيل NNAPI
  • IPC: الاتصال البيني للعمليات بين "وقت تشغيل NNAPI" و"برنامج التشغيل" رقم الاعتماد
  • Driver: عملية تشغيل مسرِّعة الأعمال

إنشاء بيانات تحليل التوصيف

وبافتراض أنك اطّلعت على شجرة مصدر AOSP على $ANDROID_BUILD_TOP، باستخدام مثال تصنيف صور TFLite استهدافًا، يمكنك إنشاء بيانات تحليل NNAPI باستخدام الخطوات التالية:

  1. يمكنك بدء تتبُّع النظام في Android باستخدام الأمر التالي:
$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 باسم العملية. المحدد في بيان التطبيق.

سيؤدي ذلك إلى إبقاء إحدى وحدة تحكم Shell مشغولة، لا تُشغل الأمر في الخلفية لأنّه ينتظر بشكل تفاعلي إنهاء enter.

  1. بعد بدء أداة تجميع سجلات النظام، ابدأ التطبيق وشغِّل اختبار قياس الأداء.

يمكنك في هذه الحالة تشغيل تطبيق Image Classification من "استوديو Android". أو مباشرةً من واجهة مستخدم الهاتف التجريبي إذا كان التطبيق قد سبق تثبيته. لإنشاء بعض بيانات NNAPI، يجب إعداد التطبيق لاستخدام NNAPI من خلال تحديد NNAPI كجهاز مستهدف في مربع حوار إعداد التطبيق.

  1. عند اكتمال الاختبار، قم بإنهاء تتبع النظام عن طريق الضغط على 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: طباعة جميع الأحداث التي تم تجميعها من سجل النظام - --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_parser

يعتمد تطبيق Parse_systrace على تتبُّع نظام Android المدمَجة الأخرى. يمكنك إضافة آثار لعمليات معيّنة في تطبيقك باستخدام واجهة برمجة تطبيقات systrace (للغة Java ، للتطبيقات المحلية ) بأسماء أحداث مخصّصة.

لربط الأحداث المخصّصة بمراحل نشاط التطبيق، أضِف اسم الحدث أولاً بإحدى السلاسل التالية:

  • [NN_LA_PI]: حدث على مستوى التطبيق للإعداد
  • [NN_LA_PP]: حدث على مستوى التطبيق للاستعداد
  • [NN_LA_PC]: حدث على مستوى التطبيق في ميزة التجميع
  • [NN_LA_PE]: الحدث على مستوى التطبيق للتنفيذ

إليك مثال على كيفية تغيير مثال تصنيف صور TFLite عن طريق إضافة القسم runInferenceModel للمرحلة Execution تحتوي طبقة Application الأخرى على أقسام preprocessBitmap الأخرى التي لن يتم اعتبارها في تقارير NNAPI. سيكون القسم "runInferenceModel" هو جزء من أحداث تتبُّع النظام التي تتم معالجتها بواسطة المحلل اللغوي لسجل النظام في 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().

تحديد المواعيد النهائية

يمكن للتطبيقات تحديد مواعيد نهائية لكلٍ من تجميع النماذج والاستنتاج.

مزيد من المعلومات عن المعاملات

يتناول القسم التالي مواضيع متقدمة حول استخدام المعاملات.

نقاط التوتر الكمّية

يعتبر متنزس الكمّي طريقة مضغوطة لتمثيل صفيفة n من الأبعاد قيم النقطة العائمة.

يدعم NNAPI عوامل العشرات الكميّة غير المتماثلة 8 بت. وبالنسبة إلى هذه المؤشرات، يتم تمثيل قيمة كل خلية بعدد 8 بت صحيح. الأجهزة المرتبطة متنسورة هو مقياس وقيمة نقطة صفرية. وتُستخدم هذه الخوارزمية لتحويل 8 بت الأعداد الصحيحة في قيم النقطة العائمة التي يتم تمثيلها.

المعادلة هي:

(cellValue - zeroPoint) * scale

حيث تكون قيمة zeroPoint هي عدد صحيح 32 بت والمقياس عائم 32 بت نقطة.

بالمقارنة مع متسابقات قيم النقاط العائمة 32 بت، بمقاسات الكمية 8 بت هناك ميزتان:

  • تطبيقك أصغر، لأنّ الأوزان المدرَّبة تستغرق ربع الحجم من موتّرات 32 بت.
  • غالبًا ما يتم تنفيذ العمليات الحسابية بشكلٍ أسرع. ويرجع ذلك إلى قلة البيانات التي يجب جلبها من الذاكرة وكفاءة المعالِجات مثل الخصائص المنصات الصلبة (DSP) في حساب الأعداد الصحيحة.

وعلى الرغم من إمكانية تحويل نموذج النقطة العائمة إلى نموذج كَمي، المستخدم قد أظهرت أنه يتم تحقيق نتائج أفضل من خلال تدريب نموذج نموذج مباشرة. وفي الواقع، تتعلم الشبكة العصبية تعويض دقة متزايدة لكل قيمة. لكل موتر كمي، يتم حساب يتم تحديد قيم zeroPoint أثناء عملية التطبيق.

في NNAPI، يمكنك تعريف أنواع متسابقه الكمّي عن طريق تعيين حقل النوع ANeuralNetworksOperandType هيكل البيانات ANEURALNETWORKS_TENSOR_QUANT8_ASYMM يمكنك أيضًا تحديد المقياس وقيمة نقطة الصفر للمتسلل في تلك البيانات البنية.

بالإضافة إلى مأخذ القوة غير المتماثلة 8 بت، تدعم NNAPI ما يلي:

المعاملات الاختيارية

هناك بعض العمليات، مثل ANEURALNETWORKS_LSH_PROJECTION، اتخاذ معاملات اختيارية. للإشارة في النموذج إلى أن المعامل الاختياري تم إسقاطها، فقم باستدعاء ANeuralNetworksModel_setOperandValue() مع تمرير NULL للمخزن المؤقت و0 للطول.

إذا كان القرار بشأن ما إذا كان المعامل موجودًا أم لا يختلف حسب كل ستشير إلى أنه تم حذف المعامل باستخدام ANeuralNetworksExecution_setInput() أو ANeuralNetworksExecution_setOutput() مع تمرير NULL للمخزن المؤقت و0 للطول.

قيم ترتيب غير معروف

قدّم نظام Android 9 (مستوى واجهة برمجة التطبيقات 28) معاملات نماذج ذات أبعاد غير معروفة، ولكن رتبة معروفة (عدد الأبعاد). تقديم Android 10 (مستوى واجهة برمجة التطبيقات 29) المضاعفات ذات الرتبة غير المعروفة كما هو موضح في ANeure NetworksOperandType.

مقياس أداء NNAPI

يتوفّر مقياس أداء NNAPI على AOSP في platform/test/mlts/benchmark. (التطبيق المعياري) وplatform/test/mlts/models (النماذج ومجموعات البيانات).

يقيّم مقياس الأداء وقت الاستجابة والدقة ويقارن بين السائقين وما شابه. باستخدام Tensorflow Lite الذي يتم تشغيله على وحدة المعالجة المركزية (CPU) لنفس الطرازات ومجموعات البيانات.

لاستخدام مقياس الأداء، عليك اتّباع الخطوات التالية:

  1. وصِّل جهاز Android مستهدَفًا بالكمبيوتر وافتح نافذة طرفية. تأكَّد من إمكانية الوصول إلى الجهاز من خلال adb.

  2. في حال ربط أكثر من جهاز Android واحد، عليك تصدير الجهاز المستهدَف. متغيّر بيئة واحد (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 '""'

بعد التمكين، ينشئ التسجيل المطوَّل إدخالات السجل على مستوى المعلومات بعلامة تم تعيينها إلى اسم المرحلة أو المكون.

إلى جانب الرسائل التي يتم التحكم فيها من debug.nn.vlog، توفر مكونات واجهة برمجة التطبيقات NNAPI إدخالات أخرى للسجل على مستويات مختلفة، يستخدم كل واحد منها علامة سجل محددة.

للحصول على قائمة بالمكوّنات، ابحث في شجرة المصدر باستخدام التعبير التالي:

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

يعرض هذا التعبير حاليًا العلامات التالية:

  • أداة إنشاء الصور المصغّرة
  • طلبات معاودة الاتصال
  • أداة إنشاء التحويل البرمجي
  • وحدة المعالجة المركزية (CPU)
  • أداة إنشاء التنفيذ
  • وحدة التحكّم التنفيذية
  • خادم ExecutionBurstServer
  • خطة التنفيذ
  • سائق فيبوناتشي
  • تفريغ الرسم البياني
  • ملف IndexedShapeWrapper
  • ساعة IonWatcher
  • مدير
  • الذاكرة
  • أدوات الذاكرة
  • نموذج وصفي
  • معلومات النموذج
  • مصمم النماذج
  • الشبكات العصبية
  • أداة حلّ العمليات
  • العمليات
  • عمليات التشغيل
  • معلومات الحزمة
  • رمز 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 لإنشاء معلومات السجلّ المطوَّل.