बर्स्ट निष्पादन और तेज़ संदेश कतारें

न्यूरल नेटवर्क्स एचएएल 1.2 बर्स्ट निष्पादन की अवधारणा का परिचय देता है। बर्स्ट निष्पादन उसी तैयार मॉडल के निष्पादन का एक क्रम है जो तेजी से उत्तराधिकार में होता है, जैसे कि कैमरा कैप्चर या क्रमिक ऑडियो नमूनों के फ्रेम पर काम करना। बर्स्ट ऑब्जेक्ट का उपयोग बर्स्ट निष्पादन के एक सेट को नियंत्रित करने और निष्पादन के बीच संसाधनों को संरक्षित करने के लिए किया जाता है, जिससे निष्पादन में कम ओवरहेड होता है। बर्स्ट ऑब्जेक्ट तीन अनुकूलन सक्षम करते हैं:

  1. निष्पादन के अनुक्रम से पहले एक बर्स्ट ऑब्जेक्ट बनाया जाता है, और अनुक्रम समाप्त होने पर मुक्त किया जाता है। इस वजह से, फटी हुई वस्तु का जीवनकाल ड्राइवर को संकेत देता है कि उसे कितने समय तक उच्च-प्रदर्शन स्थिति में रहना चाहिए।
  2. एक बर्स्ट ऑब्जेक्ट निष्पादन के बीच संसाधनों को संरक्षित कर सकता है। उदाहरण के लिए, एक ड्राइवर पहले निष्पादन पर एक मेमोरी ऑब्जेक्ट को मैप कर सकता है और बाद के निष्पादन में पुन: उपयोग के लिए बर्स्ट ऑब्जेक्ट में मैपिंग को कैश कर सकता है। किसी भी कैश्ड संसाधन को तब जारी किया जा सकता है जब बर्स्ट ऑब्जेक्ट नष्ट हो जाता है या जब एनएनएपीआई रनटाइम बर्स्ट ऑब्जेक्ट को सूचित करता है कि संसाधन की अब आवश्यकता नहीं है।
  3. एक बर्स्ट ऑब्जेक्ट ऐप और ड्राइवर प्रक्रियाओं के बीच संचार करने के लिए तेज़ संदेश कतार (एफएमक्यू) का उपयोग करता है। यह विलंबता को कम कर सकता है क्योंकि FMQ HIDL को बायपास करता है और साझा मेमोरी में एक परमाणु परिपत्र FIFO के माध्यम से डेटा को सीधे दूसरी प्रक्रिया में भेजता है। उपभोक्ता प्रक्रिया किसी वस्तु को हटाना और एफआईएफओ में तत्वों की संख्या को मतदान करके या एफएमक्यू के इवेंट ध्वज पर प्रतीक्षा करके प्रसंस्करण शुरू करना जानती है, जो निर्माता द्वारा संकेत दिया जाता है। यह इवेंट फ़्लैग एक तेज़ यूज़रस्पेस म्यूटेक्स (फ्यूटेक्स) है।

एफएमक्यू एक निम्न-स्तरीय डेटा संरचना है जो सभी प्रक्रियाओं में कोई आजीवन गारंटी नहीं देती है और इसमें यह निर्धारित करने के लिए कोई अंतर्निहित तंत्र नहीं है कि एफएमक्यू के दूसरे छोर पर प्रक्रिया अपेक्षा के अनुरूप चल रही है या नहीं। नतीजतन, यदि एफएमक्यू के निर्माता की मृत्यु हो जाती है, तो उपभोक्ता उस डेटा के इंतजार में फंस सकता है जो कभी नहीं आता है। इस समस्या का एक समाधान ड्राइवर के लिए एफएमक्यू को उच्च-स्तरीय बर्स्ट ऑब्जेक्ट के साथ जोड़ना है ताकि यह पता लगाया जा सके कि बर्स्ट निष्पादन कब समाप्त हुआ है।

क्योंकि बर्स्ट निष्पादन समान तर्कों पर काम करते हैं और अन्य निष्पादन पथों के समान परिणाम लौटाते हैं, अंतर्निहित एफएमक्यू को एनएनएपीआई सेवा ड्राइवरों से समान डेटा पास करना होगा। हालाँकि, FMQs केवल सादे-पुराने-डेटा प्रकारों को स्थानांतरित कर सकते हैं। जटिल डेटा को स्थानांतरित करना सीधे एफएमक्यू में नेस्टेड बफ़र्स (वेक्टर प्रकार) को क्रमबद्ध और डीसेरिएलाइज़ करके और मांग पर मेमोरी पूल हैंडल को स्थानांतरित करने के लिए एचआईडीएल कॉलबैक ऑब्जेक्ट का उपयोग करके पूरा किया जाता है। यदि कतार अवरुद्ध हो रही है तो MessageQueue::writeBlocking का उपयोग करके, या यदि कतार नॉनब्लॉकिंग है तो MessageQueue::write उपयोग करके FMQ के निर्माता पक्ष को परमाणु रूप से उपभोक्ता को अनुरोध या परिणाम संदेश भेजना होगा।

बर्स्ट इंटरफ़ेस

न्यूरल नेटवर्क्स एचएएल के लिए बर्स्ट इंटरफेस hardware/interfaces/neuralnetworks/1.2/ में पाए जाते हैं और नीचे वर्णित हैं। एनडीके परत में बर्स्ट इंटरफेस के बारे में अधिक जानकारी के लिए, frameworks/ml/nn/runtime/include/NeuralNetworks.h देखें।

प्रकार.हाल

types.hal एफएमक्यू पर भेजे जाने वाले डेटा के प्रकार को परिभाषित करता है।

  • 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 तैयार मॉडल से IBurstContext ऑब्जेक्ट बनाने की विधि के साथ HAL 1.2 में विस्तारित किया गया है।

  • configureExecutionBurst : एक बर्स्ट ऑब्जेक्ट को कॉन्फ़िगर करता है जिसका उपयोग तेजी से उत्तराधिकार में तैयार मॉडल पर कई अनुमानों को निष्पादित करने के लिए किया जाता है।

ड्राइवर में बर्स्ट निष्पादन का समर्थन करें

HIDL NNAPI सेवा में बर्स्ट ऑब्जेक्ट का समर्थन करने का सबसे सरल तरीका बर्स्ट उपयोगिता फ़ंक्शन ::android::nn::ExecutionBurstServer::create का उपयोग करना है, जो ExecutionBurstServer.h में पाया जाता है और libneuralnetworks_common और libneuralnetworks_util स्थिर पुस्तकालयों में पैक किया जाता है। इस फ़ैक्टरी फ़ंक्शन में दो ओवरलोड हैं:

  • एक ओवरलोड IPreparedModel ऑब्जेक्ट के लिए एक पॉइंटर स्वीकार करता है। यह उपयोगिता फ़ंक्शन मॉडल को निष्पादित करने के लिए IPreparedModel ऑब्जेक्ट में executeSynchronously विधि का उपयोग करता है।
  • एक अधिभार एक अनुकूलन योग्य IBurstExecutorWithCache ऑब्जेक्ट को स्वीकार करता है, जिसका उपयोग संसाधनों को कैश करने के लिए किया जा सकता है (जैसे hidl_memory मैपिंग) जो कई निष्पादन में बने रहते हैं।

प्रत्येक ओवरलोड एक IBurstContext ऑब्जेक्ट (जो बर्स्ट ऑब्जेक्ट का प्रतिनिधित्व करता है) लौटाता है जिसमें अपना स्वयं का समर्पित श्रोता थ्रेड होता है और प्रबंधित करता है। यह थ्रेड requestChannel FMQ से अनुरोध प्राप्त करता है, अनुमान लगाता है, फिर resultChannel FMQ के माध्यम से परिणाम लौटाता है। यह थ्रेड और IBurstContext ऑब्जेक्ट में मौजूद अन्य सभी संसाधन स्वचालित रूप से तब रिलीज़ हो जाते हैं जब बर्स्ट का क्लाइंट IBurstContext से अपना संदर्भ खो देता है।

वैकल्पिक रूप से, आप IBurstContext का अपना कार्यान्वयन बना सकते हैं जो समझता है कि IPreparedModel::configureExecutionBurst को भेजे गए requestChannel और resultChannel FMQ पर संदेश कैसे भेजें और प्राप्त करें।

बर्स्ट उपयोगिता फ़ंक्शन 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();
}