תוספי ספקים

תוספי ספקים של Neural Networks API (NNAPI), הוצגו ב- Android 10 הוא אוספים של פעולות וסוגי נתונים שהוגדרו על ידי הספק. במכשירים עם NN HAL 1.2 ואילך, הנהגים יכולים לספק פעולות בהתאמה אישית שמואצלות בחומרה על ידי תמיכה בתוספים התואמים של הספק. תוספי הספקים לא משנים את ההתנהגות של הפעולות הקיימות.

תוספים של ספקים מספקים חלופה מובנית יותר לסוגי הנתונים ולפעולות של יצרני ציוד מקורי, שהוצאו משימוש ב-Android 10. למידע נוסף, ראו פעולות וסוגי נתונים של OEM.

רשימת ההיתרים לשימוש בתוספים

רק אפליקציות 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) מספק תמיכה בסיומת זמן ריצה. הקטע הזה מספק בסקירה כללית על ממשק 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 סביבת זמן הריצה מתייחסת אליו כאל blob של נתונים גולמיים בגודל שרירותי.

פעולות OEM (יצרן ציוד מקורי) וסוגי נתונים

ל-NNAPI יש פעולה של OEM וסוגי נתונים של OEM, כדי לאפשר ליצרני המכשירים לספק פונקציונליות מותאמת אישית ספציפית לנהג. סוגי הפעולות והנתונים האלה משמשים רק אפליקציות של יצרני ציוד מקורי (OEM). הסמנטיקה של OEM (יצרן ציוד מקורי) סוגי הפעולות והנתונים הם ספציפיים ל-OEM (יצרן הציוד המקורי) ועשויים להשתנות בכל שלב. ה-OEM (יצרן הציוד המקורי) סוגי הפעולות והנתונים מקודדים באמצעות OperationType::OEM_OPERATION, OperandType::OEM ו-OperandType::TENSOR_OEM_BYTE.