איך להאיץ מודלי שפה גדולים על מעבד ועל מאיץ גרפי עם ONNX Runtime: מדריך מעשי

המודל מגיב לאט, והעומס גדל מהר יותר מיכולות החומרה. אנו מגדירים ומבצעים אופטימיזציה של אינפרנס מקצה לקצה: מאתרים צווארי בקבוק, מתאימים מצב האצה ומקצרים את זמן התגובה פי כמה. אנו מעבירים תצורות, תרשימים ונהלים, כדי שהתוצאה תעבוד גם בלעדינו.

תחומי פיתוח AI

שאלות נפוצות

העבודות האחרונות

  • פיתוח אפליקציית ווב עבור FEEDME
    פיתוח אפליקציית ווב עבור FEEDME
    1359
  • פיתוח חנות מקוונת לחברת FURNORO
    פיתוח חנות מקוונת לחברת FURNORO
    1330
  • עיצוב לוגו לחברת B2B Advance
    עיצוב לוגו לחברת B2B Advance
    776
  • פיתוח אפליקציית ווב עבור Enviok
    פיתוח אפליקציית ווב עבור Enviok
    1077
  • פיתוח לוגו חברת AIDER
    פיתוח לוגו חברת AIDER
    1022
  • פיתוח CRM עבור Chasseurs
    פיתוח CRM עבור Chasseurs
    1113

ONNX Runtime אופטימיזציית אינפרנס: היכן מתבזבזת המהירות

השהיית התגובה של המודל היא סכום של שלבים, ולא הזמן של ריצה אחת. בקשה עוברת הכנת קלט, חישוב, עיבוד-בתר והמתנה למשאב פנוי, ובכל צעד הזמן מתבזבז מסיבה משלו. כשמודדים רק את הריצה עצמה, התמונה נראית מעודדת, אבל המשתמש עדיין ממתין — ההפסדים חבויים במפרקים.

הקטע הראשון — הכנת הקלט: טוקניזציה, התאמת טיפוסים, פריסת טנסורים והעתקת נתונים לזיכרון המחשב. בבקשות קצרות ובמודלים קומפקטיים דווקא הפעולות האלה הופכות לצוואר הבקבוק של עיבוד הבקשה: השכבות מחושבות מהר יותר מאשר הנתונים מספיקים להגיע אליהן. פרופיל הביצוע של המודל, שנלקח לפי שלבים ולא כמכלול, מראה מיד אסימטריה כזו.

הקטע השני — הריצה עצמה והעומס על המחשב. כאן הזמן מתבזבז על ליבות לא אופטימליות, המרות פורמט מיותרות ועל גרף שלא נבנה עבור מאיץ מסוים. ONNX Runtime מספק לכך סט של מנופים: ספק ביצוע לפי החומרה הזמינה, אופטימיזציות גרף, מיזוג פעולות והפחתת דיוק היכן שאיכות התגובה עומדת בכך.

הקטע השלישי — עיבוד-בתר והמתנה לשחרור משאב. פענוח, בחירת וריאנטים ומיון תוצאות מתחרים על אותו תהליך כמו הריצה, ובבקשות מקבילות מתווספת תור.

זמן התגובה תחת עומס שיא גדל באופן לא ליניארי, ולכן חשוב לא ההשהיה הממוצעת בבקשה בודדת, אלא ההתנהגות תחת עומס — דווקא שם רואים מה לאפטמז ראשון.

מה מואץ: השהיה, תפוקה, עומס

האצת האינפרנס מתפרקת לשלושה גדלים בלתי תלויים, ותיקונים לעיתים רחוקות משפרים את כולם בבת אחת.

צומת על ONNX Runtime עם ספק ביצוע מותאם ובאצ'ינג מחזיק פי כמה יותר בקשות בשנייה מאשר אותו צומת עם הגדרות ברירת מחדל: ליבות החישוב מפסיקות להיות סרק בין קריאות, ונתוני הקלט מקובצים כך שהזיכרון נקרא ברצף. התפוקה של צומת אחד נמדדת לפניהן ואחריהן — זה המספר הראשון שמראה את האפקט.

השהיה ממוצעת מטעה: היא מסווה את הזנב, שהוא זה שקובע את חוויית המשתמש. לכן אנו מסתכלים על החציון ועל האחוזון ה-95–99 בנפרד — הזנב מתכווץ בצורה מורגשת יותר מהחציון, כי מה שנעלם הוא לא העבודה הממוצעת אלא ענפים נדירים ויקרים: בנייה מחדש של הגרף, העתקות מיותרות של טנסורים, המתנה בתור.

ניצולת הציוד מראה היכן בדיוק מתבזבז הזמן. עומס נמוך של המחשב בזמן תור מלא אומר שהעבודה תקועה בהכנת נתונים; התמונה ההפוכה — פגיעה בתפוקת הזיכרון. כשהפרופילים האלה מתיישרים, צומת אחד מחזיק את אותה תעבורה בלי להוסיף חומרה.

תוצאה נפרדת — מחלקת תקלות שהוסרה. תחת עומס שיא הבקשות הצטברו בתור, פגו זמני המתנה, לקוחות חזרו על קריאות והגבירו את העומס.

מרווח תפוקה והשהיה צפויה מסירים את המפל הזה כולו, וחימום אחרי עלייה מפסיק לאכול את הפניות הראשונות: ריצות חימום ומטמון לשימוש חוזר של גרפים מקומפלים הופכים את הצומת למוכן לעומס מיד אחרי העלייה.

מצבי האצה: השוואת גישות ומגבלות

מצבי ההאצה לא מחליפים זה את זה — הם מונחים בשכבות, וכל אחד נוסף דורש מרווח בזיכרון או בדיוק. ONNX Runtime מפעיל אותם בנפרד, אבל הבחירה מתחילה במה שדווקא נתקע: זמן החישוב, נפח המודל או ההמתנה בתור.

מצב מתי מתאים מגבלות
אופטימיזציית גרף חישוב מודל מוכן, אין לשנות משקלים, נדרש רווח בלי אימון מחדש עוזר רק בצירופי אופרטורים שאפשר למזג; בגרף דליל האפקט קרוב לאפס
כימות משקלים חסר זיכרון או נדרשת עבודה על מעבד בלי מאיץ ירידת דיוק בשכבות רגישות — חובה בדיקה על הסט שלכם; חלק מהפעולות נשארות בדיוק מלא
עיבוד בקשות באצוות הרבה פניות מקבילות ויש מרווח בזיכרון ההשהיה של תגובה בודדת גדלה, בבקשות בודדות אין טעם
מטמון בקשות חוזרות פניות תבניתיות: תשובות עזר, סימון, סיווג חסר תועלת בבקשות ייחודיות, דרושה מדיניות איפוס ומקום לאחסון
מעבד בלבד, בלי מאיץ המאיץ לא זמין או שהעומס נדיר ההשהיה גבוהה בסדר גודל, תקרת הבקשות המקבילות נמוכה יותר

בפועל משלפים מצבים: משקלים מכווצים יחד עם אופטימיזציית גרף נותנים את הרווח הגדול ביותר, המטמון מסיר פניות חוזרות לפני החישוב, ועיבוד באצוות מופעל היכן שהשהיית התגובה אינה קריטית.

כל שילוב אנחנו מריצים על הסט שלכם ומשווים את התשובות למופת בדיוק מלא — אחרת ההאצה תתברר ככזו ששולמה עבורה בשגיאות שקטות של המודל.

שלבי העבודה: מביקורת צווארי בקבוק עד מסירת התוצאה

מתחילים במדידות, ולא בתיקון התצורה: בלי פרופיל של האינפרנס הנוכחי כל אופטימיזציה הופכת לניחוש. אנחנו מודדים כמה זמן לוקח לעיבוד-מקדים, למעבר עצמו במודל ולעיבוד-בתר, ורק אחרי זה מחליטים מה לשנות. להלן — סדר העבודה שכל פרויקט עובר.

  1. ביקורת ומדידות ביצועים. אנחנו לוקחים פרופיל על התפלגות עומס אמיתית, ולא סינתטית. מפרידים את הזמן לפי שלבים, בוחנים ניצולת מאיץ, דליפות זיכרון ותורי בקשות — צוואר הבקבוק מתגלה עוד לפני תחילת העבודה.
  2. תרשים פריסה. קובעים היכן המודל פועל: על מעבד, על מאיץ או היברידי, כמה עותקים מעלים, איך מקבצים בקשות לאצוות ומה מחזיקים במטמון. התרשים נקבע לפני ההגדרה, אחרת האופטימיזציה נתקעת בארכיטקטורה.
  3. הגדרת האינפרנס. ממירים את המודל לייצוג הביניים ONNX Runtime, מפעילים כימות, מתאימים ספק ביצוע ומיזוג אופרטורים. משנים פרמטרים אחד-אחד, עם מדידה אחרי כל צעד.
  4. סט בקשות מופת. אוספים בקשות מהפעלה אמיתית, כולל ארוכות ובעלות מקרה קצה. עליהן מחשבים השהיה ותפוקה לפני ואחרי — המספרים חייבים לשחזר גם בצד שלכם.
  5. בקרת איכות התשובות. משווים את הפלט של המודל המאופטם ושל המקורי על סט המופת, מתעדים את שיעור ההתאמות ואת ניתוח החריגות. אם האיכות יורדת מתחת לסף המוסכם, מחזירים את התצורה ומחפשים מצב אחר.
  6. מסירה והדרכת הצוות. מוסרים תצורות, סקריפטים לשחזור מדידות, סדר עדכון המודל וניתוח תקלות אופייניות. מעבירים הדרכה: המהנדסים שלכם צריכים לדעת לחזור על המדידה ולפרוס את הבנייה בלעדינו.

הסדר עקרוני: מדידות לפני הגדרה, בדיקת איכות לפני מסירה. אחרת האצת התגובה מתגלגלת לרגרסיות שמציפות רק בהפעלה — ואז צריך לחזור אחורה על שירות חי.

חבילת המסירה: תצורות, תרשימים ותקנונים

הפרויקט לא מסתיים בשירות עובד — לצוות שלכם נשאר סט ארטיפקטים שלפיו אפשר לעדכן, להרחיב ולשחזר את המערכת בלעדינו. להלן — מה בדיוק אנחנו מוסרים ולמה כל מסמך נדרש בפועל.

  • תצורות סביבה — קבצי פרמטרים להפעלה, מגבלות זיכרון ותהליכי מעבד, הגדרות עיבוד בקשות באצוות. עם הערות: איזה פרמטר לשנות עם גידול העומס, ואיזה אסור לגעת בו בלי אימון מחדש של המודל.
  • תרשים פריסה — טופולוגיית השירותים, היכן יושב המודל, היכן המטמון, אילו צמתים מתרחבים אופקית ואילו דורשים רזרבה.
  • מדיניות גישה ותפקידים — חלוקת הרשאות: מי מפרסם גרסה חדשה של המודל, מי קורא יומנים ומדדים, מי משנה תצורה. עם מטריצת תפקידים ותיאור חשבונות שירות.
  • תיעוד תפעול — תקנון הפעלה ועצירה, בדיקת תקינות השירות, ניתוח תקלות אופייניות עם סימפטומים ופעולות התורן.
  • תקנון עדכון וחזרה לגרסה קודמת — סדר פרסום בנייה חדשה של המודל, זמן החזרה לקודמת ותנאים שבהם החזרה מופעלת אוטומטית.
  • סט מדדים וספים — אילו מדדים נלקחים, באילו ערכים מופעלת התראה, ואיך להבדיל בין ירידת איכות התשובות לתקלת רשת.
  • הוראות לשחזור הסביבה — מניפסטים של בנייה ותלויות, כדי לפרוס סטנד מאפס על מכונה אחרת.

כל מסמך אנחנו כותבים עבור מבצע מסוים: מהנדס תורן, מפתח או מנהל. סט כזה מסיר את התלות בקבלן — השינויים מבוצעים בכוח הצוות שלכם, ואנחנו נשארים בקשר למקרים מורכבים.

מקרה בוחן: איך צמצמנו את זמן התגובה של המודל בחצי

המשימה הגיעה משירות תמיכה פנימית: עובדים שאלו שאלה על בסיס הידע והמתינו לתשובה בחלון הצ'אט. בשיא צומת העבודה הגיע לעומס מלא, תור הבקשות גדל, חלק מהפניות נשרו בגלל זמן המתנה — אנשים חזרו לחיפוש ידני במסמכים.

הניתוח התחיל במדידות: מדדנו כמה זמן לוקח להכנת הנתונים, לפלט המודל עצמו ולהרכבת התשובה. את רוב הזמן אכל לא המודל, אלא בנייה מחדש מתמדת של גרף החישוב עבור כל קריאה ופירוק הבקשות אחת-אחת.

הגרף הועבר ל-ONNX Runtime, צורת הקלטים קובעה, הופעלו מיזוג אופרטורים ומטמון מצבי ביניים, והמשקלים הובאו לייצוג שלם.

מדידות לפני ואחרי

  • זמן התגובה של המודל — מ-3.2 ל-1.3 שניות על אותה חומרה;
  • עומס שיא של הצומת — מ-94 ל-58 אחוזים;
  • מספר הצמתים לאותה תעבורה — חצי;
  • שיעור התשובות שהתאימו לסימון המופת — 93 אחוזים לפני ואחרי.

השירות מחזיק תעבורת שיא בלי תור ובלי תקלות, והמרווח בצמתים מאפשר להגדיל עומס בלי רכישה דחופה של שרתים. הלקוח קיבל קו מדידות לשחזור: כל ריצה עוקבת משווית לקו הבסיס המקובע, ולכן האפקט של כל אופטימיזציה נראה מיד.

מה לעשות אם המודל כבר פרוס ומגיב לאט

מודל פרוס לעיתים רחוקות מאט בגלל הארכיטקטורה. לרוב הזמן הולך לעיבוד-מקדים, להמתנה בתור, לסריאליזציה של התשובה ולחישובים מיותרים, והפלט עצמו תופס נתח קטן יותר.

לכן הצעד הראשון — לפרק את ההשהיה לפי שלבים: מדידות בכניסה, ביציאה של המודל ובמסירה ללקוח מראות היכן בדיוק מתבזבז הזמן, ורק אחרי זה בוחרים מה לגעת בו.

אם אי אפשר לשנות את החוזה, עובדים ברמת הסביבה, וקוד האפליקציה נשאר אותו דבר. המודל מועבר לייצוג ביניים של גרף: ONNX Runtime אופטימיזציית אינפרנס מאפשרת בחירת ספק ביצוע, ופעולות כבדות עוברות למאיץ, והשאר נשאר על המעבד.

מספר תהליכי העבודה, גודל האצווה ורמת אופטימיזציית הגרף נקבעים בתצורה — אלה הגדרות, לא כתיבה מחדש של הלוגיקה.

הלאה — נפח החישובים ועבודה חוזרת. כימות משקלים מקטין את גודל המודל ומאיץ את המעבר הישיר בלי אימון מחדש; שימוש חוזר בהקשר המחושב מסיר חישוב חוזר בכל צעד יצירה; עיבוד באצוות מיישר את העומס בשיאים. כל צעד הפיך, והתשובות לפני ואחרי מושוות — לפי הפער רואים היכן האיכות ירדה.

מתקינים את זה בהדרגה: הגרסה המאופטמת פועלת לצד הנוכחית, מקבלת עותק של התעבורה, והמדדים נלקחים על בקשות חיות — השהיה, שיעור תקלות, התאמת תשובות. המעבר נעשה בהעברת תעבורה, והחזרה — בהחזרת הארטיפקט הקודם, ולכן הסיכון מוגבל לריליס אחד. הקלטים, הפלטים ותרשים התשובה לא משתנים, ושירותים חיצוניים לא מבחינים בהחלפת הריצה.

מפרקים ספקות טכניים נפוצים של לקוחות

אופטימיזציית אינפרנס נתקעת לא בבחירת הכלי, אלא ביכולת לבדוק את התוצאה: חשוב לדעת היכן בדיוק מתבזבזת האיכות, האם המדידה תחזור על סטנד אחר ומה יקרה לשירות שכבר פועל. ONNX Runtime כאן הוא מבצע, וההחלטות מתקבלות לפי מדדים.

האם כימות שובר את דיוק המודל?

הבאת משקלים לייצוג 8-ביט אכן משנה את הפלט, ולכן את האובדן מודדים, ולא משערים. אנחנו מריצים סט בקשות מופת לפני ואחרי האופטימיזציה ומשווים את איכות התשובות עם שיעור החריגות.

אם הירידה חורגת מהסף המוסכם, שכבות רגישות נשארות בדיוק מלא ומאיצים רק את הכבדות — המהירות עולה, והאיכות נשארת במסלול.

איך בודקים את התוצאה, ולא רק את המהירות?

אוספים סט רגרסיה מהבקשות האמיתיות שלכם עם תשובות מופת. כל וריאנט תצורה רץ עליו, ומתועדים גם האיכות וגם ההשהיה, והבחירה נעשית לפי עקומת «איכות — מהירות», ולא לפי מדידה מוצלחת אחת.

האם המדידות שחזרו על מכונה אחרת?

למדידה יש משמעות רק אם היא חוזרת על עצמה. אנחנו מקבעים את גרסת המודל, פרמטרי היצירה, הרכב הסט ומצב החימום, מריצים סדרה של פעמים ובוחנים את הפיזור. בדוח נשארים תיאור הסטנד ופקודת ההפעלה — אתם בודקים מחדש את המספרים אצלכם.

מה עם דרישות החומרה והחזרה אחורה?

האצה על מעבד לא דורשת מאיצים נפרדים, והווריאנט עם הם נותן רווח רק בעומס מספיק. קודם לוקחים פרופיל של העומס הנוכחי ומתאימים תצורה אליו. המעבר נעשה בשלבים: תצורה חדשה מופעלת לצד הישנה, והחזרה נעשית בהחלפה בלי בנייה מחדש של השירות.

נדון במשימה: נכין תוכנית והערכה

כדי שתוכנית העבודה תהיה ריאלית ולא כללית, צריך הקשר קצר: היכן כרגע מחושב המודל, איזו תגובה לבקשה נחשבת לקבילה, כמה פניות מגיעות בשיא והאם יש דרישות להחזיק את הנתונים בתוך הקונטור.

זה מספיק כדי להציע תרשים אופטימיזציית אינפרנס קונקרטי — על מעבד או מאיץ — ולנקוב בלוחות זמנים לפי שלבים.

  • מה נדרש מכם: תרחיש שימוש — יצירה, סיווג או חיפוש בבסיס ידע, בתוספת מדידות השהיה ותפוקה נוכחיות.
  • מגבלות חומרה: אילו מעבדים ומאיצים זמינים, האם אפשר לשנות תצורת מכונות, האם יש מגבלות זיכרון.
  • דרישות לקונטור: היכן מותר לעבד נתונים, האם יש מקטעים סגורים, אילו כללי גישה חלים.
  • מה אנחנו מחזירים: תוכנית עבודה לפי שלבים עם הערכת זמנים לכל אחד — מנטילת מדידות והכנת המודל ועד לפריסה בסביבת העבודה.
  • סדר התקשורת: נקודת קשר אחת מצידנו, סטטוס פעם בשבוע במייל או בשיחה קצרה, גישה לסביבת בדיקה לאימות התוצאה.
  • קריטריוני קבלה: ערכי השהיה ותפוקה שנקבעו לפני ההתחלה, ולפיהם אנו מחשיבים את התוצאה כמושגת.
  • תוכנית חזרה אחורה: איך חוזרים לתצורה המקורית אם אחרי הפריסה המדדים יתבררו כגרועים יותר.

תארו את המשימה בצורה חופשית — נחזור עם תוכנית עבודה והערכת זמנים. אם לא יהיה די בנתוני הפתיחה בשביל דיוק, נשאל שאלות ממוקדות ונציין מיד מה מזה משפיע על משך הביצוע.