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

Android 10 में पेश किए गए Neural Networks API (NNAPI) के वेंडर एक्सटेंशन, वेंडर की ओर से तय की गई कार्रवाइयों और डेटा टाइप का कलेक्शन हैं. 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 का इस्तेमाल करके एन्कोड किया जाता है.