לא צריך לבחור בין הנוחות של AI מוכן לשימוש לבין הגמישות של מודל בהתאמה אישית – אפשר לפרוס את שניהם באפליקציה אחת קלה במיוחד, בלי להוסיף מגה-בייטים של קבצים בינאריים מיותרים.
בסשן הזה נדגים איך לבנות את הארכיטקטורה הכפולה הזו באפליקציה אחת ל-Android. נראה איך להשתמש ב-ML Kit למשימות קלאסיות של למידת מכונה שמוכנות לשימוש (כמו סריקת מסמכים) לצד LiteRT עצמאי ב-Play Services לעומסי עבודה מותאמים אישית של ראייה ממוחשבת או אודיו. נסביר לעומק איך שני נתיבי ההטמעה מתאחדים כדי להשתמש בסביבת זמן הריצה המודרנית של LiteRT, וכך לספק לאפליקציה ביצועים חלקים עם שיפור מהירות באמצעות חומרה במעבד (CPU) ובמעבדים גרפיים (GPU), עם נפח הורדה של כמעט אפס בייטים.
נקודות חשובות למפתחים:
-ביצועים ללא פשרות: גם מודלים מוכנים לשימוש וגם מודלים בהתאמה אישית עוברים האצת חומרה באופן אוטומטי באמצעות CompiledModel API המאוחד.
-קובצי APK קטנים: אפשר להקטין באופן משמעותי את גודל ההורדה של האפליקציה על ידי העברת סביבות זמן הריצה של ML Kit ו-LiteRT ל-Play Services.
-שילוב היברידי: לומדים איך להריץ כמה תהליכי עבודה של למידת מכונה במקביל בסביבת הייצור בלי התנגשויות בין משאבים.
play-services-litert, להפעיל את LiteRt.initialize כדי לקבל סביבה ולהעביר אותה אל CompiledModel.create.תמליל
ערב טוב לכולם.
אנחנו עומדים להתחיל את השיחה.
לכן, כשאנשים אומרים היום "AI במכשיר", הם בדרך כלל מתכוונים למודלים גדולים של שפה.
מוקדם יותר היום, ראיתם כמה הרצאות על Gemini Nano שכללו את ML Kit, Firebase והרבה מוצרים אחרים של Google.
השיעור הזה עוסק בחצי השני: למידת מכונה קלאסית והמודל שאתם מביאים בעצמכם.
סביר להניח שהשתמשתם בו כמה פעמים היום בלי לדעת.
נסו לחשוב על אפליקציות שבהן טשטשתם את הרקע, השתמשתם בסורק ברקודים או ערכתם תמונות.
הרבה מהעבודה הזו התמקדה בלמידת מכונה קלאסית, ובדרך כלל היא אפילו פועלת במכשיר.
אם הוספתם פעם אחת מהתכונות האלה לאפליקציה או ל-APK שלכם, בטח נתקלתם בדילמה הזו: האם להשתמש ב-API מוכן לשימוש, או להביא מודל משלי?
מה תהיה ההשפעה על גודל האפליקציה?
היום אתם לא צריכים לבחור בין פתרון מוכן לבין מודל משלכם.
למעשה, אפשר לעשות את שניהם באמצעות סביבת זמן ריצה אחת קלה.
קוראים לי צ'ינטן פאריק.
אני מנהל מוצר של LiteRT, ואיתי נמצא פרגוס, מנהל הנדסה של שירותי למידת מכונה ב-Android.
שלום.
בסוף תראו איך אפשר ליצור אפליקציה אחת שמריצה שני מודלים בכל פריים של מצלמה בקצב של כ-30 FPS.
אז יש ארבעה חלקים להרצאה הזו.
בחלק הראשון נדבר על פתרונות ה-AI של Google במכשיר, ונתמקד בלמידת מכונה קלאסית, כלומר ML Kit ו-LiteRT.
אחר כך נסקור את החידושים ב-LiteRT וב-Play Services.
המאמר הזה יעסוק גם ב-API החדש של CompiledModel מ-LiteRT ובמכשירים שאנחנו תומכים בהם.
שלוש, נראה לכם איך ליצור אפליקציה חדשה.
פרגוס יסביר איך לפתח אפליקציה עם ML Kit ומודל בהתאמה אישית, והכול ב-APK אחד.
ולסיום, נראה לכם איך לשדרג אפליקציה קיימת באמצעות מצב סוכן.
אתם יכולים גם ליצור אפליקציה חדשה בעזרת הסוכן הזה.
טוב.
אז קודם כול, מה זה LiteRT?
LiteRT הוא סביבת זמן הריצה של Google להסקת מסקנות במכשיר למודלים שלכם.
הוא משתמש באותו פורמט קובץ .tflite שבו השתמשתם בעבר ב-TensorFlow Lite.
הוא תוכנן מחדש כדי לשפר את הביצועים והוא תומך גם במספר מסגרות.
זה אומר שאתם יכולים לייבא מודלים מ-PyTorch, מ-TensorFlow ואפילו מ-JAX, כדי להמיר אותם לפורמט FlatBuffer ל-LiteRT.
מאז 2022, TensorFlow Lite ב-Google Play Services הוא סביבת זמן הריצה הרשמית במכשיר Android למודלים בהתאמה אישית.
היום הוא מקבל שדרוג משמעותי, ועל זה נדבר הרבה בהרצאה הזו.
השדרוג יביא את ה-API העדכני ביותר של LiteRT CompiledModel, כולל הסקת GPU משופרת חדשה שתהיה מהירה פי 1.4, וגם מאפשרת לך לבנות אפליקציות קטנות יותר בגדלים קטנים בהרבה של APK.
אז למה להעביר את זה דרך Play Services?
יש כמה יתרונות, וזו בהחלט בעיה גדולה שאני רואה בהרבה שיחות שאני שומע, שבהן גודל האפליקציה וה-APK הופכים לאתגר אמיתי, נכון?
כך שזמן הריצה קצר.
סביבת זמן הריצה לא נמצאת ב-APK, ולכן אתם מסתמכים על לקוח "רזה", מה שמקטין את ה-APK בכ-8MB.
היתרון השני הוא יעילות.
יש לכם עותק אחד של סביבת זמן הריצה, כך שסביבת זמן הריצה של LiteRT משותפת לכל האפליקציות.
אם יש לכם הרבה אפליקציות, כל אחת מהן יכולה לחסוך לכם 8MB.
הנפח הזה מצטבר מהר מאוד כשמנסים לחסוך מקום בכונן ולהשתמש באפליקציה קלה יותר.
שנית, הוא מתוחזק.
Google מספקת את תיקוני הבאגים, מטפלת בבעיות במנהלי ההתקנים של ה-GPU כדי שאתם לא תצטרכו לעשות את זה, וגם כל עדכוני האבטחה האחרים מגיעים דרך עדכונים אוטומטיים.
וכמו שציינתי, ה-GPU מהיר יותר, אז מקבלים GPU מהיר פי 1.4, וגם על זה נרחיב בהמשך.
מבחינת הכיסוי, אנחנו יכולים לשלוח למכשירי Android ישנים יותר.
LiteRT ב-Play Services תומך בגרסאות Android החל מגרסה 7 משנת 2016.
וגם, כמו שפרגוס יראה לכם, המכשירים החדשים האחרים שאנחנו מתרחבים אליהם בשקפים הבאים.
אז זהו כלי ההעברה, ובואו נדבר על השלב הבא, זמן הריצה.
לכן, LiteRT הוא לא חדש והוא לא ניסיוני.
TensorFlow Lite ו-LiteRT כבר פועלים ביותר מ-250,000 אפליקציות כיום.
היום היא פועלת גם ביותר מ-3.8 מיליארד מכשירים.
אז יכול להיות שאתם משתמשים בהרבה אפליקציות, ואתם אפילו לא יודעים שהן פועלות על בסיס זה.
וזה גם שווה ערך ליותר מטריליון הסקות בכל יום, נכון?
במסגרת הזו, נתקלנו בכל בעיה אפשרית בערכת השבבים, הצלחנו לטפל בבעיות ב-ROM או במנהל ההתקן של ה-GPU, ויש לנו פתרון עקיף בשבילכם.
Google מפעילה את LiteRT גם באפליקציות הדגל שלה, בפלטפורמות שונות ואפילו בכמה מכשירים.
אפקטים של YouTube Shorts, פילוח רקע ב-Meet, תיקון טשטוש בתמונה – אלה כמה דוגמאות למודלים של וידאו בזמן אמת ומודלים כבדים של תמונות שפועלים ב-LiteRT.
זה גם חשוב מאוד כי הפיכת תרחישי השימוש למהירים ומושכים למשתמשים הופכת לקריטית ביותר, נכון?
אז זו אותה סביבת זמן ריצה שהקשחנו בשביל התכונות המובילות האלה, וזה מה שאתם מקבלים דרך Play Services.
אז בואו נדבר גם על הסיבות להשתמש ב-AI במכשיר.
אם חשובים לכם דברים כמו זמן אחזור, פרטיות, עבודה אופליין או עלויות נמוכות, כדאי להריץ את המודל אופליין, נכון?
יכולות להיות עוד סיבות, אבל אלה כמה מהסיבות הברורות ביותר ששמענו להפעלה במכשיר.
בנוסף, הפעלה במכשיר לא תמיד בחינם.
יש כמה ניואנסים ואתגרים.
אז נדבר גם על חלק מהאתגרים האלה ועל הדרך להתמודד איתם, בסדר?
אז ביצועים: כמו שראיתם, נכון, חלק מהדוגמאות מהאפליקציות הקודמות, תקציבי זמן האחזור והזיכרון תמיד מצומצמים, נכון?
וידאו ואודיו בזמן אמת דורשים יעילות גבוהה במיוחד.
גם תכונות אינטראקטיביות פשוטות צריכות להיות מהירות.
אחרת, אתם עלולים לאבד את התעניינות המשתמשים.
מגוון חומרות: יש מאות מערכות על שבב (SoC) עם הגדרות שונות של מעבדים (CPU) ומעבדים גרפיים (GPU).
אתם לא יכולים לכתוב קוד לכל המקרים האלה, נכון?
איך פותרים את הבעיות האלה?
גודל ה-APK: הוספת סביבת זמן ריצה מקורית גם מגדילה את הקובץ להורדה, וזה יכול להשפיע על שיעורי ההמרה.
התאמה אישית: אימון המודל, האיכות וגודל המודל – כל אלה קריטיים מאוד עוד לפני הפריסה.
אז כן, פיתוח של אפליקציה מעולה במכשיר יכול להיות משימה קשה.
אבל בכל אחד מהמצבים האלה, אנחנו רוצים שהפלטפורמה תעשה את העבודה בשבילכם ולא להיפך, נכון?
מגוון המוצרים של Google שפועלים במכשיר נועד להתמודד עם האתגרים האלה, ונעבור עליהם בהמשך.
אז היום נתמקד בשני פתרונות פשוטים, נכון?
יש שתי דרכים קלות להוסיף AI במכשיר באמצעות Play Services.
מסלול 1 הוא המסלול המלא שמשתמש ב-ML Kit, נכון?
אלה ממשקי API מוכנים לשימוש לראייה ממוחשבת ולשפה, שדורשים מומחיות מוגבלת ב-ML. הם כוללים מודלים רבים וכולם מסופקים דרך Play Services.
בשקפים הבאים נציג כמה דוגמאות לכל אחד מהם.
הנתיב בהתאמה אישית, דרך LiteRT.
בעזרת LiteRT אתם יכולים להביא מודל משלכם ולהריץ אותו ב-CPU או ב-GPU.
גם סביבת זמן הריצה מגיעה מ-Play Services.
אז הוא נמצא ב-- אז אתם לא צריכים לכלול אותו ב-APK.
אפשר להשתמש בשתי השיטות.
הם גם יכולים לעבוד טוב יותר ביחד.
וזה בדיוק מה שנבנה היום בדקות הקרובות.
אבל קודם, בואו נדבר על מה ש-ML Kit כולל.
הנה מה ש-ML Kit כולל כברירת מחדל.
אז אם אתם כבר חושבים שחלק מהיכולות האלה עונות על הצרכים שלכם, זו נקודת התחלה מצוינת, וכבר יש לכם יתרון.
יש לנו כיסוי לראייה, לברקודים, למסמכים, לטקסט, לתנוחות, להרבה מהיכולות האלה, לממשקי API של שפה כמו תרגום, לתשובות חכמות ואפילו לחילוץ ישויות, נכון?
הנקודה החשובה היא שהרבה מממשקי ה-API האלה לראייה ולשפה פועלים עם LiteRT מאחורי הקלעים.
לכן, אם ML Kit מתאים לצרכים שלכם, אתם יכולים להתחיל כאן.
ואם לא, אתם יכולים להשתמש במודל משלכם.
והנה הנקודה החשובה: ML Kit והמודל בהתאמה אישית לא יהיו שתי סביבות זמן ריצה, נכון, כמו שציינתי.
אפשר לחשוב עליהם כמו שתי דלתות כניסה שמובילות לאותו LiteRT שפועל מאחורי הקלעים.
לכן, LiteRT יהיה סביבת זמן הריצה של Play שתתזמר את שתי היכולות האלה.
לכן, אם האפליקציה שלכם כבר משתמשת ב-ML Kit מחנות Play, אתם יכולים להמשיך להשתמש בה.
אחרת, נסקור גם את הנתיב של LiteRT.
אז בואו נדבר גם על מה שחדש ב-LiteRT.
כמו שציינתי, LiteRT הוא פיתוח של TensorFlow Lite, נכון?
אז השיפורים הכי גדולים הם שיש לנו GPU מהיר יותר.
ה-GPU המהיר יותר תומך ב-OpenCL וב-OpenGL, ויש לו גם תמיכה בפלטפורמות שונות, אפילו בקצוות עורפיים של Metal.
לכן, אתם בהחלט יכולים להשתמש בזה בכמה פלטפורמות לפי הצורך.
זה גם פשוט יותר.
יש לנו תהליך עבודה מאוחד אחד להאצת CPU, GPU ו-NPU.
נכון לעכשיו, CPU ו-GPU נמצאים ב-Play Services, ואילו NPU מקובץ דרך LiteRT, וזהו תהליך שנמצא כרגע בעבודה.
אז בעבר, כל מאיץ דרש הגדרת נציג שונה, נכון?
עכשיו צריך לעשות את זה רק פעם אחת.
כך שיש API אחד עם חזרה אוטומטית ל-CPU, ואין צורך להגדיר נציגים ייעודיים.
ואפשר פשוט להשתמש בקריאות למאיץ שיכולות לנהל את זה בצורה הרבה יותר פשוטה ועם פחות קוד.
הוא גם חזק, אותו מודל פועל בכמה פלטפורמות, כמו שציינתי.
הגמישות היא מרכיב קריטי.
לכן הפורמט .tflite נשאר ללא שינוי.
אם כבר יש לכם אפליקציה, אתם עדיין יכולים להשתמש בפורמט הזה.
אם אתם מפתחים אפליקציה חדשה, אתם יכולים להעביר את פורמט הקובץ הזה שוב.
עוד דבר מעניין הוא שאנחנו תומכים ב-Interpreter API, שהיה בעבר ב-TensorFlow Lite.
אם אתם רוצים להעביר את האפליקציה בשלבים, Interpreter API כלול גם ב-LiteRT החדש, כך שקל להעביר את האפליקציה.
וזה זמן הריצה.
בואו נדבר על מה שאפשר לבנות עם זה.
אלה האפליקציות ל-Android שמפתחים היום.
הכל, החל מאפקטים של מצלמה, עריכת תמונות, הקלדה חכמה, משחקים ודמויות, נכון?
הרבה מהאפליקציות האלה יצטרכו יכולות בזמן אמת.
ה-GPU שולח פריימים ישירות מהמצלמה, וחשוב שהדברים יתבצעו במהירות ובזמן אמת.
חלק מהמודלים האלה לעריכת תמונות גם הופכים לכבדים יותר.
אותו דבר לגבי יכולות ה-AR/VR שראיתם בחלק מההדגמות עם המשקפיים, הרבה מהן מריצות את LiteRT מאחורי הקלעים.
זו אותה סביבת זמן ריצה שפועלת מאחורי התכונות המובילות של Google, וגם ב-Play Services, כך שאתם מקבלים את כל זה בלי להוסיף שום דבר ל-APK.
עכשיו נבנה אפליקציה, ופרגוס יראה לנו איך.
בואו נעשה את זה.
תודה, Chintan.
אז אני אדבר קצת על מה שחדש ב-LiteRT ב-Google Play Services.
אז רגע לפני שנתחיל, עוד חדשות: כל מה שראיתם עכשיו פועל לא רק בטלפון, LiteRT ב-Play Services זמין גם ב-Wear OS וב-Android Automotive OS.
כך אפשר להפעיל מודלים במכשיר בשעון או במכשיר לביש אחר, או ברכב עצמו.
בעבר היה אפשר להשתמש באפליקציה בטלפון כאפליקציה נלווית ל-Wear, אבל עכשיו אפשר להפעיל אותה במכשיר הלביש עצמו, וגם ב-Android Automotive.
כך שיש לכם את אותו API, אותו מודל .tflite, אבל יותר פלטפורמות.
אין צורך בהטמעה נפרדת לכל גורם צורה, אפשר פשוט להשתמש באותה הטמעה לכל המכשירים השונים האלה.
היתרון של מודל ההפצה של Play Services הוא שאנחנו יכולים להסב את זה לגרסאות מוקדמות יותר כדי להריץ את זה במכשירים ישנים יותר.
לכן, ב-Android Automotive OS אנחנו תומכים בגרסאות החל מ-Android 11, שהושקה ב-2020, וב-Wear OS אנחנו תומכים בגרסאות החל מ-Wear OS 4.
אוקיי.
אז עכשיו אדבר על שני מסלולים שונים: פיתוח אפליקציה חדשה ושדרוג אפליקציה קיימת.
זה מה שנעשה בשאר השיחה.
אז נתחיל עם אפליקציה לדוגמה שמשלבת את השימוש ב-ML Kit עם מודל GPU בהתאמה אישית שפועל ב-LiteRT.
כדי לשדרג אפליקציה קיימת, צריך לבצע שלושה שינויים קטנים: שינוי ב-Gradle כדי לעדכן את יחסי התלות, שינוי ב-init כדי להפעיל את LiteRT ב-Play Services, ואז לעבור מ-Interpreter API ל-CompiledModel API.
אבל קודם נראה לך את האפליקציה החדשה, כי השדרוג יהיה הרבה יותר הגיוני אחרי שתראה למה אתה משדרג.
אז אתם מפתחים אפליקציה חדשה.
זו האפליקציה שאנחנו הולכים ליצור.
התכונה הזו מאפשרת לכם להופיע בחדות בשידור חי מהמצלמה, כשהרקע שלכם מקבל סגנון אומנותי.
אז אנחנו הולכים לקחת את הפריים של המצלמה.
אנחנו נעביר את התמונות מהפריים של המצלמה דרך פילוח תמונות הסלפי של ML Kit.
זהו אחד מממשקי ה-API המוכנים לשימוש של ML Kit.
הפעולה הזו תיצור מסכה לחזית שתציין אילו מהפיקסלים בתמונה תואמים לאדם שבתמונה.
ואז אנחנו הולכים לקחת את המודל המותאם אישית שלנו, שהוא כמו מודל מסוג העברת סגנון, הוא הולך להחיל סגנון על תמונה.
אנחנו הולכים להחיל את זה על כל הפריים של המצלמה, אבל בעצם רק החלק של הרקע מעניין אותנו, כי בסופו של דבר אנחנו הולכים לקחת את הפריים המקורי של המצלמה ואת המסכה, ואת הרקע עם הסגנון, ועם קצת לוגיקה פשוטה לשלב אותם, כך שיהיה לנו פריים מורכב שבו שמרנו על הנושא, והרקע הוא עם הסגנון.
לכן, אנחנו רוצים להשתמש בממשקי API מוכנים לשימוש כשהם קיימים, ובממשקי API בהתאמה אישית כשהם מבדילים את האפליקציה שלנו.
זה החלק הראשון שבו אנחנו מפעילים את ה-API של ML Kit לפילוח תמונות סלפי.
// 1. Configure and create segmenter client
val segmenter = Segmentation.getClient(
SelfieSegmenterOptions.Builder()
.setDetectorMode(
SelfieSegmenterOptions.STREAM_MODE)
.build())
// 2. Prepare image & run inference
fun processFrame(mediaImage: Image) {
val image = InputImage.fromMediaImage(
mediaImage, /* rotationDegrees= */ 0)
segmenter.process(image)
.addOnSuccessListener { mask -> … }
}אז זה בדיוק כמו API רגיל, נכון?
זה ממש הלחם והחמאה של מפתחי Android.
אתם יודעים, פשוט מסתכלים במסמכי התיעוד של ה-API או מבקשים מ-Gemini לבנות את זה בשבילכם.
אבל אתם יודעים, זה די פשוט.
אתם יוצרים לקוח ומעבירים כמה אפשרויות כשאתם יוצרים את הלקוח.
במקרה הזה, אנחנו מציינים מצב סטרימינג כדי שנוכל לעבד סטרימינג של פריימים של וידאו.
ואז, יש שם שיטה שנקראת process, והקריאה החוזרת (callback) ממנה תקבל את המסכה שמוחזרת, שמחושבת על ידי פילוח סלפי.
והקלט הוא התמונה מהמצלמה.
וכל ממשקי ה-API האלה משתמשים בסוגים ברמת האפליקציה, ולא בטנזורים גולמיים, כך שאתם באמת מתכנתים ברמה גבוהה מאוד וזה ממש פשוט.
בחלק השני, המודל בהתאמה אישית, נשתמש במודל PyTorch.
אני חושב שצ'ינטאן קיבל את זה מאחד הדברים כמו Kaggle או Hugging Face…
בסדר.
כן, ואפשר גם להמיר את הקבצים שלך, אתה יודע.
אתם יכולים ליצור מודל משלכם.
סליחה, אני חוזרת אחורה.
כן, אז ככה נראה סטאק התוכנות.
אתם יכולים לקחת מודל PyTorch, להמיר ולכמת אותו, ואז לקבל מודל LiteRT.
לאחר מכן, אתם מפיצים את הקובץ עם האפליקציה שלכם, איך שאתם רוצים.
אפשר לכלול אותו כחלק מהאפליקציה כנכס או להוריד אותו בנפרד.
שתי הדרכים יעבדו.
והוא נמצא מעל סביבת זמן הריצה של LiteRT ב-Play Services.
ויש גם ליבות של מעבדים (CPU) לאופטימיזציה במעבד, ו-ML Drift הוא השם של מאיץ ה-GPU.
כן, אז כמו שאמרתי, אתם מקבלים את מודל TFLite, אתם יכולים לאמן את המודל בעצמכם, למצוא מודל קיים, שתי הדרכים עובדות.
כדי להמיר מ-PyTorch, צריך רק כמה שורות של Python.
import litert_torch
model = my_models.Stylizer().eval()
# Convert with torch.export under the hood
edge_model = litert_torch.convert(
model, sample_inputs)
edge_model.export("stylizer_f32.tflite")אז אתם מתקינים את LiteRT-Torch באמצעות pip, מפעילים את litert_torch.convert, מעבירים לו sample_inputs שיכולים להיות קלטים אקראיים, ומייצאים קובץ TFLite.
אגב, אם אתם מכירים את ai-edge-torch, אז LiteRT-Torch הוא השם החדש שלו.
וגם הקוונטיזציה היא מאוד פשוטה.
# Python
# previously ai_edge_quantizer
from litert_quantizer import quantizer, recipe
qt = quantizer.Quantizer("stylizer_f32.tflite")
# int8 weights, float activations
qt.load_quantization_recipe(
recipe.dynamic_wi8_afp32())
qt.quantize().export_model("stylizer_int8.tflite")מייבאים את המכמת ואת המתכון מ-LiteRT Quantizer.
כשאתם בונים את המכמת, אתם מעבירים את מודל הנקודה הצפה המקורי, אתם מעבירים מתכון שזה המתכון הסטנדרטי שאנחנו משתמשים בו שאנחנו ממליצים עליו ל-GPU, שמשתמש במשקלים של מספרים שלמים של 8 ביט, אבל שומר על ההפעלות כנקודה צפה של 32 ביט.
ואז פשוט מפעילים את quantize ואת export_model כדי לשמור את מודל הפלט.
זה יהיה מודל מכוונן שאפשר להפעיל, והמשקלים שלו יהיו הרבה יותר קטנים והוא יפעל בצורה יעילה יותר.
אוקיי, אז כן, ה-API של CompiledModel ב-GPU הוא המקום שבו זה באמת מצטיין.
כמו שצ'ינטן ציין, יש האצה משמעותית ב-GPU מדור קודם של TFLite.
המספרים המדויקים משתנים קצת ממודל למודל, אבל אפשר לצפות לשיפור של פי 1.4.
עד פי 10 יותר מהר מהסקת מסקנות של מעבד (CPU), אז זה, אתם יודעים, היתרון הגדול, נכון?
אם אתם משתמשים במודלים היום, רובכם כנראה מריצים אותם על מעבד (CPU), ומפספסים שיפור של פי 10 בביצועים שאפשר לקבל ממעבד גרפי (GPU).
זה תמריץ אמיתי.
מה הופך אותו למהיר?
אוקיי, אז יש הרבה דברים שאנחנו תומכים בהם, למשל, ביצוע אסינכרוני כדי שתוכלו לקחת AHardwareBuffer ולהעביר אותו ישירות או מאגר OpenGL מצינור עיבוד הנתונים של רינדור המצלמה, ולהעביר אותו ישירות למאגר טנזור.
אנחנו תומכים באופטימיזציה של Zero-copy, אז בעצם כשמנסים לעבד דברים, אתם יודעים, עם תקציב של זמן אחזור נמוך, כמו כשצריך לעבד כל פריים תוך כמה עשרות אלפיות השנייה, אז אפילו רק העתקה של מאגר זיכרון יכולה להיות תקורה לא טריוויאלית.
לכן, באפליקציות שדורשות עיבוד בזמן אמת, כדאי להשתמש באופטימיזציה של אפס העתקות, ואנחנו תומכים בזה.
וכמו שצ'ינטן ציין, היא פועלת בכמה פלטפורמות ותומכת ב-OpenGL, ב-OpenCL וב-Metal, בתור הקצה העורפי של ה-GPU.
ואחרון חביב, הכלי לאופטימיזציה של ML Drift הוא בקוד פתוח.
הוא זמין במסגרת רישיון Apache.
לאחרונה Google הפכה אותו לקוד פתוח.
אוקיי, ועכשיו, הנה, הנה הקוד של האפליקציה.
// Kotlin
// Build once, off the main thread.
private val model: CompiledModel =
CompiledModel.create(
context.assets,
"stylizer_int8.tflite",
// Simple GPU setup!
CompiledModel.Options(Accelerator.GPU),
environment
)
// Reuse buffers across frames.
private val inputBuffers = model.createInputBuffers()
private val outputBuffers = model.createOutputBuffers()
fun stylize(input: FloatArray): FloatArray {
inputBuffers[0].writeFloat(input)
model.run(inputBuffers, outputBuffers) // sync
return outputBuffers[0].readFloat()
}כמו שאפשר לראות, הוא די קטן ופשוט.
כלומר, אתם יוצרים את המודל פעם אחת, ואז משתמשים בו שוב בכל פריים.
אז כאן, CompiledModel.create מעביר את קובץ ה- .tflite.
פשוט מציינים שרוצים להריץ ב-GPU, ואז יוצרים את הקלט ואת outputBuffers.
ואז, בלולאה הראשית, שבה אתם מעבדים כל פריים, אתם קוראים ל-model.run ומעבירים את הקלט והפלט.
אחרי שכותבים ל-inputBuffers, מתקשרים אל model.run ואז קוראים מ-outputBuffers.
אוקיי.
אה, כן, ואז אם פשוט מציינים שם GPU, הוא יפעל ב-GPU.
אם תציינו שם גם CPU וגם GPU, המערכת תנסה להפעיל את ה-GPU.
אם ה-GPU לא זמין מסיבה כלשהי, המערכת תשתמש ב-CPU.
לכן, במקרים מסוימים, יכול להיות שה-CPU החלופי לא יהיה יעיל מספיק לאפליקציה שלכם, ובמקרים כאלה כדאי לציין רק את ה-GPU.
בדרך כלל, תרצו שתהיה לכם אפשרות חלופית של מעבד (CPU).
אוקיי.
לכן, פיתחנו אותו עם חבילת LiteRT, שעדיין לא משתמשת ב-Play Services.
אז בואו נראה איך משתמשים ב-LiteRT ב-Play Services.
אז יש שלושה שינויים: הראשון הוא השינוי בתלות.
// Easier with CompiledModel API: 3 steps
// 1. app/build.gradle: replace litert with play-services-litert
- implementation 'com.google.ai.edge.litert:litert:...'
+ implementation 'com.google.android.gms:play-services-litert:17.0.0' // also pulls in litert-apiפשוט מחליפים את מה שצריך בקובץ Gradle או בכל מקום אחר, בכל מערכת build שבה אתם משתמשים, בכל מקום אחר שבו אתם מציינים את יחסי התלות של חבילת Maven, זה מה שאתם הולכים לשנות.
צריך להסיר את התלות ב-litert או כל אחת מהתלויות בחבילות Maven הישנות יותר של TensorFlow Lite, ולהחליף אותן ב-play-services-litert.
הפעולה הזו גם מושכת את החבילה litert-api.
עכשיו, אם אתם כותבים שכבת ביניים שרק רוצה להסתמך על LiteRT, אבל לא ממש משנה אם זמן הריצה מגיע מהאפליקציה או משירותי Play, אתם יכולים פשוט להסתמך על LiteRT API, ולהשתמש בסביבה כפרמטר קלט.
השלב השני הוא פרמטר הסביבה.
שם אתם מספקים את הזרקת התלות, כדי לציין שאתם רוצים להשתמש ב-Play Services LiteRT.
לכן, מייבאים את gms.litert.LiteRt וקוראים לפונקציית האיניציאליזציה, ומעבירים את ההקשר, שהוא הפעילות ב-Android.
// 2. Initialize the LiteRT Environment from Play services (context = your Activity)
- val environment = Environment.create(...)
+ import com.google.android.gms.litert.LiteRt
+ val environment = LiteRt.initialize(context).await()
// 3. Pass environment whenever you call CompiledModel.create
// That's it! The rest of your app uses the normal CompiledModel APIs from litert-api.וזה דבר אסינכרוני, אז צריך לקרוא ל- .await או שהשאר יתבסס על קריאה חוזרת (callback).
ולבסוף, אחרי שיש לכם את הסביבה הזו, אתם פשוט מעבירים אותה בכל פעם שאתם קוראים ל-CompiledModel.create.
כך הוא ישתמש בסביבת זמן הריצה של LiteRT מ-Play Services.
וזהו זה.
כלומר, שאר האפליקציה משתמשת באותם ממשקי API של LiteRT CompiledModel מ-LiteRT API.
שאר קוד ההסקה לא משתנה כשמשתמשים ב-Play Services.
ואתם יכולים לבצע את ההעברה הזו באופן הדרגתי.
אתם לא חייבים לעשות הכול בבת אחת, אלא יכולים להעביר רכיב אחד בכל פעם.
אם יש לכם אפליקציה גדולה, כדאי להעביר כל רכיב שמשתמש ב-LiteRT, ואז תוכלו להעביר אחד בכל פעם ולבדוק אחד בכל פעם.
החיסרון היחיד הוא שאתם מקבלים רק את היתרון של הגודל, והחיסכון במקום מתרחש רק כשאתם מסירים את התלות האחרונה בסביבת זמן הריצה בחבילה.
ואם כן, אזהרה נוספת היא שלא כדאי לערבב אובייקטים בין LiteRT ב-Play Services לבין LiteRT בחבילה.
לכן, אם אתם מקבלים טנזורים, מודלים מקומפלים או מפרשים מ-LiteRT ב-Play Services, אל תעבירו אותם ל-LiteRT בחבילה, ולהפך.
אבל חוץ מזה, אפשר לשלב בין הדברים האלה בלי בעיה.
אוקיי.
אז זה היה תהליך של יצירת אפליקציה חדשה.
עכשיו אסביר איך לשדרג אפליקציה קיימת.
לכן, יכול להיות שיש לכם אפליקציה קיימת שמשתמשת ב-Interpreter API.
זהו ה-API הישן יותר של TFLite שמשתמש במפרש כמחלקה הראשית.
אז בצד שמאל יש את הקוד שמשתמש ב-Interpreter API, ובצד ימין יש את הקוד החדש של CompiledModel API.
// Dependencies (Gradle):
// play-services-tflite-java and/or litert (bundled)
// Init
TfLite.initialize(context).await()
// Load
val interpreterOptions =
InterpreterApi.Options().apply {
runtime = TfLiteRuntime.FROM_SYSTEM_ONLY
}
val interpreter =
InterpreterApi.create(modelFile, interpreterOptions)
// Prepare inputs/outputs
val inputs = …
val outputs = …
// Execute
interpreter.run(inputs, outputs)// Dependencies (Gradle):
// play-services-litert
// Init
val environment =
LiteRt.initialize(context).await()
// Load
val modelOptions = CompiledModel.Options(Accelerator.CPU)
val model =
CompiledModel.create(modelPath, modelOptions, environment)
// Prepare inputs/outputs
val inputBuffers = model.createInputBuffers()
val outputBuffers = model.createOutputBuffers()
// Execute
model.run(inputBuffers, outputBuffersאז פשוט משנים את TfLite.initialize ל-LiteRt.initialize, ועכשיו הפונקציה מחזירה סביבה.
ואז מעבירים את הסביבה אל CompiledModel.create.
אז זה שינוי קטן, בלי הגדלה של ה-APK.
בשקף הבא נראה איך לעשות את זה עם GPU, וזו רק עוד אפשרות אחת.
אז זה הקוד הנוסף שצריך כדי להפעיל את ה-GPU.
// Dependencies (Gradle):
// play-services-tflite-java and/or litert (bundled)
// Init
val initOptions = TfLiteInitializationOptions.builder()
.setEnableGpuDelegateSupport(true).build()
TfLite.initialize(context, initOptions).await()
val useGpu =
TfLiteGpu.isGpuDelegateAvailable(context).await()
// Load
val interpreterOptions =
InterpreterApi.Options().apply {
runtime = TfLiteRuntime.FROM_SYSTEM_ONLY
}
if (useGpu) {
interpreterOptions.addDelegateFactory(
GpuDelegateFactory());
}
val interpreter =
InterpreterApi.create(modelFile, interpreterOptions)
// Prepare inputs/outputs
val inputs = …
val outputs = …
// Execute
interpreter.run(inputs, outputs)// Dependencies (Gradle):
// play-services-litert
// Init
val initOptions = LiteRtInitializationOptions.builder()
.setEnableGpu(true).build()
val environment = LiteRt.initialize(context, initOptions).await()
// Load
val modelOptions =
CompiledModel.Options(Accelerator.CPU, Accelerator.GPU)
val model =
CompiledModel.create(modelPath, modelOptions, environment)
// Prepare inputs/outputs
val inputBuffers = model.createInputBuffers()
val outputBuffers = model.createOutputBuffers()
// Execute
model.run(inputBuffers, outputBuffers)כמו שאתם רואים, הקוד ב-API החדש להפעלת GPU קצת יותר פשו-- כן, יותר פשוט מהקוד הקודם.
לכן, הקריאה הראשונה ל-setEnableGpu באפשרויות האתחול של LiteRT, שמועברת לאחר מכן אל LiteRt.initialize, תגרום לטעינת הקוד של מאיץ ה-GPU באפליקציה.
ואז, כשיוצרים את modelOptions ומעבירים אותם אל CompiledModel.create, מציינים באיזה מאיץ להשתמש למודל מסוים, אם רוצים שמודל אחר יפעל רק ב-GPU, או ב-GPU עם חלופה של מעבד (CPU), או רק במעבד (CPU).
טוב.
כן, כמו שאפשר לראות, הפעלת ה-GPU הרבה יותר פשוטה עם ה-API החדש.
אז מה בעצם אתם מרוויחים?
צ'ינטאן יסביר לכם.
טוב.
אוקיי, תודה פרגוס.
אז בואו נדבר על מה כל זה נותן לנו, נכון?
אז זוכרים שאמרנו שאנחנו הולכים לבנות אפליקציה? בואו נראה מה בעצם בנינו.
אז זה אני, בכל מקרה, ומה שעשינו כאן זה שהשתמשנו ב-ML Kit כדי למצוא אותי, כך שהפילוח נעשה על ידי API מוכן לשימוש כמו ML Kit.
אז זה פשוט למצוא את הראש שלי שם.
ואז LiteRT משתמש במודל אחר שדומה להעתקת סגנון כדי לצבוע את הרקע.
יתרונות נוספים שציינו הם חיסכון של כ-8MB בנפח האחסון, סביבת זמן ריצה אחת שמשמשת את כל האפליקציות, או לפחות את אלה שמשותפות כאן, עדכונים אוטומטיים וגם GPU מהיר יותר שמאפשר להגיע לקצב של כ-30 FPS במקרים שבהם נדרש עיבוד בזמן אמת כדי לספק חוויית משתמש עשירה.
והחלק הכי טוב הוא שלא צריך לעשות את כל זה באופן ידני.
יש גם סקיל חדש שהשקנו לאחרונה ב-Android, בעצם פרסמנו סקיל של Android LiteRT שמשדרגת את ML במכשיר תוך דקות, נכון?
אז אפשר לעשות כמה דברים: לשדרג אפליקציה קיימת, ליצור תבנית לאפליקציה חדשה, וגם לשדרג את האפליקציה כדי להשתמש בשילוב החדש הזה של Play Services.
כל זה זמין.
הקישור מופיע בשקף, הוא מופיע גם ב-GitHub, והוא יופיע גם במסמכי התיעוד ובבלוג שלנו.
וכן, אז זה אמור להיות שימושי גם לכל מי שרוצה לבצע את השינוי בקרוב.
אז פרגוס יספר לנו מה השלב הבא.
לכן, אנחנו מחויבים ל-AI במכשיר עם LiteRT.
אנחנו ממשיכים להשקיע משאבים רבים בשיפור האצת ה-GPU והכיסוי של המודלים, וממשיכים לספק עדכונים שוטפים ל-LiteRT 2.x, גם ל-LiteRT בקוד פתוח וגם לחבילת Maven של LiteRT ב-Play Services, שהיא LiteRT ב-Play Services.
אנחנו גם נמשיך לספק תאימות לדורות קודמים.
סביבת זמן הריצה של Play Services תמשיך לתמוך באפליקציות שנוצרו באמצעות ערכות SDK ישנות יותר.
כן.
זה ממש חשוב למשתמשים שלנו, וזה ממש חשוב לנו.
ערכות ה-SDK של LiteRT 1.x נמצאות עכשיו במצב תחזוקה, אז הן מקבלות רק תיקוני אבטחה קריטיים.
אנחנו גם נפסיק להשתמש ב-NNAPI, שהוצאנו משימוש ב-2024, וסביר להניח שהוא יוסר החל מ-2027.
לכן, אם אתם משתמשים ב-NNAPI, אתם צריכים לעבור להשתמש בהאצת GPU או בהאצת NPU עם LiteRT בחבילה.
אוקיי.
כן.
לכן, ככל שתעברו מוקדם יותר לגרסה 2.x ול-CompiledModel, כך תצטרכו לעשות פחות בהמשך.
אז יש שלושה דברים שחשוב לזכור.
אז תבנו.
כדאי להתחיל עם ML Kit, ואם הוא כבר עושה את מה שאתם צריכים, זה מצוין.
אם לא, השתמשו ב-LiteRT למודלים בהתאמה אישית.
כדאי לשדרג ל-LiteRT ב-Google Play Services כדי לחסוך מקום ב-APK ולהשתמש בסביבת זמן הריצה המשותפת.
כדאי גם להשתמש ב-API של CompiledModel כדי להסיק מסקנות מהר יותר ובקלות רבה יותר באמצעות GPU.
כן.
הכול מתועד באתר התיעוד של LiteRT ב-AI Edge בכתובת ה-URL שמופיעה כאן.
אז כן.
תודה שהצטרפתם אלינו, ואנחנו כבר לא יכולים לחכות לראות מה תבנו.
// 1. Configure and create segmenter client
val segmenter = Segmentation.getClient(
SelfieSegmenterOptions.Builder()
.setDetectorMode(
SelfieSegmenterOptions.STREAM_MODE)
.build())
// 2. Prepare image & run inference
fun processFrame(mediaImage: Image) {
val image = InputImage.fromMediaImage(
mediaImage, /* rotationDegrees= */ 0)
segmenter.process(image)
.addOnSuccessListener { mask -> … }
}import litert_torch
model = my_models.Stylizer().eval()
# Convert with torch.export under the hood
edge_model = litert_torch.convert(
model, sample_inputs)
edge_model.export("stylizer_f32.tflite")# Python
# previously ai_edge_quantizer
from litert_quantizer import quantizer, recipe
qt = quantizer.Quantizer("stylizer_f32.tflite")
# int8 weights, float activations
qt.load_quantization_recipe(
recipe.dynamic_wi8_afp32())
qt.quantize().export_model("stylizer_int8.tflite")// Kotlin
// Build once, off the main thread.
private val model: CompiledModel =
CompiledModel.create(
context.assets,
"stylizer_int8.tflite",
// Simple GPU setup!
CompiledModel.Options(Accelerator.GPU),
environment
)
// Reuse buffers across frames.
private val inputBuffers = model.createInputBuffers()
private val outputBuffers = model.createOutputBuffers()
fun stylize(input: FloatArray): FloatArray {
inputBuffers[0].writeFloat(input)
model.run(inputBuffers, outputBuffers) // sync
return outputBuffers[0].readFloat()
}// Easier with CompiledModel API: 3 steps
// 1. app/build.gradle: replace litert with play-services-litert
- implementation 'com.google.ai.edge.litert:litert:...'
+ implementation 'com.google.android.gms:play-services-litert:17.0.0' // also pulls in litert-api// 2. Initialize the LiteRT Environment from Play services (context = your Activity)
- val environment = Environment.create(...)
+ import com.google.android.gms.litert.LiteRt
+ val environment = LiteRt.initialize(context).await()
// 3. Pass environment whenever you call CompiledModel.create
// That's it! The rest of your app uses the normal CompiledModel APIs from litert-api.// Dependencies (Gradle):
// play-services-tflite-java and/or litert (bundled)
// Init
TfLite.initialize(context).await()
// Load
val interpreterOptions =
InterpreterApi.Options().apply {
runtime = TfLiteRuntime.FROM_SYSTEM_ONLY
}
val interpreter =
InterpreterApi.create(modelFile, interpreterOptions)
// Prepare inputs/outputs
val inputs = …
val outputs = …
// Execute
interpreter.run(inputs, outputs)// Dependencies (Gradle):
// play-services-litert
// Init
val environment =
LiteRt.initialize(context).await()
// Load
val modelOptions = CompiledModel.Options(Accelerator.CPU)
val model =
CompiledModel.create(modelPath, modelOptions, environment)
// Prepare inputs/outputs
val inputBuffers = model.createInputBuffers()
val outputBuffers = model.createOutputBuffers()
// Execute
model.run(inputBuffers, outputBuffers// Dependencies (Gradle):
// play-services-tflite-java and/or litert (bundled)
// Init
val initOptions = TfLiteInitializationOptions.builder()
.setEnableGpuDelegateSupport(true).build()
TfLite.initialize(context, initOptions).await()
val useGpu =
TfLiteGpu.isGpuDelegateAvailable(context).await()
// Load
val interpreterOptions =
InterpreterApi.Options().apply {
runtime = TfLiteRuntime.FROM_SYSTEM_ONLY
}
if (useGpu) {
interpreterOptions.addDelegateFactory(
GpuDelegateFactory());
}
val interpreter =
InterpreterApi.create(modelFile, interpreterOptions)
// Prepare inputs/outputs
val inputs = …
val outputs = …
// Execute
interpreter.run(inputs, outputs)// Dependencies (Gradle):
// play-services-litert
// Init
val initOptions = LiteRtInitializationOptions.builder()
.setEnableGpu(true).build()
val environment = LiteRt.initialize(context, initOptions).await()
// Load
val modelOptions =
CompiledModel.Options(Accelerator.CPU, Accelerator.GPU)
val model =
CompiledModel.create(modelPath, modelOptions, environment)
// Prepare inputs/outputs
val inputBuffers = model.createInputBuffers()
val outputBuffers = model.createOutputBuffers()
// Execute
model.run(inputBuffers, outputBuffers)