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

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

वेंडर एक्सटेंशन, ओईएम ऑपरेशन और डेटा टाइप के लिए, ज़्यादा स्ट्रक्चर्ड विकल्प उपलब्ध कराते हैं. ओईएम ऑपरेशन और डेटा टाइप, Android 10 में अब इस्तेमाल नहीं किए जाते. ज़्यादा जानकारी के लिए, ओईएम ऑपरेशन और डेटा टाइप देखें.

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

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

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

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

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

वेंडर, एक्सटेंशन की परिभाषा वाली हेडर फ़ाइल बनाता है और उसे बनाए रखता है. A एक्सटेंशन की परिभाषा का पूरा उदाहरण 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 क्लाइंट में एक्सटेंशन इस्तेमाल करना

The 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, में डेटा जोड़ा जा सकता है. रनटाइम इसे किसी भी साइज़ के रॉ डेटा ब्लॉब के तौर पर लेता है.

ओईएम ऑपरेशन और डेटा टाइप

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