7.12. מעבדי-קצה

רשת זיהוי אינה פולטת תיבות. היא פולטת טנזור אחד או יותר שהמבנה שלהם תלוי בארכיטקטורה שנגדה אומן המודל – טנזור דו-ממדי של חיזויים מועמדים עבור גלאי ממשפחת YOLO, זוג טנזורים (boxes, scores) עבור גלאי MediaPipe, רשימה שטוחה של קואורדינטות נקודות מפתח עבור רשת תנוחה. היישום אינו יכול לקרוא אף אחד מהם ישירות; מה שהוא רוצה – רשימת תיבות, רשימת נקודות מפתח, פירוט לפי מחלקה – צריך להיות מפוענח מתוך הטנזור הגולמי.

המפענח הזה הוא מעבד-קצה. המודול ml.postprocessing מקבץ אותם לפי מערכת האקולוגית של המקור.

7.12.1. Darknet

ml.postprocessing.darknet מפענח מודלים מעידן YOLO המקורי. YOLO v2 הציג את רעיונות ה-grid וה-anchor שרוב הגלאים המאוחרים ירשו בצורה כלשהי, ולכן מבנה v2 הוא נקודת ההתחלה הנקייה ביותר.

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

בכל תא רשת, הרשת אינה חוזה תיבה יש מאין. היא בוחרת מבין כמה צורות התייחסות שנבחרו מראש הנקראות anchors – זוגות (width, height) קבועים שנגזרו לא-מקוון על ידי אשכול גדלי התיבות במערך האימון כך שיכסו את העצמים האופייניים שהמודל צפוי לראות. תפקיד הרשת בכל תא הוא לחזות, עבור כל anchor, היסט קטן למרכז התיבה בתוך התא, קנה מידה על הרוחב והגובה של ה-anchor, ציון objectness (הסבירות שמשהו נמצא שם), ווקטור הסתברות לכל מחלקה. רשת 13 על 13 עם 5 ה-anchors שבברירת המחדל ו-20 מחלקות פולטת אפוא 13 * 13 * 5 * (4 + 1 + 20) = 21,125 מספרים לכל הסקה.

YoloV2 מפענח את המבנה הזה: הוא עובר על התאים, מיישם את ההיסטים וקני המידה של כל anchor כדי לשחזר קואורדינטות תיבה מוחלטות, משלב objectness עם הסתברות מחלקה לציון לכל מחלקה, מבצע ספּוּף לפי סף, ודוחף את השורדים ל-NMS. המחלקה מקבלת ארגומנט בנאי anchors= כאשר המודל אומן נגד טבלת anchors מותאמת אישית ונסוגה לברירת מחדל מובנית אחרת. וריאנטים המכוונים לקבוצות מחלקה ספציפיות מסופקים באותו תת-מודול.

7.12.2. Ultralytics

ml.postprocessing.ultralytics מפענח את דורות YOLO החדשים יותר. YoloV8 קורא פלט בסדר עמודות (column-major) שבו כל עמודה היא חיזוי anchor יחיד המכיל קואורדינטות תיבה ווקטור ציונים לכל מחלקה – ערוץ ה-objectness שפלטי YOLO מוקדמים נשאו הוסר ב-v8, וציוני המחלקה עומדים בפני עצמם. הסקירה המודרכת של YOLOv8 עוברת על הפענוח טנזור-אחר-טנזור. גרסאות ישנות יותר מעידן Ultralytics מסופקות באותו תת-מודול עבור מודלים שאומנו נגד המבנים שלהן.

7.12.3. MediaPipe

ml.postprocessing.mediapipe מפענח את המשפחה הקלילה של Google למכשירי קצה. BlazeFace הוא גלאי הפנים המתואר ב-hello-blazeface: גלאי מהיר מבוסס-anchor שפולט תיבות ושש קואורדינטות ציון-דרך (landmark) לכל פנים, המוחזרות כ-tuples בצורת (box, score, keypoints) כאשר נקודות הציון מצורפות לכל תיבה ולא כרשימת פלט נפרדת. מודלים לזיהוי כפות ידיים, ציוני-דרך ותנוחה מאותה משפחה מסופקים לצידו ופועלים לפי אותה צורת החזרה של נקודות מפתח מצורפות.

7.12.4. בחירת אחד

מעבד-הקצה הנכון נקבע על פי הארכיטקטורה שנגדה אומן המודל, ולא על פי מה שהיישום רוצה. קובץ .tflite של YOLOv8 מפוענח נכון רק דרך YoloV8; קובץ .tflite של BlazeFace רק דרך BlazeFace. בחירת מעבד-הקצה היא חלק מבחירת המודל. כאשר ארכיטקטורת מודל אינה מיוצגת על ידי מעבד-קצה מובנה, כתיבת אחד משלכם היא פשוטה.

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