一、简介
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()