一、簡介
YOLO-v2-tiny是基于YOLO(You Only Look Once)實時目標檢測算法的輕量級版本,專門為嵌入式設備和資源受限環境優化。本模型能夠檢測20種常見物體類別,在保持較高檢測精度的同時大幅減少了計算量和模型大小。
20種物體檢測模型, 使用 YOLO v2 tiny 網絡, 具體的20種類別看詳情介紹
20 個物體類別:
aeroplane, bicycle, bird, boat, bottle, bus, car, cat, chair, cow,
diningtable, dog, horse, motorbike, person, pottedplant, sheep, sofa, train, tvmonitor
二、使用方法
下載模型后得到三個文件: .py 示例腳本, .smodel模型文件,labels.txt文件
只需要py 示例腳本, .smodel模型文件,將模型下載到 0x800000(因為示例代碼中讀取模型位置為 0x800000)
或者放到SD卡里
開機運行效果
MaixPy運行基于tiny-yolov2的20分類
三、技術參數
-
輸入分辨率:224×224或320×240(QVGA)
-
錨點(anchors)參數:(1.08,1.19,3.42,4.41,6.63,11.38,9.42,5.11,16.62,10.52)
-
置信度閾值:0.5
-
非極大值抑制(NMS)閾值:0.3
- 錨框(Anchor Boxes)在YOLO算法中的作用:
-
錨框是預定義的一組邊界框模板,用于預測目標物體的位置和尺寸
-
網絡不是直接預測絕對坐標,而是預測相對于錨框的偏移量
-
合適的錨框尺寸可以加速訓練并提高檢測精度
- 為什么是10個參數?
-
每個錨框需要2個參數(寬度w和高度h)
-
示例代碼中使用了5個錨框,因此需要 5錨框 × 2參數 = 10個數值
對應的錨點參數為:
anchor = (w1, h1, w2, h2, w3, h3, w4, h4, w5, h5)
- 錨框數量的選擇
-
5個錨框是YOLOv2/v3常用的配置(尤其是對于人臉檢測這類相對單一的目標)
-
錨框的尺寸是通過K-means聚類在訓練數據集上統計得到的:
-
對訓練集中所有真實框(Ground Truth)的寬高進行聚類
-
選擇5個最具代表性的寬高組合作為錨框
-
- 代碼中的具體錨點參數
anchor = (1.889, 2.5245, 2.9465, 3.94056, 3.99987, 5.3658, 5.155437, 6.92275, 6.718375, 9.01025)
解析:
- 實際表示5個錨框的寬高:
[(1.889,2.5245), (2.9465,3.94056), (3.99987,5.3658), (5.155437,6.92275), (6.718375,9.01025)]
- 這些值是通過在人臉數據集上聚類得到的,適合檢測不同比例的人臉。
- 為什么需要多個錨框?
-
覆蓋不同比例的人臉:
-
近距離人臉(大錨框)
-
遠距離人臉(小錨框)
-
-
適應不同長寬比:
-
正臉(接近正方形)
-
側臉(可能更寬或更窄)
-
- 理解YOLO中的NMS閾值調整
非極大值抑制(Non-Maximum Suppression, NMS)是目標檢測中用于消除冗余檢測框的關鍵后處理步驟。NMS閾值的調整直接影響模型的檢測結果,下面我將詳細解釋NMS閾值(0.3-0.5)的含義和調整策略。
-
6.1. NMS基本原理
NMS的工作流程:-
對所有檢測框按置信度(confidence score)排序
-
選擇置信度最高的框作為保留框
-
計算其他框與這個保留框的交并比(IoU)
-
刪除所有IoU大于閾值的框
-
對剩余的框重復上述過程
-
-
6.2. NMS閾值的含義
NMS閾值(0.3-0.5)指的是IoU的閾值:-
IoU(Intersection over Union): 兩個框重疊面積與并集面積的比值
-
NMS閾值就是判斷兩個框是否"過于相似"的標準
-
-
6.3. 不同閾值的效果
-
6.3.1 NMS閾值=0.3(代碼默認值)
-
效果:更嚴格,只保留不太重疊的框
-
優點:減少重復檢測,輸出更簡潔
-
缺點:可能漏掉實際存在的相鄰物體
-
適用場景:物體間距較大,重疊少的情況
-
-
6.3.2 NMS閾值=0.5
-
效果:更寬松,允許更多重疊框通過
-
優點:能檢測到靠得很近的物體
-
缺點:可能產生多個框檢測同一物體
-
適用場景:密集物體檢測,小物體檢測
-
-
四 、模型架構
YOLO-v2-tiny相比完整版YOLOv2做了以下簡化:
-
更少的卷積層:減少了網絡深度,降低了計算復雜度
-
更小的特征圖:減少了特征圖尺寸,提升推理速度
-
優化的錨點設計:使用5個預定義的錨點框(anchor boxes)來預測物體位置
-
提高檢測精度:降低置信度閾值(如0.3),但會增加誤檢
-
減少誤檢:提高置信度閾值(如0.7),但可能漏檢
-
處理重疊框:調整NMS閾值(0.3-0.5之間)
五、完整代碼
import sensor, image, lcd, time
import KPU as kpu
import gc, sysCOLOR_RED = (255,0,0)
COLOR_GREEN = (0,255,0)
COLOR_BLUE = (0,0,255)
COLOR_WHITE = (255,255,255)def lcd_show_except(e):import uioerr_str = uio.StringIO()sys.print_exception(e, err_str)err_str = err_str.getvalue()img = image.Image(size=(224,224))img.draw_string(0, 10, err_str, scale=1, color=COLOR_RED)lcd.display(img)def main(anchors, labels = None, model_addr="/sd/m.smodel", sensor_window=(224, 224), lcd_rotation=0, sensor_hmirror=False, sensor_vflip=False):sensor.reset()sensor.set_pixformat(sensor.RGB565)sensor.set_framesize(sensor.QVGA)sensor.set_hmirror(sensor_hmirror)# `enable`: 1 表示開啟水平鏡像 0 表示關閉水平鏡像sensor.set_vflip(sensor_vflip)sensor.run(1)lcd.init(type=1)lcd.rotation(lcd_rotation)lcd.clear(lcd.WHITE)if not labels:with open('labels.txt','r') as f:exec(f.read())if not labels:print("no labels.txt")img = image.Image(size=(320, 240))img.draw_string(90, 110, "no labels.txt", color=COLOR_RED, scale=2)lcd.display(img)return 1try:img = image.Image("startup.jpg")lcd.display(img)except Exception:img = image.Image(size=(320, 240))img.draw_string(90, 110, "loading model...", color=COLOR_WHITE, scale=2)lcd.display(img)task = kpu.load(model_addr)kpu.init_yolo2(task, 0.5, 0.3, 5, anchors) ##1、task: 指定任務類型,例如是檢測還是分類。在YOLO中,通常設置為"detection"。#2、threshold: 置信度閾值,用于過濾掉低置信度的檢測結果。閾值范圍是[0,1],值越高,則模型只會輸出置信度更高的預測結果。#3、nms_value: 非最大抑制(Non-Maximum Suppression, NMS)的閾值,用于減少重疊框的數量。NMS閾值同樣在[0,1]范圍內,值越高,則保留的框越少,重疊越小。#4、classes: 類別數量,表示模型需要識別的對象類別數。#5、anchors: 錨點(Anchors)是YOLO中用來預測邊界框的先驗框尺寸。這些尺寸是在訓練數據集上通過k-means聚類得到的。try:while 1:img = sensor.snapshot()t = time.ticks_ms()objects = kpu.run_yolo2(task, img)t = time.ticks_ms() - tif objects:for obj in objects:pos = obj.rect()img.draw_rectangle(pos)img.draw_string(pos[0], pos[1], "%s : %.2f" %(labels[obj.classid()], obj.value()), scale=2, color=COLOR_GREEN)img.draw_string(0, 200, "t:%d ms" %(t), scale=2, color=COLOR_BLUE)lcd.display(img)except Exception as e:raise efinally:kpu.deinit(task)if __name__ == "__main__":try:labels = ['aeroplane', 'bicycle', 'bird', 'boat', 'bottle', 'bus', 'car', 'cat', 'chair', 'cow', 'diningtable', 'dog', 'horse', 'motorbike', 'person', 'pottedplant', 'sheep', 'sofa', 'train', 'tvmonitor']anchors = (1.08, 1.19, 3.42, 4.41, 6.63, 11.38, 9.42, 5.11, 16.62, 10.52)main(anchors = anchors, labels=labels, model_addr="/sd/m.smodel", lcd_rotation=1, sensor_window=(224, 224))except Exception as e:sys.print_exception(e)lcd_show_except(e)finally:gc.collect()