一、简介
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, sys
COLOR_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 uio
err_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 1
try:
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() - t
if 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 e
finally:
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()