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

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

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

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

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

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

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

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

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