איך שיפורים של WebAssembly ו-WebGPU משפרים את הביצועים של למידת המכונה באינטרנט.
מסקנות מ-AI באינטרנט
כולנו שמענו את הסיפור של המותג: ה-AI משנה את העולם שלנו. האינטרנט אינו יוצא מן הכלל.
השנה נוספו ל-Chrome תכונות מבוססות-AI גנרטיבי, כולל יצירת עיצוב בהתאמה אישית או עזרה בכתיבה של טיוטת טקסט ראשונה. אבל AI הוא הרבה יותר מזה; בינה מלאכותית יכולה להעשיר את אפליקציות האינטרנט עצמן.
דפי אינטרנט יכולים להטמיע רכיבים חכמים לראייה, כמו בחירת פנים או זיהוי תנועות, לסיווג אודיו או לזיהוי שפה. בשנה האחרונה, ראינו שהבינה המלאכותית הגנרטיבית הולכת וגדלה, כולל כמה הדגמות מרשימות מאוד של מודלים גדולים של שפה (LLM) באינטרנט. כדאי לקרוא על AI מעשי במכשיר למפתחי אתרים.
מסקנות מ-AI באינטרנט זמינות היום בחלק גדול של מכשירים, ועיבוד AI יכול להתרחש בדף האינטרנט עצמו תוך שימוש בחומרה במכשיר של המשתמש.
היתרון הזה חשוב מכמה סיבות:
- עלויות מופחתות: הרצת הסקת המסקנות בלקוח הדפדפן מפחיתה משמעותית את העלויות בצד השרת, וזה יכול להיות שימושי במיוחד לשאילתות של AI גנרטיבי, שיכולות להיות יקרות במידה רבה יותר משאילתות רגילות.
- זמן אחזור: באפליקציות שרגישות במיוחד לזמן אחזור, כמו אפליקציות אודיו או וידאו, השלמת העיבוד של כל העיבוד במכשיר מובילה לזמן אחזור קצר.
- פרטיות: הרצה בצד הלקוח עשויה גם לבטל נעילה של סיווג חדש של אפליקציות שמחייבות פרטיות מוגברת, ולא ניתן לשלוח נתונים לשרת.
איך עומסי עבודה (workloads) של AI פועלים היום באינטרנט
כיום, מפתחי אפליקציות וחוקרים בונים מודלים באמצעות frameworks, מודלים מופעלים בדפדפן באמצעות סביבת זמן ריצה כמו Tensorflow.js או ONNX Runtime Web, וזמני הריצה משתמשים ב-Web APIs לביצוע.
בסופו של דבר, כל זמני הריצה האלה מסתיימים בהרצה במעבד (CPU) באמצעות JavaScript או WebAssembly, או ב-GPU דרך WebGL או WebGPU.
עומסי עבודה (workloads) של למידת מכונה
עומסי עבודה (workloads) של למידת מכונה (ML) דוחפים מעבדי Tensor דרך תרשים של צמתים חישוביים. Tensors הם הקלט והפלט של הצמתים האלה, שמבצעים כמות גדולה של חישוב על הנתונים.
זה חשוב מהסיבות הבאות:
- טנזורים הם מבני נתונים גדולים מאוד, שמבצעים חישובים על מודלים שיכולים לכלול מיליארדי משקולות
- התאמה לעומס (scaling) והסקת מסקנות יכולות להוביל למקבילות של נתונים. כלומר, מתבצעות אותן פעולות בכל הרכיבים של הטנזור.
- למידת מכונה לא דורשת דיוק. יכול להיות שתזדקקו למספר נקודה צפה (float) של 64 ביט כדי לנחות על הירח, אך ייתכן שתזדקקו לים של מספרים של 8 ביט או פחות לצורך זיהוי פנים.
למרבה המזל, מעצבי הצ'יפים הוסיפו תכונות שיגרמו למודלים לפעול מהר יותר וקר יותר, ואפילו לאפשר את ההפעלה שלהם בכלל.
בינתיים, בצוותים של WebAssembly ו-WebGPU, אנחנו פועלים לחשוף את היכולות החדשות האלה למפתחי אתרים. אם אתם מפתחי אפליקציות אינטרנט, לא סביר שתשתמשו בפרימיטיבים האלה ברמה נמוכה לעיתים קרובות. אנחנו צופים ששרשראות הכלים או ה-frameworks שבהן אתם משתמשים יתמכו בתכונות ובתוספים חדשים, וכך אתם יכולים להפיק תועלת משינויים קלים בתשתית. אבל אם אתם רוצים לכוונן ידנית את הביצועים של האפליקציות, התכונות האלה רלוונטיות לעבודה.
WebAssembly
WebAssembly (Wasm) הוא פורמט קוד קומפקטי ויעיל שזמני הריצה יכולים להבין ולהפעיל בו. הם נועדו לנצל את יכולות החומרה הבסיסיות, כך שניתן לפעול במהירות כמעט מקורית. הקוד מאומת ומופעל בסביבה מוגנת בזיכרון.
המידע על מודול Wasm מיוצג באמצעות קידוד בינארי צפוף. בהשוואה לפורמט מבוסס-טקסט, המשמעות היא פענוח מהיר יותר, טעינה מהירה יותר וצמצום השימוש בזיכרון. הוא נייד במובן שאינו מניח הנחות לגבי הארכיטקטורה הבסיסית שאינן נפוצות כבר בארכיטקטורות מודרניות.
המפרט של WebAssembly הוא איטרטיבי ועובדים עליו בקבוצת קהילה פתוחה של W3C.
הפורמט הבינארי לא מתבסס על הנחות לגבי סביבת המארח, ולכן הוא מתוכנן לפעול היטב גם בהטמעות שאינן באינטרנט.
אפשר להדר את האפליקציה פעם אחת ולרוץ בכל מקום: מחשב, מחשב נייד, טלפון או כל מכשיר אחר שיש בו דפדפן. מידע נוסף על הנושא הזה זמין במאמר כתיבת פעם אחת, הרצה בכל מקום שמומש באמצעות WebAssembly.
רוב אפליקציות הייצור שמפעילות מסקנות מ-AI באינטרנט משתמשות ב-WebAssembly, גם למחשוב מעבד (CPU) וגם לממשק עם מחשוב למטרה מיוחדת. באפליקציות נייטיב, אפשר לגשת למחשוב לשימוש כללי וגם למחשוב למטרה מיוחדת, כי האפליקציה יכולה לגשת ליכולות של המכשיר.
באינטרנט, מטעמי ניידות ואבטחה, אנחנו מעריכים בקפידה את קבוצת הפרמיטיביות שנחשפת. איזון בין נגישות האינטרנט לבין הביצועים הטובים ביותר שהחומרה מספקת.
WebAssembly היא הפשטה ניידת של מעבדים (CPU), ולכן כל המסקנות של Wasm עובדות במעבד. זו לא האפשרות עם הביצועים הטובים ביותר, אבל מעבדים (CPU) זמינים באופן נרחב ועובדים ברוב עומסי העבודה, ברוב המכשירים.
בעומסי עבודה קטנים יותר, כמו עומסי עבודה של טקסטים או אודיו, ה-GPU יהיה יקר. יש כמה דוגמאות מהתקופה האחרונה שבהן Wasm היא הבחירה הנכונה:
- Adobe משתמשת ב-Tensorflow.js כדי לשפר את Photoshop באינטרנט.
- נוספו טשטוש של הרקע ב-Google Meet – אחד מהאפקטים הראשונים באינטרנט שמבוססים על Wasm.
- ב-YouTube יש כמה אפקטים של מציאות רבודה.
- אפשר לערוך אונליין ב-Google Photos.
אפשר לגלות עוד יותר הדגמות בהדגמות בקוד פתוח, כמו: whisper-tiny , llama.cpp ו-Gemma2B שפועלות בדפדפן.
גישה הוליסטית לאפליקציות
צריך לבחור עקרונות ראשוניים על סמך מודל למידת המכונה הספציפי, תשתית האפליקציה וחוויית השימוש הכוללת שמיועדת למשתמשים
לדוגמה, בזיהוי ציוני דרך של MediaPipe, ההֶקֵּשׁ ממעבד (CPU) ומהֶקֵּשׁ מ-GPU (פועל במכשיר Apple M1), אבל יש מודלים שבהם השונות יכולה להיות גדולה יותר באופן משמעותי.
כשמדובר בעומסי עבודה (workload) של למידת מכונה, אנחנו מביאים בחשבון תפיסת עולם מלאה של האפליקציות, תוך כדי הקשבה לכותבי framework ולשותפי אפליקציות, כדי לפתח ולשלוח את השיפורים המבוקשים ביותר. באופן כללי, הן מחולקות לשלוש קטגוריות:
- חשיפה של תוספים למעבד (CPU) שקריטיים לביצועים
- הפעלת הפעלה של מודלים גדולים יותר
- הפעלת יכולת פעולה הדדית בצורה חלקה עם ממשקי API אחרים באינטרנט
מחשוב מהיר יותר
כמו כן, המפרט של WebAssembly כולל רק קבוצה מסוימת של הוראות שאנחנו חושפים באינטרנט. עם זאת, החומרה ממשיכה להוסיף הוראות חדשות יותר שמגדילות את הפערים בין הביצועים של מודעות מותאמות לביצועים של WebAssembly.
חשוב לזכור שמודלים של למידת מכונה לא תמיד דורשים רמות דיוק גבוהות. SIMD רגוע הוא הצעה שמפחיתה חלק מהדרישות המחמירות של אי-דטרמיניזם, מה שמוביל ליצירת קוד מהר יותר לפעולות וקטוריות מסוימות שמהוות נקודות חמות לביצועים. נוסף לכך, גרסה של כרטיס SIMD רגועה כוללת מוצרי נקודה חדשים והוראות ל-FMA שמאיצות עומסי עבודה קיימים מפי 1.5 עד 3 פעמים. הפריט נשלח בגרסה 114 של Chrome.
פורמט הנקודה הצפה לפי חצי דיוק משתמש ב-16 סיביות עבור IEEE FP16 במקום ב-32 סיביות המשמשות לערכים של דיוק יחיד. בהשוואה לערכים של דיוק יחיד, יש מספר יתרונות לשימוש בערכי חצי דיוק, דרישות זיכרון מצומצמות יותר, שמאפשרים אימון ופריסה של רשתות נוירונים גדולות יותר ורוחב פס בזיכרון מצומצם. רמת דיוק מופחתת מאיצה את העברת הנתונים והפעולות המתמטיות.
מודלים גדולים יותר
מצביעים לזיכרון לינארי של Wasm מיוצגים כמספרים שלמים של 32 ביט. יש לכך שתי השלכות: הגודל של הזיכרון מוגבל ל-4GB (כשלמחשבים יש הרבה יותר זיכרון RAM פיזי גדול מזה), וקוד האפליקציה שמטרגט את Wasm צריך להיות תואם לגודל של מצביע של 32 ביט (שהוא מוגדר בו).
במיוחד במודלים גדולים כמו שיש לנו היום, טעינת המודלים האלה ב-WebAssembly עלולה להיות מגבילה. הצעת Memory64 מסירה את ההגבלות האלה מהזיכרון ליניארי כך שיהיו גדולים מ-4GB, תוך התאמה לשטח הכתובות של פלטפורמות נייטיב.
יש לנו הטמעת נתונים פעילה ב-Chrome והיא צפויה להישלח בהמשך השנה. בינתיים, אפשר להריץ ניסויים עם הדגל chrome://flags/#enable-experimental-webassembly-features
ולשלוח לנו משוב.
יכולת פעולה טובה יותר באינטרנט
WebAssembly יכולה להיות נקודת הכניסה למחשוב למטרה מיוחדת באינטרנט.
ניתן להשתמש ב-WebAssembly כדי להביא אפליקציות GPU לאינטרנט. כלומר, אותה אפליקציית C++ שיכולה לפעול במכשיר יכולה לפעול גם באינטרנט, עם שינויים קלים.
ל-Emscripten, כלי המהדר של Wasm, כבר יש קישורים ל-WebGPU. זו נקודת הכניסה להסקת מסקנות מ-AI באינטרנט, ולכן חשוב מאוד ש-Wasm יוכל לפעול בצורה חלקה בשיתוף עם שאר פלטפורמת האינטרנט. אנחנו עובדים על כמה הצעות שונות בתחום הזה.
שילוב מובטח של JavaScript (JSPI)
אפליקציות אופייניות ל-C ו-C++ (כמו גם שפות רבות אחרות) נכתבות בדרך כלל מול API סינכרוני. המשמעות היא שהאפליקציה תפסיק לפעול עד שהפעולה תסתיים. אפליקציות חסימה כאלה בדרך כלל אינטואיטיביות יותר לכתיבה מאשר אפליקציות שהן מודעות אסינכרוניות.
כשפעולות יקרות חוסמות את ה-thread הראשי, הן יכולות לחסום קלט/פלט (I/O) וה-jank (ה-jank) גלוי למשתמשים. יש חוסר התאמה בין מודל תכנות סינכרוני של אפליקציות נייטיב לבין המודל האסינכרוני של האינטרנט. הדבר בעייתי במיוחד באפליקציות מדור קודם, שהניוד שלהן יהיה יקר. ב-Emscripten יש דרך לעשות זאת באמצעות Asyncify, אבל זו לא תמיד האפשרות הטובה ביותר – קוד גדול יותר ויעיל פחות.
הדוגמה הבאה היא חישוב פיבונאצ'י, תוך שימוש בהבטחות JavaScript להוספה.
long promiseFib(long x) {
if (x == 0)
return 0;
if (x == 1)
return 1;
return promiseAdd(promiseFib(x - 1), promiseFib(x - 2));
}
// promise an addition
EM_ASYNC_JS(long, promiseAdd, (long x, long y), {
return Promise.resolve(x+y);
});
emcc -O3 fib.c -o b.html -s ASYNCIFY=2
בדוגמה הזו, חשוב לשים לב לדברים הבאים:
- המאקרו
EM_ASYNC_JS
יוצר את כל קוד החיבור הנדרש כדי שנוכל להשתמש ב-JSPI כדי לגשת לתוצאה של ההבטחה, בדיוק כמו שהיא עושה עבור פונקציה רגילה. - אפשרות מיוחדת של שורת הפקודה,
-s ASYNCIFY=2
. הפעולה הזו מפעילה את האפשרות ליצור קוד שמשתמש ב-JSPI כדי להתממשק עם ייבוא של JavaScript שמחזיר הבטחות.
מידע נוסף על JSPI, על אופן השימוש בו ועל היתרונות שלו, זמין במאמר היכרות עם WebAssembly JavaScript Promise Integration API בגרסה v8.dev. מידע נוסף על גרסת המקור הנוכחית לניסיון.
בקרת הזיכרון
למפתחים יש שליטה מועטה מאוד בזיכרון Wasm. שהזיכרון של המודול הוא בבעלותו. כל ממשקי API שזקוקים לגישה לזיכרון הזה חייבים להעתיק פנימה או להעתיק אותו, והשימוש הזה עשוי להצטבר. לדוגמה, ייתכן שאפליקציית גרפיקה תצטרך להעתיק ולהעתיק כל פריים.
המטרה של ההצעה בקרת זיכרון היא לספק שליטה פרטנית יותר בזיכרון הלינארי של Wasm ולצמצם את מספר העותקים בצינור עיבוד הנתונים של האפליקציה. ההצעה הזו היא בשלב 1. אנחנו יוצרים את אב הטיפוס שלה ב-V8, מנוע ה-JavaScript של Chrome, כדי לשפר את ההתפתחות של התקן.
מחליטים איזה קצה עורפי מתאים לכם
המעבד (CPU) זמין בכל מקום, אבל לא תמיד זו האפשרות הטובה ביותר. מחשוב למטרה מיוחדת ב-GPU או במאיצים יכולים להציע ביצועים בסדר גודל גבוה יותר, במיוחד בדגמים גדולים יותר ובמכשירים מתקדמים. הדבר נכון גם לגבי אפליקציות מקוריות וגם לגבי אפליקציות אינטרנט.
סוג הקצה העורפי שתבחרו תלוי באפליקציה, ב-framework או ב-toolchain וגם בגורמים אחרים שמשפיעים על הביצועים. עם זאת, אנחנו ממשיכים להשקיע בהצעות שמאפשרות ליבה של Wasm לעבוד טוב עם שאר פלטפורמת האינטרנט, ובעיקר עם WebGPU.