yolo v1发表在CVPR2016上,是经典的one-stage检测算法。在没接触yolo之前,我曾经就和师兄争论过,是否能把bounding box的坐标和宽高像分类网络那样预测出来,Yolo v1的出现证明了我的猜测是对的。
论文标题: 《You Only Look Once: Unified, Real-Time Object Detection》
论文地址:https://arxiv.org/pdf/1506.02640.pdf
推荐git: https://github.com/leviome/yolo_1_pytorch
这个repo是本人维护的,删掉了很多繁杂的部分,只保留最基本的yolo训练和预测结构。有利于快速上手,以及后期自定义添加插件。
v1是yolo系列的开山之作,以简洁的网络结构,简单的复现过程(作者给出详细教程)而受到CVer们的追捧。
yolo_v1奠定了yolo系列算法“分而治之”的基调,在yolo_v1上,输入图片被划分为7X7的网格,如下图所示:
如上图所示,输入图片被划分为7x7个单元格,每个单元格独立作检测。
在这里很容易被误导:每个网格单元的视野有限而且很可能只有局部特征,这样就很难理解yolo为何能检测比grid_cell大很多的物体。其实,yolo的做法并不是把每个单独的网格作为输入feed到模型,在inference的过程中,网格只是物体中心点位置的划分之用,并不是对图片进行切片,不会让网格脱离整体的关系。
可以通过yolo_v1的structure来进一步理解,相比faster r-cnn那种two-stage复杂的网络结构而言,yolo_v1的网络结构显得亲民得多。基本思想是这样:预测框的位置、大小和物体分类都通过CNN暴力predict出来。
上面是结构图yolo_v1结构图,通过结构图可以轻易知道前向传播的计算过程,是很便于读者理解的。v1的输出是一个7x7x30的张量,7x7表示把输入图片划分位7x7的网格,每一个小单元的另一个维度等于30。30=(25+20)。代表能预测2个框的5个参数(x,y,w,h,score)和20个种类。
|
S
S
Sx
S
S
Sx
(
B
∗
5
+
C
)
(B*5+C)
(B∗5+C) = 7x7x(25 + 20)|
|:|
|SxS表示网格数量,B表示每个网格生成框的个数,C表示能检测识别的种类。|
可以看出输出张量的深度影响yolo_v1能检测目标的种类。v1的输出深度只有30,意味着每个单元格只能预测两个框(而且只认识20类物体),这对于密集型目标检测和小物体检测都不能很好适用。
训练
正如前面所说的,yolo是端到端训练,对于预测框的位置、size、种类、置信度(score)等信息的预测都通过一个损失函数来训练。
l
o
s
s
loss
loss
=
=
=
λ
c
o
o
r
d
{\lambda}_{coord}
λcoord
∑
i
=
0
S
2
\sum_{i=0}^{S^2}
∑i=0S2
∑
j
=
0
B
\sum_{j=0}^B
∑j=0B
l
i
j
o
b
j
l_{ij}^{obj}
lijobj$[(x_i - \hat{x_i})2+(y_i-\hat{y_i})2] + $
λ
c
o
o
r
d
{\lambda}_{coord}
λcoord
∑
i
=
0
S
2
\sum_{i=0}^{S^2}
∑i=0S2
∑
j
=
0
B
\sum_{j=0}^B
∑j=0B
l
i
j
o
b
j
l_{ij}^{obj}
lijobj$[(\sqrt{w_i}- \sqrt{\hat{w_i}})2+(\sqrt{h_i}-\sqrt{\hat{h_i}})2] + $
∑
i
=
0
S
2
\sum_{i=0}^{S^2}
∑i=0S2
∑
j
=
0
B
\sum_{j=0}^B
∑j=0B
l
i
j
o
b
j
l_{ij}^{obj}
lijobj$(c_i - \hat{c_i})^2 + $
λ
n
o
o
b
j
{\lambda}_{noobj}
λnoobj
∑
i
=
0
S
2
\sum_{i=0}^{S^2}
∑i=0S2
∑
j
=
0
B
\sum_{j=0}^B
∑j=0B
l
i
j
n
o
o
b
j
l_{ij}^{noobj}
lijnoobj$(c_i - \hat{c_i})^2 + $
∑
i
=
0
S
2
\sum_{i=0}^{S^2}
∑i=0S2
∑
c
∈
c
l
a
s
s
e
s
\sum_{c\in classes}
∑c∈classes$(p_i©- \hat{p_i}©)^2 $
S
2
S^2
S2表示网格数,在这里是7x7。
B
B
B表示每个单元格预测框的个数,这里是2。
第一行就总方误差( sum-squared error)来当作位置预测的损失函数,第二行用根号总方误差来当作宽度和高度的损失函数。第三行和第四行对置信度confidence也用SSE作为损失函数。第五行用SSE作类别概率的损失函数。最后将几个损失函数加到一起,当作yolo v1的损失函数。
l
i
j
o
b
j
l_{ij}^{obj}
lijobj取值为0和1,即单元格内是否有目标。
λ
c
o
o
r
d
{\lambda}_{coord}
λcoord = 5
λ
n
o
o
b
j
{\lambda}_{noobj}
λnoobj = 0.5
从上面公式也可以看得出来,yolo_v1就是选用最简单的SSE作为损失函数(PS:还没交叉熵复杂)。不过,能解决问题是王道。
总结
v1对于整个yolo系列的价值,即v2/v3还保留的特性,可以总结为3点:
- leaky ReLU,相比普通ReLU,leaky并不会让负数直接为0,而是乘以一个很小的系数(恒定),保留负数输出,但衰减负数输出;公式如下: y = { x , x > 0 0.1 x , o t h e r w i s e y =\begin{cases} x, x>0\\ 0.1x, otherwise \end{cases} y={x,x>00.1x,otherwise
- 分而治之,用网格来划分图片区域,每块区域独立检测目标;
- 端到端训练。损失函数的反向传播可以贯穿整个网络,这也是one-stage检测算法的优势。