7.7. Normalization¶
ml.Model.predict() מקבלת רשימה של קלטים מכיוון שלחלק מהרשתות יש יותר מטנזור קלט אחד, אך לרשימה אין דרך לשאת ארגומנטים לכל קלט באופן מוטמע – אין משבצת kwarg עבור ”חתוך את הקלט הזה אל (x, y, w, h) אך הותר את שאר הקלטים לבדם“. ml.preprocessing.Normalization הוא העוטף הממלא את הפער הזה. מופע Normalization מחזיק את הפרמטרים עבור קלט אחד; הסקריפט מעביר את הקלט העטוף ברשימת ה-predict בכל פעם שהוא צריך משהו מלבד ברירות המחדל.
הסיבה הנפוצה ביותר לפנות אליו היא לחתוך אזור מסוים של הפריים שנלכד אל הרשת במקום את התמונה כולה.
7.7.1. פרמטרים¶
Normalization(scale=(0.0, 1.0),
mean=(0.0, 0.0, 0.0),
stdev=(1.0, 1.0, 1.0),
roi=None)
roi– מלבן(x, y, w, h)בפריים המקור לחיתוך לפני שינוי הגודל. ברירת המחדל היא הפריים כולו. רוב השימושים ב-Normalizationמגדירים רק את הפרמטר הזה.scale– הטווח(min, max)שטנזורי קלט בנקודה צפה מצפים לו לאחר הנרמול. טווח הפיקסלים0..255ממופה באופן ליניארי לתוך טווח זה. ערכים נפוצים הם(0.0, 1.0)עבור רשתות שאומנו ב-ReLU ו-(-1.0, 1.0)עבור רשתות מנורמלות סימטרית.mean– ממוצע(R, G, B)לכל ערוץ המוחסר מהתמונה לאחר קנה המידה. תואם את סטטיסטיקות הערוצים שמולן הרשת אומנה –(0.485, 0.456, 0.406)עבור רשתות הנגזרות מ-ImageNet הוא הדוגמה הקנונית. רשתות גווני אפור מצמצמות את הממוצע לערך לומה (luma) באמצעות הנוסחה הסטנדרטית0.299*R + 0.587*G + 0.114*B.stdev– סטיית תקן(R, G, B)לכל ערוץ שהתמונה מחולקת בה לאחר חיסור הממוצע, שוב בהתאמה לסטטיסטיקות האימון של הרשת. מצומצמת ללומה (luma) באותו אופן עבור רשתות גווני אפור.
7.7.2. מתי הפרמטרים חשובים¶
scale, mean, ו-stdev מתעלמים מהם כאשר input_dtype של הרשת הוא int8 או uint8. עבור רשתות בעלות קלט שלם (integer), בייטי התמונה החתוכה נכתבים אל הטנזור ישירות, וה-input_scale וה-input_zero_point של הרשת עצמה מטפלים בהמרה משלם לממשי. שלושת הפרמטרים חשובים רק כאשר הרשת מצפה לקלט בנקודה צפה.
roi נקרא בכל מקרה – הוא שולט באיזה חלק של פריים המקור מגיע אל הרשת בלי קשר ל-input dtype.
7.7.3. ROI ושינוי גודל¶
ה-ROI מותאם בקנה מידה דו-ליניארי מממדי המקור שלו אל ממדי הקלט של הרשת. התמונה ממורכזת ביעד וקנה המידה ממלא את היעד – הוא אינו משמר את יחס הגובה-רוחב. ROI שאינו ריבועי שמוזן אל קלט רשת ריבועי יוצא מתוח אופקית או אנכית.
האם המתיחה חשובה תלוי ברשת. מודלי זיהוי פנים ונקודות ציון כמו משפחת MediaPipe (BlazeFace, FaceLandmarks, HandLandmarks, MoveNet) אומנו מול חיתוכים ריבועיים ומתדרדרים במהירות כאשר יחס הגובה-רוחב של הקלט סוטה; עבורם, היישום צריך לתת להם ROI ריבועי – בין על ידי לכידה בגודל פריים ריבועי באמצעות window() ובין על ידי חיתוך עם הפרמטר roi=. מזהי עצמים ממשפחת YOLO מאומנים בדרך כלל עם הגברה (augmentation) הכוללת מתיחות אקראיות ומקבלים ROI שאינו ריבועי ללא אובדן דיוק רב; העברת הפריים הנלכד המלא ישר פנימה היא בדרך כלל בסדר.
כאשר ממדי הקלט של הרשת תואמים את ה-ROI במדויק, קנה המידה מתמוטט להעתקה, שהיא המקרה הזול ביותר.
7.7.4. גבירה על ברירת המחדל¶
predict() עוטפת כל קלט image.Image ב-Normalization() באופן אוטומטי – עם פרמטרי ברירת המחדל לעיל. רוב המודלים שמגיעים עם המצלמה אומנו מול טווחי פיקסלים שברירות המחדל כבר מכסות, ולכן המקרה הנפוץ הוא להעביר את התמונה ישירות:
result = model.predict([img])
כדי להשתמש ב-ROI מותאם אישית – הגבירה הנפוצה ביותר – בנו Normalization עם ה-ROI מוגדר וקשרו אליו את התמונה:
from ml.preprocessing import Normalization
norm = Normalization(roi=(80, 60, 160, 120))
result = model.predict([norm(img)])
כדי להתאים לסטטיסטיקות הערוצים מזמן האימון של הרשת, הגדירו את הפרמטרים בנקודה צפה:
norm = Normalization(scale=(0.0, 1.0),
mean=(0.485, 0.456, 0.406),
stdev=(0.229, 0.224, 0.225))
result = model.predict([norm(img)])
קריאה למופע Normalization על התמונה מחזירה מופע קשור חדש שמתוכו המנוע ממלא את הטנזור. המופע הקשור הוא מה ש-predict מקבלת במקום התמונה הגולמית, ומכיוון שזהו אובייקט לכל קלט, רשת רב-קלטית יכולה לשלב תמונות עם ROI שונים באותה רשימת predict.
עבור רשתות המצפות לקלטים שהיישום כבר ייצר בצורת טנזור – חוצץ (buffer) מהתקן היקפי, ndarray שחושב על ידי צינור אחר, נתונים מספריים שאינם תמונה – דלגו על Normalization כליל והעבירו את ה-ndarray או ישות בת-קריאה (callable) המייצרת אותו. predict() מעבירה אותם הלאה אל המנוע ללא עטיפה.