7.7. Normalization

ml.Model.predict() รับ รายการ ของอินพุตเพราะบางโครงข่ายมีเทนเซอร์อินพุตมากกว่าหนึ่งตัว แต่รายการไม่มีทางส่งอาร์กิวเมนต์ต่ออินพุตแบบ inline -- ไม่มีช่อง kwarg สำหรับ "ครอบตัด อินพุตนี้ เป็น (x, y, w, h) แต่ปล่อยอินพุตอื่น ๆ ไว้" ml.preprocessing.Normalization คือ wrapper ที่เติมช่องว่างนั้น อินสแตนซ์ Normalization เก็บพารามิเตอร์สำหรับอินพุตหนึ่งตัว สคริปต์ส่ง wrapped input ในรายการ 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) ที่เทนเซอร์อินพุต floating-point คาดหวังหลัง normalization ช่วงพิกเซล 0..255 จะถูกแมปเชิงเส้นเข้าสู่ช่วงนี้ ค่าทั่วไปคือ (0.0, 1.0) สำหรับโครงข่ายที่ฝึกด้วย ReLU และ (-1.0, 1.0) สำหรับโครงข่ายที่ normalize แบบสมมาตร

  • mean -- ค่าเฉลี่ยต่อช่องสัญญาณ (R, G, B) ที่ถูกลบออกจากภาพหลังการ scaling ตรงกับสถิติช่องสัญญาณที่โครงข่ายถูกฝึกมา -- (0.485, 0.456, 0.406) สำหรับโครงข่ายที่มาจาก ImageNet เป็นตัวอย่างที่เป็นต้นแบบ โครงข่าย grayscale จะลด mean ให้เป็นค่า luma โดยใช้สูตรมาตรฐาน 0.299*R + 0.587*G + 0.114*B

  • stdev -- standard deviation ต่อช่องสัญญาณ (R, G, B) ที่ภาพถูกหารด้วยหลังจากลบ mean แล้ว ตรงกับสถิติการฝึกของโครงข่ายเช่นกัน ลดเป็นค่า luma ในลักษณะเดียวกันสำหรับโครงข่าย grayscale

7.7.2. เมื่อพารามิเตอร์มีความสำคัญ

scale, mean, และ stdev จะถูกเพิกเฉยเมื่อ input_dtype ของโครงข่ายเป็น int8 หรือ uint8 สำหรับโครงข่ายที่รับอินพุตจำนวนเต็ม ไบต์ภาพที่ครอบตัดจะถูกเขียนลงในเทนเซอร์โดยตรง และ input_scale และ input_zero_point ของโครงข่ายจะจัดการการแปลง int-to-real พารามิเตอร์ทั้งสามมีความสำคัญเฉพาะเมื่อโครงข่ายคาดหวังอินพุต floating-point

roi จะถูกอ่านในทุกกรณี -- มันควบคุมว่าส่วนใดของเฟรมต้นฉบับที่จะส่งถึงโครงข่ายโดยไม่คำนึงถึง input dtype

7.7.3. ROI และการปรับขนาด

ROI จะถูก scale แบบ bilinear จากขนาดต้นฉบับเป็นขนาดอินพุตของโครงข่าย ภาพจะถูกจัดตรงกลางในปลายทางและการ scaling จะเติมเต็มปลายทาง -- ไม่ได้รักษา aspect ratio ROI ที่ไม่เป็นสี่เหลี่ยมจัตุรัสที่ป้อนให้กับอินพุตโครงข่ายแบบสี่เหลี่ยมจัตุรัสจะออกมาแบบถูกยืดตามแนวนอนหรือแนวตั้ง

ว่าการยืดมีความสำคัญหรือไม่ขึ้นอยู่กับโครงข่าย โมเดลการตรวจจับใบหน้าและ landmark อย่างตระกูล MediaPipe (BlazeFace, FaceLandmarks, HandLandmarks, MoveNet) ถูกฝึกกับ crop แบบสี่เหลี่ยมจัตุรัสและประสิทธิภาพลดลงอย่างรวดเร็วเมื่อ aspect ratio ของอินพุตผิดเพี้ยน สำหรับโมเดลเหล่านั้น แอปพลิเคชันต้องให้ ROI แบบสี่เหลี่ยมจัตุรัส -- ไม่ว่าจะโดยการบันทึกที่ framesize แบบสี่เหลี่ยมจัตุรัสผ่าน window() หรือโดยการครอบตัดด้วยพารามิเตอร์ roi= detector วัตถุตระกูล YOLO มักถูกฝึกด้วย augmentation ที่รวม random stretch และรับ ROI ที่ไม่เป็นสี่เหลี่ยมจัตุรัสโดยไม่สูญเสียความแม่นยำมาก การส่งเฟรมที่บันทึกทั้งหมดเข้าไปตรง ๆ มักเป็นเรื่องปกติ

เมื่อขนาดอินพุตของโครงข่ายตรงกับ ROI พอดี การ scale จะกลายเป็นการคัดลอก ซึ่งเป็นกรณีที่ถูกที่สุด

7.7.4. การแทนที่ค่าเริ่มต้น

predict() จะ wrap อินพุต image.Image แต่ละตัวด้วย Normalization() โดยอัตโนมัติ -- พารามิเตอร์เริ่มต้นข้างต้น โมเดลส่วนใหญ่ที่มาพร้อมกับ cam ถูกฝึกกับช่วงพิกเซลที่ค่าเริ่มต้นครอบคลุมอยู่แล้ว ดังนั้นกรณีทั่วไปคือการส่งภาพโดยตรง:

result = model.predict([img])

เพื่อใช้ ROI ที่กำหนดเอง -- การแทนที่ที่พบบ่อยที่สุด -- สร้าง Normalization พร้อม ROI ที่ตั้งค่าและผูกภาพเข้ากับมัน:

from ml.preprocessing import Normalization

norm = Normalization(roi=(80, 60, 160, 120))
result = model.predict([norm(img)])

เพื่อให้ตรงกับสถิติช่องสัญญาณตอน training ของโครงข่าย ตั้งค่าพารามิเตอร์ floating-point:

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 instance บนภาพจะส่งคืน instance ที่ผูกใหม่ที่ engine ใช้เติมเทนเซอร์จาก instance ที่ผูกคือสิ่งที่ predict รับแทนภาพดิบ และเนื่องจากมันเป็น object ต่ออินพุต โครงข่ายที่มีหลายอินพุตจึงสามารถผสมภาพที่มี ROI ต่างกันในรายการ predict เดียวกันได้

สำหรับโครงข่ายที่คาดหวังอินพุตที่แอปพลิเคชันได้ผลิตในรูปแบบเทนเซอร์แล้ว -- บัฟเฟอร์จากอุปกรณ์ต่อพ่วง ndarray ที่คำนวณโดย pipeline อื่น ข้อมูลตัวเลขที่ไม่ใช่ภาพ -- ข้ามการใช้ Normalization ทั้งหมดและส่ง ndarray หรือ callable ที่ผลิตมันแทน predict() จะส่งผ่านสิ่งเหล่านั้นไปยัง engine โดยไม่ต้อง wrap