پسوند فروشنده

افزونه‌های فروشنده‌ی API شبکه‌های عصبی (NNAPI)، که در اندروید ۱۰ معرفی شده‌اند، مجموعه‌ای از عملیات و انواع داده‌ی تعریف‌شده توسط فروشنده هستند. در دستگاه‌هایی که NN HAL 1.2 یا بالاتر را اجرا می‌کنند، درایورها می‌توانند با پشتیبانی از افزونه‌های فروشنده‌ی مربوطه، عملیات شتاب‌دهی سخت‌افزاری سفارشی را ارائه دهند. افزونه‌های فروشنده، رفتار عملیات موجود را تغییر نمی‌دهند.

افزونه‌های فروشنده، جایگزین ساختاریافته‌تری برای عملیات و انواع داده‌های OEM ارائه می‌دهند که در اندروید ۱۰ منسوخ شده‌اند. برای اطلاعات بیشتر، به عملیات و انواع داده‌های OEM مراجعه کنید.

لیست مجاز استفاده از افزونه‌ها

افزونه‌های فروشنده فقط می‌توانند توسط برنامه‌های اندروید و فایل‌های باینری بومی که به صراحت در پارتیشن‌های /product ، /vendor ، /odm و /data مشخص شده‌اند، استفاده شوند. برنامه‌ها و فایل‌های باینری بومی واقع در پارتیشن /system نمی‌توانند از افزونه‌های فروشنده استفاده کنند.

فهرستی از برنامه‌ها و فایل‌های باینری اندروید که مجاز به استفاده از افزونه‌های فروشنده NNAPI هستند در /vendor/etc/nnapi_extensions_app_allowlist ذخیره می‌شود. هر خط از این فایل شامل یک ورودی جدید است. یک ورودی می‌تواند یک مسیر باینری بومی باشد که با یک اسلش (/) پیشوند شده است، به عنوان مثال، /data/foo ، یا نام یک بسته برنامه اندروید، به عنوان مثال، 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) پشتیبانی از افزونه‌های زمان اجرا را فراهم می‌کند. این بخش مروری بر رابط برنامه‌نویسی کاربردی زبان 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,
        },
    },
}

از ۳۲ بیتی که برای شناسایی انواع و عملیات استفاده می‌شود، بیت‌های بالای 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 کدگذاری می‌شوند.