תוספי ספקים ל-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, או שם של חבילת APK, לדוגמה, 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, ¶ms, 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.
המיפוי מהקידומת לשם התוסף הוא חד-חד-ערכי (ביג'קציה) עבור מודל נתון. יכול להיות שערכים שונים של תחיליות יתאימו לאותו שם של תוסף במודלים שונים.
הדרייבר צריך לאמת פעולות של תוספים וסוגי נתונים, כי זמן הריצה של NNAPI לא יכול לאמת פעולות מסוימות של תוספים וסוגי נתונים.
לאופרנדים של תוספים יכולים להיות נתונים משויכים ב-operand.extraParams.extension, שהסביבה בזמן הריצה מתייחסת אליהם כאל blob של נתונים גולמיים בגודל שרירותי.
פעולות OEM וסוגי נתונים
ל-NNAPI יש פעולת OEM וסוגי נתונים של OEM כדי לאפשר ליצרני מכשירים לספק פונקציונליות מותאמת אישית וספציפית למנהל התקן. סוגי הפעולות והנתונים האלה משמשים רק אפליקציות של יצרני ציוד מקורי (OEM). הסמנטיקה של פעולות OEM וסוגי הנתונים היא ספציפית ל-OEM ויכולה להשתנות בכל שלב. סוגי הפעולות והנתונים של יצרן הציוד המקורי מקודדים באמצעות OperationType::OEM_OPERATION, OperandType::OEM ו-OperandType::TENSOR_OEM_BYTE.