赞
踩
目标检测=识别+定位
RCNN
,Fast RCNN
,Faster RCNN
都是先提取候选框再送入检测网络,忽略了全局的信息。对R-CNN
系列感兴趣的可以跳转到我的另一篇博文:R-CNN、Fast RCNN和Faster RCNN网络介绍。YOLO
是个单阶段的模型,直接在特征图上进行信息提取,是一个全局的信息。接下来我们分两步讲解YOLOv1
模型:预测阶段和训练阶段。此外关于yolov1
的代码解读,逐行逐句的分析你可以在我的另一篇博文在查看:YOLOv1代码分析——pytorch版保姆级教程。
如下图是两种框架,一种是普通的YOLOv1
框架,一种是微型的。微型的速度更快,模型更小,但是准确率有所下降。
我们先看预测阶段,输入网络的是一个
448
×
448
448\times448
448×448的图像,输出的是一个
7
×
7
×
30
7\times7\times30
7×7×30的张量,这个张量里面就包含了我们要检测的类别,坐标信息,解析这些参数就能得到目标检测结果。那么这个张量为什么是
7
×
7
×
30
7\times7\times30
7×7×30呢?看下面的图,首先网络把输入的图像经过一些列卷积等操作划分成了
s
×
s
s\times s
s×s个grid,
s
=
7
s=7
s=7。其中,每个grid需要预测2个bounding box(预测框),这两个框的大小宽高都不确定,可能很大,很宽,也可能很小,很窄。只要这个bounding box的中心点落在这个grid里面就说明这个bounding box是由这个grid所预测的。每个bounding box包含5个参数(
x
,
y
,
h
,
w
,
c
x,y,h,w,c
x,y,h,w,c),其中
x
,
y
,
h
,
w
,
c
x,y,h,w,c
x,y,h,w,c分别表示预测框的中心点横坐标,纵坐标,高度和宽度,以及bounding box里面包含物体的概率。在下图的展示中的最上面的一个图,框的线越粗表示置信度越高,越细表示置信度越低。总共
49
49
49个grid生成
98
98
98个bounding box
。同时每个grid还能生成所有类别的条件概率,什么意思呢?上面不是讲了每个bounding box
里面有五个参数吗,其中一个
c
c
c置信度参数,表示包含物体的概率,那么每个grid
还能生成所有类别的条件概率就是在这个grid
包含物体的条件下,是哪一个类别的概率(是猫还是狗),这样就获得了20各类别的各自概率,就对应这30维向量的后面20个参数。如下图的最下面的图所示,每个类别的概率用不同的颜色标出来了,每个grid
之只能预测一个概率最高的类别(经过后处理和NMS得到)。通过上面的分析我们可以得出30是怎么来的,他就是
2
×
5
(
x
,
y
,
h
,
w
,
c
)
+
20
2\times5(x,y,h,w,c)+20
2×5(x,y,h,w,c)+20。再次强调后面20维的向量是在包含物体的条件下计算出来的某个类别的概率。简单概括YOLOv1就是输入是一个
448
×
448
448\times448
448×448的图像,输出是一个
7
×
7
×
(
2
×
5
+
20
)
=
1470
7\times7\times(2\times5+20)=1470
7×7×(2×5+20)=1470个数字。
这个地方你应该会有疑问,一个grid预测两个bounding box,而一个grid只预测一个类别,那么用哪个bounding box来预测呢,还有如果我预测的两个bounding box一个包含物体,一个不包含物体,或者两个bounding box都包含物体,那么我应该用哪个bounding box里面的
c
c
c来计算是哪个类别的物体呢?这个问题我们下面讲后处理过程的时候再讲。
如上图所示,用颜色表示不同的类别,粗细表示置信度就得到了上面的中间图的结果,经过过滤低置信度的框,NMS
处理就得到得了最终的目标检测预测结果。
注意:以上分析的仅仅是预测阶段,预测阶段,预测阶段
接下来我们再来讲下YOLOv1预测阶段的后处理过程:置信度过滤+非极大值抑制(NMS)。
后处理时做什么呢?就是把刚才预测的杂乱无章的98个bounding box
进行筛选过滤,重复的预测框只保留一个,获得最终目标检测的结果。主要包含把低置信度的框去掉,重复的框去掉,只保留一个。如下图所示,后处理就是把
7
×
7
×
30
7\times7\times30
7×7×30的张量变成最后的检测结果,中间过程先看成黑盒子。
NMS处理过程:
- 找到置信度最大的框,该框是目标的概率是最大的,得到第1个框,注意这里是按照框的置信度排序来寻找的;
- 依次计算其他相同类别框与第1个框的重合度(IOU值),如果大于一定阈值,抑制掉;
- 剩下的框中,同样找置信度最大的框,为第2个框,抑制掉重合的框;
- 反复执行上述步骤,直到剩下最后一个框,此亦为目标框。
NMS处理详细介绍可以参考这个博文:NMS——非极大值抑制
现在我们来看下这
7
×
7
×
30
7\times7\times30
7×7×30维张量是如何变成最后的预测结果的,如下图所示,我们先取出其中的一个grid
来看,每个grid
包含30个数字
5
+
5
+
20
5+5+20
5+5+20构成,每个grid预测两个bounding box
,后面的20表示该grid
对20个类别的条件类别概率,就是假设该grid
预测物体的条件下,20个类别的概率分别是多少。
我们上面讲的都是假设该grid
预测物体的条件下,20个类别的概率分别是多少。下面我们把这20个条件概率把他单独拿出来跟bounding box
的置信度相乘,即条件概率乘上条件本身发生的概率就得到了全概率,就是说该bounding box
包含物体的概率乘上在他包含物体的条件下各个类别的概率,那么就得到了他真正是属于哪个类别的概率。那么每个grid都能获得2个20维的全概率,如下图的黄色竖条,分别表示两个预测框。总共98个bounding box
一共获得98个20维的全概率向量。图中的黄色竖条表示他20个类别的概率分别是多少。
通过上面的处理,我们获得了下面的乱图:就是上面的98个黄色竖条可视化出来的结果,粗细表示置信度(包含物体的概率),颜色表示类别。
我们如何通过上面的乱图获得最后的目标检测结果呢?
答:按照类别进行非极大值抑制。
我们先假设狗是20个类别中的第一个类别。设置一个阈值,先把小于设定阈值的给抹零,然后按照狗概率高低进行排序,然后在对排序后的结果进行非极大值抑制。经过非极大值抑制之后就获得了一幅图上所有狗这一目标的检测结果,对其他的类别做同样的操作获得检测结果。
经过上面的操作就获得了一个包含很多零的稀疏矩阵,如果某个向量里面含有非零值,我们就把他的类别拎出来,得分也拎出来,就得到得了最终的目标检测结果。
注意:以上后处理仅仅是预测阶段,预测阶段,预测阶段,训练阶段不需要NMS处理,因为在训练阶段,不管他是不是负责预测物体,他在损失函数里面都占有一席之地。只是在训练出来模型之后进行待测图片预测之后才需要进行后处理,把低置信度的框过滤掉,再把重复识别物体的重复框值挑出一个。训练和预测一定要分开理解。
在实际代码中,我们在进行非极大值抑制之前实际上是先滤除每个grid cell
中置信度比较小的那个框,只对最终剩余的49
个框按照类别进行非极大值抑制。有疑问的可以跳转到我对yolov1
的代码讲解博文看下源码分析的predict.py
部分代码的Decode
函数。下面附上部分代码,完整源码请跳转到:YOLOv1代码分析——pytorch版保姆级教程。
# 接受的result的形状为1*7*7*30
def Decode(self, result):
# 去掉batch维度
result = result.squeeze()
# 提取置信度信息,并在最后一个维度增加一维,跟后面匹配result[:, :, 4]的形状为7*7,最后变为7*7*1
grid_ceil1 = result[:, :, 4].unsqueeze(2)
# 同上
grid_ceil2 = result[:, :, 9].unsqueeze(2)
# 两个置信度信息按照维度2拼接
grid_ceil_con = torch.cat((grid_ceil1, grid_ceil2), 2)
# 按照第二个维度进行最大值求取,一个grid ceil两个bbox,两个confidence,也就是找置信度比较大的那个,形状都是7*7
grid_ceil_con, grid_ceil_index = grid_ceil_con.max(2)
# 找出一个gird cell中预测类别最大的物体的索引和预测条件类别概率
class_p, class_index = result[:, :, 10:].max(2)
# 计算出物体的真实概率,类别最大的物体乘上置信度比较大的那个框得到最终的真实物体类别概率
class_confidence = class_p * grid_ceil_con
# 定义一个张量,记录位置信息
bbox_info = torch.zeros(7, 7, 6)
for i in range(0, 7):
for j in range(0, 7):
# 获取置信度比较大的索引位置
bbox_index = grid_ceil_index[i, j]
# 把置信度比较大的那个框的位置信息保存到bbox_info中,另一个直接抛弃
bbox_info[i, j, :5] = result[i, j, (bbox_index * 5):(bbox_index+1) * 5]
# 真实目标概率
bbox_info[:, :, 4] = class_confidence
# 类别信息
bbox_info[:, :, 5] = class_index
# 返回预测的结果,7*7*6 6 = bbox4个信息+类别概率+类别代号
return bbox_info
下面我们开始介绍训练阶段!训练阶段!训练阶段!
刚才我们讲了YOLOv1
的预测阶段,即模型训练好之后送入待测图片获得目标检测结果的过程。下面我们介绍下YOLOv1
模型的训练阶段。这也是理解YOLOv1
模型的关键,下面我尽量用通俗的语言来讲解怎么训练YOLOv1
模型。
我们知道深度学习(监督学习)都是通过梯度下降和反向传播的方法迭代的去微调网络神经元的权重来使得损失函数最小化的过程,而目标检测就是一个典型的监督学习问题,在训练集上给定的有输入图像,又有输入图像的标签,即在输入的图像上面已经标记好的ground truth
,我们要设计的算法就是尽可能的去拟合这个人工标记的框,让损失函数尽可能最小,损失函数我们后面再介绍。
以下图为例,如下图是一个人工标注的框(绿色的框),人工标注的框的中心落点在哪个grid
, 就由哪个grid
预测出的两个bounding box
中的一个去负责拟合这个绿框,并且这个grid
输出的类别也应该是这个ground truth
的类别。也就是说,前面不是讲过每个grid
要获得20个类别的条件类别概率吗,那么这20个类别的概率乘以每个框的置信度获得这个全概率。以图中的狗为例,狗的概率应该是最大的,就是这个grid
的代表类别,每个grid
只能预测出一个类别,就是概率最大的类别。也就是说每个grid
只能预测出一个物体,即YOLOv1最多预测出
7
×
7
=
49
7\times7=49
7×7=49个物体(个人理解:这里如果按照上面的98个框进行非极大值抑制则最多可以预测98个目标,如有不对,请各位小伙伴指正)。
还记得前面的紫色字体提出的问题吗?训练阶段,每个grid
预测两个bounding box
,那么究竟由哪个bounding box
来负责拟合这个ground truth
呢?(注意:预测阶段是通过置信度过滤和NMS
处理,和训练阶段的处理方法不一样,不要搞混了,这一点也是很多小伙伴容易搞混的地方)。训练阶段应该是由那个和ground truth交并比(IoU)最大的去负责拟合ground truth
。如下图就是外围大的框去负责拟合逼近ground truth
。另外一个框直接被抛弃掉了,什么都不用做,只需要让他的object
尽量小就行了,在损失函数中会体现出来。所以我们损失函数的设计就是让负责预测物体的框尽可能的拟合ground truth
。
上面讲的是有ground truth
中心点落在的grid
,那么如果没有ground truth
落在的grid
怎么处理呢?这时候grid
所预测的两个框都被直接抛弃了,这两框只需要让置信度越小越好,置信度越接近与0越好,其他什么都不要做。
注意:以上讲的bounding box
无论多大,多宽,他们的中心点都落在所属的grid
里面。
通过上面的介绍,我们就能构建YOLOv1
的损失函数了。
观察上面的损失函数,总共有五项(都是一个回归问题)。
bounding box
中心点定位误差,要和ground truth
尽可能拟合,
x
x
x带上标的是标注值,不带上标的是预测值。bounding box
的宽高定位误差,加根号是为了使得对小框的误差更敏感,如下图所示。bounding box
的置信度误差,标签值实际上就是bounding box
和ground truth
的
I
o
U
IoU
IoU。预测的置信度应该是越跟
I
o
U
IoU
IoU越接近越好。bounding box
的置信度误差,就是所有被抛弃的bounding box
。让他们预测出来的置信度最好都是0,标签值就是0。这个被抛弃的bounding box
包含两类bounding box
,一类是负责检测物体的grid
预测被抛弃的bounding box
,一类是不负责检测物体的grid
预测的bounding box
。grid
的分类误差。上面的
λ
c
o
o
r
d
\lambda_{coord}
λcoord和
λ
n
o
o
b
j
\lambda_{noobj}
λnoobj在原文中分别赋值5和0.5,表示对真正负责检测物体的bounding box
和置信度误差给与更高的权重,不负责检测物体的bounding box
和置信度误差给与比较低的权重。bounding box
负责检测物体,那么他所在的那个grid也负责检测物体,如果一个bounding box
负责检测物体,那么另外一个bounding box
就不负责检测物体。也就是在上面的黄框,红框和蓝框所对应的变量,黄框如果为1,蓝框也为1,红框和绿框一个为1,,另一个则为0。下标
i
i
i表示
s
×
s
s\times s
s×s个grid,
j
j
j表示
j
j
j个bounding box
,咋YOLOv1里面
i
=
49
i=49
i=49,
j
=
2
j=2
j=2。总结一下损失函数,需要计算的是由四部分:
yolov1的标签形式:
先创建一个全0的矩阵 7 × 7 × 30 7 \times7 \times30 7×7×30的lable,label里面记录的是每个标注框(包含物体)的宽高信息以及中心点坐标相对于所在网格左上角的偏移量,置信度标签值1,类别信息,两份标注框的信息一样的,其他的位置全为0。那么在训练网络的时候需要生成的数据格式也是这样的,不然不好计算损失。
需要计算以下几个损失函数(对应着代码分析看):
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。