第三十九章 YOLO2人臉檢測實驗
從本章開始,將通過幾個實例介紹Kendryte K210上的KPU,以及CanMV下KPU的使用方法,本章將先介紹YOLO2網絡的人臉檢測應用在CanMV上的實現。通過本章的學習,讀者將學習到YOLO2網絡的人臉檢測應用在CanMV上的實現。
本章分為如下幾個小節:
39.1 maix.KPU模塊介紹
39.2 硬件設計
39.3 程序設計
39.4 運行驗證
39.1 maix.KPU模塊介紹
Kendryte K210片上擁有一個KPU,KPU是通用的神經網絡處理器,它可以在低功耗的情況下實現卷據神經網絡的計算,實時獲取被檢測目標的大小、坐標和種類,對人臉或者物體進行檢測和分類。
Kendryte K210片上KPU的主要特點如下所示:
1. 支持計算多層卷積神經網絡,每層卷積神經網絡的控制參數可單獨配置
2. 支持中斷模式,可配置加速器在每層卷積結束后是否產生中斷信號
3. 支持輸入圖像片上存儲,存儲容量大小為2M字節,卷積結果可由DMA讀出
4. 支持輸入輸出通道數目、輸入輸出圖像行高列寬可配置,其中通道數目范圍在1~1024之間,輸出行高列寬與輸入相同,或者是輸入處于2或者4且向下取整
5. 支持兩種卷積內核,分別為1*1和3*3,卷積步長為1,十種池化方式,包括bypass、步長為1且大小為2*2的均值、步長為1且大小為2*2的最大值、步長為2且大小為2*2的均值、步長為2且大小為2*2的最大值、步長為2且大小為2*2的左上值、步長為2且大小為2*2的右上值、步長為4且大小為4*4的均值、步長為4且大小為4*4的最大值、步長為4且大小為4*4的左上值
6. 支持兩種padding方式,分別為任意填充和取最近值
7. 支持在輸入圖像行高超過256時,自動對卷積結果進行抽樣,僅保留奇數行奇數列結果
8. 支持卷積參數、批歸一化參數、激活參數配置,AI加速器主動讀取,讀取地址可配置
9. 支持卷據參數片上存儲,存儲容量為72K字節,可以邊卷積邊讀取卷據參數,每層網絡最多可以讀取64次
10. 支持mobilenet-V1
11. 實時工作時最大支持神經網絡參數大小為5.5MiB到5.9MiB
12. 非實時工作最大支持網絡參數大小為Flash大小扣除軟件占用大小
在CanMV中可以使用CanMV提供的maix.KPU模塊操作Kendryte K210上的KPU。maix.KPU模塊對圖像進行卷積運算,并提供了一些網絡的支持,使得開發者能夠很方便地在Kendryte K210上使用CanMV實現一些需要卷積神經網絡計算的應用。
maix.KPU模塊提供了KPU構造函數,用于創建一個KPU對象,KPU構造函數如下所示:
class KPU()
通過KPU構造函數可以創建并初始化一個KPU對象。
KPU構造函數的使用示例如下所示:
from maix import KPU
kpu = KPU()
maix.KPU為KPU對象提供了load_kmodel()方法,用于從文件系統或Flash中加載網絡模型,load_kmodel()方法如下所示:
load_kmodel(path, size)
load_kmodel()方法用于為KPU對象從文件系統或Flash中加載網路模型,網絡模型加載后會被加載到內存中等待使用。
path指的是網絡模型在文件系統中的路徑或網絡模型在Flash中的起始地址。
size指的是網絡模型在Flash中的大小,當使用文件系統的方式加載網絡模型時,該參數無效。
load_kmodel()方法的使用示例如下所示:
from maix import KPU
kpu = KPU()
kpu.load_kmode("/sd/KPU/face_detect_320x240.kmodel")
maix.KPU模塊為KPU對象提供了init_yolo2()方法,用于初始化yolo2網絡模型,init_yolo2()方法如下所示:
KPU.init_yolo2(anchor=None, anchor_num=5, img_w=320, img_h=240, net_w=320, net_h=240, layer_w=10, layer_h=8, threshold=0.7, nms_value=0.4, classes=1)
init_yolo2()方法用于初始化yolo2網絡模型,同時為yolo2網絡傳入一些必要的參數,只有在使用YOLO2網絡模型時,才需要用到該方法。
anchor指的是錨點參數,錨點參數是網絡在訓練前就確定下來的一組數據,同一個網絡模型的錨點參數是固定的,錨點參數與網絡模型綁定。
anchor_num指的是錨點的數量,固定為len(anchor)//2,即錨點參數數據大小的一半。
img_w和img_h指的是輸入圖像的寬度和高度,這決定了畫框的邊界,如果輸入圖像是由一張小尺寸的圖像擴充來的,可以將這兩個參數設置為原圖的寬度和高度。
net_w和net_h指的是模型需要的圖像的寬度和高度,這是在網絡模型訓練前就確定好的,與網絡模型綁定。
layer_w和layer_h指的是網絡模型的層寬和層高,這是在網絡模型訓練前就確定號的,與網路模型綁定。
threshold指的是概率閾值,在網絡識別到物體后,之后當被識別物體的可信度大于概率閾值,才會輸出該結果,取值范圍為[0, 1],默認為0.7。
nums_value指的是box_iou門限,為了防止同一個物體被框出多個框,當在同一個物體上框出兩個框時,這兩個框的交叉區域占兩個框總占用面積的比例如果小于這個參數值,就取其中概率最大的一個框,默認為0.4。
classes指的是網絡要分辨目標的類數,這是在網絡模型訓練前就確定好的,與網絡模型綁定,默認為1。
init_yolo2()方法的使用示例如下所示:
from maix import KPU
import image
anchor = (0.1075, 0.126875, 0.126875, 0.175, 0.1465625, 0.2246875, 0.1953125, 0.25375, 0.2440625, 0.351875, 0.341875, 0.4721875, 0.5078125, 0.6696875, 0.8984375, 1.099687, 2.129062, 2.425937)
names = ['face']
kpu = KPU()
kpu.load_kmode("/sd/KPU/face_detect_320x240.kmodel")
kpu.init_yolo2(anchor, anchor_num=len(anchor) // 2, img_w=320, img_h=240, net_w=320, net_h=240, layer_w=10, layer_h=8, threshold=0.5, nms_value=0.2, classes=len(names))
maix.KPU模塊為KPU對象提供了run_with_output()方法,用于將圖像送入KPU進行運算,并獲取運算結果,run_with_output()方法如下所示:
KPU.run_with_output(input, getlist, get_feature)
run_with_output()方法用于將圖像送入KPU進行運算,并獲取運算結果,且能夠指定返回結果的數據類型。
input指的是輸入的圖像,需要是Image對象,因此可以是攝像頭的輸出圖像,或是文件系統中的圖像文件。
getlist指的是是否返回浮點數列表,當為True時,返回浮點數列表,默認為False。
get_feature指的是是否返回L2歸一化后的浮點特征值(最大允許256),當為True時,返回L2歸一化后的浮點特征值,默認為False。
run_with_output()方法的使用示例如下所示:
from maix import KPU
import image
img = image.Image(size=(320, 240))
anchor = (0.1075, 0.126875, 0.126875, 0.175, 0.1465625, 0.2246875, 0.1953125, 0.25375, 0.2440625, 0.351875, 0.341875, 0.4721875, 0.5078125, 0.6696875, 0.8984375, 1.099687, 2.129062, 2.425937)
names = ['face']
kpu = KPU()
kpu.load_kmode("/sd/KPU/face_detect_320x240.kmodel")
kpu.init_yolo2(anchor, anchor_num=len(anchor) // 2, img_w=320, img_h=240, net_w=320, net_h=240, layer_w=10, layer_h=8, threshold=0.5, nms_value=0.2, classes=len(names))
kpu.run_with_output(input=img, getlist=False, get_feature=False)
maix.KPU模塊為KPU對象提供了regionlayer_yolo2()方法,用于進行YOLO2運算,并獲取其運算結果,regionlayer_yolo2()方法如下所示:
KPU.regionlayer_yolo2()
regionlayer_yolo2()方法用于進行YOLO2運算,并返回一個二維列表,每個子列表表示識別到的一個物體的信息,包含了物體在輸入圖像上左上角的X坐標、Y坐標、寬度、高度,以及class的類別序號,以及置信度。
regionlayer_yolo2()方法的使用示例如下所示:
from maix import KPU
import image
img = image.Image(size=(320, 240))
anchor = (0.1075, 0.126875, 0.126875, 0.175, 0.1465625, 0.2246875, 0.1953125, 0.25375, 0.2440625, 0.351875, 0.341875, 0.4721875, 0.5078125, 0.6696875, 0.8984375, 1.099687, 2.129062, 2.425937)
names = ['face']
kpu = KPU()
kpu.load_kmode("/sd/KPU/face_detect_320x240.kmodel")
kpu.init_yolo2(anchor, anchor_num=len(anchor) // 2, img_w=320, img_h=240, net_w=320, net_h=240, layer_w=10, layer_h=8, threshold=0.5, nms_value=0.2, classes=len(names))
kpu.run_with_output(input=img, getlist=False, get_feature=False)
objs = kpu.regionlayer_yolo2()
for obj in objs:
? ? print("Rect: %d, %d, %d, %d" % (obj[0], obj[1], obj[2], obj[3]))
? ? print("Class number: %d" % (obj[4]))
print("Prob: %.2f" % (obj[5]))
maix.KPU模塊為KPU對象提供了feature_compare()方法,用于進行特征比對,feature_compare()方法如下所示:
KPU.feature_compare(feature_0, feature_1)
feature_compare()方法用于對兩組特征進行特征比對,比對兩組特征數據并給出相似度得分,得分越高表示兩組特征的相似度也就越高。
feature_0和feature_1指的是兩組特征數據,浮點列表,最大值為256。
feature_compare()方法會返回兩組比較特征的相似度得分值。
feature_compare()方法的使用示例如下所示:
feature = kpu.run_with_output(img, get_feature = True)
score = kpu.feature_compare(record_feature, feature)
print(score)
39.2 硬件設計
39.2.1 例程功能
1. 獲取攝像頭輸出的圖像,并送入KPU進行YOLO2的人臉檢測模型運算,后將運算結果和攝像頭輸出的圖像一起顯示在LCD上。
39.2.2 硬件資源
本章實驗內容,主要講解maix.KPU模塊的使用,無需關注硬件資源。
39.2.3 原理圖
本章實驗內容,主要講解maix.KPU模塊的使用,無需關注原理圖。
39.3 程序設計
39.3.1 maix.KPU模塊介紹
有關maix.KPU模塊的介紹,請見第39.1小節《maix.KPU模塊介紹》。
39.3.2 程序流程圖
39.3.3 main.py代碼
main.py中的腳本代碼如下所示:
import lcd
import sensor
import gc
from maix import KPU
lcd.init()
sensor.reset()
sensor.set_framesize(sensor.QVGA)
sensor.set_pixformat(sensor.RGB565)
sensor.set_hmirror(False)
anchor = (0.1075, 0.126875, 0.126875, 0.175, 0.1465625, 0.2246875, 0.1953125, 0.25375, 0.2440625, 0.351875, 0.341875, 0.4721875, 0.5078125, 0.6696875, 0.8984375, 1.099687, 2.129062, 2.425937)
names = ['face']
# 構造KPU對象
face_detecter = KPU()
# 加載模型文件
face_detecter.load_kmodel("/sd/KPU/face_detect_320x240.kmodel")
# 初始化YOLO2網絡
face_detecter.init_yolo2(anchor, anchor_num=len(anchor) // 2, img_w=320, img_h=240, net_w=320, net_h=240, layer_w=10, layer_h=8, threshold=0.5, nms_value=0.2, classes=len(names))
while True:
? ? img= sensor.snapshot()
? ? # 進行KPU運算
? ?face_detecter.run_with_output(input=img, getlist=False, get_feature=False)
? ? # 進行YOLO2運算
? ?faces = face_detecter.regionlayer_yolo2()
? ? for face in faces:
? ?? ? img.draw_rectangle(face[0], face[1], face[2], face[3], color=(0, 255, 0))
? ?? ? img.draw_string(face[0] + 2, face[1] + 2, "%.2f" % (face[5]), color=(0, 255, 0))
? ?? ? img.draw_string(face[0] + 2, face[1] + 10, names[face[4]], color=(0, 255, 0))
? ? lcd.display(img)
? ? gc.collect()
可以看到一開始是先初始化了LCD和攝像頭。
接著是構造一個KPU對象,并從文件系統中加載YOLO2人臉檢測網絡需要用到的網絡模型,并初始化YOLO2網絡。
然后便是在一個循環中不斷地獲取攝像頭輸出的圖像,并將其送入KPU中進行運算,然后再進行YOLO2網絡運算,最后便得到網絡識別出人臉在輸入圖像上的一些信息,將這些信息繪制到圖像上后,在LCD上顯示圖像。
39.4 運行驗證
將DNK210開發板連接CanMV IDE,點擊CanMV IDE上的“開始(運行腳本)”按鈕后,將攝像頭對準人臉,讓其采集到人臉圖像,隨后便能在LCD上看到攝像頭輸出的圖像,同時圖像中的人臉均被綠色的矩形框框出,并在矩形框內的左上角標出了人臉的置信度,如下圖所示: