إضافات المورّدين

إنّ إضافات مورّد Neural Networks API (NNAPI)، التي تم طرحها في Android 10، هي مجموعات من العمليات وأنواع البيانات التي يحدّدها المورّد. على الأجهزة التي تعمل بإصدار NN HAL 1.2 أو إصدار أعلى، يمكن أن توفّر برامج التشغيل عمليات مخصّصة مُسرَّعة على مستوى الأجهزة من خلال إتاحة إضافات المورّد المقابلة. لا تُعدِّل إضافات المورّد سلوك العمليات الحالية.

توفّر إضافات المورّد بديلاً أكثر تنظيمًا لعمليات ومورّدات OEM، والتي تمّ تجاهلها في Android 10. لمزيد من المعلومات، يُرجى الاطّلاع على عمليات ومورّدات OEM.

القائمة المسموح بها لاستخدام الإضافات

لا يمكن استخدام إضافات المورّد إلا من خلال تطبيقات Android والملفات الثنائية الأصلية المحدّدة بشكل صريح على أقسام /product و/vendor و/odm و/data. لا يمكن للتطبيقات والملفات الثنائية الأصلية الموجودة على قسم /system استخدام إضافات المورّد.

يتم تخزين قائمة بتطبيقات Android والملفات الثنائية المسموح لها باستخدام إضافات مورّد NNAPI في /vendor/etc/nnapi_extensions_app_allowlist. يحتوي كل سطر في الملف على إدخال جديد. يمكن أن يكون الإدخال مسار ملف ثنائي أصلي مسبوقًا بشرطة مائلة (/)، مثلاً /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. إنّ عملية الربط من البادئة إلى اسم الإضافة هي عملية تطابق أحادي (bijection) لنموذج معيّن. قد تتطابق قيم البادئة المختلفة مع اسم الإضافة نفسه في نماذج مختلفة.

يجب أن يتحقّق برنامج التشغيل من عمليات الإضافة وأنواع البيانات لأنّ وقت تشغيل NNAPI لا يمكنه التحقّق من عمليات الإضافة وأنواع البيانات المحدّدة.

يمكن أن تحتوي مُعامِلات الإضافة على بيانات مرتبطة في operand.extraParams.extension، والتي يعاملها وقت التشغيل على أنّها كائن ثنائي كبير غير مُعالَج للبيانات بحجم عشوائي.

عمليات ومورّدات OEM

يحتوي NNAPI على عملية OEM وأنواع بيانات OEM للسماح لمصنّعي الأجهزة بتوفير وظائف مخصّصة خاصة ببرنامج التشغيل. لا يتم استخدام أنواع العمليات والبيانات هذه إلا من خلال تطبيقات OEM. إنّ دلالات عمليات ومورّدات OEM خاصة بمصنّع OEM ويمكن أن تتغيّر في أي وقت. يتم ترميز عمليات ومورّدات OEM باستخدام OperationType::OEM_OPERATION وOperandType::OEM وOperandType::TENSOR_OEM_BYTE.