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

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

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

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

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

يتم تخزين قائمة بتطبيقات Android والبرامج الثنائية المسموح لها باستخدام إضافات مورّد NNAPI في /vendor/etc/nnapi_extensions_app_allowlist. يحتوي كل سطر من الملف على إدخال جديد. يمكن أن يكون الإدخال مسارًا ثنائيًا أصليًا مسبوقًا بشرطة مائلة (/)، على سبيل المثال /data/foo، أو اسم حِزمة تطبيق Android، على سبيل المثال com.foo.bar.

يتم فرض القائمة المسموح بها من المكتبة المشتركة لوقت تشغيل NNAPI. توفر هذه المكتبة الحماية من الاستخدام غير المقصود وليس من التحايل المتعمد من خلال أحد التطبيقات مباشرة باستخدام واجهة HAL لبرنامج التشغيل في 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.

لمعرفة ما إذا كان الجهاز متوافقًا مع الإضافة، يمكنك استخدام 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، التي يتعامل معها وقت التشغيل كمجموعة بيانات أولية بحجم عشوائي.

أنواع البيانات وعمليات المصنّع الأصلي للجهاز

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