7.7. Normalization

ml.Model.predict() nhận một danh sách đầu vào vì một số mạng nơ-ron có nhiều hơn một tensor đầu vào, nhưng danh sách không có cách truyền các đối số theo từng đầu vào trực tiếp -- không có slot kwarg nào cho "cắt xén đầu vào này thành (x, y, w, h) nhưng để nguyên các đầu vào khác". ml.preprocessing.Normalization là wrapper lấp đầy khoảng trống đó. Một instance Normalization chứa các tham số cho một đầu vào; tập lệnh truyền đầu vào được bọc trong danh sách predict bất cứ khi nào cần gì khác ngoài giá trị mặc định.

Lý do phổ biến nhất để dùng nó là cắt xén một vùng cụ thể của khung hình đã chụp vào mạng nơ-ron thay vì toàn bộ ảnh.

7.7.1. Các tham số

Normalization(scale=(0.0, 1.0),
              mean=(0.0, 0.0, 0.0),
              stdev=(1.0, 1.0, 1.0),
              roi=None)
  • roi -- hình chữ nhật (x, y, w, h) trong khung hình nguồn để cắt xén trước khi thay đổi kích thước. Mặc định là toàn bộ khung hình. Hầu hết các cách dùng Normalization chỉ đặt tham số này.

  • scale -- phạm vi (min, max) mà các tensor đầu vào dạng số thực dấu phẩy động mong đợi sau khi chuẩn hóa. Phạm vi điểm ảnh 0..255 được ánh xạ tuyến tính vào phạm vi này. Các giá trị phổ biến là (0.0, 1.0) cho các mạng nơ-ron được huấn luyện với ReLU và (-1.0, 1.0) cho các mạng nơ-ron được chuẩn hóa đối xứng.

  • mean -- giá trị trung bình (R, G, B) theo từng kênh được trừ đi từ ảnh sau khi tỷ lệ hóa. Khớp với thống kê kênh mà mạng nơ-ron được huấn luyện -- (0.485, 0.456, 0.406) cho các mạng nơ-ron từ ImageNet là ví dụ điển hình. Các mạng nơ-ron thang xám giảm giá trị trung bình thành giá trị luma bằng công thức chuẩn 0.299*R + 0.587*G + 0.114*B.

  • stdev -- độ lệch chuẩn (R, G, B) theo từng kênh mà ảnh được chia cho sau khi trừ giá trị trung bình, cũng khớp với thống kê huấn luyện của mạng nơ-ron. Được giảm thành luma theo cách tương tự cho các mạng nơ-ron thang xám.

7.7.2. Khi nào tham số quan trọng

scale, mean, và stdev bị bỏ qua khi input_dtype của mạng nơ-ron là int8 hoặc uint8. Đối với các mạng nơ-ron đầu vào số nguyên, các byte ảnh đã cắt xén được ghi trực tiếp vào tensor và input_scaleinput_zero_point của mạng nơ-ron xử lý việc chuyển đổi số nguyên sang thực. Ba tham số chỉ quan trọng khi mạng nơ-ron mong đợi đầu vào dạng số thực dấu phẩy động.

roi được đọc trong mọi trường hợp -- nó kiểm soát phần nào của khung hình nguồn đến được mạng nơ-ron bất kể dtype đầu vào là gì.

7.7.3. ROI và thay đổi kích thước

ROI được co giãn song tuyến từ kích thước nguồn của nó đến kích thước đầu vào của mạng nơ-ron. Ảnh được căn giữa trong đích và tỷ lệ lấp đầy đích -- không bảo tồn tỷ lệ khung hình. Một ROI không vuông được đưa vào đầu vào mạng nơ-ron vuông sẽ bị kéo dài theo chiều ngang hoặc chiều dọc.

Việc kéo dài có quan trọng hay không phụ thuộc vào mạng nơ-ron. Các mô hình (ML) phát hiện khuôn mặt và điểm đặc trưng như họ MediaPipe (BlazeFace, FaceLandmarks, HandLandmarks, MoveNet) được huấn luyện trên các vùng cắt xén vuông và giảm độ chính xác nhanh khi tỷ lệ khung hình đầu vào bị sai; với các mô hình (ML) này, ứng dụng cần cung cấp ROI vuông -- hoặc bằng cách chụp ở kích thước khung hình vuông qua window() hoặc bằng cách cắt xén với tham số roi=. Các bộ phát hiện đối tượng họ YOLO thường được huấn luyện với tăng cường dữ liệu bao gồm các phép kéo dài ngẫu nhiên và chấp nhận ROI không vuông mà không mất nhiều độ chính xác; truyền toàn bộ khung hình đã chụp trực tiếp vào thường là ổn.

Khi kích thước đầu vào của mạng nơ-ron khớp chính xác với ROI, tỷ lệ thu gọn thành một phép sao chép, đây là trường hợp rẻ nhất.

7.7.4. Ghi đè giá trị mặc định

predict() bọc mỗi đầu vào image.Image với Normalization() tự động -- các tham số mặc định ở trên. Hầu hết các mô hình (ML) đi kèm với camera được huấn luyện trên phạm vi điểm ảnh mà giá trị mặc định đã bao phủ, vì vậy trường hợp phổ biến là truyền ảnh trực tiếp:

result = model.predict([img])

Để sử dụng ROI tùy chỉnh -- ghi đè phổ biến nhất -- xây dựng Normalization với ROI được đặt và gắn ảnh vào nó:

from ml.preprocessing import Normalization

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

Để khớp với thống kê kênh theo thời gian huấn luyện của mạng nơ-ron, đặt các tham số số thực dấu phẩy động:

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)])

Gọi instance Normalization trên ảnh trả về một instance mới đã gắn kết mà engine lấp đầy tensor từ đó. Instance đã gắn kết là những gì predict chấp nhận thay cho ảnh thô, và vì nó là đối tượng theo từng đầu vào, một mạng nơ-ron nhiều đầu vào có thể kết hợp các ảnh với ROI khác nhau trong cùng một danh sách predict.

Đối với các mạng nơ-ron mong đợi đầu vào mà ứng dụng đã tạo sẵn ở dạng tensor -- một bộ đệm từ ngoại vi, một ndarray được tính bởi pipeline khác, dữ liệu số không phải ảnh -- bỏ qua Normalization hoàn toàn và truyền ndarray hoặc một callable tạo ra nó. predict() truyền những thứ đó thẳng đến engine mà không bọc.