这一周的内容重点较多,相对不易理解,更是包含了著名的YOLO算法。因此拿出来做个总结。 笔记参照这位大哥 https://github.com/AlbertHG/Coursera-Deep-Learning-deeplearning.ai/tree/master/04-Convolutional%20Neural%20Networks/week3
1. 问题描述:
- 目标定位(Object localization):定位问题意味着,不仅要用算法判断图片中是不是一辆汽车,还要在图片中标记出它的位置,用边框(Bounding Box)把目标物体圈起来。这类问题中 通常只有一个较大的对象位于图片中间位置。
- 目标检测 (Object detection):图片可以含有多个对象,且单张图片中会有多个不同分类的对象。
对于目标定位和检测问题,为了定位图片中汽车的位置,可以让神经网络可以输出 ( 1 + 4 + n ) (1 + 4 + n) (1+4+n) 个数字,其中,1代表图片中有目标的概率 P c Pc Pc,4用来定位目标,可以用红框的中心点坐标 b x b_x bx、 b y b_y by和边界框的高和宽 b h b_h bh、 b w b_w bw来表示。n是待检测的类别数。「将图片左上角标记为 (0, 0),右下角标记为 (1, 1)」
综上,目标的标签 Y Y Y有如下两种形式:
[
P
c
b
x
b
y
b
h
b
w
c
1
c
2
c
3
]
,
w
h
e
n
P
c
=
1
:
[
1
b
x
b
y
b
h
b
w
c
1
c
2
c
3
]
,
w
h
e
n
P
c
=
0
:
[
0
?
?
?
?
?
?
?
]
\left[\begin{matrix}P_c\\ b_x\\ b_y\\ b_h\\ b_w\\ c_1\\ c_2\\ c_3\end{matrix}\right] ,when P_c=1:\left[\begin{matrix}1\\ b_x\\ b_y\\ b_h\\ b_w\\ c_1\\ c_2\\ c_3\end{matrix}\right] ,when P_c=0:\left[\begin{matrix}0\\ ?\\ ?\\ ?\\ ?\\ ?\\ ?\\ ?\end{matrix}\right]
⎣⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎡Pcbxbybhbwc1c2c3⎦⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎤,whenPc=1:⎣⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎡1bxbybhbwc1c2c3⎦⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎤,whenPc=0:⎣⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎡0???????⎦⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎤
若
P
c
P_c
Pc=0,表示没有检测到目标,则输出label后面的7个参数都可以忽略(用 ? 来表示)。
损失函数可以表示为 L ( y ^ , y ) L(\hat y, y) L(y^,y),如果使用平方误差形式,对于不同的 P c P_c Pc有不同的损失函数(注意下标 i i i指标签的第 i i i个值):
P c = 1 P_c=1 Pc=1,即 y 1 = 1 y_1=1 y1=1:
L ( y ^ , y ) = ( y ^ 1 − y 1 ) 2 + ( y ^ 2 − y 2 ) 2 + ⋯ + ( y ^ 8 − y 8 ) 2 L(\hat y,y)=(\hat y_1-y_1)^2+(\hat y_2-y_2)^2+\cdots+(\hat y_8-y_8)^2 L(y^,y)=(y^1−y1)2+(y^2−y2)2+⋯+(y^8−y8)2
损失值就是不同元素的平方和。
P c = 0 P_c=0 Pc=0,即 y 1 = 0 y_1=0 y1=0:
L ( y ^ , y ) = ( y ^ 1 − y 1 ) 2 L(\hat y,y)=(\hat y_1-y_1)^2 L(y^,y)=(y^1−y1)2
对于这种情况,不用考虑其它元素,只需要关注神经网络输出的准确度即可。
- 特征点检测(Landmark detection): 神经网络可以像标识目标的中心点位置那样,通过输出图片上的特征点,来实现对目标特征的识别。在标签中,这些特征点以多个二维坐标的形式表示。
举个例子:假设需要定位一张人脸图像,同时检测其中的64个特征点,这些点可以帮助我们定位眼睛、嘴巴等人脸特征。
具体的做法:准备一个卷积网络和一些特征集,将人脸图片输入卷积网络,输出1或0(1表示有人脸,0表示没有人脸)并输出 ( l 1 x , l 1 y ) (l_{1x},l_{1y}) (l1x,l1y) ……直到 ( l 64 x , l 64 y ) (l_{64x},l_{64y}) (l64x,l64y)。这里用 l l l代表一个特征,此例中有129个输出单元,其中1表示图片中有人脸,128表示64个特征点的坐标,由此实现对图片的人脸检测和定位。
2. 基于滑动窗口的目标检测(Sliding Windows Detection)
构造训练集:
- 训练集X:将有汽车的图片进行适当的剪切,剪切成整张几乎都被汽车占据的小图或者没有汽车的小图;
- 训练集Y:对X中的图片进行标注,有汽车的标注1,没有汽车的标注0。
使用符合上述要求的这些训练集构建CNN模型,可使得模型有较高的识别率。接着选择大小适宜的窗口与合适的固定步幅,对测试图片进行从左到右、从上倒下的滑动遍历。每个窗口区域使用已经训练好的 CNN 模型进行识别判断。随后可以选择更大的窗口,并重复遍历+识别的操作。
滑动窗算法的优点是原理简单,且不需要人为选定目标区域(检测出目标的滑动窗即为目标区域)。但是其缺点也很明显,首先滑动窗的大小和步进长度都需要人为直观设定。滑动窗过小或过大,步进长度过大均会降低目标检测正确率。每次滑动窗区域都要进行一次CNN网络计算,如果滑动窗和步进长度较小,整个目标检测的算法运行时间会很长。所以,滑动窗算法虽然简单,但是性能不佳,不够快,不够灵活。
- 滑动窗口的卷积实现:滑动窗算法可以使用卷积方式实现,以提高运行速度,节约重复运算成本。
- 单个滑动窗口区域进入CNN网络模型时,包含全连接层。滑动窗口算法卷积实现的第一步就是将全连接层转变成为卷积层,如下图所示,使用与上层尺寸一致的滤波算子进行卷积运算:
- 我们无需自己去滑动窗口截取图片的一小部分然后检测,卷积可以自动实现滑动窗口。
- 单个滑动窗口区域进入CNN网络模型时,包含全连接层。滑动窗口算法卷积实现的第一步就是将全连接层转变成为卷积层,如下图所示,使用与上层尺寸一致的滤波算子进行卷积运算:
如下图中间一行卷积的初始图,我们假设输入的图像是16 x 16 x 3的,而窗口大小是14 x 14 x 3,我们要做的是把蓝色区域输入卷积网络,生成0或1分类,接着向右滑动2个元素,形成的区域输入卷积网络,生成0或1分类,然后接着滑动,重复操作。我们在16 x 16 x 3的图像上卷积了4次,输出了4个标签,这4次卷积里很多计算是重复的。
而实际上,我们可以直接对这个16 x 16 x 3的图像进行卷积,如上图中间一行的卷积的整个过程,这个卷积实际上涵盖了先前提到的重复计算,其中蓝色的区域就是先前用来卷积的第一块区域,到最后它变成了2 x 2 x 4的块的左上角那一块,最后的输出为2 x 2=4个,分别对应先前输出的4个标签。
因此我们不需要把原图分成四个部分,分别用卷积去检测,而是把它们作为一张图片输入给卷积网络进行计算,其中的公有区域可以共享很多计算。
同理,当图片大小是28 x 28 x 3的时候,CNN网络得到的输出层为8 x 8 x 4,共64个窗口结果。( 28 − 14 2 + 1 = 8 \frac{28-14}{2} + 1 = 8 228−14+1=8)
我们不用依靠连续的卷积操作来识别图片中的汽车,我们可以对整张图片进行卷积,一次得到所有的预测值,如果足够幸运,神经网络便可以识别出汽车的位置。
3. 边界框的预测
卷积方式实现的滑动窗口算法使得预测时计算效率大大提高。但是其存在的问题是:不能输出最精准的边界框(Bounding Box)
YOLO(You Only Look Once)算法可以解决这类问题,生成更加准确的目标区域(如下图红色窗口)。
YOLO算法首先将原始图片分割成n x n网格,每个网格代表一块区域。为简化说明,上图中将图片分成3 x 3网格。
然后,利用卷积形式实现滑动窗口算法的思想,对该原始图片构建CNN网络,得到的的输出层维度为3 x 3 x 8。其中,3 x 3对应9个网格,每个网格的输出包含8个元素: y = [ P c b x b y b h b w c 1 c 2 c 3 ] y=\left[\begin{matrix}P_c\\ b_x\\ b_y\\ b_h\\ b_w\\ c_1\\ c_2\\ c_3\end{matrix}\right] y=⎣⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎡Pcbxbybhbwc1c2c3⎦⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎤
如果目标中心坐标 ( b x , b y ) (b_x,b_y) (bx,by) 不在当前网格内,则当前网格Pc=0;相反,则当前网格 P c = 1 P_c=1 Pc=1(即只看中心坐标是否在当前网格内)。判断有目标的网格中, b x , b y , b h , b w b_x,b_y,b_h,b_w bx,by,bh,bw 限定了目标区域。
值得注意的是,当前网格左上角坐标设定为 ( 0 , 0 ) (0, 0) (0,0),右下角坐标设定为 ( 1 , 1 ) (1, 1) (1,1), ( b x , b y ) (b_x,b_y) (bx,by) 表示坐标值,范围限定在 [ 0 , 1 ] [0,1] [0,1]之间,但是 b h , b w b_h,b_w bh,bw 可以大于 1。因为目标可能超出该网格,横跨多个区域。目标可以占据多个网格,但目标中心坐标必然在一个网格之内。
划分的网格可以更密一些。网格越小,则多个目标的中心坐标被划分到一个网格内的概率就越小,这恰恰是我们希望看到的。
总结: YOLO的做法和图像分类和定位算法非常像,它显式地输出边界框坐标,所以这能让神经网络输出边界框,可以具有任意宽高比,并且能输出更精确的坐标,不会受到滑动窗口分类器的步长大小限制。而且,这是一个卷积实现,你并没有在3 × 3网格上跑9次算法,而是单次卷积实现,共享了和多计算步骤,这保证了YOLO算法的高效。
4. 非极大值抑制 (Non-Max Suppression)
对于汽车目标检测的例子中,若我们将图片分成很多精细(19*19)的格子。最终预测输出的结果中,可能会有相邻的多个格子里均检测出都具有同一个对象。非极大值抑制依据各边界框和拥有最大
P
c
Pc
Pc的边界框的交并比来作出判断。
- 交并比(Intersection over union): 如图所示,红色方框为真实目标区域,蓝色方框为检测目标区域。两块区域的交集为绿色部分,并集为紫色部分。蓝色方框与红色方框的接近程度可以用IoU比值来定义:
I
o
U
=
I
U
IoU=\frac{I}{U}
IoU=UI
IoU可以表示任意两块区域的接近程度。IoU值介于0~1之间,且越接近1表示两块区域越接近。一般在目标检测任务中,约定如果 I o U > = 0.5 IoU>=0.5 IoU>=0.5 ,那么就说明检测正确。当然标准越大,则对目标检测算法越严格。得到的IoU值越大越好。
以上图为例来说明非极大值抑制的过程:
- 只保留每一个概率高( P c > = 0.6 P_c>=0.6 Pc>=0.6)的格子,此处共有5个格子有高概率检测出目标,分别是0.8、0.7、0.9、0.6、0.7。
- 找出极大值0.9,以该格子预测出的边界框为目标,其余边界框分别与其求交并比。此处,右边概率为0.6和0.7的边界框与之交并比较大,因此将这两个格子的预测结果舍弃。
- 找出剩余概率中的极大值,此处为左边的0.8,用相同的方法舍弃0.7的那个预测结果。
非极大值意味着只输出概率最大的分类结果,同时抑制那些概率不是极大值,却在边界框预测结果上比较接近极大值预测结果的边界框。上述是单对象检测,对于多对象检测,输出标签中就会有多个分量。正确的做法是:对每个输出类别分别独立进行一次非极大值抑制。
5. Anchor Boxes
到目前为止,我们介绍的都是一个网格至多只能检测一个目标。那对于多个目标重叠的情况,例如一个人站在一辆车前面,该如何使用YOLO算法进行检测呢?方法是使用不同形状的Anchor Boxes。
如图所示,同一网格出现了两个目标:人和车。为了同时检测两个目标,我们可以设置两个Anchor Boxes,Anchor box 1检测人,Anchor box 2检测车。即每个网格多加了一层输出。原来的输出维度是 3 x 3 x 8,现在是3 x 3 x 2 x 8(也可以写成3 x 3 x 16的形式)。这里的2表示有两个Anchor Boxes,用来在一个网格中同时检测多个目标。每个Anchor box都有一个
P
c
P_c
Pc值,若两个
P
c
P_c
Pc值均大于某阈值,则检测到了两个目标。
对于重叠的目标,这些目标的中点有可能会落在同一个网格中,对于我们之前定义的输出: y i = [ P c b x b y b h b w c 1 c 2 c 3 ] T y_{i} = \left[ \begin{array}{l} P_{c}\ b_{x}\ b_{y}\ b_{h}\ b_{w}\ c_{1}\ c_{2}\ c_{3} \end{array} \right]^T yi=[Pc bx by bh bw c1 c2 c3]T ,只能得到一个目标的输出。而Anchor box 则是预先定义多个不同形状的Anchor box,我们需要把预测目标对应地和各个Anchor box 关联起来,所以我们重新定义目标向量:
y i = [ P c b x b y b h b w c 1 c 2 c 3 P c b x b y b h b w c 1 c 2 c 3 ⋯   ] T y_{i} = \left[ P_{c}\ b_{x}\ b_{y}\ b_{h}\ b_{w}\ c_{1}\ c_{2}\ c_{3}\ P_{c}\ b_{x}\ b_{y}\ b_{h}\ b_{w}\ c_{1}\ c_{2}\ c_{3}\cdots\right]^T yi=[Pc bx by bh bw c1 c2 c3 Pc bx by bh bw c1 c2 c3⋯]T
用这样的多目标向量分别对应不同的Anchor box,从而检测出多个重叠的目标。
以刚才的图为例,里面有行人和汽车,在经过了极大值抑制操作之后,最后保留了两个边界框(Bounding Box)。行人形状更接近Anchor box 1,汽车形状更接近Anchor box 2,所以我们将人和汽车分配到不同的输出位置。
如何判断边界框和哪个Anchor box匹配:
- 将边界框和Anchor box进行交并比计算,将交并比高的边界框和Anchor box组队。
当然,如果格子中只有汽车的时候,我们使用了两个Anchor box,那么此时我们的目标向量就成为: y i = [ 0 ? ? ? ? ? ? ? 1 b x b y b h b w 0 1 0 ] T y_{i} = \left[ 0\ ?\ ?\ ?\ ?\ ?\ ?\ ?\ 1\ b_{x}\ b_{y}\ b_{h}\ b_{w}\ 0\ 1\ 0\right]^T yi=[0 ? ? ? ? ? ? ? 1 bx by bh bw 0 1 0]T, 其中,“?”代表的是该位置是什么样的参数我们都不关心。
难点问题:
如果我们使用了两个Anchor box,但是同一个格子中却有三个对象的情况,此时只能用一些额外的手段来处理;同一个格子中存在两个对象,但它们的Anchor box 形状相同,此时也需要引入一些专门处理该情况的手段。 但是以上的两种问题出现的可能性不会很大,对目标检测算法不会带来很大的影响。
Anchor box 的选择:
- 一般人工指定Anchor box 的形状,选择5~10个以覆盖到多种不同的形状,可以涵盖我们想要检测的对象的形状;
- 高级方法:K-means 算法:将不同对象形状进行聚类,用聚类后的结果来选择一组最具代表性的Anchor box,以此来代表我们想要检测对象的形状。
6. 整套YOLO算法
将上述关于YOLO算法组件组装在一起构成YOLO对象检测算法。
假设我们要在图片中检测三种目标:行人、汽车和摩托车,同时使用两种不同的Anchor box。
- 构造训练集:根据工程目标,将训练集做如下规划。
- 输入X:同样大小的完整图片;
- 目标Y:使用 3 × 3 3\times3 3×3 网格划分,输出大小 3 × 3 × 2 × 8 3\times3\times2\times8 3×3×2×8(其中3 × 3表示3×3个网格,2是anchor box的数量,8是向量维度) ,或者 3 × 3 × 16 3\times3\times16 3×3×16。
- 对不同格子中的小图,定义目标输出向量Y,如下图示例。
- 对于格子1的目标y就是这样的 y = [ 0 ? ? ? ? ? ? ? 0 ? ? ? ? ? ? ? ] T y = \left[ 0\ ?\ ?\ ?\ ?\ ?\ ?\ ?\ 0\ ?\ ?\ ?\ ?\ ?\ ?\ ?\right]^T y=[0 ? ? ? ? ? ? ? 0 ? ? ? ? ? ? ?]T。
- 而对于格子2的目标y则应该是这样: y = [ 0 ? ? ? ? ? ? ? 1 b x b y b h b w 0 1 0 ] T y = \left[ 0\ ?\ ?\ ?\ ?\ ?\ ?\ ?\ 1\ b_{x}\ b_{y}\ b_{h}\ b_{w}\ 0\ 1\ 0\right]^T y=[0 ? ? ? ? ? ? ? 1 bx by bh bw 0 1 0]T。
- 训练集中,对于车子有这样一个边界框(编号3),水平方向更长一点。所以若有两个anchor boxes,anchor box 1(编号4)和anchor box 2(编号5),红框和anchor box 2的交并比更高,那么车子就和向量的下半部分相关。要注意,这里和anchor box 1有关的
P
c
P_c
Pc是0,剩下这些分量我们就都不关心;对于anchor box 2,由于
P
c
P_c
Pc是1,所以用(
b
x
,
b
y
,
b
h
,
b
w
b_x,b_y,b_h,b_w
bx,by,bh,bw)来指定红边界框的位置。
- 模型预测:输入与训练集中相同大小的图片,同时得到每个格子中不同的输出结果: 3 × 3 × 2 × 8 3\times3\times2\times8 3×3×2×8 。 输出的预测值,以下图为例:
- 左上的格子(编号1)对应输出预测y(编号3)
- 中下的格子(编号2)对应输出预测y(编号4)
- 运行非最大值抑制(NMS)(为展示效果,换一张复杂的图):
- step1: 假设使用了2个Anchor box,那么对于每一个网格,我们都会得到预测输出的2个bounding boxes,其中一个 P c P_c Pc比较高;
- step2: 抛弃概率 P c P_c Pc值低的预测bounding boxes;
- step3: 对每个对象(如行人、汽车、摩托车)分别使用NMS算法得到最终的预测边界框。