"学YOLO的念头是想整个游戏外挂!"
目录
基本原理
模型推理
学习一个新的神经网络结构,作者认为整明白输入和输出是怎么回事就OK了,至于中间的推理过程设计,不是搞学术的,没必要那么明白。
就拿YOLOv3的网络输入和输出来讲,它的输入shape是[N,3,416,416],这个shape的含义很好理解,就是N张416*416的三通道图片(彩色图片),而我们需要重点关注它的输出,它的输出有三部分:[N,255,13,13]、[N,255,26,26]、[N,255,52,52]。其中里面的N自然是指的N张图片,再看里面的255,255=3*(4+1+80),这里的80指的是分类数,意思是该模型可识别80种物体,采用的是one-hot编码,其中4指代的是预测框的中心点坐标(x, y)和预测框的高h和宽w,而1指代的是置信度,范围在0到1之间,3指代的是预测框的数量,有三个,有一个锚框就会有一个预测框。
预测框信息应包含预测框的中心点坐标(x,y)和预测框的高h和宽w,和框里面框的是啥东西的one-hot编码代表物品类别,还有置信度,所以是(4+80+1)。
YOLO进行目标检测的时候,会在逻辑上把图片划分为S*S的网格,在YOLOv3中,它把一个图片从三种不同的尺度进行划分,这也解释了该模型的输出,为什么有三组。因为它从不同尺度去检测物体,从大的感受野看,从小的感受野看,然后给出三组的预测框,可以让预测框更加准确与完整。
其次,在同一个尺度下,每个网格都拥有3个以该网格为中心点的锚框,3个锚框的大小是不一样的。在目标检测中,每个锚框都会预测一个预测框出来,所以一个网格就有三个预测框,这也更好地解释了模型输出shape的实际含义,拿一个尺度的输出shape而言就是[图片数量, 预测框数量*预测框信息量, W, H],其中W*H可以理解为网格数量。
那现在YOLOv3输出了不同尺度下的全部预测框,我们可以看到不同尺度下的预测框密密麻麻的怎么变成右边清爽的模样呢?就需要引入两个概念了IOU与NMS。
IOU交并比
IOU,全称Intersection over Union,即交并比,是衡量目标检测中边界框重叠程度的关键指标。它通过计算两个边界框的交集面积与并集面积之比来得到。简而言之,交集面积除以并集面积。
NMS非极大值抑制
NMS,全称Non-Maximum Suppression,即非极大值抑制,是一种常用的目标检测算法中的后处理步骤。以下是NMS的操作步骤:
- 将所有预测框,按照置信度进行降序排序
- 依次选择置信度最高的框作为基准,并计算它与其他预测框的IOU值
- 如果某个预测框与基准框的IOU值大于预设的阈值,则认为该预测框与基准框重叠度较高,则将其移除
- 选择下一个置信度最高的框作为基准
- 重复以上过程,直到所有预测框都被处理完成
利用NMS我们就可以实现以上清爽的效果了,在目标检测任务中,NMS是处理重叠预测框、提高检测精度的关键步骤。
模型训练
了解了模型推理的过程,我们就要想一个问题,预测框怎么来的?换而言之,锚框怎么变成预测框?锚框的大小不是一开始就被设定的死死的嘛?
锚框的大小和中心点(网格的左上角)确实是被设置的死死的,但我们可以让其中心点偏移,宽高拉伸,至于偏移量和拉伸量,这不就是神经网络需要训练的参数嘛?而原来的锚框经过中心点偏移和宽高拉伸就变成了预测框。
我们也可以观察到这个偏移量和拉伸量还有点特别,偏移量用了sigmoid函数,拉伸量用了exp函数。偏移量用sigmoid函数,是因为我们规定一个网格的宽和高都为1,而该函数y值取值范围在0到1之间,这样可以保证一个网格的预测框中心点只会在该网格里面,不会跑到别的网格里面去。拉伸量用exp是保证了预测框的宽高是正数。
损失函数LOSS
我们看预测框携带的信息有:预测框的中心点坐标,预测框的宽高,预测框内物体的种类,预测框的置信度。想要预测框与真实框的信息一致,是不是很显然这既是一个回归问题,也是一个分类问题,分类问题一般用Cross Entropy损失,回归问题一般用MSE损失,但飞桨这里用的是MAE(L1损失)。
代码实现
目前,yolo体系是十分成熟的,很多深度学习框架(pytorch,ts)都有yolo库,不需要咱们再手搓yolo了,作者用的是paddleDetection,用paddle主要是因为他们有免费的平台给你训练,主流的还是pytorch感觉,以下是paddle-Detection的快速入门。
docs/tutorials/QUICK_STARTED_cn.md · PaddlePaddle/PaddleDetection - Gitee.comhttps://gitee.com/paddlepaddle/PaddleDetection/blob/release/2.7/docs/tutorials/QUICK_STARTED_cn.md#%E4%BA%8C%E5%87%86%E5%A4%87%E6%95%B0%E6%8D%AE paddleDetection进行数据训练时,可能会报下面的错误。大概就是0维张量不能被Tensor.numpy()[0]这么使用,以后只能写成float(Tensor)了。解决办法,目前是降paddle-paddle到2.4版本。
Warning:: 0D Tensor cannot be used as 'Tensor.numpy()[0]' . In order to avoid this problem, 0D Tensor will be changed to 1D numpy currently, but it's not correct and will be removed in release 2.6. For Tensor contain only one element, Please modify 'Tensor.numpy()[0]' to 'float(Tensor)' as soon as possible, otherwise 'Tensor.numpy()[0]' will raise error in release 2.6。
"再学学Python怎么控制鼠标键盘,自瞄外挂不就成了嘛?"
YOLO学习渠道
以下是作者学习YOLO基本原理与代码实现的推荐学习渠道。
飞桨AI Studio星河社区 - 人工智能学习与实训社区 (baidu.com)https://aistudio.baidu.com/education/group/info/1617