वेंडर एक्सटेंशन

Android 10 में पेश किए गए Neural Networks API (NNAPI) के वेंडर एक्सटेंशन, वेंडर की ओर से तय की गई कार्रवाइयों और डेटा टाइप का कलेक्शन हैं. NN HAL 1.2 या इसके बाद के वर्शन चलाने वाले डिवाइसों पर, ड्राइवर संबंधित वेंडर एक्सटेंशन की मदद से, हार्डवेयर से तेज़ी से होने वाली कार्रवाइयों की कस्टम सुविधा दे सकते हैं. वेंडर एक्सटेंशन, मौजूदा कार्रवाइयों के व्यवहार में कोई बदलाव नहीं करते.

वेंडर एक्सटेंशन, OEM ऑपरेशन और डेटा टाइप की तुलना में ज़्यादा स्ट्रक्चर्ड विकल्प देते हैं जिन्हें Android 10 में बंद कर दिया गया था. ज़्यादा जानकारी के लिए, OEM कार्रवाइयां और डेटा टाइप देखें.

एक्सटेंशन के इस्तेमाल की अनुमति वाली सूची

वेंडर एक्सटेंशन का इस्तेमाल सिर्फ़ /product, /vendor, /odm, और /data पार्टिशन में साफ़ तौर पर बताए गए Android ऐप्लिकेशन और नेटिव बाइनरी से ही किया जा सकता है. /system पार्टिशन में मौजूद ऐप्लिकेशन और नेटिव बाइनरी, वेंडर एक्सटेंशन का इस्तेमाल नहीं कर सकते.

NNAPI वेंडर एक्सटेंशन का इस्तेमाल करने की अनुमति वाले Android ऐप्लिकेशन और बाइनरी की सूची, /vendor/etc/nnapi_extensions_app_allowlist में सेव की गई है. फ़ाइल की हर लाइन में एक नई एंट्री होती है. कोई एंट्री, नेटिव बाइनरी पाथ हो सकती है. इसके आगे स्लैश (/) लगा होता है. जैसे, /data/foo या किसी Android ऐप्लिकेशन पैकेज का नाम, जैसे कि com.foo.bar.

अनुमति वाली सूची को NNAPI रनटाइम की शेयर की गई लाइब्रेरी से लागू किया जाता है. यह लाइब्रेरी गलती से इस्तेमाल किए जाने से बचाती है, लेकिन NNAPI ड्राइवर एचएएल इंटरफ़ेस का इस्तेमाल करके सीधे ऐप्लिकेशन की ओर से जान-बूझकर किए गए धोखा देने से नहीं बचाती.

वेंडर एक्सटेंशन की परिभाषा

वेंडर, एक्सटेंशन की परिभाषा वाली हेडर फ़ाइल बनाता और उसे मैनेज करता है. एक्सटेंशन की परिभाषा का पूरा उदाहरण example/fibonacci/FibonacciExtension.h में देखा जा सकता है.

हर एक्सटेंशन का एक यूनीक नाम होना चाहिए, जो वेंडर के रिवर्स डोमेन नेम से शुरू होता है.

const char EXAMPLE_EXTENSION_NAME[] = "com.example.my_extension";

यह नाम, कार्रवाइयों और डेटा टाइप के लिए नेमस्पेस के तौर पर काम करता है. NNAPI इस नाम का इस्तेमाल, वेंडर एक्सटेंशन के बीच अंतर करने के लिए करता है.

कार्रवाइयों और डेटा टाइप का एलान, runtime/include/NeuralNetworks.h में बताए गए तरीके की तरह से किया जाता है.

enum {
    /**
     * A custom scalar type.
     */
    EXAMPLE_SCALAR = 0,

    /**
     * A custom tensor type.
     *
     * Attached to this tensor is {@link ExampleTensorParams}.
     */
    EXAMPLE_TENSOR = 1,
};

enum {
    /**
     * Computes example function.
     *
     * Inputs:
     * * 0: A scalar of {@link EXAMPLE_SCALAR}.
     *
     * Outputs:
     * * 0: A tensor of {@link EXAMPLE_TENSOR}.
     */
    EXAMPLE_FUNCTION = 0,
};

एक्सटेंशन ऑपरेशन में किसी भी तरह के ऑपरेंड टाइप का इस्तेमाल किया जा सकता है. इसमें, नॉन एक्सटेंशन ऑपरेंड टाइप और अन्य एक्सटेंशन के ऑपरेंड टाइप शामिल हैं. जब किसी अन्य एक्सटेंशन से ऑपरेंड टाइप का इस्तेमाल किया जा रहा हो, तो ड्राइवर को उस एक्सटेंशन के साथ काम करना चाहिए.

एक्सटेंशन, एक्सटेंशन ऑपरेंड के साथ कस्टम स्ट्रक्चर का एलान भी कर सकते हैं.

/**
 * Quantization parameters for {@link EXAMPLE_TENSOR}.
 */
typedef struct ExampleTensorParams {
    double scale;
    int64_t zeroPoint;
} ExampleTensorParams;

NNAPI क्लाइंट में एक्सटेंशन का इस्तेमाल करें

runtime/include/NeuralNetworksExtensions.h (C API) फ़ाइल, रनटाइम एक्सटेंशन के साथ काम करती है. इस सेक्शन में, C API की खास जानकारी दी गई है.

यह देखने के लिए कि डिवाइस पर एक्सटेंशन काम करता है या नहीं, ANeuralNetworksDevice_getExtensionSupport का इस्तेमाल करें.

bool isExtensionSupported;
CHECK_EQ(ANeuralNetworksDevice_getExtensionSupport(device, EXAMPLE_EXTENSION_NAME,
                                                   &isExtensionSupported),
         ANEURALNETWORKS_NO_ERROR);
if (isExtensionSupported) {
    // The device supports the extension.
    ...
}

एक्सटेंशन ऑपरेंड वाला मॉडल बनाने के लिए, ANeuralNetworksModel_getExtensionOperandType का इस्तेमाल करके ऑपरेंड टाइप और कॉल ANeuralNetworksModel_addOperand का इस्तेमाल करें.

int32_t type;
CHECK_EQ(ANeuralNetworksModel_getExtensionOperandType(model, EXAMPLE_EXTENSION_NAME, EXAMPLE_TENSOR, &type),
         ANEURALNETWORKS_NO_ERROR);
ANeuralNetworksOperandType operandType{
        .type = type,
        .dimensionCount = dimensionCount,
        .dimensions = dimensions,
};
CHECK_EQ(ANeuralNetworksModel_addOperand(model, &operandType), ANEURALNETWORKS_NO_ERROR);

इसके अलावा, अतिरिक्त डेटा को एक्सटेंशन ऑपरेंड से जोड़ने के लिए, ANeuralNetworksModel_setOperandExtensionData का इस्तेमाल करें.

ExampleTensorParams params{
        .scale = 0.5,
        .zeroPoint = 128,
};
CHECK_EQ(ANeuralNetworksModel_setOperandExtensionData(model, operandIndex, &params, sizeof(params)),
         ANEURALNETWORKS_NO_ERROR);

एक्सटेंशन ऑपरेशन वाला मॉडल बनाने के लिए, ANeuralNetworksModel_getExtensionOperationType का इस्तेमाल करके कार्रवाई का टाइप और ANeuralNetworksModel_addOperation को कॉल करें.

ANeuralNetworksOperationType type;
CHECK_EQ(ANeuralNetworksModel_getExtensionOperationType(model, EXAMPLE_EXTENSION_NAME, EXAMPLE_FUNCTION,
                                                        &type),
         ANEURALNETWORKS_NO_ERROR);
CHECK_EQ(ANeuralNetworksModel_addOperation(model, type, inputCount, inputs, outputCount, outputs),
         ANEURALNETWORKS_NO_ERROR);

किसी NNAPI ड्राइवर में एक्सटेंशन के लिए सहायता जोड़ें

ड्राइवर, IDevice::getSupportedExtensions तरीके से काम करने वाले एक्सटेंशन की रिपोर्ट करते हैं. दिखाई गई सूची में, इस्तेमाल किए जा सकने वाले हर एक्सटेंशन के बारे में जानकारी देने वाली एक एंट्री होनी चाहिए.

Extension {
    .name = EXAMPLE_EXTENSION_NAME,
    .operandTypes = {
        {
            .type = EXAMPLE_SCALAR,
            .isTensor = false,
            .byteSize = 8,
        },
        {
            .type = EXAMPLE_TENSOR,
            .isTensor = true,
            .byteSize = 8,
        },
    },
}

टाइप और ऑपरेशन की पहचान करने के लिए इस्तेमाल किए गए 32 बिट में से, हाई Model::ExtensionTypeEncoding::HIGH_BITS_PREFIX बिट, एक्सटेंशन प्रीफ़िक्स और सबसे कम Model::ExtensionTypeEncoding::LOW_BITS_TYPE बिट, एक्सटेंशन के टाइप या कार्रवाई के बारे में बताते हैं.

किसी ऑपरेशन या ऑपरेंड टाइप को हैंडल करते समय, ड्राइवर को एक्सटेंशन प्रीफ़िक्स की जांच करनी चाहिए. अगर एक्सटेंशन प्रीफ़िक्स में कोई वैल्यू नहीं है, तो ऑपरेशन या ऑपरेंड टाइप को एक्सटेंशन का टाइप माना जाता है. अगर वैल्यू 0 है, तो ऑपरेशन या ऑपरेंड टाइप को एक्सटेंशन का टाइप नहीं माना जाएगा.

किसी एक्सटेंशन के नाम से प्रीफ़िक्स को मैप करने के लिए, इसे model.extensionNameToPrefix में खोजें. दिए गए मॉडल के लिए प्रीफ़िक्स से एक्सटेंशन के नाम तक की मैपिंग, वन-टू-वन कम्यूनिकेशन्स (बायजेक्शन) होती है. अलग-अलग प्रीफ़िक्स वैल्यू, अलग-अलग मॉडल में एक ही एक्सटेंशन नाम से मेल खा सकती हैं.

ड्राइवर को एक्सटेंशन ऑपरेशन और डेटा टाइप की पुष्टि करनी होगी, क्योंकि NNAPI रनटाइम, कुछ खास एक्सटेंशन कार्रवाइयों और डेटा टाइप की पुष्टि नहीं कर सकता.

एक्सटेंशन ऑपरेंड के डेटा को operand.extraParams.extension में जोड़ा जा सकता है, जिसे रनटाइम, रॉ डेटा ब्लॉब की तरह आर्बिट्रेरी साइज़ मानता है.

OEM की कार्रवाई और डेटा टाइप

NNAPI में OEM कार्रवाई और OEM डेटा टाइप मौजूद हैं, ताकि डिवाइस मैन्युफ़ैक्चरर, ड्राइवर को अपनी पसंद के मुताबिक सुविधाएं दे सकें. इस ऑपरेशन और डेटा टाइप का इस्तेमाल सिर्फ़ OEM ऐप्लिकेशन करते हैं. OEM की कार्रवाई और डेटा टाइप के सिमेंटिक्स, OEM के हिसाब से होते हैं और इनमें किसी भी समय बदलाव किया जा सकता है. OEM कार्रवाई और डेटा टाइप को OperationType::OEM_OPERATION, OperandType::OEM, और OperandType::TENSOR_OEM_BYTE का इस्तेमाल करके कोड में बदला जाता है.