המרת מודל ל-TFLite: מה נשבר ביציאה
המרת מודל ל-TFLite היא לא "לשמור בפורמט אחר", אלא לבנות מחדש את הגרף עבור אינפרנץ במובייל. לחלק מהאופרטורים אין מקבילה ברנטיים, ובמקום שגיאה ברורה תקבלו או קריסה בדגם מכשיר מסוים, או החלפה שקטה של המסלול המואץ במסלול חלופי איטי.
האופרטורים שאינם נתמכים מתבטאים בדרכים שונות: הממיר מדווח עליהם ישירות או מוציא אזהרה ובונה מודל שמחושב אבל לא נכון. שכבות מותאמות אישית, גדלים דינמיים של קלטים, ופעולות על מבנים דלילים יש לשכתב לקבוצה נתמכת.
סיפור נפרד — קוונטיזציה. ייצוג שלמים של משקלים מכווץ את המודל ומאיץ את הפלט, אבל בלי סט כיול מייצג הדיוק יורד בצורה לא אחידה: המדד הממוצע נשמר, אבל במחלקות נדירות ההידרדרות כפולה ומכופלת. לכן ירידת דיוק מחפשים לא לפי המספר הכללי, אלא לפי פרוסות נתונים.
פערים בתוצאות במכשיר נוצרים גם בגלל הדלגייטים: מאיצים חומרתיים משנים את סדר החישוב והעיגול, והפלט מפסיק להתאים לתקן הייחוס. צריך בדיקות פאריטי לכל פלט וסבילויות מפורשות, ולא בדיקת דוגמת הדגמה אחת.
מבחוץ זה נראה כעלייה בזמן התגובה אצל חלק מהמשתמשים וקריסות במכשירים מסוימים: המסלול המואץ חוזר למעבד, נכנס תרוטלינג, וחסר זיכרון. בהמשך נפרק איך כל אחד מהסוגים האלה של תקלות נסגר בשלב ההמרה.
מה נותנת אופטימיזציה למכשיר מסוים
מודל שאומן על מאיצים בשרת מתנהג אחרת בטלפון: התגובה נמדדת בשניות, הארטיפקט לא נכנס לגודל סביר של אפליקציה, וחלק מהפעולות במכשירים זולים נכשלות. המרת מודל ל-TensorFlow Lite מתרגמת את הגרף לפורמט שמופעל במכשיר, ואופטימיזציה לפלטפורמה מסוימת הופכת אותו למתאים לעבודה.
קוונטיזציה ל-8 ביט שלמים — המנוף המרכזי: המשקלים והאקטיבציות מכוילים על דוגמאות אמיתיות, ורק שכבות שבהן ירידת האיכות מורגשת במדד נשארות ברמת דיוק מלאה. נפח הזיכרון מצטמצם פי 3–4, והגידול במהירות גבוה יותר במעבדים חלשים — בדיוק במקום שצריך אותו.
מדידות שפורסמו על ידי הקהילה נותנות אותו סדר גודל: הארטיפקט — ממאות לעשרות מגהבייט, התגובה — משניות לעשיריות.
הרצת שכבות על המאיץ הגרפי או המודול העצבי מאיצה את הריצה, אבל אופרטור אחד לא נתמך מחזיר קטע מהגרף למעבד המרכזי — התגובה מתחילה לקפוץ. לכן בודקים את הרכב האופרטורים מראש, ובודקים את המסלול החלופי על כל משפחת מכשירים יעד.
כל העיבוד מתבצע מקומית: אין בקשות לשרת, אין כשלים בגלל ערוץ תקשורת, והנתונים לא עוזבים את המכשיר. עבור רפואה, פיננסים ותרחישים תעשייתיים זה מסיר את רוב השאלות לגבי נתונים אישיים.
שיעור הכשלים מחושב לפי המכשירים החלשים, לא לפי מכשירי הדגל: דגמים זולים, התחממות, חוסר בזיכרון. לפני האופטימיזציה הרצות כושלות שם מגיעות ל-10–15%, אחרי — לאחוזים בודדים באותה איכות תשובה.
השוואת מצבים: קוונטיזציה, דלגייטים, דחיסה
מצבי האופטימיזציה לא מחליפים זה את זה: קוונטיזציה משנה את פורמט המשקלים והאקטיבציות, דלגייטים מעבירים את החישוב למאיץ של המכשיר, וגיזום משקלים מסיר קשרים מיותרים ברשת עצמה.
אפשר לשלב אותם ולעיתים קרובות צריך, אבל הסדר חשוב — קודם גיזום עם כיוונון עדין, אחר כך קוונטיזציה, והדלגייט נבחר בשלב הבנייה עבור אוכלוסיית מכשירים מסוימת.
להלן האפשרויות שבהן באמת בוחרים בזמן המרת מודל ל-TFLite, עם המגבלות של כל אחת.
| אפשרות | מתי מתאים | מגבלות |
|---|---|---|
| קוונטיזציה float16 של משקלים | צריך גודל קטן יותר עם כמעט אפס אובדן איכות | מקטין רק את המשקל: במעבד זמן הפלט כמעט לא משתנה, והרווח מתבטא במאיץ הגרפי |
| קוונטיזציה שלמה דינמית | יש הרבה שכבות קונבולוציה, אין סט נתונים מייצג | המשקלים נדחסים, האקטיבציות מחושבות בנקודה צפה — הרווח בזמן חלקי |
| קוונטיזציה שלמה עם כיול | אוכלוסיית המכשירים אחידה, חשובים משקל מינימלי וזמן צפוי | צריך סט נתונים מייצג, מחלקות נדירות מאבדות דיוק, חלק מהאופרטורים נופל מהמסלול המואץ |
| דלגייט למאיץ גרפי | המודל מורכב מאופרטורים נתמכים, השהיה קריטית | אופרטורים מחוץ לרשימה חוזרים למעבד, צריכת הזיכרון עולה |
| דלגייט למודול עצבי | מכשירים מאותה משפחה עם מאיץ ייעודי | תלות בדגם המכשיר, חלק מהשכבות בכל זאת הולכות למעבד |
| גיזום משקלים עם כיוונון עדין | הרשת מלכתחילה עודפת, צריך מרווח בזיכרון | בלי תמיכה בליבות דלילות במכשיר הרווח לא מתבטא |
את הבחירה מאשרים במדידות על אוכלוסיית היעד: זמן פלט, שיעור האופרטורים על המאיץ והאיכות על מדגם מוחזק.
סדר העבודה: אבחון, סכימה, כוונון, בדיקה
סדר השלבים אינו מקרי: כל צעד הבא נשען על המדידות של הקודם. אם מדליקים קוונטיזציה מיד בלי לקבע קו בסיס, אובדן הדיוק יתגלה כבר בפרודקשן — במכשירי המשתמשים, ולא בסטנד. לכן מתחילים באבחון ומסיימים במסירה, כדי שאפשר יהיה לבדוק ולחזור לכל שינוי.
- אבחון מצב קיים. מפרקים את ארכיטקטורת המודל, טנסורי הקלט והפלט, ומוצאים צווארי בקבוק — עיבוד מקדים של פריימים, עיבוד לאחר, וההסקה עצמה. קובעים מדדי בסיס במכשיר היעד: זמן פלט, צריכת זיכרון, התנהגות תחת עומס ממושך.
- סכימת צינור הבנייה. מגדירים מאיפה מגיעים המשקלים, איך משוחזר הייצוא, איפה נשמרים הארטיפקטים והגרסאות שלהם. אחרי זה המרת מודל ל-TFLite הופכת לפקודה ניתנת לשחזור, ולא לפעולה ידנית במחשב של המפתח.
- כוונון מצב האופטימיזציה. בוחרים סוג קוונטיזציה — מקוונטיזציה של משקלים ועד שלמה — ודלגייטים עבור מאיצים מסוימים. את הבחירה מנמקים במדידה: איפה הרווח במהירות מכסה את אובדן הדיוק, ואיפה לא.
- בנייה ותיקונים. מריצים את המודל דרך הממיר, מחליפים אופרטורים לא תואמים, ומכווננים פרמטרים של הייצוג. שולטים בשני מספרים: גודל הארטיפקט והאיכות על סט ולידציה.
- בדיקה במכשירים. בודקים על אוכלוסייה אמיתית — דורות שונים של שבבים, נפח זיכרון, גרסאות מערכת. מסתכלים על המקרה הגרוע, לא על הממוצע: התחלה קרה, התחממות, חוסר בזיכרון.
- מסירת העבודה. מוסרים צינור מכוונן, נוהל להוצאת גרסה חדשה, סקריפטים למדידות ודוח עם מספרים לפני ואחרי. צוות הלקוח ממשיך בהמשך לחזור על המחזור בעצמו.
ארטיפקטים של הפרויקט: קונפיגורציות, סכימות, נהלים
אנחנו מוסרים את הפרויקט כך שאפשר יהיה לבנות ולבדוק אותו בלעדינו: המרת מודל ל-TFLite ניתנת לשחזור — זה לא סקריפט אחד, אלא סט קבצים שלפיהם כל מהנדס יקבל את אותו ארטיפקט. להלן מה בדיוק נשאר אצל הלקוח במאגר ובמסמכים.
- קונפיגורציות בנייה — פרמטרי המרה (צורות קלט, סוג קוונטיזציה, רשימת אופרטורים עם מעבר למימוש חלופי) מוצאים לקבצים, ולא נשמרים בראש של המהנדס.
- סכימת הצינור: איפה מאמנים משקלים, איפה מבוצעת ההמרה, איפה מריצים בדיקות על מכשיר אמיתי ובאיזה שלב מפרסמים את הארטיפקט.
- כללי ניהול גרסאות — קישור בין גרסת הדאטהסט, המשקלים והארטיפקט המומר, כדי שחזרה לכל בנייה קודמת תהיה חד-משמעית.
- נוהל בדיקות: בדיקות לפערים בפלטים לפני ואחרי קוונטיזציה, זמן פלט וצריכת זיכרון על סט מכשירים תקני.
- מטריצת מאיצים — אילו מופעלים, על אילו דגמי מכשירים וגרסאות מערכת נבדקו ואיך המודל מתנהג בהיעדרם.
- תיעוד: איך בונים את הארטיפקט מאפס, איך חוזרים לגרסה קודמת ואילו מגבלות יש לקונפיגורציה הנוכחית.
- דוח השוואה — טבלה לפי דיוק וזמן פלט לפני ואחרי דחיסה על סט קבוע של נתוני קלט.
מקרה בוחן: איך צמצמנו את גודל המודל והסרנו השהיות
הלקוח הגיע עם מודל זיהוי שעבד היטב בטלפוני דגל והתפרק על שאר המכשירים. הארטיפקט לא נכנס לתקציב הזיכרון, חלק מהפעולות עברו למסלול חישוב איטי, והתגובה במכשירים חלשים התארכה. מדידות לפני התחלה: ב-9% מהמכשירים עיבוד הפריים לא נכנס לחלון שהוקצה, וב-4% האפליקציה קרסה באתחול.
מה עשינו
הקמנו סטנד של מכשירים מדורות שונים וקבענו מדדי בסיס לכל אחד — בלי זה האופטימיזציה הופכת לניחוש. המודל נבנה מחדש לפורמט TensorFlow Lite עם קוונטיזציה, מכוילת על נתונים אמיתיים של הלקוח, ולא על סינתטיקה: המשקלים הובאו לייצוג שלמים, וקטעים רגישים לדיוק נשארו ללא שינוי.
לכל מחלקת שבבים התאמנו מאיץ חומרה, חלק מהאופרטורים הוצאו לעיבוד מקדים, וענפים כבדים בגרף פוצלו לשני מעברים עם מטמון ביניים.
מה קרה
גודל הארטיפקט קטן פי ארבעה, זמן התגובה במכשירים חלשים — פי שלושה. שיעור המכשירים שלא נכנסים לחלון העיבוד ירד מ-9% ל-0.6%, והקריסות באתחול נעלמו כסוג כשל. הדיוק אחרי דחיסה ירד בטווח של אחוז אחד — זה מאושר בהרצה על מדגם מוחזק לפני כל גרסה.
הבדיקה מתבצעת על אוכלוסייה של כמה עשרות דגמי מכשירים: אם בנייה חדשה מדרדרת בהשהיה או בזיכרון, היא לא מגיעה לפרסום.
במה דלגייט שונה מקוונטיזציה ומה לבחור
דלגייט וקוונטיזציה פותרים משימות שונות, ובלבול ביניהם מוביל לכך שמחפשים האצה במקום שבו היא לא נמצאת. דלגייט הוא דרך ביצוע: חלק מהגרף של הפעולות עובר מהמעבד המרכזי למאיץ הגרפי או למודול העצבי של המכשיר.
קוונטיזציה היא דרך ייצוג: המשקלים והאקטיבציות נשמרים בפורמט שלמים במקום נקודה צפה, ובזכות זה הארטיפקט שוקל פי כמה פחות, והאריתמטיקה מחושבת מהר יותר.
מכאן גם סדר היישום. קוונטיזציה מתבצעת בשלב המרת המודל ל-TFLite — זו תכונה של הקובץ המוכן, שנקבעת לפני בניית האפליקציה. דלגייט מתחבר בשלב ההרצה, באתחול המפרש, ולא משפיע על תוכן הקובץ. לכן קודם מגדירים את הדיוק והיעד ופורמט המשקלים, ורק אחר כך בוחרים מבצע לפורמט הזה.
הם משולבים יחד ממש לא תמיד באופן אוטומטי. לא כל דלגייט תומך בכל סט האופרטורים השלמים: צמתים לא נתמכים חוזרים למעבד המרכזי, הגרף נקרע לקטעים, והעברת טנסורי ביניים בין המאיץ למעבד אוכלת את הרווח. סימן לבעיה — האצה נמוכה מהצפוי וגידול בצריכת האנרגיה במפגשים ארוכים.
קריטריון הבחירה פשוט. אם המגבלה היא גודל האפליקציה ונפח הזיכרון, מתחילים בקוונטיזציה. אם המודל נכנס לזיכרון אבל לא עומד בהשהיה, מנסים דלגייט.
אם במכשיר יש מודול עצבי וצריך השהיה מינימלית, שמים את שני המצבים — אבל עם בקרה של שיעור האופרטורים שבאמת עברו למאיץ, ושל פערים בפלטים מול תוצאת ייחוס.
ספקות לגבי דיוק, גודל ותאימות
ספקות הנדסיים סביב המרת מודל ל-TensorFlow Lite הם כמעט תמיד אותם: כמה יירד הדיוק אחרי קוונטיזציה, מה לעשות עם פעולות שאין ברנטיים, ואיך לעדכן את הרשת בלי להוציא בנייה חדשה של האפליקציה. להלן תשובות ישירות לכל סעיף.
כמה יירד הדיוק?
תלוי במצב. קוונטיזציה של משקלים נותנת שברי אחוז במדד היעד, סכימת שמונה ביט מלאה — מורגשת יותר, במיוחד בזיהוי עצמים קטנים. לכן משווים זוגות "לפני/אחרי" על מדגם מוחזק ועל סט כיול מנתונים אמיתיים.
מה לעשות עם אופרטורים לא נתמכים?
שלושה מסלולים: להחליף צומת במקבילה נתמכת, לבנות אופרטור מותאם אישית, או להשאיר קטע במבצע חלופי. הבחירה — לפי כמה זמן פלט מוסיף המעקף וכמה יציב הוא עובד על שבבים שונים.
אפשר לעדכן את המודל בלי להוציא גרסת אפליקציה?
כן, אם הרשת והממשק מופרדים: המשקלים נמצאים בארטיפקט נפרד, האפליקציה מושכת את הגרסה העדכנית וחוזרת לקודמת במקרה של הידרדרות במדדים. בנייה חדשה נדרשת רק כשמשתנה מבנה הקלטים-פלטים.
איך בודקים תאימות מכשירים?
מרכיבים מטריצת מכשירי יעד ומריצים את הבנייה על כל אחד: שבבים שונים, האצה דרך מאיץ גרפי או מודול עצבי, חזרה למסלול חלופי. התחלה והתנהגות תחת עומס מראים פערים בין מכשירים טוב יותר ממדד ממוצע.
בואו נדון במשימה: מה צריך כדי להתחיל
כדי שההערכה תישען על עובדות ולא על הנחות, מספיקים לנו כמה נתוני פתיחה. ככל שהתרחיש מתואר מדויק יותר, כך מהר יותר נציין שלבים, לוחות זמנים וסיכונים.
- הגדרת המשימה — איפה המודל עובד: במכשיר המשתמש או בפנייה לשרת, מי המשתמש ואיזו תשובה נחשבת נכונה.
- נתוני מקור — מה מגיע לקלט: פריימים מהמצלמה, תמונות, אודיו או טקסט. מספיק 10-20 דוגמאות של נתונים אמיתיים, כולל מקרים מורכבים.
- הצינור הנוכחי — על מה אומן המודל, באיזה פורמט נשמר, האם היו ניסיונות המרה ל-TFLite ובאיזה שלב הם נעצרו.
- רשימת מכשירים — דגמי טלפונים, ענפי מערכות הפעלה, שיעור המכשירים החלשים בקהל: מהם תלויים הקוונטיזציה והדלגייטים.
- מדדי איכות — מה אסור לאבד: דיוק, שלמות, השהיית תגובה, צריכת סוללה. מדידות על הגרסה הנוכחית מאיצות משמעותית את העבודה.
- מגבלות הפרויקט — גודל אפליקציה מותר, זיכרון זמין, דרישות פרטיות, צורך בעבודה ללא רשת.
- לוחות זמנים לשלבים — תאריכים מחייבים: השקה, הצגה ללקוח, שיא עונתי. הם קובעים את סדר העבודה.
לפי נתוני הפתיחה האלה אנחנו מכינים הערכה ותוכנית: חלוקה לפי שלבים, הרכב העבודה, נקודות בדיקה של התוצאה וסיכונים. תארו את המשימה בצורה חופשית — נחזור עם הערכה ותוכנית, ואת הנתונים החסרים נוציא כשלב נפרד.







