תוספי ספקים

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

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

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

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