מנהלי התקנים של Neural Networks API

בדף הזה מופיעה סקירה כללית לגבי אופן ההטמעה של מנהל התקן של ממשק ה-API של רשתות נוירונים (NNAPI). פרטים נוספים זמינים במסמכי התיעוד שבקובצי הגדרת ה-HAL ב-hardware/interfaces/neuralnetworks. הטמעה של מנהל התקן לדוגמה נמצאת ב-frameworks/ml/nn/driver/sample.

למידע נוסף על Neural Networks API, ראו Neural Networks API.

HAL של רשתות נוירונים

HAL של רשתות הנוירונים (NN) מגדיר הפשטה של המכשירים השונים, כמו יחידות עיבוד גרפיות (GPU) ומעבדי אותות דיגיטליים (DSP), שנמצאים במוצר (לדוגמה, טלפון או טאבלט). מנהלי ההתקנים למכשירים האלה חייבים לעמוד בדרישות של NN HAL. הממשק מצוין בקובצי הגדרת ה-HAL ב-hardware/interfaces/neuralnetworks.

המעבר הכללי של הממשק בין המסגרת לנהג מתואר באיור 1.

זרימה של רשתות נוירונים

איור 1. זרימה של רשתות נוירונים

אתחול

בזמן האתחול, ה-framework שולח לנהג שאילתה לגבי היכולות שלו באמצעות IDevice::getCapabilities_1_3. המבנה @1.3::Capabilities כולל את כל סוגי הנתונים ומייצג ביצועים לא קשורים באמצעות וקטור.

כדי לקבוע איך להקצות חישובים למכשירים הזמינים, המסגרת הרעיונית משתמשת ביכולות כדי להבין באיזו מהירות ובאיזו מהירות אנרגיה יכולה להיות יעילה כל נהג יכול לבצע פעולה. כדי לספק את המידע הזה, מנהל ההתקן צריך לספק מספרי ביצועים סטנדרטיים שמבוססים על הפעלה של עומסי עבודה (workloads) של הפניות.

כדי לקבוע את הערכים שמנהל התקן מחזיר בתגובה ל-IDevice::getCapabilities_1_3, צריך להשתמש באפליקציית בנצ'מרק של NNAPI כדי למדוד את הביצועים של סוגי הנתונים המתאימים. מומלץ להשתמש במודלים של MobileNet v1 ו-v2, asr_float ו-tts_float למדידת ביצועים של ערכי נקודות צפות של 32 ביט, והמודלים הכמותיים של MobileNet v1 ו-v2 מומלצים לערכי קומות ב-8 ביט. מידע נוסף זמין במאמר חבילה לבדיקת למידת מכונה ב-Android.

ב-Android 9 ומטה, המבנה Capabilities כולל מידע על ביצועי הנהגים רק עבור נקודה צפה (floating-point) וטנצ'רים כמותיים, ולא כולל סוגי נתונים סקלריים.

כחלק מתהליך האתחול, המערכת עשויה לשלוח שאילתות לגבי מידע נוסף באמצעות IDevice::getType, IDevice::getVersionString, IDevice:getSupportedExtensions ו-IDevice::getNumberOfCacheFilesNeeded.

בין ההפעלות מחדש של המוצרים, ה-framework מצפה שכל השאילתות שמתוארות בקטע הזה ידווחו תמיד על אותם הערכים לנהג נתון. אחרת, אפליקציה שמשתמשת במנהל ההתקן הזה עלולה להפגת ביצועים נמוכים או התנהגות שגויה.

אוסף

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

בזמן האיסוף של המודל, ה-framework שולח את המודל לכל נהג מועמד באמצעות קריאה ל-IDevice::getSupportedOperations_1_3. כל מנהל התקן מחזיר מערך של בוליאניים המציינים אילו פעולות של המודל נתמכות. נהג יכול לקבוע שהוא לא יכול לתמוך בפעולה מסוימת מכמה סיבות. לדוגמה:

  • הנהג לא תומך בסוג הנתונים הזה.
  • מנהל ההתקן תומך רק בפעולות עם פרמטרים ספציפיים של קלט. לדוגמה, מנהל התקן עשוי לתמוך בפעולות קונבולוציה בגודל 3x3 ו-5x5, אבל לא בפעולות קונבולוציה בגודל 7x7.
  • לנהג יש מגבלות זיכרון שמונעות ממנו לטפל בתמונות גדולות או בקלט גדול.

במהלך ההידור, יכולים להיות ממדים או דירוג לא ידועים לקלט, לפלט ולאופרנדים הפנימיים של המודל, כפי שמתואר ב-OperandLifeTime. למידע נוסף, ראו צורת פלט.

ה-framework מורה לכל נהג/ת שנבחר להתכונן לבצע קבוצת משנה של המודל באמצעות קריאה ל-IDevice::prepareModel_1_3. לאחר מכן, כל מנהל התקן הרכב את קבוצת המשנה שלו. לדוגמה, נהג יכול ליצור קוד או ליצור עותק עם סדר מחדש של המשקולות. מכיוון שיכול להיות פרק זמן משמעותי בין הידור המודל לבין ביצוע בקשות, לא כדאי להקצות משאבים כמו מקטעים גדולים של זיכרון המכשיר במהלך הידור.

אם הפעולה מצליחה, הנהג יחזיר את הכינוי @1.3::IPreparedModel. אם הנהג מחזיר קוד כשל בהכנת קבוצת המשנה של המודל, ה-framework מריץ את המודל כולו במעבד.

כדי לקצר את משך הזמן שנדרש לאיסוף כאשר מופעלת אפליקציה, הנהג יכול לשמור במטמון פריטי מידע של הידור. למידע נוסף, ראו שמירה במטמון של הידור.

ביצוע

כשאפליקציה מבקשת מה-framework לבצע בקשה, ה-framework קורא ל-method IPreparedModel::executeSynchronously_1_3 כברירת מחדל כדי לבצע הרצה סינכרונית במודל מוכן. אפשר גם לבצע בקשה באופן אסינכרוני באמצעות ה-method execute_1_3, ה-method executeFenced (ראו Fenced integration), או לבצע אותה באמצעות ביצוע רצף.

קריאות ביצוע סינכרוניות משפרות את הביצועים ומצמצמות את תקורת השרשורים בהשוואה לקריאות אסינכרוניות, כי השליטה מוחזרת לתהליך האפליקציה רק אחרי הביצוע. כלומר, לנהג לא נדרש מנגנון נפרד כדי ליידע את תהליך האפליקציה על כך שההפעלה הושלמה.

בשיטה execute_1_3 האסינכרונית, אמצעי הבקרה חוזר לתהליך האפליקציה אחרי שהביצוע מתחיל, והנהג צריך להודיע למסגרת כשהביצוע מסתיים באמצעות @1.3::IExecutionCallback.

הפרמטר Request שמועבר לשיטת ההרצה מפרט את האופרנדים של הקלט והפלט שמשמשים לביצוע. בזיכרון שמאחסן את נתוני האופרנד צריך להשתמש בסדר שורה-ראשי, כאשר המאפיין הראשון חוזר על עצמו, ובלי מרווח פנימי בסוף כל שורה. למידע נוסף על סוגי האופרנדים, ראו מועדפים.

כשמתבצעת בקשה למנהלי התקנים מסוג NN HAL 1.2 ואילך, סטטוס השגיאה, צורת הפלט ופרטי התזמון מוחזרים ל-framework. במהלך הביצוע, לפלט או לאופרנדים פנימיים של המודל עשויים להיות מאפיין לא ידוע אחד או יותר או דירוג לא ידוע. כשלאופרנד אחד לפחות של פלט יש מימד או דירוג לא ידועים, הנהג צריך להחזיר מידע בגודל דינמי של הפלט.

לנהגים עם NN HAL 1.1 ומטה, מוחזר רק סטטוס השגיאה כשנשלחת בקשה. כדי שהביצוע יושלם בהצלחה, צריך לציין את המאפיינים של האופרנדים של הקלט והפלט. לאופרנדים פנימיים יכול להיות מאפיין לא ידוע אחד או יותר, אבל צריך לציין להם דירוג.

בבקשות של משתמשים שכוללות מספר נהגים, ה-framework אחראי על שמירת זיכרון הביניים ולסדר את הקריאות לכל נהג.

אפשר לשלוח כמה בקשות במקביל באותו @1.3::IPreparedModel. הנהג יכול לבצע בקשות במקביל או לבצע סריאליזציה של הפעולות.

המסגרת יכולה לבקש מנהג לשמור יותר ממודל מוכן אחד. לדוגמה, הכנת המודל m1, הכנה של m2, הפעלת בקשה r1 ב-m1, הפעלה של r2 ב-m2, הפעלה של r3 ב-m1, הפעלה של r4 ב-m2, השקה (כפי שמתואר בניקוי) m1 וגרסאות m2.

כדי למנוע הפעלה איטית ראשונה שעלולה לפגוע בחוויית המשתמש (לדוגמה, רעד בפריים הראשון), הנהג צריך לבצע את רוב האתחולים בשלב ההידור. האתחול בהפעלה הראשונה צריך להיות מוגבל לפעולות שמשפיעות לרעה על תקינות המערכת כשמפעילים אותן בשלב מוקדם, כמו הזמנת אגירת נתונים זמניים גדולים או הגברת קצב השעון של המכשיר. יכול להיות שמנהלי התקנים שיכולים להכין רק מספר מוגבל של מודלים בו-זמנית יצטרכו לבצע את האתחול בהפעלה הראשונה.

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

כדי לשפר את הביצועים של כמה הפעלות ברצף מהיר, הנהג יכול לשמור על מאגרי נתונים זמניים או להגדיל את קצב השעון. אם לא נוצרות בקשות חדשות אחרי פרק זמן קבוע, מומלץ ליצור שרשור של הטיימר המפקח (watchdog) כדי לשחרר משאבים.

צורת הפלט

לבקשות שבהן אופרנד אחד או יותר של פלט לא צוינו בכל המאפיינים, מנהל ההתקן צריך לספק רשימה של צורות פלט שמכילות את פרטי המאפיין לכל אופרנד פלט אחרי הביצוע. למידע נוסף על מאפיינים: OutputShape

אם ביצוע נכשל בגלל מאגר פלט קטן מדי, מנהל ההתקן חייב לציין לאילו אופרנדים של פלט אין גודל מספיק של מאגר נתונים זמני ברשימה של צורות הפלט. כמו כן, עליהם לדווח על מידע ממדי גדול ככל האפשר, תוך שימוש באפס עבור מימדים לא ידועים.

תזמון

ב-Android 10, האפליקציה יכולה לבקש את זמן הביצוע אם באפליקציה צוין מכשיר אחד שאפשר להשתמש בו בתהליך הידור. למידע נוסף, ראו MeasureTiming וזיהוי והקצאה של מכשירים. במקרה כזה, כשמבצעים בקשה, מנהל התקן NN HAL 1.2 צריך למדוד את משך הביצוע או לדווח על UINT64_MAX (כדי לציין שמשך הזמן לא זמין). הנהג/ת צריך/ה לצמצם את הקנסות על הביצועים שנובעים ממדידת משך הביצוע.

הנהג מדווח על משכי הזמן הבאים במיקרו-שניות במבנה Timing:

  • זמן הביצוע במכשיר: לא כולל את זמן הביצוע במנהל ההתקן, שרץ במעבד המארח.
  • זמן הביצוע במנהל ההתקן: כולל את זמן הביצוע במכשיר.

משכי הזמן האלה חייבים לכלול את הזמן שבו הביצוע מושעה, לדוגמה, שבו משימות אחרות קיצו את הביצוע או כשהוא בהמתנה למשאב זמין.

אם הנהג לא התבקש למדוד את משך הביצוע או כשיש שגיאה בביצוע, הוא צריך לדווח על משכי הזמן בתור UINT64_MAX. גם אם הנהג מתבקש למדוד את משך הביצוע, הוא יכול לדווח על הערך UINT64_MAX לפי השעה במכשיר, הזמן במנהל או שניהם. כשהנהג מדווח על שני משכי הזמן כערך שאינו UINT64_MAX, זמן הביצוע במנהל התקן צריך להיות שווה לזמן במכשיר או ארוך יותר.

הרצה מגודרת

ב-Android 11, NNAPI מאפשר להרצת הפעלות להמתין לרשימה של נקודות אחיזה של sync_fence, ולהחזיר אובייקט sync_fence, שמזוהה עם השלמת הביצוע. כך אפשר לצמצם את התקורה במודלים של רצפים קטנים ובתרחישים לדוגמה של סטרימינג. הפעלת הגדרות מגודרת גם מאפשרת יכולת פעולה הדדית יעילה יותר עם רכיבים אחרים שיכולים לאותת או להמתין ל-sync_fence. למידע נוסף על sync_fence ראו מסגרת סנכרון.

בביצוע מוגדר, ה-framework קורא ל-method IPreparedModel::executeFenced כדי להפעיל הפעלה אסינכרונית מגודרת במודל מוכן, עם וקטור של גדרות סנכרון שצריך להמתין לו. אם המשימה האסינכרונית תסתיים לפני שהשיחה חוזרת, אפשר להחזיר כינוי ריק בשביל sync_fence. צריך להחזיר גם אובייקט IFencedExecutionCallback כדי לאפשר ל-framework להריץ שאילתות על מידע על סטטוס השגיאה ועל משך הזמן.

אחרי שמשלימים את הביצוע, אפשר לשלוח שאילתה על שני ערכי התזמון הבאים, שמודדים את משך הביצוע, דרך IFencedExecutionCallback::getExecutionInfo.

  • timingLaunched: משך הזמן מרגע הקריאה של executeFenced ועד ל-executeFenced מסמנת את הערך syncFence שמוחזר.
  • timingFenced: משך הזמן מרגע שכל גדרות הסנכרון שנמצאות בהמתנה מופיעות כאשר executeFenced מסמן את הערך syncFence שמוחזר.

זרימת בקרה

במכשירים עם Android מגרסה 11 ואילך, ה-NNAPI כולל שתי פעולות בקרה, IF ו-WHILE, שמקבלות מודלים אחרים כארגומנטים ומפעילים אותם באופן מותנה (IF) או שוב ושוב (WHILE). למידע נוסף איך להטמיע את זה, ראו תהליך הבקרה.

איכות השירות

ב-Android 11, NNAPI כולל איכות שירות משופרת (QoS) כי הוא מאפשר לאפליקציה לציין את סדר העדיפויות היחסי של המודלים שלה, את הזמן המקסימלי הצפוי להכנת מודל ואת משך הזמן המקסימלי הצפוי להשלמת הביצוע. למידע נוסף, ראו איכות השירות.

ניקוי

כשאפליקציה מסיימת להשתמש במודל מוכן, ה-framework מסיר את ההפניה שלה לאובייקט @1.3::IPreparedModel. כשכבר אין הפניה לאובייקט IPreparedModel, הוא מושמד באופן אוטומטי בשירות הנהג שיצר אותו. בשלב הזה אפשר להשתמש במשאבים ספציפיים לדגם בהטמעה של כלי ההסבה לנהג. אם שירות הנהג רוצה שהאובייקט IPreparedModel יושמד באופן אוטומטי כשהוא לא צריך יותר את האובייקט, הוא לא יכול להכיל הפניות לאובייקט IPreparedModel אחרי שהאובייקט IPreparedeModel מוחזר דרך IPreparedModelCallback::notify_1_3.

שימוש במעבד

על מנהלי ההתקנים להשתמש במעבד (CPU) כדי להגדיר חישובים. אסור לנהגים להשתמש במעבד (CPU) כדי לבצע חישובי תרשימים כי זה מפריע ליכולת של ה-framework להקצות את העבודה בצורה נכונה. הנהג צריך לדווח ל-framework על החלקים שהוא לא יכול לטפל בהם, ולאפשר ל-framework לטפל במנוחה.

ה-framework מספק הטמעה של מעבד (CPU) לכל הפעולות של NNAPI, מלבד פעולות שהוגדרו על ידי הספק. למידע נוסף, ראו תוספי ספקים.

לפעולות שבוצעו ב-Android 10 (רמת API 29) יש רק הטמעה של מעבד (CPU) להתייחסות, כדי לוודא שהבדיקות של ה-CTS וה-VTS נכונות. עדיף להשתמש בהטמעות אופטימליות שכלולות ב-frameworks של למידת מכונה בנייד על פני הטמעה של מעבדי NNAPI.

פונקציות עזר

ה-codebase של NNAPI כולל פונקציות של כלים ששירותי מנהלי ההתקנים יכולים להשתמש בהן.

הקובץ frameworks/ml/nn/common/include/Utils.h מכיל פונקציות שונות של כלי שירות, כמו פונקציות שמשמשות לרישום ביומן ולהמרה בין גרסאות NN HAL שונות.

  • VLogging: VLOG הוא מאקרו wrapper מסביב ל-LOG של Android, שמתעד את ההודעה רק אם התג המתאים מוגדר במאפיין debug.nn.vlog. חייבים לקרוא ל-initVLogMask() לפני כל שיחה ל-VLOG. אפשר להשתמש במאקרו VLOG_IS_ON כדי לבדוק אם VLOG מופעל כרגע, וכך לדלג על קוד רישום ביומן מורכב אם אין בו צורך. הערך של המאפיין צריך להיות אחד מהערכים הבאים:

    • מחרוזת ריקה שמציינת שלא צריך לבצע רישום ביומן.
    • האסימון 1 או all, שמציין שכל הרישום ביומן הסתיים.
    • רשימת תגים שמופרדת באמצעות רווחים, פסיקים או נקודתיים, שמציינת איזה רישום ביומן צריך לבצע. התגים הם compilation, cpuexe, driver, execution, manager ו-model.
  • compliantWithV1_*: מחזירה את הערך true אם אפשר להמיר אובייקט NN HAL לאותו סוג של גרסת HAL אחרת בלי לאבד מידע. לדוגמה, קריאה ל-compliantWithV1_0 ב-V1_2::Model מחזירה false אם המודל כולל סוגי פעולות שנוספו ב-NN HAL 1.1 או ב-NN HAL 1.2.

  • convertToV1_*: המרה של אובייקט NN HAL מגרסה אחת לגרסה אחרת. אזהרה מתועדת אם ההמרה מובילה לאובדן מידע (כלומר, אם הגרסה החדשה של הסוג לא יכולה לייצג את הערך באופן מלא).

  • יכולות: אפשר להשתמש בפונקציות nonExtensionOperandPerformance ו-update כדי לבנות את השדה Capabilities::operandPerformance.

  • מאפייני שאילתות מסוגים: isExtensionOperandType, isExtensionOperationType, nonExtensionSizeOfData, nonExtensionOperandSizeOfData, nonExtensionOperandTypeIsScalar, tensorHasUnspecifiedDimensions.

הקובץ frameworks/ml/nn/common/include/ValidateHal.h מכיל פונקציות שימושיות לאימות שאובייקט NN HAL תקף לפי מפרט גרסת ה-HAL שלו.

  • validate*: הפונקציה מחזירה את הערך true אם אובייקט NN HAL תקין לפי מפרט גרסת ה-HAL שלו. סוגי ה-OEM וסוגי התוספים לא מאומתים. לדוגמה, validateModel מחזירה false אם המודל מכיל פעולה שמפנה לאינדקס אופרנד שלא קיים, או לפעולה שלא נתמכת בגרסת ה-HAL הזו.

הקובץ frameworks/ml/nn/common/include/Tracing.h מכיל פקודות מאקרו, שנועדו לפשט את הוספת נתוני systracing לקוד של רשתות נוירונים. לדוגמה, תוכלו לראות את ההפעלות של פקודות המאקרו NNTRACE_* במנהל ההתקן לדוגמה.

הקובץ frameworks/ml/nn/common/include/GraphDump.h מכיל פונקציית כלי עזר שיוצרת פלט של התוכן של Model בפורמט גרפי למטרות ניפוי באגים.

  • graphDump: כתיבת ייצוג של המודל בפורמט Graphviz (.dot) לזרם שצוין (אם סופק) או ל-Logcat (אם לא סופק זרם).

אימות

כדי לבדוק את ההטמעה של ה-NNAPI, צריך להשתמש בבדיקות VTS ו-CTS שכלולות ב-framework של Android. VTS מפעיל את הנהגים באופן ישיר (בלי להשתמש ב-framework), ואילו CTS מיישם את הנהגים באופן עקיף דרך המסגרת. הבדיקות האלה בודקות את כל ה-methods של ה-API, ומוודאים שכל הפעולות שנתמכות על ידי מנהלי ההתקנים פועלות כראוי ומספקות תוצאות שעומדות בדרישות הדיוק.

אלה דרישות הדיוק ב-CTS וב-VTS עבור NNAPI:

  • Floating-point: b(expected - Actual) <= atol + rtol * b(expected); כאשר:

    • ל-fp32, atol = 1e-5f, rtol = 5.0f * 1.1920928955078125e-7
    • ל-fp16, atol = rtol = 5.0f * 0.0009765625f
  • כמותית: כל אחד בנפרד (חוץ מהשנייה mobilenet_quantized, עד שלוש)

  • בוליאני: התאמה מדויקת

אחת הדרכים שבהן CTS בודק NNAPI היא יצירת תרשימים פסאודו-אקראיים קבועים המשמשים לבדיקה ולהשוואה של תוצאות הביצוע מכל מנהל התקנים עם יישום ההפניה של NNAPI. במקרה של נהגים עם NN HAL 1.2 ואילך, אם התוצאות לא עומדות בקריטריונים לדיוק, CTS מדווח על שגיאה ומשאיר קובץ מפרט למודל שנכשל ב-/data/local/tmp לניפוי באגים. למידע נוסף על הקריטריונים לקביעת דיוק, ראו TestRandomGraph.cpp ו-TestHarness.h.

בדיקת Fuzz

המטרה של בדיקת fuzz היא לאתר קריסות, טענות נכוֹנוּת (assertions), הפרות זיכרון או התנהגות לא מוגדרת כללית בקוד שנבדק, עקב גורמים כמו קלט לא צפוי. לבדיקת NNAPI fuzz, ב-Android נעשה שימוש בבדיקות שמבוססות על libFuzzer, שיעילותן לבצע fuzzer, כי הן משתמשות בכיסוי שורות של מקרי בדיקה קודמים כדי ליצור קלט אקראי חדש. לדוגמה, ב-libFuzzer יש העדפה למקרי בדיקה שרצים על שורות קוד חדשות. הפעולה הזו מפחיתה משמעותית את משך הזמן שנדרש כדי למצוא קוד בעייתי.

כדי לבצע בדיקת fuzz כדי לאמת את ההטמעה של מנהל ההתקן, משנים את frameworks/ml/nn/runtime/test/android_fuzzing/DriverFuzzTest.cpp בכלי הבדיקה libneuralnetworks_driver_fuzzer שנמצא ב-AOSP כך שיכלול את קוד מנהל ההתקן. למידע נוסף על בדיקת fuzz של NNAPI, ראו frameworks/ml/nn/runtime/test/android_fuzzing/README.md.

אבטחה

מכיוון שתהליכים של אפליקציות מתקשרים ישירות עם התהליך של הנהג, הנהגים צריכים לאמת את הארגומנטים של השיחות שהם מקבלים. האימות הזה מאומת על ידי VTS. קוד האימות הוא ב-frameworks/ml/nn/common/include/ValidateHal.h.

צריך גם לוודא שאפליקציות לא יוכלו להפריע לאפליקציות אחרות כשהם משתמשים באותו מכשיר.

חבילת הכלים לבדיקת למידת מכונה ב-Android

חבילת Android Machine Learning Test Suite (MLTS) היא נקודת השוואה ל-NNAPI שכלולה ב-CTS וב-VTS, לצורך אימות הדיוק של מודלים אמיתיים במכשירים של ספקים. נקודת ההשוואה בוחנת את זמן האחזור והדיוק ומשווה בין התוצאות של מנהלי ההתקנים לתוצאות באמצעות TF Lite שפועל במעבד (CPU), מאותו דגם ומאותו מערכי נתונים. כך אפשר להבטיח שהדיוק של הנהג לא פחות טוב מהטמעת ההפניה למעבד (CPU).

מפתחים של פלטפורמת Android משתמשים גם ב-MLTS כדי להעריך את זמן האחזור והדיוק של מנהלי התקנים.

נקודת ההשוואה של NNAPI נמצאת בשני פרויקטים ב-AOSP:

מודלים ומערכי נתונים

נקודת ההשוואה של NNAPI משתמשת במודלים ובמערכי הנתונים הבאים.

  • MobileNetV1 צף ו-u8 כמותי בגדלים שונים, פועלים מול קבוצת משנה קטנה (1,500 תמונות) של מערך הנתונים של Open אימג' בגרסה 4.
  • MobileNetV2 צף ו-u8 כמותי בגדלים שונים, פועלים מול קבוצת משנה קטנה (1,500 תמונות) של מערך הנתונים של Open אימג' בגרסה 4.
  • מודל אקוסטי של טקסט לדיבור (LSTM) שמבוסס על זיכרון ארוך טווח, פועל מול קבוצת משנה קטנה של קבוצת CMU ארקטית.
  • מודל אקוסטי מבוסס LSTM לזיהוי דיבור אוטומטי, שפועל מול קבוצת משנה קטנה של מערך הנתונים LibriSpeech.

למידע נוסף, ראו platform/test/mlts/models.

בדיקת מתח

חבילת הבדיקות של למידת מכונה ב-Android כוללת סדרה של בדיקות קריסה כדי לאמת את החוסן של נהגים בתנאי שימוש כבדים או בתרחישים פינתיים של התנהגות הלקוחות.

כל בדיקות הקריסה מספקות את התכונות הבאות:

  • זיהוי תקלה: אם לקוח ה-NNAPI נתקע במהלך הבדיקה, הבדיקה תיכשל עם הסיבה לכשל HANG וחבילת הבדיקות תעבור לבדיקה הבאה.
  • זיהוי קריסות של לקוח NNAPI: בדיקות שורדות קריסות של לקוח ובדיקות נכשלות עם הסיבה לכשל CRASH.
  • זיהוי של תאונת דרכים: הבדיקות יכולות לזהות קריסה של מנהל התקן שגורמת לכשל בקריאת NNAPI. שימו לב שיכולות להיות קריסות בתהליכי מנהלי ההתקנים שלא גורמות לכשל NNAPI ולא גורמות לבדיקה להיכשל. כדי לטפל בבעיה כזו, מומלץ להריץ את הפקודה tail ביומן המערכת במקרה של שגיאות או קריסות שקשורות לנהג.
  • טירגוט של כל המאיצים הזמינים: הבדיקות מבוצעות מול כל מנהלי ההתקנים הזמינים.

לכל בדיקות הקריסה יש ארבע תוצאות אפשריות:

  • SUCCESS: הביצוע הושלם ללא שגיאה.
  • FAILURE: הביצוע נכשל. בדרך כלל הסיבה לכך היא כשל בבדיקת מודל, שמציין שהנהג לא הצליח להדר או להפעיל את המודל.
  • HANG: תהליך הבדיקה הפסיק להגיב.
  • CRASH: תהליך הבדיקה קרס.

מידע נוסף על בדיקות עומסים ורשימה מלאה של בדיקות קריסה זמין ב-platform/test/mlts/benchmark/README.txt.

שימוש ב-MLTS

כדי להשתמש ב-MLTS:

  1. מחברים מכשיר יעד לתחנת העבודה ומוודאים שאפשר להגיע אליו דרך adb. כדאי לייצא את משתנה הסביבה ANDROID_SERIAL של מכשיר היעד אם יותר ממכשיר אחד מחובר.
  2. cd לספריית המקור ברמה העליונה של Android.

    source build/envsetup.sh
    lunch aosp_arm-userdebug # Or aosp_arm64-userdebug if available.
    ./test/mlts/benchmark/build_and_run_benchmark.sh
    

    בסיום הרצה של נקודת השוואה, התוצאות מוצגות כדף HTML ומועברות אל xdg-open.

למידע נוסף, ראו platform/test/mlts/benchmark/README.txt.

גרסאות HAL של רשתות נוירונים

בקטע הזה מתוארים השינויים שבוצעו בגרסאות HAL של רשתות נוירונים ו-Android.

Android 11

ב-Android 11 אנחנו משיקים את NN HAL 1.3, שכולל את השינויים החשובים הבאים.

  • תמיכה בקוונטיזציה חתומה של 8 ביט ב-NNAPI. הוספת סוג האופרנד TENSOR_QUANT8_ASYMM_SIGNED. מנהלי התקנים עם NN HAL 1.3 שתומכים בפעולות עם קוונטיזציה לא חתומה צריכים גם לתמוך בווריאציות החתומות של הפעולות האלה. כשמריצים גרסאות חתומות ולא חתומות של רוב הפעולות הכמויות, מנהלי ההתקנים צריכים להפיק את אותן התוצאות עד קיזוז של 128. לדרישה הזו יש חמישה חריגים: CAST, HASHTABLE_LOOKUP, LSH_PROJECTION, PAD_V2 ו-QUANTIZED_16BIT_LSTM. הפעולה QUANTIZED_16BIT_LSTM לא תומכת באופרנדים חתומים וארבע הפעולות האחרות תומכות בקונטיזציה חתומה, אבל לא מחייבות שהתוצאות יהיו זהות.
  • תמיכה בביצוע פעולות מגודרות שבהן ה-framework קורא ל-method IPreparedModel::executeFenced כדי להפעיל הפעלה אסינכרונית עם גבולות במודל מוכן, עם וקטור של גדרות סנכרון שצריך להמתין לו. תוכלו לקרוא מידע נוסף במאמר Fenced דקות.
  • תמיכה בתהליך הבקרה. הפונקציה מוסיפה את הפעולות IF ו-WHILE, שלוקחות מודלים אחרים כארגומנטים ומבצעות אותם באופן מותנה (IF) או באופן חוזר (WHILE). מידע נוסף זמין במאמר תהליך הבקרה.
  • שיפור איכות השירות (QoS), כי אפליקציות יכולות לציין את העדיפות היחסית של המודלים, את משך הזמן המקסימלי הצפוי להכנת מודל ומשך הזמן המקסימלי הצפוי להשלמת הביצוע. למידע נוסף, ראו איכות השירות.
  • תמיכה בדומיינים של זיכרון שמספקים ממשקי הקצאה למאגרי נתונים זמניים בניהול הנהג. כך ניתן להעביר זיכרונות נייטיב של המכשיר בין הפעלות שונות, וכך למנוע העתקה וטרנספורמציה מיותרת של נתונים בין הפעלות רצופות לאותו מנהל התקן. למידע נוסף, ראו דומיינים של זיכרון.

10 Android

ב-Android 10 אנחנו משיקים את NN HAL 1.2, שכולל את השינויים החשובים הבאים.

  • המבנה Capabilities כולל את כל סוגי הנתונים, כולל סוגי נתונים סקלריים, ומייצג ביצועים לא קשורים באמצעות וקטור במקום שדות עם שם.
  • ה-methods getVersionString ו-getType מאפשרות ל-framework לאחזר את סוג המכשיר (DeviceType) ואת פרטי הגרסה. למידע נוסף, ראו גילוי והקצאה של מכשירים.
  • ה-method executeSynchronously נקראת כברירת מחדל כדי לבצע הרצה באופן סינכרוני. ה-method execute_1_2 מנחה את ה-framework לבצע הפעלה באופן אסינכרוני. פרטים נוספים מופיעים בקטע ביצוע.
  • הפרמטר MeasureTiming ל-executeSynchronously, execute_1_2, וביצוע רצף מציין אם מנהל ההתקן צריך למדוד את משך הביצוע. התוצאות מדווחות במבנה Timing. למידע נוסף, ראו תזמון.
  • תמיכה בפעולות שבהן אופרנד אחד או יותר של פלט הוא בעל מאפיין או דירוג לא ידועים. ראו צורת פלט.
  • תמיכה בתוספי ספקים, שהם אוספים של פעולות וסוגי נתונים שהוגדרו על ידי הספק. הנהג מדווח על תוספים נתמכים באמצעות השיטה IDevice::getSupportedExtensions. למידע נוסף, ראו תוספי ספקים.
  • יכולת של אובייקט ברצף (bursts) כדי לשלוט על סדרת ביצוע רצפים באמצעות תורי הודעות מהירים (FMQ) לתקשורת בין תהליכים של אפליקציה ומנהל התקן, וכך לצמצם את זמן האחזור. ראו פעולות של רצף הודעות ותורים מהירים של הודעות.
  • תמיכה ב-AHardwareBuffer כדי לאפשר לנהג לבצע פעולות בלי להעתיק נתונים. ראו AHardwareBuffer.
  • תמיכה משופרת בשמירה במטמון של ארטיפקטים של הידור (compilation) כדי לקצר את משך הזמן שמשמש להידור כשהאפליקציה מופעלת. למידע נוסף, ראו שמירה במטמון של הידור במטמון.

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

  • סוגי אופציות

    • ANEURALNETWORKS_BOOL
    • ANEURALNETWORKS_FLOAT16
    • ANEURALNETWORKS_TENSOR_BOOL8
    • ANEURALNETWORKS_TENSOR_FLOAT16
    • ANEURALNETWORKS_TENSOR_QUANT16_ASYMM
    • ANEURALNETWORKS_TENSOR_QUANT16_SYMM
    • ANEURALNETWORKS_TENSOR_QUANT8_SYMM
    • ANEURALNETWORKS_TENSOR_QUANT8_SYMM_PER_CHANNEL
  • פעולות

    • ANEURALNETWORKS_ABS
    • ANEURALNETWORKS_ARGMAX
    • ANEURALNETWORKS_ARGMIN
    • ANEURALNETWORKS_AXIS_ALIGNED_BBOX_TRANSFORM
    • ANEURALNETWORKS_BIDIRECTIONAL_SEQUENCE_LSTM
    • ANEURALNETWORKS_BIDIRECTIONAL_SEQUENCE_RNN
    • ANEURALNETWORKS_BOX_WITH_NMS_LIMIT
    • ANEURALNETWORKS_CAST
    • ANEURALNETWORKS_CHANNEL_SHUFFLE
    • ANEURALNETWORKS_DETECTION_POSTPROCESSING
    • ANEURALNETWORKS_EQUAL
    • ANEURALNETWORKS_EXP
    • ANEURALNETWORKS_EXPAND_DIMS
    • ANEURALNETWORKS_GATHER
    • ANEURALNETWORKS_GENERATE_PROPOSALS
    • ANEURALNETWORKS_GREATER
    • ANEURALNETWORKS_GREATER_EQUAL
    • ANEURALNETWORKS_GROUPED_CONV_2D
    • ANEURALNETWORKS_HEATMAP_MAX_KEYPOINT
    • ANEURALNETWORKS_INSTANCE_NORMALIZATION
    • ANEURALNETWORKS_LESS
    • ANEURALNETWORKS_LESS_EQUAL
    • ANEURALNETWORKS_LOG
    • ANEURALNETWORKS_LOGICAL_AND
    • ANEURALNETWORKS_LOGICAL_NOT
    • ANEURALNETWORKS_LOGICAL_OR
    • ANEURALNETWORKS_LOG_SOFTMAX
    • ANEURALNETWORKS_MAXIMUM
    • ANEURALNETWORKS_MINIMUM
    • ANEURALNETWORKS_NEG
    • ANEURALNETWORKS_NOT_EQUAL
    • ANEURALNETWORKS_PAD_V2
    • ANEURALNETWORKS_POW
    • ANEURALNETWORKS_PRELU
    • ANEURALNETWORKS_QUANTIZE
    • ANEURALNETWORKS_QUANTIZED_16BIT_LSTM
    • ANEURALNETWORKS_RANDOM_MULTINOMIAL
    • ANEURALNETWORKS_REDUCE_ALL
    • ANEURALNETWORKS_REDUCE_ANY
    • ANEURALNETWORKS_REDUCE_MAX
    • ANEURALNETWORKS_REDUCE_MIN
    • ANEURALNETWORKS_REDUCE_PROD
    • ANEURALNETWORKS_REDUCE_SUM
    • ANEURALNETWORKS_RESIZE_NEAREST_NEIGHBOR
    • ANEURALNETWORKS_ROI_ALIGN
    • ANEURALNETWORKS_ROI_POOLING
    • ANEURALNETWORKS_RSQRT
    • ANEURALNETWORKS_SELECT
    • ANEURALNETWORKS_SIN
    • ANEURALNETWORKS_SLICE
    • ANEURALNETWORKS_SPLIT
    • ANEURALNETWORKS_SQRT
    • ANEURALNETWORKS_TILE
    • ANEURALNETWORKS_TOPK_V2
    • ANEURALNETWORKS_TRANSPOSE_CONV_2D
    • ANEURALNETWORKS_UNIDIRECTIONAL_SEQUENCE_LSTM
    • ANEURALNETWORKS_UNIDIRECTIONAL_SEQUENCE_RNN

ב-Android 10 מופיעים עדכונים לרבות מהפעולות הקיימות. העדכונים קשורים בעיקר לנושאים הבאים:

  • תמיכה בפריסת הזיכרון של NCHW
  • תמיכה בטנזטורים עם דירוג שונה מ-4 בפעולות של Softmax ונירמול
  • תמיכה בקיפולים מורחבים
  • תמיכה בקלט עם קוונטיזציה מעורבת ב-ANEURALNETWORKS_CONCATENATION

ברשימה הבאה מוצגות הפעולות ששונו ב-Android 10. לפרטים מלאים על השינויים, ראו OperationCode במשאבי העזרה של NNAPI.

  • ANEURALNETWORKS_ADD
  • ANEURALNETWORKS_AVERAGE_POOL_2D
  • ANEURALNETWORKS_BATCH_TO_SPACE_ND
  • ANEURALNETWORKS_CONCATENATION
  • ANEURALNETWORKS_CONV_2D
  • ANEURALNETWORKS_DEPTHWISE_CONV_2D
  • ANEURALNETWORKS_DEPTH_TO_SPACE
  • ANEURALNETWORKS_DEQUANTIZE
  • ANEURALNETWORKS_DIV
  • ANEURALNETWORKS_FLOOR
  • ANEURALNETWORKS_FULLY_CONNECTED
  • ANEURALNETWORKS_L2_NORMALIZATION
  • ANEURALNETWORKS_L2_POOL_2D
  • ANEURALNETWORKS_LOCAL_RESPONSE_NORMALIZATION
  • ANEURALNETWORKS_LOGISTIC
  • ANEURALNETWORKS_LSH_PROJECTION
  • ANEURALNETWORKS_LSTM
  • ANEURALNETWORKS_MAX_POOL_2D
  • ANEURALNETWORKS_MEAN
  • ANEURALNETWORKS_MUL
  • ANEURALNETWORKS_PAD
  • ANEURALNETWORKS_RELU
  • ANEURALNETWORKS_RELU1
  • ANEURALNETWORKS_RELU6
  • ANEURALNETWORKS_RESHAPE
  • ANEURALNETWORKS_RESIZE_BILINEAR
  • ANEURALNETWORKS_RNN
  • ANEURALNETWORKS_ROI_ALIGN
  • ANEURALNETWORKS_SOFTMAX
  • ANEURALNETWORKS_SPACE_TO_BATCH_ND
  • ANEURALNETWORKS_SPACE_TO_DEPTH
  • ANEURALNETWORKS_SQUEEZE
  • ANEURALNETWORKS_STRIDED_SLICE
  • ANEURALNETWORKS_SUB
  • ANEURALNETWORKS_SVDF
  • ANEURALNETWORKS_TANH
  • ANEURALNETWORKS_TRANSPOSE

9 Android

NN HAL 1.1 הושק ב-Android 9 והוא כולל את השינויים הבולטים הבאים.

  • IDevice::prepareModel_1_1 כולל את הפרמטר ExecutionPreference. הנהג יכול להשתמש בנתונים האלה כדי לשנות את אופן ההכנה שלו, מתוך ידיעה שהאפליקציה מעדיפה לחסוך בצריכת הסוללה או שהיא תבצע את המודל בשיחות רצופות מהירות.
  • נוספו תשע פעולות חדשות: BATCH_TO_SPACE_ND, DIV, MEAN, PAD, SPACE_TO_BATCH_ND, SQUEEZE, STRIDED_SLICE, SUB, TRANSPOSE.
  • האפליקציה יכולה לציין שאפשר להריץ חישובים של ציפה ב-32 ביט באמצעות טווח צף (float) ו/או דיוק של 16 ביט, על ידי הגדרת הערך Model.relaxComputationFloat32toFloat16 ל-true. המבנה Capabilities כולל את השדה הנוסף relaxedFloat32toFloat16Performance, כדי שהנהג יוכל לדווח ל-framework על הביצועים הרגועים שלו.

Android מגרסה 8.1

הגרסה הראשונית של Neural Networks HAL (1.0) הושקה ב-Android 8.1. למידע נוסף: /neuralnetworks/1.0/.