בדף הזה מוסבר איך מטמיעים מנהל התקן של Neural Networks API (NNAPI). פרטים נוספים זמינים במסמכי התיעוד בקובצי ההגדרה של HAL ב-hardware/interfaces/neuralnetworks
.
דוגמה להטמעה של מנהל התקן מופיעה בכתובת frameworks/ml/nn/driver/sample
.
מידע נוסף על Neural Networks API זמין במאמר Neural Networks API.
Neural Networks HAL
שכבת ההפשטה של חומרה (HAL) של רשתות עצביות (NN) מגדירה הפשטה של מכשירים שונים, כמו יחידות לעיבוד גרפי (GPU) ומעבדי אותות דיגיטליים (DSP), שנמצאים במוצר (לדוגמה, טלפון או טאבלט). מנהלי ההתקנים של המכשירים האלה צריכים להיות תואמים ל-NN HAL. הממשק מוגדר בקובצי ההגדרה של HAL ב-hardware/interfaces/neuralnetworks
.
התרשים הכללי של הממשק בין המסגרת לבין מנהל ההתקן מוצג באיור 1.
איור 1. זרימת רשתות נוירונים
אתחול
באתחול, המסגרת שולחת שאילתה לדרייבר לגבי היכולות שלו באמצעות IDevice::getCapabilities_1_3
.
המבנה @1.3::Capabilities
כולל את כל סוגי הנתונים ומייצג ביצועים לא משופרים באמצעות וקטור.
כדי לקבוע איך להקצות חישובים למכשירים הזמינים, המסגרת משתמשת ביכולות כדי להבין כמה מהר ועם כמה יעילות אנרגטית כל מנהל התקן יכול לבצע הרצה. כדי לספק את המידע הזה, הנהג צריך לספק מספרי ביצועים סטנדרטיים על סמך הביצוע של עומסי עבודה של הפניה.
כדי לקבוע את הערכים שהדרייבר מחזיר בתגובה ל-IDevice::getCapabilities_1_3
, משתמשים באפליקציית ההשוואה של NNAPI כדי למדוד את הביצועים עבור סוגי הנתונים המתאימים. מומלץ להשתמש במודלים MobileNet v1 ו-v2, asr_float
ו-tts_float
כדי למדוד את הביצועים של ערכי נקודה צפה של 32 ביט, ובמודלים MobileNet v1 ו-v2 quantized כדי למדוד את הביצועים של ערכים כמותיים של 8 ביט. מידע נוסף זמין במאמר בנושא חבילת בדיקות ללמידת מכונה ב-Android.
ב-Android מגרסה 9 ומטה, המבנה של Capabilities
כולל מידע על ביצועי הדרייבר רק עבור טנסורים של נקודה צפה וטנסורים כמותיים, ולא כולל סוגי נתונים סקלריים.
במסגרת תהליך האתחול, יכול להיות שהמסגרת תבצע שאילתה כדי לקבל מידע נוסף, באמצעות IDevice::getType
, IDevice::getVersionString
, IDevice:getSupportedExtensions
ו-IDevice::getNumberOfCacheFilesNeeded
.
בין הפעלות מחדש של המוצר, המסגרת מצפה שכל השאילתות שמתוארות בקטע הזה ידווחו תמיד על אותם ערכים עבור מנהל התקן נתון. אחרת, יכול להיות שהביצועים של אפליקציה שמשתמשת במנהל ההתקן הזה יהיו נמוכים יותר או שההתנהגות שלה תהיה שגויה.
קומפילציה
המסגרת קובעת באילו מכשירים להשתמש כשהיא מקבלת בקשה מאפליקציה. ב-Android 10, אפליקציות יכולות לגלות ולציין את המכשירים שהמסגרת בוחרת מתוכם. מידע נוסף זמין במאמר בנושא גילוי מכשירים והקצאתם.
בזמן הידור המודל, המסגרת שולחת את המודל לכל מנהל התקן מועמד על ידי קריאה ל-IDevice::getSupportedOperations_1_3
.
כל מנהל התקן מחזיר מערך של ערכים בוליאניים שמציינים אילו פעולות של המודל נתמכות. יכולות להיות כמה סיבות לכך שמנהל התקן לא יכול לתמוך בפעולה מסוימת. לדוגמה:
- מנהל ההתקן לא תומך בסוג הנתונים.
- הדרייבר תומך רק בפעולות עם פרמטרים ספציפיים של קלט. לדוגמה, יכול להיות שדרייבר יתמוך בפעולות קונבולוציה של 3x3 ו-5x5, אבל לא של 7x7.
- לדרייבר יש מגבלות זיכרון שמונעות ממנו לטפל בגרפים או בקלטים גדולים.
במהלך הקומפילציה, יכול להיות שלאופרנדים הפנימיים, של הקלט ושל הפלט של המודל, כפי שמתואר במאמר OperandLifeTime
, לא יהיו מימדים או דרגה ידועים. מידע נוסף זמין במאמר בנושא צורת הפלט.
המסגרת מורה לכל אחד מהדרייברים שנבחרו להתכונן להפעלת קבוצת משנה של המודל על ידי קריאה ל-IDevice::prepareModel_1_3
.
כל נהג מרכיב את קבוצת המשנה שלו. לדוגמה, יכול להיות שדרייבר ייצור קוד או ייצור עותק של המשקלים עם שינוי בסדר. יכול להיות שיעבור הרבה זמן בין ההידור של המודל לבין הביצוע של הבקשות, ולכן לא כדאי להקצות משאבים כמו נתחים גדולים של זיכרון המכשיר במהלך ההידור.
אם הפעולה בוצעה בהצלחה, מוחזר מנהל התקן @1.3::IPreparedModel
handle. אם מנהל ההתקן מחזיר קוד שגיאה כשמכינים את קבוצת המשנה של המודל, המסגרת מריצה את המודל כולו ב-CPU.
כדי לקצר את הזמן שנדרש לקומפילציה כשאפליקציה מופעלת, מנהל התקן יכול לשמור במטמון את תוצרי הקומפילציה. מידע נוסף זמין במאמר בנושא שמירה במטמון של קומפילציה.
ביצוע
כשאפליקציה מבקשת מהמסגרת לבצע בקשה, המסגרת קוראת ל-method של HAL IPreparedModel::executeSynchronously_1_3
כברירת מחדל כדי לבצע הפעלה סינכרונית במודל מוכן.
אפשר גם להפעיל בקשה באופן אסינכרוני באמצעות השיטה execute_1_3
, השיטה executeFenced
(ראו ביצוע מוגבל) או באמצעות ביצוע מהיר.
קריאות להפעלה סינכרונית משפרות את הביצועים ומצמצמות את התקורה של השרשור בהשוואה לקריאות אסינכרוניות, כי השליטה מוחזרת לתהליך האפליקציה רק אחרי שההפעלה מסתיימת. המשמעות היא שהדרייבר לא צריך מנגנון נפרד כדי להודיע לתהליך האפליקציה שההפעלה הושלמה.
בשיטה האסינכרונית execute_1_3
, השליטה חוזרת לתהליך האפליקציה אחרי שההפעלה מתחילה, והדרייבר צריך להודיע למסגרת מתי ההפעלה מסתיימת, באמצעות @1.3::IExecutionCallback
.
הפרמטר Request
שמועבר לשיטת ההפעלה מציג את האופרנדים של הקלט והפלט שמשמשים להפעלה. הזיכרון שבו מאוחסנים נתוני האופרנד חייב להיות מסודר לפי סדר השורות, כשהמימד הראשון חוזר על עצמו הכי לאט, ולא יכול להיות ריפוד בסוף אף שורה. מידע נוסף על סוגי אופרנדים זמין במאמר אופרנדים.
בדרייברים של NN HAL בגרסה 1.2 ומעלה, כשבקשה מסתיימת, סטטוס השגיאה, צורת הפלט ופרטי התזמון מוחזרים למסגרת. במהלך ההפעלה, יכול להיות שלפלט או לאופרנדים פנימיים של המודל יש מימד לא ידוע אחד או יותר או דרגה לא ידועה. אם לפחות לאחד מאופרנדי הפלט יש דרגה או מאפיין לא ידועים, מנהל התקן צריך להחזיר מידע על פלט בגודל דינמי.
במנהלי התקנים עם NN HAL בגרסה 1.1 ומטה, רק סטטוס השגיאה מוחזר כשבקשה מסתיימת. כדי שהביצוע יושלם בהצלחה, צריך לציין באופן מלא את המאפיינים של אופרנדים של קלט ופלט. לאופרנדים פנימיים יכולים להיות מימד אחד או יותר לא ידועים, אבל צריך לציין את הדרגה שלהם.
בבקשות משתמש שכוללות כמה דרייברים, המסגרת אחראית להקצאת זיכרון ביניים ולסדר את הקריאות לכל דרייבר.
אפשר להפעיל כמה בקשות במקביל באותו @1.3::IPreparedModel
.
הנהג יכול לבצע בקשות במקביל או לבצע את הבקשות ברצף.
המסגרת יכולה לבקש ממנהל ההתקן לשמור יותר ממודל מוכן אחד. לדוגמה, הכנת מודל m1
, הכנת m2
, ביצוע בקשה r1
ב-m1
, ביצוע r2
ב-m2
, ביצוע r3
ב-m1
, ביצוע r4
ב-m2
, שחרור (כפי שמתואר בניקוי) m1
ושחרור m2
.
כדי למנוע ביצוע ראשון איטי שעלול לגרום לחוויית משתמש גרועה (לדוגמה, גמגום של הפריים הראשון), מומלץ שהדרייבר יבצע את רוב ההפעלות הראשוניות בשלב הקומפילציה. ההפעלה הראשונית צריכה להיות מוגבלת לפעולות שמשפיעות לרעה על תקינות המערכת אם הן מתבצעות מוקדם מדי, כמו הקצאת מאגרי נתונים זמניים גדולים או הגדלת קצב השעון של מכשיר. יכול להיות שיהיה צורך להפעיל אתחול של דרייברים שיכולים להכין רק מספר מוגבל של מודלים בו-זמנית, בפעם הראשונה שהם מופעלים.
ב-Android 10 ומעלה, במקרים שבהם מבוצעות כמה פעולות עם אותו מודל מוכן ברצף מהיר, הלקוח יכול לבחור להשתמש באובייקט של פרץ ביצוע כדי לתקשר בין תהליכי האפליקציה והדרייבר. מידע נוסף זמין במאמר הפעלות של פרצי תנועה ותורים מהירים של הודעות.
כדי לשפר את הביצועים של כמה הפעלות ברצף מהיר, מנהל ההתקן יכול להשתמש במאגרי נתונים זמניים או להגדיל את קצב השעון. מומלץ ליצור שרשור של כלב שמירה כדי לשחרר משאבים אם לא נוצרות בקשות חדשות אחרי פרק זמן קבוע.
צורת הפלט
בבקשות שבהן לא צוינו כל המימדים של אופרנד פלט אחד או יותר, מנהל ההתקן צריך לספק רשימה של צורות פלט שמכילה את פרטי המימדים של כל אופרנד פלט אחרי ההרצה. מידע נוסף על מאפיינים זמין במאמר 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
זמין במאמר מסגרת סנכרון.
בהרצה מוגבלת, המסגרת קוראת לשיטה IPreparedModel::executeFenced
כדי להפעיל הרצה מוגבלת ואסינכרונית במודל מוכן עם וקטור של גדרות סנכרון להמתנה. אם המשימה האסינכרונית מסתיימת לפני שהקריאה מחזירה ערך, אפשר להחזיר מצביע ריק עבור sync_fence
. כדי שהמסגרת תוכל לשלוח שאילתות לגבי סטטוס השגיאה ומשך הזמן, צריך להחזיר גם אובייקט IFencedExecutionCallback
.
אחרי השלמת ההרצה, אפשר לשלוח שאילתה דרך IFencedExecutionCallback::getExecutionInfo
כדי לקבל את שני ערכי התזמון הבאים שמודדים את משך ההרצה:
-
timingLaunched
: משך הזמן שחלף מהרגע שבו מתבצעת קריאה ל-executeFenced
ועד שהפונקציהexecuteFenced
מסמנת את הערךsyncFence
שמוחזר. -
timingFenced
: משך הזמן שחלף מהרגע שבו כל מחסומי הסנכרון שהביצוע ממתין להם מסומנים, ועד שהפונקציהexecuteFenced
מסמנת את הערךsyncFence
שמוחזר.
בקרת זרימה
במכשירים עם Android מגרסה 11 ואילך, ה-NNAPI כולל שתי פעולות של זרימת בקרה, IF
ו-WHILE
, שמקבלות מודלים אחרים כארגומנטים ומבצעות אותם באופן מותנה (IF
) או חוזר (WHILE
). למידע נוסף על אופן ההטמעה, אפשר לעיין במאמר בנושא זרימת בקרה.
איכות השירות
ב-Android 11, NNAPI כולל שיפור באיכות השירות (QoS) בכך שהוא מאפשר לאפליקציה לציין את העדיפויות היחסיות של המודלים שלה, את משך הזמן המקסימלי שצפוי להכנת מודל ואת משך הזמן המקסימלי שצפוי להשלמת ביצוע. מידע נוסף זמין במאמר בנושא איכות השירות.
ניקוי
כשאפליקציה מסיימת להשתמש במודל מוכן, המסגרת משחררת את ההפניה שלה לאובייקט @1.3::IPreparedModel
. כשאין יותר הפניה לאובייקט IPreparedModel
, הוא נהרס אוטומטית בשירות של מנהל ההתקן שיצר אותו. אפשר לשחרר משאבים ספציפיים למודל בשלב הזה בהטמעה של ה-destructor של הדרייבר. אם שירות ה-driver רוצה שהאובייקט IPreparedModel
ייהרס באופן אוטומטי כשאין בו יותר צורך אצל הלקוח, הוא לא יכול להחזיק הפניות לאובייקט IPreparedModel
אחרי שהאובייקט IPreparedeModel
הוחזר דרך IPreparedModelCallback::notify_1_3
.
שימוש במעבד
מנהלי התקנים אמורים להשתמש במעבד כדי להגדיר חישובים. אסור לנהגים להשתמש במעבד כדי לבצע חישובים של תרשימים, כי זה משבש את היכולת של המסגרת להקצות עבודה בצורה נכונה. הדרייבר צריך לדווח למסגרת על החלקים שהוא לא יכול לטפל בהם, ולאפשר למסגרת לטפל בשאר.
המסגרת מספקת הטמעה של CPU לכל הפעולות של NNAPI, למעט פעולות שמוגדרות על ידי הספק. מידע נוסף זמין במאמר תוספים של ספקים.
לפעולות שהוצגו ב-Android 10 (רמת API 29) יש רק הטמעה של CPU להפניה, כדי לוודא שהבדיקות של CTS ו-VTS נכונות. ההטמעות שעברו אופטימיזציה ונכללות במסגרות של למידת מכונה בנייד עדיפות על פני ההטמעה של NNAPI CPU.
פונקציות בסיסיות
בבסיס הקוד של NNAPI יש פונקציות עזר שאפשר להשתמש בהן בשירותי מנהלי התקנים.
הקובץ
frameworks/ml/nn/common/include/Utils.h
מכיל פונקציות שונות של כלי עזר, כמו אלה שמשמשות לרישום ביומן ולביצוע המרה בין גרסאות שונות של NN HAL.
VLogging:
VLOG
היא פקודת מאקרו עוטפת של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 שכלולות במסגרת Android. ב-VTS, ההפעלה של הדרייברים מתבצעת ישירות (בלי להשתמש במסגרת), ואילו ב-CTS, ההפעלה מתבצעת בעקיפין דרך המסגרת. הבדיקות האלה בודקות כל method ב-API ומוודאות שכל הפעולות שנתמכות על ידי הדרייברים פועלות בצורה תקינה ומספקות תוצאות שעומדות בדרישות הדיוק.
הדרישות בנוגע לדיוק ב-CTS וב-VTS עבור NNAPI הן:
מספרים ממשיים: abs(expected - actual) <= atol + rtol * abs(expected); where:
- 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 מדווחת על שגיאה ומבצעת dump של קובץ מפרט עבור המודל שנכשל בתיקייה /data/local/tmp
לצורך ניפוי באגים.
פרטים נוספים על קריטריוני הדיוק זמינים במאמרים TestRandomGraph.cpp
וTestHarness.h
.
בדיקת Fuzz
המטרה של בדיקת fuzzing היא למצוא קריסות, טענות, הפרות של זיכרון או התנהגות כללית לא מוגדרת בקוד שנבדק, עקב גורמים כמו קלט לא צפוי. לצורך בדיקת fuzzing של NNAPI, מערכת Android משתמשת בבדיקות שמבוססות על libFuzzer. הבדיקות האלה יעילות ב-fuzzing כי הן משתמשות בכיסוי שורות של תרחישי בדיקה קודמים כדי ליצור קלטים אקראיים חדשים. לדוגמה, libFuzzer מעדיף תרחישי בדיקה שפועלים בשורות קוד חדשות. כך אפשר לקצר משמעותית את משך הזמן שנדרש לבדיקות כדי למצוא קוד בעייתי.
כדי לבצע בדיקת fuzzing לאימות ההטמעה של מנהל ההתקן, צריך לשנות את הקובץ
frameworks/ml/nn/runtime/test/android_fuzzing/DriverFuzzTest.cpp
בכלי הבדיקה libneuralnetworks_driver_fuzzer
שנמצא ב-AOSP, כך שיכלול את קוד מנהל ההתקן. מידע נוסף על בדיקת fuzzing של NNAPI זמין במאמר בנושא frameworks/ml/nn/runtime/test/android_fuzzing/README.md
.
אבטחה
מכיוון שתהליכי האפליקציה מתקשרים ישירות עם תהליך ה-Driver, ה-Drivers חייבים לאמת את הארגומנטים של הקריאות שהם מקבלים. האימות הזה מתבצע על ידי VTS. קוד האימות נמצא בהודעה frameworks/ml/nn/common/include/ValidateHal.h
.
בנוסף, מפתחים צריכים לוודא שאפליקציות לא יפריעו לפעולה של אפליקציות אחרות כשהן פועלות באותו מכשיר.
חבילת בדיקה של למידת מכונה ב-Android
חבילת הבדיקות של למידת מכונה (MLTS) ב-Android היא מדד ביצועים של NNAPI שכלול ב-CTS וב-VTS לצורך אימות הדיוק של מודלים אמיתיים במכשירי ספקים. ההשוואה בודקת את זמן האחזור ואת הדיוק, ומשווה בין התוצאות של הדרייברים לבין התוצאות של TF Lite שפועל במעבד, עבור אותו מודל ומערכי נתונים. כך מוודאים שהדיוק של ה-driver לא יהיה נמוך יותר מההטמעה לדוגמה של ה-CPU.
מפתחים בפלטפורמת Android משתמשים גם ב-MLTS כדי להעריך את זמן האחזור ואת הדיוק של הדרייברים.
המדד NNAPI מופיע בשני פרויקטים ב-AOSP:
platform/test/mlts/benchmark
(אפליקציית השוואה)-
platform/test/mlts/models
(מודלים ומערכי נתונים)
מודלים ומערכי נתונים
המדד של NNAPI מבוסס על המודלים ומערכי הנתונים הבאים.
- MobileNetV1 float ו-u8 quantized בגדלים שונים, מופעלים על קבוצת משנה קטנה (1,500 תמונות) של Open Images Dataset v4.
- MobileNetV2 float ו-u8 quantized בגדלים שונים, מופעלים על קבוצת משנה קטנה (1,500 תמונות) של Open Images Dataset v4.
- מודל אקוסטי מבוסס זיכרון לטווח קצר (LSTM) לטקסט לדיבור, שפועל על קבוצת משנה קטנה של ערכת CMU Arctic.
- מודל אקוסטי מבוסס-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:
- מחברים את מכשיר היעד לתחנת העבודה ומוודאים שאפשר להגיע אליו דרך adb.
אם מחוברים יותר ממכשיר אחד, מייצאים את משתנה הסביבה
ANDROID_SERIAL
של מכשיר היעד. 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 של רשתות נוירונים
בקטע הזה מתוארים השינויים שבוצעו בגרסאות של Android ושל Neural Networks HAL.
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
לא תומכת באופרנדים חתומים, וארבע הפעולות האחרות תומכות בקוונטיזציה חתומה אבל לא מחייבות שהתוצאות יהיו זהות. - תמיכה בהרצות מוגבלות, שבהן המסגרת קוראת לשיטה
IPreparedModel::executeFenced
כדי להפעיל הרצה מוגבלת ואסינכרונית במודל מוכן עם וקטור של גדרות סנכרון להמתנה. מידע נוסף זמין במאמר בנושא הרצה מוגבלת. - תמיכה בבקרת זרימה. נוספו הפעולות
IF
ו-WHILE
, שמקבלות מודלים אחרים כארגומנטים ומבצעות אותם באופן מותנה (IF
) או חוזר (WHILE
). מידע נוסף זמין במאמר זרימת בקרה. - איכות שירות (QoS) משופרת, כי האפליקציות יכולות לציין את העדיפויות היחסיות של המודלים שלהן, את משך הזמן המקסימלי שצפוי להכנת מודל ואת משך הזמן המקסימלי שצפוי להשלמת הביצוע. מידע נוסף מופיע במאמר בנושא איכות השירות.
- תמיכה בדומיינים של זיכרון שמספקים ממשקי הקצאה עבור מאגרי נתונים שמנוהלים על ידי מנהל ההתקן. כך אפשר להעביר זיכרונות מקוריים של מכשירים בין הפעלות, ולמנוע העתקה והמרה מיותרות של נתונים בין הפעלות עוקבות באותו מנהל התקן. מידע נוסף זמין במאמר דומיינים בזיכרון.
Android 10
Android 10 כולל את NN HAL 1.2, שכולל את השינויים הבאים:
- המבנה
Capabilities
כולל את כל סוגי הנתונים, כולל סוגי נתונים סקלריים, ומייצג ביצועים לא רגועים באמצעות וקטור ולא באמצעות שדות עם שמות. - השיטות
getVersionString
ו-getType
מאפשרות למסגרת לאחזר את סוג המכשיר (DeviceType
) ופרטי הגרסה. פרטים נוספים זמינים במאמר בנושא איתור מכשירים והקצאתם. - השיטה
executeSynchronously
מופעלת כברירת מחדל כדי לבצע הרצה באופן סינכרוני. השיטהexecute_1_2
אומרת למסגרת לבצע הרצה באופן אסינכרוני. מידע נוסף זמין במאמר בנושא ביצוע. - הפרמטר
MeasureTiming
שלexecuteSynchronously
,execute_1_2
ושל burst execution מציין אם מנהל ההתקן צריך למדוד את משך הביצוע. התוצאות מדווחות במבנהTiming
. מידע על תזמון - תמיכה בהרצות שבהן לאופרנד פלט אחד או יותר יש מימד או דרגה לא ידועים. מידע נוסף על צורת הפלט
- תמיכה בתוספים של ספקים, שהם אוספים של פעולות וסוגי נתונים שהוגדרו על ידי הספק. התוספים הנתמכים בדוחות הנהגים מועברים באמצעות השיטה
IDevice::getSupportedExtensions
. מידע נוסף על תוספים של ספקים - היכולת של אובייקט burst לשלוט בסדרה של הפעלות burst באמצעות תורים מהירים של הודעות (FMQ) כדי לתקשר בין תהליכי האפליקציה והדרייבר, וכך להפחית את זמן האחזור. מידע נוסף על ביצועים מהירים של תורים להודעות
- תמיכה ב-AHardwareBuffer כדי לאפשר למנהל ההתקן לבצע הפעלות בלי להעתיק נתונים. מידע נוסף זמין במאמר בנושא AHardwareBuffer.
- שיפרנו את התמיכה בשמירת תוצרי קומפילציה במטמון כדי לקצר את הזמן שנדרש לקומפילציה כשמפעילים אפליקציה. מידע נוסף על שמירת קומפילציות במטמון
ב-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
Android 9
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 ביט יכולים להתבצע באמצעות טווח ו/או דיוק של מספרים ממשיים 16 ביט על ידי הגדרת
Model.relaxComputationFloat32toFloat16
ל-true
. למבנהCapabilities
יש שדה נוסףrelaxedFloat32toFloat16Performance
כדי שהדרייבר יוכל לדווח על הביצועים המשופרים שלו למסגרת.
Android 8.1
הגרסה הראשונית של Neural Networks HAL (1.0) הושקה ב-Android 8.1. מידע נוסף זמין במאמר /neuralnetworks/1.0/
.