عمليات التنفيذ المكثّفة وقوائم الرسائل السريعة

تقدم الشبكات العصبية HAL 1.2 مفهوم عمليات تنفيذ الصور المتسلسلة. صور متسلسلة عمليات التنفيذ هي سلسلة من عمليات التنفيذ لنفس النموذج المعد والتي تحدث في التتابع السريع، مثل تلك التي تعمل على إطارات التقاط الكاميرا أو مقطع صوتي متتالي العينات. يُستخدَم عنصر المعالجة المكثّفة للتحكّم في مجموعة من عمليات التنفيذ المكثّفة، وللحفاظ على الموارد بين عمليات التنفيذ، ما يتيح لعمليات التنفيذ استخدام موارد أقل. تتيح لك ميزة "التقاط الصور المتسلسلة" إجراء ثلاثة تحسينات:

  1. يتم إنشاء عنصر معالجة مكثّفة قبل تسلسل عمليات التنفيذ، ويتم تحريره عند انتهاء التسلسل. لهذا السبب، لا شك في أن عمر الانفجار تلميحات عن برنامج التشغيل إلى المدة التي يجب أن تظل فيها في الأداء العالي الولاية.
  2. يمكن لكائن الصور المتسلسلة الاحتفاظ بالموارد بين عمليات التنفيذ. على سبيل المثال، يمكن لبرنامج IDE ربط عنصر ذاكرة في التنفيذ الأول وتخزين عملية الربط في ذاكرة التخزين المؤقت في عنصر البث لإعادة استخدامه في عمليات التنفيذ اللاحقة. يمكن تحرير أيّ مورد مخزّن مؤقتًا عند إتلاف عنصر المعالجة المكثّفة أو عندما يُعلم وقت تنفيذ NNAPI عنصر المعالجة المكثّفة بأنّ المورد لم يعُد مطلوبًا.
  3. يستخدم عنصر البث قوائم الرسائل السريعة (FMQ) للتواصل بين عمليات التطبيق وعمليات برنامج التشغيل. ويمكن أن تقليل وقت الاستجابة لأن FMQ تتخطى HIDL وتمرر البيانات مباشرةً إلى عملية أخرى من خلال FIFO دائري ذري في الذاكرة المشتركة. تعرف عملية المستهلك إزالة عنصر من "قائمة الانتظار" وبدء المعالجة إما من خلال الاستعلام عن عدد العناصر في "قائمة الانتظار بترتيب أولوية الوصول إلى الذاكرة" أو من خلال الانتظار على علامة حدث "قائمة الانتظار بأولوية الوصول إلى الذاكرة" التي يشير إليها المنتج. تُعد عملية الإبلاغ عن الحدث هذه سريعة كائن userspace التالي (futex).

"قائمة الانتظار للرسائل الفورية" هي بنية بيانات منخفضة المستوى لا تقدّم أي ضمانات مدى الحياة على مستوى العمليات ولا تتضمّن آلية مدمجة لتحديد ما إذا كانت العملية في الطرف الآخر من "قائمة الانتظار للرسائل الفورية" تعمل على النحو المتوقّع. وبالتالي، إذا كان منتج يموت FMQ، وقد يكون المستهلك عالقًا في انتظار البيانات التي لا تصل أبدًا. وَاحِدْ لحل هذه المشكلة، أن يربط السائق أجهزة FMQ كائن صورة متسلسلة ذات مستوى أعلى لاكتشاف وقت انتهاء تنفيذ الصور المتسلسلة.

نظرًا لأن عمليات تنفيذ الصور المتسلسلة تعمل على الوسيطات نفسها وتعرض نفس الوسيطات كمسارات تنفيذ أخرى، يجب أن تمرّ FMQs الأساسية البيانات نفسها إلى ومن برامج تشغيل خدمة NNAPI. ومع ذلك، لا يمكن إلا لمحطات FMQ أن تنقل أنواع البيانات البسيطة والقديمة. يتم نقل البيانات المعقدة عن طريق التسلسل وإلغاء تسلسل المخازن الاحتياطية المتداخلة (أنواع المتجهات) مباشرةً في FMQs، واستخدام عناصر معاودة الاتصال HIDL لنقل مقابض مجموعة الذاكرة عند الطلب. منتِج من FMQ إرسال الطلب أو رسائل النتائج إلى المستهلك بشكل كامل باستخدام MessageQueue::writeBlocking إذا كانت قائمة الانتظار محظورة، أو باستخدام MessageQueue::write إذا كانت قائمة المحتوى التالي لا تؤدي إلى حظر المحتوى.

واجهات الصور المتسلسلة

يمكن العثور على واجهات النبضات لـ Neural Networks HAL في hardware/interfaces/neuralnetworks/1.2/ وتكون موضّحة أدناه. لمزيد من المعلومات عن واجهات الصور المتسلسلة في NDK طبقة، انظر frameworks/ml/nn/runtime/include/NeuralNetworks.h

types.hal

types.hal يحدِّد نوع البيانات التي يتم إرسالها عبر FMQ.

  • FmqRequestDatum: عنصر واحد لتمثيل تسلسلي لشيء تنفيذ Request وقيمته MeasureTiming، ويتم إرساله عبر قائمة انتظار الرسائل السريعة .
  • FmqResultDatum: عنصر واحد لتمثيل متسلسل للقيم التي يتم عرضها من عملية تنفيذ (ErrorStatus وOutputShapes وTiming)، وهي من خلال قائمة انتظار الرسائل السريعة.

IBurstContext.hal

IBurstContext.hal يحدِّد عنصر واجهة HIDL الذي يتوفّر في خدمة الشبكات العصبية.

  • IBurstContext: كائن السياق لإدارة موارد الصور المتسلسلة.

IBurstCallback.hal

IBurstCallback.hal كائن واجهة HIDL لمعاودة الاتصال التي تم إنشاؤها بواسطة الشبكات العصبية وتستخدمه خدمة الشبكات العصبية لاسترداد بيانات hidl_memory الكائنات المقابلة لمعرّفات الخانات.

  • IBurstCallback: عنصر استدعاء تستخدمه الخدمة لاسترداد عناصر الذاكرة.

مؤسسة IPreparedModel.hal

تم توسيع نطاق IPreparedModel.hal في HAL 1.2 باستخدام طريقة لإنشاء عنصر IBurstContext من نموذج معدّ.

  • configureExecutionBurst: يضبط عنصرًا متسلسلًا يُستخدَم لتنفيذ استنتاجات متعدّدة على نموذج مُعدّ بشكل متتابع وسَريع.

إتاحة عمليات التنفيذ المكثّفة في برنامج تشغيل

وأبسط طريقة لدعم الكائنات المتسلسلة في خدمة HIDL NNAPI هي استخدام دالة فائدة الصور المتسلسلة ::android::nn::ExecutionBurstServer::create، وهي تم العثور عليها في ExecutionBurstServer.h ومضمّنة في الحزمة في libneuralnetworks_common وlibneuralnetworks_util. والمكتبات الثابتة. تحتوي دالة المصنع هذه على تحميل زائدَين:

  • يقبل أحد أشكال الترجيع المؤشر إلى عنصر IPreparedModel. هذا النمط استخدام طريقة executeSynchronously في الكائن IPreparedModel لتنفيذ النموذج.
  • تقبل التحميل الزائد عنصر IBurstExecutorWithCache قابل للتخصيص. التي يمكن استخدامها لتخزين الموارد في ذاكرة التخزين المؤقت (مثل تعيينات hidl_memory) التي تستمر عبر عمليات التنفيذ المتعددة.

تعرض كل حِمل زائدة كائن IBurstContext (يمثل الصور المتسلسلة. ) يحتوي على سلسلة المستمعين المخصصة وتديرها. تتلقّى هذه السلسلة من الرسائل طلبات من "الطلبات الفورية للمعالجة" في requestChannel، ثم تُجري الاستنتاج، ثم تُعرض النتائج من خلال "الطلبات الفورية للمعالجة" في resultChannel. يتم تلقائيًا تحرير سلسلة المحادثات هذه وجميع موارد الأخرى المضمّنة في عنصر IBurstContext عندما يفقد عميل البث المفاجئ مرجعه إلى IBurstContext.

بدلاً من ذلك، يمكنك إنشاء تطبيقك الخاص لواجهة IBurstContext الذي يفهم كيفية إرسال الرسائل واستلامها من خلال فئتي requestChannel و resultChannel FMQ اللتين تم تمريرهما إلى IPreparedModel::configureExecutionBurst.

توجد دوال المنفعة المتسلسلة في ExecutionBurstServer.h

/**
 * Create automated context to manage FMQ-based executions.
 *
 * This function is intended to be used by a service to automatically:
 * 1) Receive data from a provided FMQ
 * 2) Execute a model with the given information
 * 3) Send the result to the created FMQ
 *
 * @param callback Callback used to retrieve memories corresponding to
 *     unrecognized slots.
 * @param requestChannel Input FMQ channel through which the client passes the
 *     request to the service.
 * @param resultChannel Output FMQ channel from which the client can retrieve
 *     the result of the execution.
 * @param executorWithCache Object which maintains a local cache of the
 *     memory pools and executes using the cached memory pools.
 * @result IBurstContext Handle to the burst context.
 */
static sp<ExecutionBurstServer> create(
        const sp<IBurstCallback>& callback, const FmqRequestDescriptor& requestChannel,
        const FmqResultDescriptor& resultChannel,
        std::shared_ptr<IBurstExecutorWithCache> executorWithCache);

/**
 * Create automated context to manage FMQ-based executions.
 *
 * This function is intended to be used by a service to automatically:
 * 1) Receive data from a provided FMQ
 * 2) Execute a model with the given information
 * 3) Send the result to the created FMQ
 *
 * @param callback Callback used to retrieve memories corresponding to
 *     unrecognized slots.
 * @param requestChannel Input FMQ channel through which the client passes the
 *     request to the service.
 * @param resultChannel Output FMQ channel from which the client can retrieve
 *     the result of the execution.
 * @param preparedModel PreparedModel that the burst object was created from.
 *     IPreparedModel::executeSynchronously will be used to perform the
 *     execution.
 * @result IBurstContext Handle to the burst context.
 */
  static sp<ExecutionBurstServer> create(const sp<IBurstCallback>& callback,
                                         const FmqRequestDescriptor& requestChannel,
                                         const FmqResultDescriptor& resultChannel,
                                         IPreparedModel* preparedModel);

في ما يلي تنفيذ مرجعي لواجهة المعالجة المكثّفة للبيانات في ملف رمز المصدر المخصص لبرنامج التشغيل نموذج الشبكات العصبية على الرابط frameworks/ml/nn/driver/sample/SampleDriver.cpp.

Return<void> SamplePreparedModel::configureExecutionBurst(
        const sp<V1_2::IBurstCallback>& callback,
        const MQDescriptorSync<V1_2::FmqRequestDatum>& requestChannel,
        const MQDescriptorSync<V1_2::FmqResultDatum>& resultChannel,
        configureExecutionBurst_cb cb) {
    NNTRACE_FULL(NNTRACE_LAYER_DRIVER, NNTRACE_PHASE_EXECUTION,
                 "SampleDriver::configureExecutionBurst");
    // Alternatively, the burst could be configured via:
    // const sp<V1_2::IBurstContext> burst =
    //         ExecutionBurstServer::create(callback, requestChannel,
    //                                      resultChannel, this);
    //
    // However, this alternative representation does not include a memory map
    // caching optimization, and adds overhead.
    const std::shared_ptr<BurstExecutorWithCache> executorWithCache =
            std::make_shared<BurstExecutorWithCache>(mModel, mDriver, mPoolInfos);
    const sp<V1_2::IBurstContext> burst = ExecutionBurstServer::create(
            callback, requestChannel, resultChannel, executorWithCache);
    if (burst == nullptr) {
        cb(ErrorStatus::GENERAL_FAILURE, {});
    } else {
        cb(ErrorStatus::NONE, burst);
    }
    return Void();
}