第一课:对象定位。
对象检测是计算机视觉中的一个极速发展的领域。为了建立对象检测,你需要先学习对象定位。
接下来要解决的问题是学习建立网络,即分类并定位。这就意味着不仅仅要识别出车,并且算法也负责生成一个边框,或者画出一个红色矩形,这就是所谓的分类并定位问题。
接下来还有对象检测,即如何检测一张图片中的多个对象,全部检测并定位。
本周对于图像分类和分类定位问题,通常它们只有一个对象,通常是你要识别一个 图片正中央的一个明显的对象。
相比之下,在对象检测问题中,可能会有很多不同类别的对象,你在图像分类中学习到的方法将会对分类并定位也有用处。
定位的方法也会对物体检测有帮助。
图像分类并定位:
对于标准的图像分类流程,你输入原始图像x,经过多层卷积网络,最终输出一个特征向量,特征向量传给softmax,输出预测的结果。
如果你也想定位图中的汽车,为了实现这个,你可以改变你的神经网络,通过得到更多的输出单位,使得这个神经网络可以输出一个边框。
具体来说,你的神经网络需要额外输出4个数字。bx,by,bh和bw。这四个参数将确定检测对象的边框的参数。
所以如果你的训练集不仅仅是包含对象类别标签,而且也包含额外的四个数字,给出边界框。你可以用监督学习来让你的算法输出不仅仅是标签,还有4个变量来告诉你所检测对象的边界框。
所以可以更形式一点,根据我们如何定义目标标签y作为监督学习任务。
目标标签y的定义如下:
向量:
Pc:是否有个对象?是否包含一个对象的概率,你努力检测的其中一个类在的概率。
bx,by,bh和bw:你所检测对象的边界框。
c1,c2和c3:告诉我们是类1,类2还是类3。
记住:我们假定图片中只有一个对象,即在分类定位的问题上,最多有一个对象出现在图片中。
所以给一系列的训练例子,就可以构造出x——输入图片以及y——类别标签,对于图中有一个对象或者没有对象时,(x,y)定义了你的训练集。
最后,介绍一下你所用来训练神经网络的损失函数:
准确标签是y,神经网络输出的是y帽,那么损失是:
如果你用均方差:
if y1 = 1:8个元素的平方差和
if y1 = 0:(y1帽 - y1) ^ 2
总结一下:如果y1 = 1,你可以从8个组件的数据输出使用均方差penalize预测的平方偏差。
如果y1 = 0, 那么从第二个到第八个元素我都不关心,你所要关心的就是神经网络预测y1有多准确。
这里使用均方差是为了简化描述。现实中,你可以使用log函数,你通常可以使用均方差或者一些类似均方差的方法针对边界框的坐标。对于Pc,你可以使用类似逻辑回归计算损失,而且如果你只用均方差,效果可能也是不错的。
所以这就是你如何运用神经网络来分类一个对象,也可以用来定位它。让神经网络输出一堆数字的想法,可以告诉你图片中东西位置,被证明是一个非常强大的方法。让神经网络输出一系列数字想法的其他应用?回归?
第二课:地标检测
在上一个视频中,学习了如何通过神经网络输出四个bx,by,bh和bw来指定您希望神经网络定位的对象的边界框。
在更一般的情况下,您可以使用神经网络输出您希望神经网络识别的重要点和图像(有时称为地标,你想要神经网络识别出的东西)的X和Y坐标。
在人脸识别中,使用神经网络输出人脸上的点的很多点(64个地标,帮助你识别眼角,定义脸型等)的位置,并产生一个包含所有地标的标签训练集合。然后你可以让神经网络告诉你所有脸部重要的位置或者重要地标在哪里?
即如果用一张脸x作为图像输入,那么经过卷积神经网络,输出一个face?以及l1x,l1y...l64x,l64y,l表示地标,从而在这个例子中的到129个输出。并且这个可以告诉你图片上是否有张脸,并且所有关键特征是否在脸上。
以上就是一个从脸部识别表情的基本模块。
能够从脸上识别出表情,也是电脑图像特效的重要组成部分。
当然为了有一个这样的网络,你需要一个有标签的训练集,一组图像(x,y),由人工枯燥的遍历并注释所有这些地标。
人体姿势检测,可以建立一个神经网络从人的姿势的关键位置以及通过这个神经网络输出,得到人的姿势。
当然为了实现这个,你也需要指出关键特征l1x,l1y是胸部...
这个方法似乎很简单,仅仅是填充一堆输出单位,输出不同的你想要识别的特征的x,y坐标,声明一点,地标的身份在不同的图像中一定要一致,即标签在不同的图片中必须保持一致。但
但是如果你可以雇佣一个打标签的人或者你自己去给足够大的数据集做标记的话,那么神经网络可以输出所有的特征(地标),从而实现一个比较有趣的应用,比如姿势识别,表情识别等。
接下来建立图像检测。
第三课:目标检测
你已经了解了目标定位和地标检测,现在让我们建立一个目标检测算法。你将学会如何使用一个卷积神经网络和滑动窗口检测的算法进行目标检测。
对于一个汽车检测:
你可以先创建一个有标记的训练数据集,x和对应的y,训练集中包含紧密裁剪的汽车样例,即x(图像中)只包含车。你可以拍一个照片,然后将其余不是车的部分全部裁剪掉,然后得到一张汽车居中并占据几乎全部画面的图像。
有了这个有标记的训练数据集,你就可以训练一个卷积神经网络。然后就可以利用这个卷积神经网络进行汽车图像的识别,输出y = 1/0,是否是车。当你训练好了这个卷积神经网络之后,你就可以把它用在滑动窗口检测中了。
具体做法是:
先选择一个窗口尺寸,然后将一个小的矩形窗口(图像)输入到这个卷积神经网络中,也就是只取这个小的红色框内的图像,把它输入到卷积神经网络中,然后让神经网络做一个预测,假设对于那个红色小框区域内有没有车。
在滑动窗口检测算法中,你然后需要做的是输入,传递第二个图像作为输入,把这个移动了一点的红色小框内的图像输入到卷积神经网络中,即只输入红色框区域内的图像到卷积神经网络,再运行一次卷积神经网络,以此类推。
我这里用了一个比较大的步长来让滑动检测做的更快。但是基本思路就是遍历所有(红色窗口)尺寸的图像区域,将这些小的裁剪出来的图像传递到卷积神经网络中,然后将一定步长下每个位置的图像分类为0或1。
现在遍历完一次滑动窗口,即整个图像区域以后,你再重复一次,不过这次取一个稍微大一点的区域,根据卷积神经网络的要求调整这个区域的大小,然后把它输入到卷积神经网络中,把这个窗口在一定步长下继续滑动,遍历整个图像。
再用更大的窗口再执行第三次...
我们的期望是:如果这么做,只要图像中某处有一辆车,就会有某个窗口,对应卷积神经网络输出为1,这样你就检测到了一辆车。
这个算法之所以被称为滑动窗口检测,是因为你把这些窗口,即这些正方形边框,在一定步长下滑过整个图像,然后判定每个方框内的区域是否含有车,不过滑动窗口检测有一个很大的缺点:
就是它的计算成本。
因为你裁剪出了很多不同的正方形的图像,并让每个图像都单独通过卷积神经网络的运算,如果你使用了不密集的步长,一个很大的步长,一个很大的步幅,那么通过卷积神经网络的窗口数量会减少,但是比较粗糙的颗粒度会影响算法表现。而如果你用了比较精细的颗粒度,也就是很小的步长,那么这些小区域的数量会非常大,将它们全部通过卷积神经网络意味着很高的计算成本。
因此,在神经网络兴起之前,人们常常用更简单的分类器。即把一个简单的线性分类器运用在手动设计的特征上尽心目标检测,而且在那个时代,因为每个分类器的计算成本相对较低,只是一个线性方程,所以滑动窗口检测是可行的。
但是卷积神经网络运行一次分类任务的代价更高,这样的滑动窗口检测慢的不可行,而且除非你用非常精细的颗粒度,也就是很小的步长,你最终很难在图像中精确地定位到目标。
幸运的是这个计算成本问题有一个很好的解决方案, 更确切的说,滑动窗口检测可以以卷积的形式来更高效的实现。具体怎么做到的呢?
第四课:滑动窗口的卷积实现
滑动窗口检测算法通过卷积神经网络的方法实现速度太慢,如何解决这个问题?
如何将神经网络中的全连接层转换为卷积层?
修改原有卷积神经网络,将输出y改为4个数字,分别代表分类到softmax分类单元所区分的4个类别中每一类的概率。如何将全连接层转换为卷积层?
将全连接层的400个单元变换为用400个5 * 5过滤器,输出的维度就是1 * 1 * 400,所以与其只是把这400个看作是一组节点(全连接层),我们将它看作是1 * 1 * 400的体(过滤器),数学操作上来讲,两者是相同的,因为这400个节点中的每一个都对应一个维度为5 * 5 * 16的滤波器。也就是说这400个值中的每一个都是这5 * 5 * 16个前一层的激活值,即输入某个任意线性方程的结果。
接下来,为了实现下一个卷积层,我们将实现1 * 1的卷积,如果你有400个1 * 1的过滤器,那么下一层的维度也是1 * 1 * 400,这样就得到了这个全连接层。
最后,我们还将用一个1 * 1的滤波器,然后是softmax激活以输出一个1 * 1 * 4的数据卷。
以上就是如何将全连接层用卷积层的方式实现,从而将全连接层转换为1 * 1 * 400和 1 * 1 * 4的数据卷, 结果这几个单元集成变成了1x1x400和1x1x4的维度。
掌握了卷积知识,我们如何通过卷积实现滑动窗口对象检测算法?
该卷积操作的原理是:我们不需要把输入图片分割成4个子集,分别执行前向传播,而是把它们作为一张图片输入给卷积网络进行计算,其中的公共区域可以共享很多计算。
所以,回顾一下,实现滑动窗口,以前,你所做的就是裁剪一块区域,把它输入神经网络,直到某个区域识别出汽车。
但是现在,我们不用依靠连续的卷积操作来识别图片中的汽车,我们可以把所有的滑动图像输入卷积神经网络系统,一次性得到所有预测值。如果足够幸运,神经网络便能识别出汽车的位置。
以上就是在卷积层上应用滑动窗口算法的内容,它提高了整个算法的效率,不过这个算法仍然存在一个缺点,边界框位置不能准确得到,下节课我们看一下如何解决?
第五课:Bounding Box 预测
如何得到更精准的边界框?
在滑动窗法中,你取这些离散的位置集合,然后在上面跑分类器,在这种情况下,边界框没有一个可以完美匹配汽车的位置,有没有办法让这个算法输出更精准的边界框呢?
其中一个能得到精准边界框的算法是:YOLO算法
YOLO意思是你只看一次。在原始图像上放置一个网格,比如3x3,实际上会使用更精细的网格。
基本思路是:使用图像分类和定位算法,将算法逐一应用到9个格子中,更确切的说:你需要定义训练标签,对于9个格子中的每一个指定的一个标签y,它是八维向量。YOLO算法做的是取两个对象的中点,然后将这个对象分配给包含对象中点的格子,所以即使中心格子同时有两辆车的一部分,我们就假装中心格子没有我们感兴趣的对象。
有9个格子,总的输出尺寸是3x3x8,如果你现在要训练一个输入为100x100x3的神经网络,你有一个普通的卷积网络,包括卷积层最大池化等,最后你会有一个选择卷积层和最大池化层,得到一个3x3x8的输出。当你用反向传播训练神经网络时,将任意输入x映射到这类输出向量y。这个算法的优点是:神经网络可以输出精确的边界框,即9个格子中是否有汽车,以及汽车对应的边界框。值得注意的一点是:你把汽车分配到其中点所在的格子。
注意:
首先,这和图像分类和定位算法非常类似,它显式的输出边界框坐标,所以这能让神经网络输出边界框可以具有任意宽高比,并且能输出更精确的坐标,不会受到滑动窗口分类器的步长大小限制。
其次,这是一个卷积实现,你不需要让同一个算法跑361次,因为这是单次卷积的实现,有很多共享计算步骤。
事实上YOLO算法有一个好处:
因为这是一个卷积实现,实际上算法的运算速度非常快,可以达到实时识别。
一个小细节:如何编码这些边界框。
bx,by,bh,bw单位是相对格子尺度的比例。
所以:
0 < bx,by < 1
bh,bw 有可能 > 1
所以为了确保取值范围,还会有一些比较复杂的参数化形式。
可以让这个算法表现更好的其他思路?
第六课:交并比
你如何判断对象检测算法运作良好呢?
交并比函数可以用来评价对象检测算法。
在对象检测任务中,你希望能够同时定位对象,即刚好把需要检测的对象框起来,所以交并比函数要做的就是:
计算两个边界框交集和并集之比。一般在计算机检测任务中,如果loU大于或者等于0.5,就说检测正确,如果预测期和实际边界完美重叠,loU = 1,不过一般约定0.5是阈值用以判断预测的边界框是否正确。
这是衡量定位精确度的一种方式。
你只需要统计算法正确检测和定位对象的次数,你就可以通过loU数值来判断图像定位是否准确。
但更一般来说,loU衡量了两个边界框重叠的相对大小,如果你有两个边界框,你可以计算两个框的交并比,所以这也可以用于判断两个边界框是否相似。
非最大值抑制?
第七课:非极大值抑制
你的算法可能对同一个对象做出多次检测,所以算法不是对某个图像检测出一次,而是检测出多次,非极大值抑制的方法可以确保你的算法对每个对象只检测一次。
举个例子:
理论上应该只有一个格子作出有车的预测,但实践中当你跑对象分类和定位算法时,好几个格子都会认为自己是中点。
我们分布来介绍一下非极大值抑制是怎么起效的:
当很多格子都举手表示自己检测到一个车子的时候,可能会对同一个物体检测多次,所以非极大值抑制做的就是清理这些检测结果。
所以具体上,这个算法做的是:先看看每次的报告,每个检测结果相关的的概率pc,首先看pc最大的那个,然后就说这是最可靠的检测。
这样做以后,非极大值抑制就会逐一审查剩下的矩形,所有和这个最大边界框有很高交并比,高度重叠的其他边界框,那么这些输出将会被抑制。
从而得到:每个矩形都会被高亮显示或者变暗,可以直接抛弃变暗的那个矩形框,留下高亮显示的矩形框,就可以得到最终的预测结果。
非极大值意思是你只输出概率最大的分类结果,但抑制很接近,但不是最大值的预测结果。
算法的细节:
首先输入一个原始图像进行目标检测,你在一个19x19网格上跑一下算法,你会得到19x19x8的输出尺寸,但是这里不检测摩托车或者行人,即去掉c1、c2、c3,从而得到19x19x5的输出结果。
现在要实现非最大值抑制,你可以做的第一件事就是去除所有低于概率阈值的边界框。
所以思路是对于这361个位置,你输出一个边界框,还有那个边界框是好结果的概率,所以我们只是抛弃低概率的边界框。接下来剩下的边界框,没有抛弃没有处理过的,你就一直选择概率pc最高的边界框,然后把它输出成预测结果。这样你就可以确定输出是否有一辆车的预测。
接下来,去掉所有剩下的边界框,所有没有达到任何输出标准的边界框。用之前没有抛弃过的边界框,把这些和输出边界框有很高重叠面积和上一步输出边界框有很高交并比的边界框全部抛弃,所以while循环的第二步是上一张幻灯片中变暗的边界框和高亮标记的边界框重叠面积很高的那些编辑框抛弃掉。
在还有剩下编辑框的时候,一直这样做,把没处理的处理完,直到每个编辑框都判断过了,它们有的作为输出结果,剩下的被抛弃,因为和输出结果重叠面积太高,即交并比太高。
这节课只介绍了算法检测单个对象的情况,如果你尝试同时检测三个对象比如说,汽车,行人,摩托,那么输出向量就会有三个额外的分量。事实证明,正确的做法是独立进行三次非最大值抑制,对每个输出类别都做一次。
如果你能实现这节课所说的对象检测算法,你其实可以得到相当不错的结果,但在结束YOLO算法的介绍之前,最后还有一个细节可以进一步改善算法效果?
第八课: Anchor Boxes
到目前为止,对象检测存在的一个问题就是:每个格子只能检测出一个对象,如果你想让一个格子检测出多个对象,你可以这么做:使用anchor box这个概念。
当人和车子的中点落在同一个网格中时,对于一个带标签的向量y,能输出两个结果,我必须从两个检测结果中选一个。Anchor Box的思路是:
预先定义两个不同形状的Anchor Box,你要做的是把预测结果和这两个Anchor Box关联起来,一般来说,你可能会用更多的Anchor Box,可能是5个甚至更多。
你要做的是定义类别标签,用的向量不再是左边这个,而是重复两个。用两组向量分别表示,这个网格中有行人和汽车的概率。
总结一下:
用Anchor Box之前,你做的是:
对于训练图像中的每个对象,都根据那个对象中点位置,分配到对应的格子中,得到3x3x8的输出。
如果有了Anchor Box,你做的是:
现在每个对象都和之前的一样分配到同一个格子中,分配到对象中点所在的格子中,但是它还分配到一个和对象交并比最高的Anchor Box,所以这里有两个Anchor Box,你要观察哪一个Anchor Box和实际边界框的交并比更高。不管选的是哪个?这个对象不只分配到一个格子中,而是分配到一对,这就是对象在目标标签中的编码方式。所以现在的输出就是3x3x16(2x8)。如果你有更多对象,那么y的维度会更高。
例子:
但是如果你有两个Anchor Box,但是有三个检测对象,或者是两个Anchor Box的形状一样,这个Anchor Box算法就处理不好了。
我们建立Anchor Box是为了处理同一个框中出现两种对象的情况,实际上这种情况很难发生,特别是使用16 * 16 * 9的格子。所以也许设立Anchor Box的好处是Anchor Box能让你的学习算法能够更有针对性,特别是如果你的数据集有很瘦的对象,例如行人,或者很宽的对象,例如汽车,这样你的算法可以更有针对性的处理。
最后,怎么选择Anchor Box呢?人们一般手工指定Anchor Box形状,你可以选择5个到10个Anchor Box形状,覆盖到多种不同的形状,可以涵盖你想要检测的对象的各种形状,k聚类算法?
自动选择Anchor Box形状的高级算法?
明天我们把学到的东西融合到YOLO算法中!