7.3. Hello BlazeFace¶
BlazeFace 是來自 Google MediaPipe 集合的一個人臉偵測神經網路。單一次推論呼叫會回傳一個圍繞每張偵測到的人臉的邊界矩形,以及六個臉部特徵點——右眼、左眼、鼻子、嘴巴、右耳、左耳。每一台隨附神經網路支援的 OpenMV Cam 都在 flash 上攜帶了 blazeface_front_128.tflite 模型,因此執行一個端對端的人臉偵測器只需幾行 Python。
7.3.1. 完整指令碼¶
import csi
import ml
from ml.postprocessing.mediapipe import BlazeFace
csi0 = csi.CSI()
csi0.reset()
csi0.pixformat(csi.RGB565)
csi0.framesize(csi.VGA)
csi0.window((400, 400))
model = ml.Model("/rom/blazeface_front_128.tflite",
postprocess=BlazeFace(threshold=0.4))
while True:
img = csi0.snapshot()
for (x, y, w, h), score, keypoints in model.predict([img]):
img.draw_rectangle((x, y, w, h), color=(0, 255, 0))
ml.utils.draw_keypoints(img, keypoints, color=(255, 0, 0))
這就是整個人臉偵測器。沒有別的了;指令碼擷取一個影格、將其交給模型、走訪回傳的偵測清單,並將每張人臉的邊界矩形連同其六個特徵點繪製回影格中。IDE 預覽會即時顯示這些方框與特徵點。
7.3.2. 每一行的作用¶
前三行匯入指令碼所需的模組。csi 是相機感測器介面;ml 是本章其餘部分所討論的機器學習模組;BlazeFace 則是將 BlazeFace 的原始輸出張量轉換成指令碼所迭代的邊界框與特徵點清單的後處理器。
接下來五行設定 sensor。相機被重設到一個已知狀態、設為 RGB565 色彩、設為 VGA 解析度,然後開窗到一個 400×400 的正方形。這個窗很重要:BlazeFace 是在正方形裁切上訓練的,給它一個正方形輸入能讓網路所預期的長寬比與它在擷取到的影格中所看到的對齊。
載入模型的這一行開啟模型檔案:
model = ml.Model("/rom/blazeface_front_128.tflite",
postprocess=BlazeFace(threshold=0.4))
ml.Model 讀取指定路徑下的檔案——/rom/ 是一個稍後會介紹的常駐於 flash 的檔案系統——並回傳一個指令碼將對其執行推論的模型物件。postprocess= 關鍵字註冊了 BlazeFace 後處理器;若沒有它,predict 會回傳網路的原始輸出張量,應用程式就必須手動解碼它們。有了它,predict 則直接回傳解碼後的結果。後處理器上的 threshold=0.4 引數設定了在保留一個偵測之前網路必須回報的最低信賴度;較低的值能捕捉到較模糊的人臉,但代價是更多誤判。
其餘四行是主迴圈。每一輪都會擷取一個影格,並詢問模型它看到了什麼:
img = csi0.snapshot()
for (x, y, w, h), score, keypoints in model.predict([img]):
img.draw_rectangle((x, y, w, h), color=(0, 255, 0))
ml.utils.draw_keypoints(img, keypoints, color=(255, 0, 0))
predict() 接收一個輸入清單(此處為一張擷取到的影像),並回傳一個偵測元組(tuple)清單。每個元組包含邊界矩形 (x, y, w, h)、一個介於零與一之間的信賴度 score,以及一個 (6, 2) 的特徵點座標 ndarray——依序為右眼、左眼、鼻子、嘴巴、右耳與左耳。繪製呼叫使用 draw_rectangle()——與影像章節中每個傳統偵測器最後所用的相同基本指令——來描繪人臉的輪廓。ml.utils.draw_keypoints() 則是 ml 工具中的一個小型輔助函式,它在每個關鍵點的 (x, y) 位置以一個十字標記之。
7.3.3. 指令碼沒有說明的部分¶
撇開匯入與感測器設定,這支指令碼只有七行可執行的推論工作,但在這七行裡卻發生了大量的算術運算。擷取到的 400×400 RGB565 影格在抵達網路之前會變成一個 128×128 的量化 8 位元張量;網路針對數萬個權重執行數百個運算;產生的信賴度分數張量與方框偏移張量則在 predict 回傳之前變成一個附帶特徵點、互不重疊且經過排序的邊界框清單。這些轉換中的每一個,在應用程式有需要時都能夠加以控制,而其中有幾個對於任何非預設的模型都必須加以調校。
接下來的四個小節會逐一拆解這些轉換。依序為:
ml 模組——模型載入後
ml.Model公開了什麼,以及模型檔案實際上存放在相機的何處。推論管線——每一次
predict()呼叫的四個階段。推論引擎——執行網路算術的 CPU 與 NPU 路徑。
解碼輸出——將原始輸出張量轉換成這支指令碼所迭代的偵測結果的後處理器。
到本章結束時,讀者將能為一個並非隨相機出貨的模型撰寫等效的指令碼、解碼一個其後處理器尚不存在的張量,並推理出為何某個特定模型在某台相機上以 30 FPS 執行,而在另一台上卻只有 3 FPS。