משתמשים עם הרשאה ל-GPU ב-LiteRT

שימוש במעבדים גרפיים (GPU) כדי להריץ את המודלים של למידת מכונה (ML) יכול לשפר באופן משמעותי את הביצועים של המודל ואת חוויית המשתמש של האפליקציות שמופעלות על ידי למידת מכונה. ‫LiteRT מאפשר שימוש במעבדי GPU ובמעבדים מיוחדים אחרים באמצעות מנהל התקן של חומרה שנקרא delegates. הפעלת השימוש ב-GPU באפליקציות LiteRT ML יכולה לספק את היתרונות הבאים:

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

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

תמיכה בפעולות של למידת מכונה ב-GPU

יש כמה מגבלות על הפעולות של TensorFlow ML, או ops, שאפשר להאיץ באמצעות נציג ה-GPU של LiteRT. הנציג תומך בפעולות הבאות בדיוק של נקודה צפה של 16 ביט ו-32 ביט:

  • ADD
  • AVERAGE_POOL_2D
  • CONCATENATION
  • CONV_2D
  • DEPTHWISE_CONV_2D v1-2
  • EXP
  • FULLY_CONNECTED
  • LOGICAL_AND
  • LOGISTIC
  • LSTM v2 (Basic LSTM only)
  • MAX_POOL_2D
  • MAXIMUM
  • MINIMUM
  • MUL
  • PAD
  • PRELU
  • RELU
  • RELU6
  • RESHAPE
  • RESIZE_BILINEAR v1-3
  • SOFTMAX
  • STRIDED_SLICE
  • SUB
  • TRANSPOSE_CONV

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

פתרון בעיות בתמיכה ב-GPU

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

WARNING: op code #42 cannot be handled by this delegate.

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

דוגמאות למודלים

המודלים הבאים לדוגמה מבוססים על LiteRT כדי לנצל את היתרונות של האצת GPU, והם מסופקים לצורך עיון ובדיקה:

אופטימיזציה של יחידות GPU

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

  • פעולות שינוי צורה – חלק מהפעולות שמתבצעות במהירות במעבד עשויות להיות יקרות מאוד במעבד הגרפי במכשירים ניידים. פעולות שינוי צורה הן יקרות במיוחד להרצה, כולל BATCH_TO_SPACE,‏ SPACE_TO_BATCH,‏ SPACE_TO_DEPTH וכן הלאה. כדאי לבדוק היטב את השימוש בפעולות reshape, ולזכור שאולי הן הוחלו רק כדי לבדוק נתונים או כדי לבצע איטרציות מוקדמות של המודל. הסרת מילות המפתח האלה יכולה לשפר משמעותית את הביצועים.

  • Image data channels – ב-GPU, נתוני טנסור נפרסים ל-4 ערוצים, ולכן חישוב של טנסור עם הצורה [B,H,W,5] מתבצע בערך באותו אופן כמו חישוב של טנסור עם הצורה [B,H,W,8], אבל באופן גרוע משמעותית מאשר חישוב של טנסור עם הצורה [B,H,W,4]. אם חומרת המצלמה שבה אתם משתמשים תומכת בפריימים של תמונות ב-RGBA, הזנת הקלט הזה עם 4 ערוצים מהירה משמעותית, כי היא מונעת העתקה של הזיכרון מ-RGB עם 3 ערוצים ל-RGBX עם 4 ערוצים.

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

תמיכה מתקדמת ב-GPU

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

שימוש במודלים שעברו קוונטיזציה

בקטע הזה מוסבר איך נציג ה-GPU מאיץ מודלים עם כימות של 8 ביט, כולל:

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

איך זה עובד?

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

  • טנסורים קבועים (כמו משקלים/הטיות) עוברים דה-קוונטיזציה פעם אחת בזיכרון של ה-GPU. הפעולה הזו מתרחשת כשההרשאה מופעלת עבור LiteRT.

  • הנתונים שמוזנים לתוכנית ה-GPU והנתונים שמופקים ממנה, אם הם עברו קוונטיזציה של 8 ביט, עוברים דה-קוונטיזציה וקוונטיזציה (בהתאמה) לכל היסק. הפעולה הזו מתבצעת ב-CPU באמצעות ליבות שעברו אופטימיזציה של LiteRT.

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

מידע על הפעלת התכונה הזו באמצעות נציג GPU זמין במאמרים הבאים:

קיצור זמן ההפעלה באמצעות סריאליזציה

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

C++‎

    TfLiteGpuDelegateOptionsV2 options = TfLiteGpuDelegateOptionsV2Default();
    options.experimental_flags |= TFLITE_GPU_EXPERIMENTAL_FLAGS_ENABLE_SERIALIZATION;
    options.serialization_dir = kTmpDir;
    options.model_token = kModelToken;

    auto* delegate = TfLiteGpuDelegateV2Create(options);
    if (interpreter->ModifyGraphWithDelegate(delegate) != kTfLiteOk) return false;
      

Java

    GpuDelegate delegate = new GpuDelegate(
      new GpuDelegate.Options().setSerializationParams(
        /* serializationDir= */ serializationDir,
        /* modelToken= */ modelToken));

    Interpreter.Options options = (new Interpreter.Options()).addDelegate(delegate);
      

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

  • לאחסן את נתוני הסריאליזציה בספרייה שלא נגישה לאפליקציות אחרות. במכשירי Android, משתמשים ב-getCodeCacheDir(), שמפנה למיקום פרטי באפליקציה הנוכחית.
  • טוקן הדגם חייב להיות ייחודי למכשיר עבור הדגם הספציפי. אפשר לחשב טוקן של מודל על ידי יצירת טביעת אצבע מנתוני המודל באמצעות ספריות כמו farmhash::Fingerprint64.