1.目标定位Object localization
在构建目标检测之前,我们先了解一下目标定位(object localization),首先我们看看它的定义。
图片分类(image classification) 就是算法遍历图片,判断其中的对象是不是汽车。这节课我们要学习构建神经网络的另一个问题,即定位分类问题(classification with localization)。这意味着,我们不仅要用算法判断图片中是不是一辆汽车,还要在图片中标记出它的位置,用边框或红色方框把汽车圈起来,这就是定位分类问题(classification with localization problem)。其中“定位”(localization)的意思是判断汽车在图片中的具体位置。比如,在自动驾驶程序(autonomous driving application)中,程序不但要检测其它车辆,还要检测其它对象,如行人(pedestrians)、摩托车(motorcycles)等,稍后我们再详细讲。
分类定位问题,通常只有一个较大的对象位于图片中间位置,我们要对它进行识别和定位。而在目标检测问题中,图片可以含有多个对象(multiple objects),甚至单张图片中会有多个不同分类的对象。因此,图片分类(image classification)的思路可以帮助学习分类定位(classification with localization),而目标定位的思路又有助于学习目标检测(detection) ,我们先从分类和定位(classification with localization)开始讲起。
如上图,这是图片分类问题,输入一张图片到多层卷积神经网络。这就是卷积神经网络,它会输出一个特征向量,并反馈给softmax单元来预测图片类型。在构建汽车自动驾驶系统时,识别的对象可能包括以下几类:行人、汽车、摩托车和背景,这意味着图片中没有行人、汽车和摩托车,输出结果会是背景对象,这四个分类就是softmax函数可能输出的结果。
这就是标准的分类过程(classification pipeline),如果你还想定位图片中汽车的位置,可以让神经网络多输出几个单元,输出一个边界框。具体就是让神经网络再多输出4个数字,标记为b_x,b_y,b_h和b_w,这四个数字是被检测对象的边界框的参数化表示(parameterize)。
约定一下本周课程将使用的符号表示,图片左上角的坐标为(0,0),右下角标记为(1,1)。要确定边界框的具体位置,需要指定红色方框的中心点(midpoint),这个点表示为(b_x,b_y),边界框的高度为b_h,宽度为b_h。因此训练集(train set)不仅包含神经网络要预测的对象分类标签,还要包含表示边界框的这四个数字,接着采用监督学习算法,输出一个分类标签(class label),还有四个参数(four parameters),从而给出检测对象的边框位置。在这个例子中,b_x的理想值是0.5,因为它表示汽车位于图片水平方向的中间位置;b_y大约是0.7,表示汽车位于距离图片底部十分之三的位置;b_h约为0.3,因为红色方框的高度是图片高度的0.3倍;b_w约为0.4,红色方框的宽度是图片宽度的0.4倍。
下面具体看如何为监督学习任务定义目标标签y,如下图:
这有四个分类,神经网络输出的是这四个数字和一个分类标签,或分类标签出现的概率。目标标签y的定义如下:
这是一个向量,第一个p_c表示是否含有对象, 在这里如果对象属于前三类(行人(pedestrian)、汽车(car)、摩托车(motorcycle)),则p_c=1,如果是背景(background),则图片中没有要检测的对象,则p_c=0。我们可以认为它表示被检测对象属于某一类的概率,背景分类除外。如果检测到对象,输出被检测对象的边界框参数b_x,b_y,b_h和b_w,同时输出c_1、c_2和c_3,表示该对象属于1-3类中的哪一类(行人、汽车或者摩托车)。
在这里假设图片中只有一个对象,在这个分类定位问题中,图片最多只会出现其中一个对象。
上图中给出了两个例子的标签y的表示:只有一辆车(紫色框)和背景图像(绿色框,当p_c=0时,y的其它参数变得毫无意义,这里都写成问号,表示“毫无意义”的参数(so this is a don’t care))。针对给定的被标记的训练样本,不论图片中是否含有定位对象,构建输入图片x和分类标签y的具体过程都是如此。这些数据最终定义了训练集(define your training set)。
最后看一下神经网络的损失函数(loss function),参数为网络输出y帽和类别y,采用平方误差策略(squared error),则损失值等于每个元素相应差值的平方和,公式如下:
分析一下,当y_1=1时,平方误差策略为这8个元素预测值和实际输出结果之间差值的平方。当y_1=0时,y中的后7个元素都不用考虑,只需要考虑神经网络评估yy_1(即p_c)的准确度。
注意一下,这里用平方误差简化了描述过程,实际应用中,通常做法是对边界框坐标应用平方差或类似方法,对p_c应用逻辑回归函数,甚至采用平方预测误差也是可以的。
以上就是利用神经网络解决对象分类和定位问题的详细过程,结果证明,利用神经网络输出批量实数来识别图片中的对象是个非常有用的算法。下节课,还有另一种思路,就是把神经网络输出的实数集作为一个回归任务(regression task),这个思想也被应用于计算机视觉的其它领域,也是非常有效的。
2.特征点检测Landmark detection
神经网络也可以通过输出图片上特征点的(x,y)坐标来实现对目标特征的识别,下面看几个例子。
假设你正在构建一个人脸识别应用(face recognition application),你希望算法可以给出眼角的具体位置。眼角坐标为(x,y),让神经网络的最后一层多输出两个数字l_x和l_y,最为眼角的坐标值。如果你想知道两只眼睛的四个眼角的具体位置,那么依次用四个特征点来表示从左到右的四个眼角,例如第一个特征点(l_1x,l_1y),第二个特征点(l_2x,l_2y)等。
同样你也可以根据嘴部的关键点输出值来确定嘴的形状,也可以提取鼻子周围得到关键特征点。假设脸部有64个特征点(landmarks),有些点甚至可以定义脸部轮廓(define the edge of the face)或下颌轮廓(define the jawline)。选定特征点个数,并生成包含这些特征点的标签训练集(label training set),然后利用神经网络输出脸部关键特征点的位置。
具体做法是,准备一个卷积网络和一些特征集,将人脸图片输入卷积网络,输出1或0,1表示有人脸,0表示没有人脸,然后输出(l_1x,l_1y)……直到(l_64x,l_64y)。这里一共有129(1+2*64=129)个输出单元,由此实现对图片的人脸检测和定位。这只是一个识别脸部表情的基本构造模块(basic building block),如果你玩过Snapchat或其它娱乐类应用(other entertainment),你应该对AR(增强现实Augmented Reality)过滤器多少有些了解,Snapchat过滤器实现了在脸上画皇冠和其他一些特殊效果。
再看一个例子,上图的第三张图,如果你对人体姿态检测(people post-detection)感兴趣,也可以定义一些关键特征点(key positions),如胸部的中点(the midpoint of the chest),左肩(the left shoulder),左肘(left elbow),腰(the wrist)等,从胸部中心点(l_1x,l_1y)一直向下,一直到(l_32x,l_32y)。然后通过神经网络标注人物姿态的关键特征点,再输出这些标注过的特征点,就相当于输出了人物的姿态动作。一旦了解如何用二维坐标系(two coordinates)定义人物姿态,操作起来就相当简单了。要明确一点,特征点的特性(identity)在所有图片中必须保持一致,就好比,特征点1始终是右眼的外眼角,特征点2是右眼的内眼角,特征点3是左眼内眼角,特征点4是左眼外眼角等等。同样可以利用特征点实现其他有趣的效果,比如判断人物的动作姿态(estimate the pose of a person),识别图片中的人物表情(recognize someone’s emotion from a picture)等等。
以上就是特征点检测(landmark detection)的内容,下节课我们将利用这些构造模块来构建目标检测算法。
3.目标检测Object detection
学过了目标定位(object localization)和特征点检测(landmark detection),今天我们来构建一个目标检测算法。这节课,我们将学习如何通过卷积网络进行目标检测,采用的是基于滑动窗口的目标检测算法(the sliding windows detection algorithm)。
假如在构建一个汽车检测算法(car detection algorithm),(1)首先创建一个标签训练集(a label training set),也就是x和y表示适当剪切的汽车图片样本(closely cropped examples of cars),前三张图片是正样本(positive example),因为它们是汽车图片。(2)然后可以训练卷积网络,输入为这些适当裁剪过的图片,输出为y(0或1表示图片中有汽车或没有汽车)。(3)训练完这个卷积网络,就可以用它来实现滑动窗口目标检测(sliding windows detection),具体步骤如下。
上图是一张测试图片(test image),操作步骤如下三步:
①首先选定一个特定大小的窗口(pick a certain window sizes),将这个红色小方块(a small rectangular region)输入卷积神经网络,卷积网络开始进行预测,即判断红色方框内有没有汽车。
②接下来会继续处理第二个图像,即红色方框稍向右滑动之后的区域,并输入给卷积网络,因此输入给卷积网络的只有红色方框内的区域,再次运行卷积网络。
③然后处理第三个图像,依次重复操作,直到这个窗口滑过图像的每一个角落。
为了滑动得更快,这里选用的步幅比较大,思路是以固定步幅移动窗口,遍历图像的每个区域,把这些剪切后的小图像输入卷积网络,对每个位置按0或1进行分类,这就是所谓的图像滑动窗口操作。
重复上述操作,不过这次我们选择一个更大的窗口,截取更大的区域(take a slightly larger region),如下图:
然后第三次重复操作,这次选用更大的窗口(using even larger windows)。如下图:
第三次更大的窗口使得不论汽车在图片的什么位置,总有一个窗口可以检测到它。
这种算法叫作滑动窗口目标检测(sliding windows detection),因为以某个步幅滑动这些方框窗口遍历整张图片,对这些方形区域进行分类,判断里面有没有汽车。
滑动窗口目标检测算法也有很明显的缺点,就是计算成本(computational cost),因为你在图片中剪切出太多小方块,卷积网络要一个个地处理。如果你选用的步幅很大,显然会减少输入卷积网络的窗口个数,但是粗糙间隔尺寸可能会影响性能。反之,如果采用小粒度或小步幅,传递给卷积网络的小窗口会特别多,这意味着超高的计算成本。
所以在神经网络兴起之前,人们通常采用更简单的分类器进行目标检测,比如通过采用手工处理工程特征的简单的线性分类器(a simple linear classifier)来执行目标检测。至于误差(error),因为每个分类器的计算成本都很低,它只是一个线性函数。然而,卷积网络运行单个分类任务的成本却高得多,像这样滑动窗口太慢。除非采用超细粒度(a very fine granularity)或极小步幅(a very small stride),否则无法准确定位图片中的对象。
不过,庆幸的是,计算成本问题已经有了很好的解决方案,大大提高了卷积层上应用滑动窗口目标检测器的效率,关于它的具体实现,我们下节课再讨论。
4.滑动窗口的卷积实现Convolutional implementation of sliding windows
为了构建滑动窗口的卷积应用,首先要知道如何把神经网络的全连接层转化成卷积层。
如上图第一行,假设目标检测算法输入一个14×14×3的图像,过滤器大小为5×5,数量是16,过滤器处理之后为10×10×16。然后通过参数为2×2的最大池化操作,图像减小到5×5×16。然后添加一个连接400个单元的全连接层,接着再添加一个全连接层,最后通过softmax单元输出y。这里先做一点改动,用4个数字来表示y,它们分别对应softmax单元所输出的4个分类出现的概率。这4个分类可以是行人、汽车、摩托车和背景或其它对象。
如上图第二行,它的前几层和之前的一样,而对于全连接层,我们可以用5×5的过滤器来实现,数量是400个,输入图像大小为5×5×16,用5×5的过滤器对它进行卷积操作,过滤器实际上是5×5×16,因为在卷积过程中,过滤器会遍历这16个通道,所以这两处的通道数量必须保持一致,输出结果为1×1。假设应用400个这样的5×5×16过滤器,输出维度就是1×1×400,我们不再把它看作一个含有400个节点的集合,而是一个1×1×400的输出层。从数学角度看(mathematically),它和全连接层是一样的,因为这400个节点中每个节点都有一个5×5×16维度的过滤器,所以每个值都是上一层这些5×5×16激活值经过某个任意线性函数的输出结果。
我们再添加另外一个卷积层,这里用的是1×1卷积,假设有400个1×1的过滤器,下一层的维度是1×1×400,它其实就是上个网络中的这一全连接层。最后经由1×1过滤器的处理,得到一个softmax激活值,通过卷积网络,我们最终得到这个1×1×4的输出层,而不是这4个数字。
以上就是用卷积层代替全连接层的过程,结果这几个单元集变成了1×1×400和1×1×4的维度。
参考论文:Sermanet, Pierre, et al. “OverFeat: Integrated Recognition, Localization and Detection using Convolutional Networks.” Eprint Arxiv (2013).
掌握了卷积知识(Armed of this conversion),我们再看看如何通过卷积实现滑动窗口目标检测算法。借鉴了屏幕下方这篇关于OverFeat的论文,它的作者包括Pierre Sermanet,David Eigen,张翔,Michael Mathieu,Rob Fergus,Yann LeCun。
如上图第一行,假设向滑动窗口卷积网络输入14×14×3的图片,为了简化演示和计算过程,这里我们依然用14×14的小图片。和前面一样,神经网络最后的输出层,即softmax单元的输出是1×1×4,这里简化成正面,严格来说,14×14×3应该是一个长方体,第二个10×10×16也是一个长方体。所以,对于1×1×400的这个输出层,也只画了它1×1的那一面,所以这里显示的都是平面图,而不是3D图像。
如上图第二行,假设输入给卷积网络的图片大小是14×14×3,测试集图片是16×16×3,①现在给这个输入图片加上黄色条块,在最初的滑动窗口算法中,你会把这片蓝色区域输入卷积网络(红色笔标记)生成0或1分类。②接着滑动窗口,步幅为2个像素,向右滑动2个像素,将这个绿框区域输入给卷积网络,运行整个卷积网络,得到另外一个标签0或1。③继续将这个橘色区域输入给卷积网络,卷积后得到另一个标签,④最后对右下方的紫色区域进行最后一次卷积操作。具体操作演示如下:
我们在这个16×16×3的小图像上滑动窗口,卷积网络运行了4次,于是输出了4个标签。结果发现,这4次卷积操作中很多计算都是重复的。最终,在输出层这4个子方块中,蓝色的是图像左上部分14×14的输出(红色箭头标识),右上角方块是图像右上部分(绿色箭头标识)的对应输出,左下角方块是输入层左下角(橘色箭头标识),也就是这个14×14区域经过卷积网络处理后的结果,同样,右下角这个方块是卷积网络处理输入层右下角14×14区域(紫色箭头标识)的结果。
所以该卷积操作的原理是不需要把输入图像分割成四个子集,分别执行前向传播,而是把它们作为一张图片输入给卷积网络进行计算,其中的公共区域可以共享很多计算,就像这里我们看到的这个4个14×14的方块一样。
下面再看一个更大的图片样本。
假如对一个28×28×3的图片应用滑动窗口操作,跟上一个范例一样,以14×14区域滑动窗口,首先在这个区域应用滑动窗口,其结果对应输出层的左上角部分。接着以大小为2的步幅不断地向右移动窗口,直到第8个单元格,得到输出层的第一行。然后向图片下方移动,最终输出这个8×8×4的结果。因为最大池化参数为2,相当于以大小为2的步幅在原始图片上应用神经网络。
总结一下滑动窗口的实现过程如下:
在原图上剪切出一块区域,假设它的大小是14×14,把它输入到卷积网络。继续输入下一块14×14区域,重复操作,直到某个区域识别到汽车。注意前一页的讲解,我们不能依靠连续的卷积操作来识别图片中的汽车,我们可以对大小为28×28的整张图片进行卷积操作,一次得到所有预测值,如果足够幸运,神经网络便可以识别出汽车的位置。
以上就是在卷积层上应用滑动窗口算法的内容,它提高了整个算法的效率。不过这种算法仍然存在一个缺点(weakness),就是边界框的位置可能不够准确。下节课,我们将学习如何解决这个问题。
5.Bounding Box预测Bounding box predictions
在上一个视频中,我们了解了滑动窗口法的卷积实现,这个算法效率更高,但仍然存在问题,不能输出最精准的边界框。在这个视频中,我们看看如何得到更精准的边界框。
如上图,在滑动窗口法中,这些边界框没有一个能完美匹配汽车位置,也许右下角的蓝框是最匹配的啦。甚至最完美的框(右下角的红色框)不是正方形,而是长方形。那么有没有办法让这个算法输出更精准的边界框呢?
其中一个能得到更精准边界框的算法是YOLO算法,YOLO(You only look once)意思是你只看一次,这是由Joseph Redmon,Santosh Divvala,Ross Girshick和Ali Farhadi提出的算法。你的输入图像是100×100的,然后在图像上放一个3×3网格,也可能是其他网络。基本思路是使用图像分类(image classification)和定位算法(localization algorithm),原理与本周的第一个视频类似。例如左上的格子没有汽车,分类标签y是:
最后,9个格子中(3×3的网格)的任何一个都会得到一个8维输出向量,总的输出尺寸是3×3×8。
如果你现在要训练一个输入为100×100×3的神经网络,现在这是输入图像,然后你有一个普通的卷积网络,卷积层,最大池化层等等,选择卷积层和最大池化层,这样最后就映射到一个3×3×8输出尺寸。
所以这个算法的优点在于神经网络可以输出精确的边界框。重申一下,把对象分配到一个格子的过程是,将这个对象分配到其中点所在的格子,所以即使对象可以横跨多个格子,也只会被分配到9个格子其中之一,就是3×3网络的其中一个格子,或者19×19网络的其中一个格子。在19×19网格中,两个对象的中点(图中蓝色点所示)处于同一个格子的概率就会更低。
所以要注意:
- 这和图像分类和定位算法非常像,它显式地输出边界框坐标,能让神经网络输出边界框,可以具有任意宽高比,并且能输出更精确的坐标,不会受到滑动窗口分类器的步长大小限制。
- 这是一个卷积实现,你并没有在3×3网格上跑9次算法,或者你用的是19×19的网格,19平方是361次,所以你不需要让同一个算法跑361次。相反,这是单次卷积实现,但你使用了一个卷积网络,有很多共享计算步骤(shared computation),在处理这3×3计算中很多计算步骤是共享的,或者你的19×19的网格,所以这个算法效率很高。
- 事实上YOLO算法有一个好处,也是它受欢迎的原因,因为这是一个卷积实现,实际上它的运行速度非常快,可以达到实时(real-time)识别。
在YOLO算法中,对于这个方框(橘色),我们约定左上这个点是(0,0),然后右下这个点是(1,1),b_x和b_y必须在0-1之间,b_h和b_w可能会大于1。
总之,这就是YOLO算法(你只看一次算法),在接下来的几个视频中,Andrew会讲解一些其他的思路可以让这个算法做的更好。在此期间,如果你感兴趣,也可以看看YOLO的论文。
参考论文:Redmon, Joseph, et al. “You Only Look Once: Unified, Real-Time Object Detection.” (2015):779-788.
Andrew:不过看这些论文之前,先给你们提个醒,YOLO论文是相对难度较高的论文之一。实际上,即使是资深研究员也有读不懂研究论文的时候,必须去读源代码,或者联系作者之类的才能弄清楚这些算法的细节。但你们不要被我吓到,你们可以自己看看这些论文,如果你们感兴趣的话,但这篇论文相对较难。现在你们了解了YOLO算法的基础,我们继续讨论别的让这个算法效果更好的研究。
6.交并比Intersection over union
如何判断目标检测算法运作良好呢?在本视频中,你将了解到并交比(intersection over union)函数,可以用来评价目标检测算法。在下一个视频中,我们用它来插入一个分量来进一步改善检测算法。
交并比(loU)函数做的是计算两个边界框交集和并集之比。两个边界框的并集是这个区域,就是属于包含两个边界框区域(绿色阴影表示区域),而交集就是这个比较小的区域(橙色阴影表示区域),那么交并比就是交集的大小,这个橙色阴影面积,然后除以绿色阴影的并集面积。
参考:
交并比:IOU=(A∩B)/(A∪B)
一般来说,IoU大于等于0.5,那么结果是可以接受的,就说检测正确。如果预测器和实际边界框完美重叠,loU就是1,因为交集就等于并集。一般约定,0.5是阈值(threshold),用来判断预测的边界框是否正确。loU越高,边界框越精确。
人们定义loU这个概念是为了评价你的对象定位算法是否精准,但更一般地说,loU衡量了两个边界框重叠地相对大小。(More generally, IoU is a measure of the overlap between two bounding boxes.)如果你有两个边界框,你可以计算交集(intersession),计算并集(union),然后求两个数值的比值(the ratio of the two areas),所以这也可以判断两个边界框是否相似,我们将在下一个视频中再次用到这个函数,当我们讨论非最大值抑制(non-max suppression)时再次用到。
7.非极大值抑制Non-max suppression
目前为止的目标检测中可能出现的问题是你的算法可能对同一个对象做出多次检测。非极大值抑制(non-max suppression)这个方法可以确保你的算法对每个对象只检测一次,我们讲一个例子。
假设你需要在这张图片里检测行人和汽车,你可能会在上面放个19×19网格,理论上这辆车只有一个中点,所以它应该只被分配到一个格子里,左边的车子也只有一个中点,所以理论上应该只有一个格子做出有车的预测。
但是当你实际在运行算法时,会出现上图的情况,可能好几个格子会认为有车。
当你在361个格子上都运行一次图像检测和定位算法,最后可能会对同一个对象做出多次检测,所以非极大值抑制做的就是清理这些检测结果。这样一辆车只检测一次,而不是每辆车都触发多次检测。具体做法如下图:
首先看概率最大的那个,这个例子(右边车辆)中p_c是0.9,然后就说这是最可靠的检测(most confident detection),所以我们就用高亮标记,表明这里找到了一辆车。这么做之后,非极大值抑制就会逐一审视剩下的矩形,所有和这个最大的边框有很高交并比,高度重叠的其他边界框,那么这些输出就会被抑制。所以这两个矩形(p_c分别是0.6和0.7),和淡蓝色矩形重叠程度很高,所以会被抑制,变暗,表示它们被抑制了。
接下来,逐一审视剩下的矩形,找出概率最高,p_c最高的一个,在这种情况下是0.8,如上图,我们就认为这里检测出一辆车(左边车辆),然后非极大值抑制算法就会去掉其他loU值很高的矩形。所以现在每个矩形都会被高亮显示(highlighted)或者变暗(darkens),如果你直接抛弃变暗的矩形,那就剩下高亮显示的那些,这就是最后得到的两个预测结果。
所以这就是非极大值抑制(non-max suppression),非最大值意味着你只输出概率最大的分类结果,但抑制很接近,但不是最大的其他预测结果,所以这方法叫做非极大值抑制。
下面来看看算法的细节。假设这里只做汽车检测。
现在要实现非极大值抑制,你可以做的:
- 第一件事是,去掉所有p_c小于某个阈值的边界框,这里假设是0.6,所以只是抛弃所有低概率(low probability)的边界框。
- 接下来使用非极大值抑制,while循环的第一步你就一直选择概率p_c最高的边界框,取一个边界框,让它高亮显示,这样做出有一辆车的预测。
- while循环的第二步是上一步变暗的那些边界框以及和高亮标记的边界重叠面积很高的那些边界框抛弃掉。
到目前为止,Andrew只介绍了算法检测单个对象(a single object)的情况,如果你尝试同时检测三个对象,比如说行人、汽车、摩托,那么输出向量就会有三个额外的分量(three additional components)。事实证明,正确的做法是独立进行三次非极大值抑制,对每个输出类别都做一次。
这就是非极大值抑制,如果你能实现我们说过的目标检测算法,你其实可以得到相当不错的结果。但结束我们对YOLO算法的介绍之前,最后Andrew还有一个细节想给大家分享,可以进一步改善算法效果,就是anchor box的思路,我们下一个视频再介绍。
8.锚 Anchor Boxes
到目前为止,目标检测中存在的一个问题是每个格子只能检测出一个对象,如果想检测出多个对象,可以使用anchor box这个概念。
对于这张图片,继续使用3×3网格,注意行人的中点和汽车的中点几乎在同一个地方,两者都落入到同一个格子中。在检测这三个类别(行人、汽车和摩托车)时,它将无法输出检测结果,所以必须从两个检测结果中选一个。
而anchor box的思路是预先定义两个不同形状的anchor box,把预测结果和这两个anchor box关联起来。一般来说,你可能会用更多的anchor box,可能要5个甚至更多,但对于这个视频,我们就用两个anchor box。此时y的类别标签不再是:
而是重复两次:
前8个(上图中绿色方框标记的参数)是和anchor box 1关联的8个参数,后面的8个参数(橙色方框标记的元素)是和anchor box 2相关联。因为行人的形状更类似于anchor box 1的形状,而不是anchor box 2的形状,所以你可以用这8个数值(前8个参数),编码p_c=1,代表有个行人。然后是车子,因为车子的边界框比起anchor box 1更像anchor box 2的形状,这里第二个对象是汽车,那么绿色方框的所有参数和检测汽车相关。
总结一下,现在每个对象都和之前一样分配到对象中点所在的格子中,以及分配到和对象形状交并比最高的anchor box中。你需要观察哪一个anchor box和实际边界框的交并比更高,不管选的是哪一个,这个对象不只分配到一个格子,而是分配到一对,即(grid cell,anchor box)对,这就是对象在目标标签中的编码方式。所以现在输出y就是3×3×16,上一张幻灯片中你们看到y现在是16维的,或者你也可以看成是3×3×2×8,因为现在这里有2个anchor box,而y是8维的。y维度是8,因为我们有3个对象类别,如果你有更多对象,那么y的维度会更高。
因此,以上就是anchor box的概念,anchor box是为了处理两个对象出现在同一个格子的情况,实践中这种情况很少发生,特别是如果你用的是19×19网格而不是3×3的网格,两个对象中点处于361个格子中同一个格子的概率很低,会出现但出现频率不高。也许设立anchor box的好处在于anchor box能让你的学习算法能够更有针对性,特别是如果你的数据集有一些很高很瘦的对象,比如说行人,还有像汽车这样很宽的对象,这样你的算法就能更有针对性的处理,这样有一些输出单元可以针对检测很宽很胖的对象,比如说车子,然后输出一些单元,可以针对检测很高很瘦的对象,比如说行人。
最后,你应该怎么选择anchor box呢?人们一般手工指定anchor box形状,你可以选择5到10个anchor box形状,覆盖到多种不同的形状,可以涵盖你想要检测的对象的各种形状。还有一个更高级的版本,你们如果接触过一些机器学习,可能知道后期YOLO论文中有更好的做法,就是所谓的k-平均算法(k-means),可以将两类对象形状聚类,如果我们用它来选择一组anchor box,选择最具有代表性的一组anchor box,可以代表你试图检测的十几个对象类别,但这其实是自动选择anchor box的高级方法。如果你就人工选择一些形状,合理的考虑到所有对象的形状,你预计会检测的很高很瘦或者很宽很胖的对象,这应该也不难做。
所以这就是anchor box,在下一个视频中,我们把学到的所有东西一起融入到YOLO算法中。
9.YOLO 算法Putting it together: YOLO algorithm
你们已经学到目标检测算法的大部分组件了,在这个视频里,我们会把所有组件组装在一起构成YOLO目标检测算法。
这里有3个类别标签(行人、汽车和摩托车),如果你要用两个anchor box,那么输出y就是3×3×2×8,其中3×3表示3×3个网格,2是anchor box的数量,8是向量维度,所以最终输出尺寸就是3×3×16。
接下来看看你的算法是怎么做出预测的。
输入图像,你的神经网络的输出尺寸是这个3×3×2×8,对于9个格子,每个都有对应的向量。对于左上的格子(对应右边蓝色的y向量),这里没有任何对象,则神经网络输出的第一个和第二个p_c为0,剩下的输入一些数字,但这些数字基本上会被忽略,因为神经网络告诉你,那里没有任何东西,所以输出是不是对应一个类别的边界框无关紧要,所以基本上是一组数字,多多少少都是噪音。对于有汽车的那个格子(对应右边绿色的y向量),第一个p_c为0和一下噪音,第二个p_c是1和指定一个相对准确边界框的b_x等参数,这就是神经网络做出预测的过程。最后你要运行一下这个非极大值抑制。
我们看看一张新的测试图像,这就是运行非极大值抑制的过程。①如果你使用两个anchor box,那么对于9个格子中任何一个都会有两个预测的边界框,其中一个的概率p_c很低。但9个格子中,每个都有两个预测的边界框,比如说我们得到的边界框是是这样的,注意有一些边界框可以超出所在格子的高度和宽度(编号1所示)。②接下来你抛弃概率很低的预测,去掉这些连神经网络都说,这里很可能什么都没有,所以你需要抛弃这些(编号2所示)。③最后,如果你有三个目标检测类别,你希望检测行人,汽车和摩托车,那么你要做的是,对于每个类别单独运行非极大值抑制,处理预测结果所属类别的边界框,用非极大值抑制来处理行人类别,用非极大值抑制处理车子类别,然后对摩托车类别进行非极大值抑制,运行三次来得到最终的预测结果。所以算法的输出(output)最好能够检测出图像里所有的车子,还有所有的行人(编号3所示)。
这就是YOLO目标检测算法,这实际上是最有效的目标检测算法之一,包含了整个计算机视觉目标检测领域文献中很多最精妙的思路。这里还有一个可选的视频,你们可以看,也可以不看。
10.候选区域Region proposals (Optional)
在阅读目标检测的文献时,可能会看到候选区域(region proposals),这在计算机视觉领域是非常有影响力的概念。Andrew把这个视频定为可选视频是因为用到候选区域这一系列算法的频率没有那么高,但是这些工作是很有影响力的,你们在工作中也可能会碰到。
之前的滑动窗法算法有一个缺点是,在显然没有任何对象的区域浪费时间,因为需要对所有窗口进行检测器。
所以Ross Girshick,Jeff Donahue,Trevor Darrell,Jitendra Malik,在本幻灯片底部引用到的论文中提出一种叫做R-CNN的算法,即带区域的卷积网络(regions with convolutional network),也称带区域的CNN。R-CNN算法尝试提前选出一些区域,然后在这些区域上运行卷积网络分类器,所以这里不再针对每个滑动窗运行检测算法,而是只选择在少数窗口上运行卷积网络分类器。
如上图,选出候选区域的方法是运行图像分割算法(segmentation algorithm),得到的分割结果在最右边。比如说,分割算法在这里得到一个色块(blob),所以你可能会选择这样蓝色的边界框(编号1),然后在这个色块上运行分类器,还有这个绿色的色块(编号2),也运行一次分类器,看看有没有东西。在这种情况下,如果在蓝色色块上(编号3)运行分类器,希望你能检测出一个行人,如果你在青色色块(编号4)上运行算法,也许你可以发现一辆车。
这个细节就是所谓的分割算法,先找出可能2000多个色块,然后在这2000个色块上放置边界框并运行分类器,这样需要处理的位置可能要少的多,可以减少卷积网络分类器运行时间,比在图像所有位置运行一遍分类器要快。特别是这种情况,现在不仅是在方形区域(编号5)中运行卷积网络,也会在高高瘦瘦(编号6)的区域运行,尝试检测出行人,然后在很宽很胖的区域(编号7)运行,尝试检测出车辆,同时在各种尺度运行分类器。
这就是R-CNN的特色概念,现在看来R-CNN算法还是很慢的。所以有一系列的研究工作去改进这个算法,基本的R-CNN算法是使用某种算法求出候选区域,然后对每个候选区域运行一下分类器,每个区域会输出一个标签,有没有车子?有没有行人?有没有摩托车?并输出一个边界框,这样你就能在确实存在对象的区域得到一个精确的边界框。
注意R-CNN算法不会直接信任输入的色块边界框,它也会输出一个边界框b_x,b_y,b_h和b_w,这样得到的边界框比较精确,比单纯使用图像分割算法给出的色块边界要好,这样可以得到相当精确的边界框。
R-CNN算法的一个缺点是太慢了,所以这些年来有一些对R-CNN算法的改进工作。(上图第二行)Ross Girshik提出了Fast R-CNN算法,它基本上是R-CNN算法,不过用卷积实现了滑动窗法。最初的算法是逐一对区域分类的,所以Fast R-CNN用的是滑动窗法的一个卷积实现,这和《卷积的滑动窗口实现》中看到的大致相似,这显著提升了R-CNN的速度。
事实证明,Fast R-CNN算法的其中一个问题是得到候选区域的聚类步骤仍然非常缓慢,所以任少卿(Shaoqing Ren)、何凯明(Kaiming He)、Ross Girshick和孙剑(Jiangxi Sun)提出了更快的R-CNN算法(Faster R-CNN),使用卷积神经网络,而不是更传统的分割算法来获得候选区域色块,结果比Fast R-CNN算法快得多。不过Andrew认为大多数Faster R-CNN的算法实现还是比YOLO算法慢很多。
总之,候选区域的概念在计算机视觉领域的影响力相当大。但是这是Andrew的个人看法而不是整个计算机视觉研究界的看法,Andrew觉得候选区域是一个有趣的想法,但这个方法需要两步,首先得到候选区域,然后再分类,能够一步做完,类似于YOLO算法,在Andrew看来,是长远而言更有希望的方向。
参考:
Joseph Redmon, Santosh Divvala, Ross Girshick, Ali Farhadi – You Only Look Once: Unified, Real-Time Object Detection (2015)
Joseph Redmon, Ali Farhadi – YOLO9000: Better, Faster, Stronger (2016)
Allan Zelener – YAD2K: Yet Another Darknet 2 Keras
The official YOLO website (pjreddie.com/darknet/yol…)
本文正在参加人工智能创作者扶持计划