החל מ-Android 10, Neural Networks API (NNAPI) מספק פונקציות שתומכות בשמירת פריטים של הידור במטמון, וכך מפחית את משך הזמן הנדרש לצורך הידור כשאפליקציה מופעלת. בעזרת פונקציונליות האחסון במטמון, הנהג לא צריך לנהל או לנקות את הקבצים ששמורים במטמון. זוהי תכונה אופציונלית שאפשר להטמיע באמצעות NN HAL 1.2. למידע נוסף על הפונקציה הזו, ראו ANeuralNetworksCompilation_setCaching
.
הנהג יכול גם להטמיע מטמון של הידור בנפרד מ-NNAPI. אפשר להטמיע את זה גם אם משתמשים בתכונות NNAPI NDK ו-HAL לשמירה במטמון. AOSP מספקת ספריית שירותים ברמה נמוכה (מנוע אחסון במטמון). מידע נוסף זמין במאמר הטמעת מנוע שמירה במטמון.
סקירה כללית של תהליך העבודה
בקטע הזה מתוארים תהליכי עבודה כלליים שמוטמעת בהם תכונת השמירה במטמון של הידור.
מידע שסופק מהמטמון והצלחה במטמון
- האפליקציה מעבירה ספריית מטמון ותוצאת סיכום ייחודית למודל.
- סביבת זמן הריצה של NNAPI מחפשת את קובצי המטמון על סמך סיכום הביקורות, העדפת הביצוע והתוצאה של חלוקת המחיצות, ומוצאת את הקבצים.
- NNAPI פותח את קובצי המטמון ומעביר את הלחצנים לנהג באמצעות
prepareModelFromCache
. - הנהג מכין את המודל ישירות מקובצי המטמון ומחזיר את המודל המוכן.
סופקו מידע על המטמון וחסר מידע על המטמון
- האפליקציה מעבירה סיכום ביקורת (checksum) ייחודי למודל ספרייה של מטמון.
- סביבת זמן הריצה של NNAPI מחפשת את קובצי המטמון על סמך סיכום הביקורות, העדפת הביצוע והתוצאה של חלוקת המחיצות, ולא מוצאת את קובצי המטמון.
- NNAPI יוצר קבצי מטמון ריקים על סמך סיכום הביקורת, העדפת הביצוע והחלוקה, פותח את קבצי המטמון ומעביר את ה-handles והמודל לנהג באמצעות
prepareModel_1_2
. - מנהל ההתקן מרכיב את המודל, כותב מידע ששומר במטמון לקובצי המטמון, ומחזיר את המודל שהוכן.
לא סופקו פרטי מטמון
- האפליקציה מפעילה אוסף בלי לספק מידע על שמירה במטמון.
- האפליקציה לא מעבירה שום דבר שקשור לאחסון במטמון.
- סביבת זמן הריצה של NNAPI מעבירה את המודל לנהג באמצעות
prepareModel_1_2
. - מנהל ההתקן אוסף את המודל ומחזיר את המודל שהוכן.
פרטי המטמון
מידע השמירה במטמון שמסופק לנהג מורכב מאסימון ומנקודות אחיזה של קובצי מטמון.
אסימון
האסימון הוא אסימון לשמירה במטמון של Constant::BYTE_SIZE_OF_CACHE_TOKEN
שמזהה את המודל המוכן. אותו אסימון מסופק כששומרים את קובצי המטמון באמצעות prepareModel_1_2
ומאחזרים את המודל המוכן באמצעות prepareModelFromCache
. הלקוח של הנהג צריך לבחור אסימון עם שיעור התנגשויות נמוך. הנהג לא יכול לזהות התנגשות אסימונים. התנגשות מובילה להפעלה שנכשלה או לביצוע מוצלח שמובילה לערכי פלט שגויים.
נקודות אחיזה לקבצים של המטמון (שני סוגים של קובצי מטמון)
שני הסוגים של קובצי מטמון הם מטמון הנתונים ומטמון של המודל.
- מטמון נתונים: משמש לשמירת נתונים קבועים במטמון, כולל מאגרי טינסורים שעברו עיבוד מראש וטרנספורמציה. שינוי במטמון הנתונים לא אמור לגרום לתוצאה גרועה יותר מיצירת ערכים שגויים של פלט בזמן הביצוע.
- מטמון מודל: שמירה במטמון של מידע רגיש מבחינת אבטחה, כמו קוד של מכונה להרצה בפורמט הבינארי המקורי של המכשיר. שינוי במטמון המודל עלול להשפיע על התנהגות הביצוע של הנהג, ולקוח זדוני יכול להשתמש בכך כדי לבצע פעולות מעבר להרשאה שניתנה. לכן, הנהג צריך לבדוק אם המטמון של המודל פגום לפני הכנת המודל מהמטמון. למידע נוסף, קראו את המאמר אבטחה.
מנהל ההתקן צריך להחליט איך להפיץ את המידע במטמון בין שני הסוגים של קובצי המטמון, ולדווח על מספר הקבצים במטמון שצריך בכל סוג באמצעות getNumberOfCacheFilesNeeded
.
סביבת זמן הריצה של NNAPI תמיד פותחת את הרשאות הטיפול בקובצי המטמון עם הרשאות קריאה וכתיבה.
אבטחה
כששומרים אוסף של הידור במטמון, מטמון המודל עשוי להכיל מידע רגיש מבחינת אבטחה, כמו קוד מכונה להפעלה שעבר הידור בפורמט הבינארי המקורי של המכשיר. אם הנהג לא מוגן כראוי, שינוי במטמון של המודל עשוי להשפיע על התנהגות ההפעלה של הנהג. מכיוון שתוכן המטמון מאוחסן בספריית האפליקציה, הלקוח יכול לשנות את קובצי המטמון. לקוח עם באגים עלול לפגוע בטעות במטמון, ולקוח זדוני עלול לנצל זאת בכוונה כדי להריץ קוד לא מאומת במכשיר. בהתאם למאפיינים של המכשיר, ייתכן שמדובר בבעיית אבטחה. לכן, לנהג צריכה להיות אפשרות לזהות פגיעה אפשרית במטמון של המודל לפני שהוא מכין את המודל מהמטמון.
דרך אחת לעשות זאת היא לשמור על מפה מהאסימון לגיבוב קריפטוגרפי של המטמון של המודל. מנהל ההתקן יכול לאחסן את האסימון ואת הגיבוב של המודל במטמון כששומרים את ההידור במטמון. כדי לאחזר את האוסף מהמטמון, מנהל ההתקן בודק את הגיבוב החדש של המטמון של המודל עם האסימון המוקלט וצמד הגיבוב. המיפוי הזה אמור להישאר קבוע גם אחרי הפעלות מחדש של המערכת. הנהג יכול להשתמש בשירות של מאגר המפתחות של Android, בספריית התשתית ב-framework/ml/nn/driver/cache
או בכל מנגנון מתאים אחר כדי להטמיע מנהל מיפויים. אחרי עדכון מנהל ההתקן, צריך לאפס מחדש את מנהל המיפוי כדי למנוע הכנה של קובצי מטמון מגרסה קודמת.
כדי למנוע התקפות time-of-check to time-of-use (TOCTOU), הנהג צריך לחשב את הגיבוב המוקלט לפני השמירה בקובץ, ולחשב את הגיבוב החדש אחרי העתקת תוכן הקובץ למאגר פנימי.
הקוד לדוגמה הזה מראה איך ליישם את הלוגיקה הזו.
bool saveToCache(const sp<V1_2::IPreparedModel> preparedModel,
const hidl_vec<hidl_handle>& modelFds, const hidl_vec<hidl_handle>& dataFds,
const HidlToken& token) {
// Serialize the prepared model to internal buffers.
auto buffers = serialize(preparedModel);
// This implementation detail is important: the cache hash must be computed from internal
// buffers instead of cache files to prevent time-of-check to time-of-use (TOCTOU) attacks.
auto hash = computeHash(buffers);
// Store the {token, hash} pair to a mapping manager that is persistent across reboots.
CacheManager::get()->store(token, hash);
// Write the cache contents from internal buffers to cache files.
return writeToFds(buffers, modelFds, dataFds);
}
sp<V1_2::IPreparedModel> prepareFromCache(const hidl_vec<hidl_handle>& modelFds,
const hidl_vec<hidl_handle>& dataFds,
const HidlToken& token) {
// Copy the cache contents from cache files to internal buffers.
auto buffers = readFromFds(modelFds, dataFds);
// This implementation detail is important: the cache hash must be computed from internal
// buffers instead of cache files to prevent time-of-check to time-of-use (TOCTOU) attacks.
auto hash = computeHash(buffers);
// Validate the {token, hash} pair by a mapping manager that is persistent across reboots.
if (CacheManager::get()->validate(token, hash)) {
// Retrieve the prepared model from internal buffers.
return deserialize<V1_2::IPreparedModel>(buffers);
} else {
return nullptr;
}
}
תרחישים מתקדמים לדוגמה
בתרחישים מתקדמים לדוגמה, נהג/ת זקוקה לגישה לתוכן שנשמר במטמון (קריאה או כתיבה) אחרי שיחת האוסף. תרחישים לדוגמה:
- הדרכה בזמן אמת: ההדרכה מתעכבת עד לביצוע הראשון.
- הדרכה בכמה שלבים: בהתחלה מתבצעת הידור מהיר, ולאחר מכן מתבצעת הידור מותאם אישית (אופטימיזציה) בהתאם לתדירות השימוש.
כדי לגשת לתוכן המטמון (לקריאה או לכתיבה) אחרי קריאת ה-compilation, צריך לוודא שהדרייבר:
- השירות מעתיק את הכינויים של הקובץ במהלך ההפעלה של
prepareModel_1_2
אוprepareModelFromCache
וקורא/מעדכן את תוכן המטמון במועד מאוחר יותר. - הטמעת לוגיקה של נעילת קבצים מחוץ לקריאה הרגילה של הידור, כדי למנוע כתיבת בו-זמנית עם קריאה או כתיבת אחרת.
הטמעת מנוע שמירה במטמון
בנוסף לממשק של NN HAL 1.2 ל-compilation caching, תוכלו למצוא גם ספריית שירותי אחסון במטמון בתיקייה frameworks/ml/nn/driver/cache
. ספריית המשנה nnCache
מכילה קוד אחסון מתמיד שמאפשר לנהג להטמיע מטמון של הידור בלי להשתמש בתכונות המטמון של NNAPI. אפשר להטמיע את סוג המטמון הזה של הידור בכל גרסה של NN HAL. אם הנהג בוחר להטמיע שמירה במטמון המנותק מממשק HAL, הנהג אחראי לשחרר ארטיפקטים שנשמרו במטמון כשאין בהם יותר צורך.