סנכרון

כלים לקביעת לוח זמנים

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

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

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

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

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

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

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

סנכרון חותמת זמן

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

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

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

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

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

מדיניות קלט

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

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

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

  • קבוצות קלט מעובדות בסדר יורד של חותמות זמן.

  • אף חבילות לא נופלות והעיבוד הוא לחלוטין דטרמיניסטי.

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

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

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

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

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

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

בקרת זרימה

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

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

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