目录
1 目标定位
2 地标检测
3 目标检测
4 在卷积网络上实现滑动窗口
5 边界框预测
6 交并比
7 非极大值抑制
8 锚框
9 YOLO算法
10 用u-net进行语义分割
11 转置卷积
12 u-net 结构灵感
1 目标定位
你已经对图片分类有所了解。例如通过这张图片可以识别出这是车。接下来我们要对一张图片进行分类并定位,这意味着你不仅要识别出这是一辆车,还要知道这辆车在图片中的位置。我们还会学习目标检测,来检测在一张图片里的多个对象,把它们全部检测出来,并且定位。
对于图像分类和分类并定位问题。通常它们只有一个对象。在目标检测问题中可能会有很多对象,他们可能是来自多个不同类别的多个对象。在图像分类中学习的方法将会对分类定定位问题有帮助;学习道德定位的方法,对物体检测有帮助。让我们先来了解一下图像分类并定位。
你可能在多层卷积网络中输入一张图片,这会导致我们的卷积网络有一个特征向量,然后将特征向量传给softmax输出预测的结果。如果你要制作一辆自动驾驶的车辆,那么你的目标类别可能会有行人、车辆、摩托车、一个背景环境。
如果你想定位图中的汽车,你可以改变你的神经网络,通过得到更多的输出单元,使得这个神经网络可以输出一个边框。具体的说你的神经网络要输出额外4个数字(),这4个数字是定位对象的边框参数。
图片左上角标为坐标(0,0),右下角标为(1,1)。所以为了指定图中红色长方形边框,我们需要指定边框的中心,需要,边框的宽度
,边框的长度
如果你的训练集不仅仅是包含对象类别标签,还包含4个额外的数字给出边框。你可以用监督学习来让你的算法输出类别标签和4个变量来告诉你所检测到的对象的边界框。
在上面这个例子中理想的,位于图片的一半位置;
,大约距离图片上方70%;
,因为这个红色矩形的宽度,大约占到整个图片的30%;
,红色方框的宽度大约占整体图片的40%。
目标标签y的定义如下:如果是行人、车辆、摩托车,;如果是背景,也就是没有任何你需要检测的类别,
,你可以把
当做包含一个类别的概率。
是你所检测对象的边界框。如果
,你想知道是哪一个类别的对象。因此,
。这些定义的前提都是我们要处理图像分类并定位问题,也就是图片中最多只有一个对象,在
中,最多只有一个是1。
让我们来看一个例子。
如果一个训练集图像,那么
;如果x=
,那么
,其中?表示对应的数字无关紧要,因为图中没有对象,那么你不需要关心神经网络输出的边界框是什么,也不会关心
会是什么。
现在我们来看看怎么定义损失函数。如果你使用均方差作为损失函数,那么损失函数
2 地标检测
我们知道了神经网络输出4个变量边界框去定位对象。对于更普遍的情况我们可以让神经网络只输出重要的点和图像的(x,y)坐标。
假设你要建立一个脸部识别算法。出于某些原因,你想要算法告诉你某人的眼角在哪里,那个点有(x,y)坐标。你可以建立一个神经网络,它的输出层只输出两个数字()来告诉你这个人眼角的坐标。
现在如果你想要神经网络告诉你眼角的所有4个角,即两只眼睛的左右两个眼角。那么我们可以修改神经网络让它输出(),(
),(
),(
)
现在神经网络就输出了人脸上的眼角这4个点的预估坐标位置。如果你想要的不仅仅是这4个点,你想要输出眼周的点,你可以放置一些点。你也可以在嘴巴上放着一些点,这样你就可以提取出嘴型,从而知道一个人在笑还是没在笑。你也可以在鼻子上放置一些点。
为了讨论方便,假设人脸上有64个地标,并把这些地标作为训练集,你可以让神经网络告诉你:脸部重要的位置或者重要的地标在哪。
你可以把例如上图这样的图当做输入,让它通过神经网络,输出1或者是0(1表示有人脸;0表示没有人脸);同时输出(),(
),...........,(
)
这个可以告诉你图片中是否有人脸,并且所有关键特征是否在脸上。
为了训练这样一个神经网络,你需要一个有标签的训练集(X,Y)。
最后一个例子。如果你对人体姿势检测感兴趣的话。你也可以定义一些关键的位置,建立一个神经网络去标识人的姿势的关键位置,并输出。
为了实现这个,你也需要指出这些关键特征。
3 目标检测
现在我们已经知道了目标定位和地标检测。 现在让我们来开始搭建一个目标检测算法。在这一节中,我们将学会如何用一个卷积神经网络和滑动窗口检测的算法进行目标检测。
假设你想搭建一个汽车检测算法。你可以先创建一个有标记的训练数据集x和对应的y。训练集中包含紧密裁剪的汽车样例,也就是说x基本上只包含车。
有了这个有标记的训练数据集,你就可以训练一个卷积神经网络。输入一张紧密裁剪的图像,卷积神经网络负责输出y。当你训练好这个卷积神经网络之后,你就可以把它用在滑动窗口检测中了。
具体做法是如果你有一张上图这样的测试图像,你要做的是:先选择一个窗口尺寸。在图像中取和滑动窗口一样大小的图像,把它输入到神经网络中做预测。
再滑动窗口,取下一个图像输入到神经网络中做预测。
按照这样的方式,直到滑动窗口遍历了图片中的所有位置。
之前用滑动窗口,现在用更大的窗口
,也就是取图片中更大的窗口区域,输入到神经网络中作预测。
依次遍历完整个图像后,用更大的滑动窗口再执行一遍。
我们期望这么做:只要图像做某处有一辆车就会有某个窗口能够检测到。
这个算法之所以被称为滑动窗口检测,是因为你把这些窗口,在一定步长下划过整个图像,然后判断每个方框内的区域是否有车辆。
滑动窗口检测有一个很大的缺点:计算成本大。因为你裁剪出了很多不同的正方形图像,并让每个图像都单独通过卷积神经网络的运算。如果你使用了一个很大的步长,那么卷积神经网络的窗口数量会减少,但是它会影响算法表现;如果你使用了很小的步长,那么这些小区域的数量会很多,将它们全部通过卷积神经网络意味着很高的计算成本。
4 在卷积网络上实现滑动窗口
为了搭建一个用卷积实现的活动窗口,让我们先来看一下如何将神经网络中的全连接层转换成卷积层。
假设你的目标检测算法的输入是14×14×3的图像,使用16个5×5大小的过滤器,然后做一个2×2的最大池化,把它缩小到5×5×16,然后把它展平成400维向量,在和一个400维的向量做全连接,最后用softmax单元输出一个y。
为了做我们马上要做出的改变,将最后的输出改成4个数字,代表softmax所区分的4个类别中每一类的概率,这4个类别是行人、汽车、摩托车和背景。
现在我想做的是展示如何将这些层转化成卷积层?
前面这些层都和之前一样,只不过要把后面的全连接层换成卷积层。
用400个5×5的过滤器把5×5×16转换成1×1×400。从数学操作上来讲,这和一个全连接层是一样的。
因为这400个节点中的每一个都对应一个维度为5×5成左右的过滤器。也就是说这400个值中的每一个都是5×5×16个前一层的激活值输入某个任意的线性方程的结果。
利用这样的方式,我们就把它变成了一个卷积神经网络,如下:
在这一转换之后,让我们来看一下你怎样用卷积的形式来实现滑动窗口目标检测。
假设你的滑动窗口卷积神经网络的输入是14×14×3的图像。
你的测试集里的图像是16×16×3。如下图:
在原来的滑动窗口算法中,你可以把蓝色区域输入到卷积神经网络中,运行一次来得到分类结果0或1,然后你可以向右移动滑动窗口(本例使用2个像素的步长),然后将窗口内的图像输入到卷积神经网络中来得到标记0或1。用这样的方式,在16×16×3的图像上进行滑动窗口运算,分别得到了4个标签。
不过事实上,这里面的很多运行卷积神经网络的计算是重复的,所以对滑动窗口的卷积方式的实现,是让这几次卷积神经网络的前向运算共享计算过程。
具体来说,你可以这么做。你可以运行之前卷积神经网络,用同样的参数,同样的过滤器,如下图:
我们可以发现最后输出的这个蓝色区域就是对输入中蓝色区域做卷积运算的结果。其他的区域也是如此。
这个卷积形式所做的,不是在输入图像的4个子图像上分别做卷积运算,而是把4个合并成一个进行运算,从而利用这4个14×14图像的共同区域共享了大量的运算。
为了实现滑动窗口,之前的方法是裁剪出一个区域,让它通过卷积神经网络,然后对旁边下一个区域如法炮制,直到有可能这个区域识别出一辆车。
但是现在,我们根据之前的方式,可以实现对整张图像以卷积操作的形式,进行一次大的卷积神经网络的前向传播,同时得到所有的预测,然后就有可能识别出这辆车的位置。
5 边界框预测
我们知道了如何使用卷积来实现滑动窗口,虽然这在计算上更有效率,但是它依然无法精确输出边界框。在这里我们将学习如何更精确的预测边界框。
在使用滑动窗口的方法中,通过预先决定的窗口来扫过整个图片,可能没有一个边框与车的位置恰好吻合,也许下图这个边框是最吻合的。
另一方面,看上去一个更为精确的边界框实际上并不是一个正方形,它是一个较宽的长方形。所以是否有一个算法可以给出更精确的边界框?YOLO就是一个比较好的能精确输出边界框的算法。
下面是具体的做法。假设你有一张输入图片是100×100,接着你要将其用网格划分(这里使用3×3的网格划分,但是在实际中你会使用更细分的网格,比如19×19的网格)。基本思路是你将图片分类及定位的算法应用到这九个网格中的每一个。
对于这九个网格中的每一个,你要给定一个标签,这个标签y是一个八维的向量,第一个输出值 取决于那一个网格中是否有目标物,
指定边界层的位置,最后
给出网格中的目标物体属于哪一类。所以每一个网格中都有这样的信息,即
让我们从左上角的网格开始。左上角这个网格装没有目标物,所以这个单元格中的标签y第一个维度,因此
。所有不包含目标物体的单元格的输出标签y都是如此。
图片中有两个目标物,YOLO算法会将这两个目标物分别分配到包含它们的中心点的网格中。左边汽车的预测框的中心点落在由绿色线描绘出的网格中;右边汽车的预测框的中心点落在由黄色线描绘出的网格中,它们的标签
对于这9个网格中的每一个,都会有一个8维的输出向量。由于有3×3个网格,输出的总大小将会是3×3×8
将目标物分配到单元格中的方式,需要先找到目标物的中心点,然后再根据中心点的位置将它分配到包含该中心点的网格中。所以对于每一个目标物,即使它跨越了多个网格,他也只会被分配给这些网格中的一个。
我们该如何决定边界框的参数(),在下图用黄色线描出的网格中有一个目标物所以它的标签
。在YOLO算法中,我们把网格左上角点的坐标定为(0,0),右下角的点定为(1,1),要指定目标物中心点的位置,也就是黄点的位置。
,因为它大概在距离左边0.4左右的位置;
;边界框的宽度、高度是通过它和整个网格宽度、高度的比例来指定的,
,
6 交并比
交并比既可以用来评价目标检测算法,也可以用于往目标检测算法中加入其他特征,从而进一步改善算法。
在建立目标检测时,你希望能够进行定位目标。假如下图的红框是一个真实的边界框,而你的算法输出的是紫色这个边界框,你不知道这个结果是好还是坏。
交并比或者说IoU函数,它计算了这两个边界框的交集除以并集的比率。下图的黄色区域面积除以紫色和红色区域面积的比值就是交并比。
计算机视觉领域的原则是,如果IoU>0.5,你的结果就会被判断为正确;如果预测和真实的边界框完美重合了,此时IoU=1。
0.5经常作为一个临界值来判断预测的边界框是否准确。这只是一个常规值,如果你想更严格一点,你可以把准确的标准提高,IoU越高,边界框就越准确。因此有一个衡量定位准确度的方法就是:数出算法准确检测并定位一个目标的次数。
7 非极大值抑制
目前所学到的目标检测的问题之一是:算法可能会对同一目标进行多次检测。非极大值抑制确保算法只对每个对象进行一次检测。我们来举一个例子。
假设你想在下图中检测行人、车、摩托车,你会在图片上放着一个19×19的网格。右边这辆车只有一个中心点,它应该会被分配到一个网格单元中;同样的左边这辆车也应该只有一个中心点,也应该只有一个单元格预测出有一辆车。
实际上算法对每一个网格都进行了目标分类和定位算法,那么将会有不止一个网格被认为是车的中心点。让我们通过一个例子来看一看非极大值抑制是怎么工作的。
因为你对每个网格运行图像分类和定位的算法。在这些网格上,有可能许多网格会举手说:“我的值很大,有个目标极有可能在我的网格中”,因此对每个目标你可能会得到多个检测结果。所以非极大值一直要做的是:清理这些检测。这样每辆车只会得到一个检测结果,而不是多个结果。
具体来说,它就是先看一看每个检测结果的相关概率,选取其中概率最大的那一个框。接下来非极大值抑制再看剩下的所有方框以及所有和你选的框有着高IoU值的框,把它们抑制。接下来再从剩下所有的框找出概率最大的框,去掉任何有着高IoU值的框。
如果把下图中暗的框都去掉,剩下的框就是这两个物体的最终预测框。
这就是非极大值抑制。非极大值意思是你将要输出有着最大可能性的分类判断,抑制那些非最大可能性的邻近的方框。
现在我们来看一下这个算法的细节。首先在这个19×19的网格中,你会得到一个19×19×8的输出量。为了运用非极大值抑制,首先要做的是丢掉所有值小于某个值的的方框,这样我们就去掉了有着低概率的边界框。
如果还有剩下的边界框还没有被处理掉,将重复的选出最大pc值的边界框,将它作为一个预测结果,然后丢掉有着高IoU值的边界框。
8 锚框
目前,目标检测的问题之一是:每个网格单元只能检测一个对象,如果一个网格单元要检测多个对象该怎么办呢?我们可以利用锚框。让我们从一个例子开始了说明。
假设你有这样一张图片:
人的中点和车的中点几乎处在相同的位置,也就是说它们的中心点都落在同一个网格单元里。
对于这种情况,输出向量y没法输出两个类别,如果利用锚框的话,你需要预先定义两个不同的形状,你需要将这两个预测跟两个锚框关联起来(一般来说,你可以使用更多的锚框,但在这里只是用2个)
你要定义一个交叉标签,其中前8个是跟1号锚框关联的输出值,后8个是跟2号锚框关联的输出值。
9 YOLO算法
让我们来看看你该怎么构建训练集。假设你想训练一个算法来检测三个目标:行人、汽车、摩托车。输出y是3×3×2×8
以第1个网格为例,在这个网格中没有目标,因此
第1个锚框的,因此没有相关目标在第1个锚框;第2个锚框的
也是0,所以其他的值并不重要。
在这个图像中,除了绿色框,绝大部分的网格中都没有任何目标。对于绿色框而言,它的目标向量
遍历这个3×3的框都会得到一个16维的向量,所以最终的输出大小会是3×3×16。输入的图片也许是100×100×3,经过卷积神经网络转换后输出3×3×16
这就是训练,接下来我们看看算法如何进行预测。
输入一张图片,如果网格中没有目标,你希望你的神经网络输出的值为0,其他值不能输出一个“无所谓”的值,所以会给一些数值,但是这些数字都被无视,因为神经网络告诉你这里没有目标。
对于绿色框,你会希望输出一些数值,它能非常准确的绘出车的边界框。
如果你使用锚框,每个网格中都会得到两个预测的锚框,某些可能会有很小的概率,非常小的,你得到的锚框可能如下图所示:
如果你使用锚框,每个网格中都会得到两个预测的锚框,某些可能会有很小的概率,非常小的pc,你得到的锚框可能如下图所示:
当你去掉所有低概率的预测后,你需要单独对被预测的类别执行非极大值抑制后产生最后的结果。
10 用u-net进行语义分割
语义分割的目标是: 绘制检测到的对象周围的轮廓,以便知道哪些像素属于对象,哪些像素不属于对象。
假如你正在建造一辆自动驾驶汽车,你看到像下图这样的输入图像,想要检测其他汽车的位置。如果使用目标检测算法,是绘制其他车辆周围的边界框。这对于自动驾驶汽车来说可能已经足够了,但是如果你想让你的学习算法弄清楚这张图片中的每个像素是什么,那你可以使用语义分割算法。语义分割算法尝试标记每一个像素。
让我们深入研究语义分割的作用。为了简单起见,我们使用下面这个例子:从图片中分割出汽车。在这种情况下,你可能会使用两个标签。
1代表是汽车,0代表不是汽车,在这种情况下分割算法会输出此图像中每个像素的1或0。
如果你想更精细的分割这张图片,用1表示汽车,用2表示建筑物,3表示路面。
我们的应该网络应该怎么做到这样的输出呢?
这是一个卷积神经网络结构:
为了把这个网络变成语义分割架构,我们把最后的全连接层去掉。
由于图像经过神经网络后,尺寸会越来越小,因此为了获得全尺寸图像,我们需要逐渐扩大该图像。具体来说,当输入图像进入U-Net后,宽度要加大,通道数要减少,直到得到一个图像分割图。这就是U-Net架构的工作原理。
我们还没有讨论的一项操作是:把图像变大。为了解释这个过程,我们需要先了解如何使用反卷积(转置卷积)。
11 转置卷积
转置卷积是U-Net架构的关键部分。如何把2×2的输入放大为4×4的输出,这就是转置卷积所要做的工作。让我们来深入讨论这个问题
普通卷积的工作原理是:可能会输入一个6×6×3的图像,和5个3×3×3的过滤器进行卷积,最终得到4×4×5的输出。转置卷积则有些不同。你的输入可能是2×2,用一个3×3的过滤器进行卷积,最终得到的输出是4×4。从这里可以看出输出大于原始输入。
我们使用padding,它会作用在输出上,假设p=1;步长s=2
让我们来看看转置卷积的工作原理。
在普通的卷积中,通常要把过滤器放置在输入上面,然后将其相乘再相加;在转置卷积中是在输出上放置过滤器。
首先输入中的第1个元素2和过滤器中的每一个元素相乘,把这个3×3的值放在输出中。填充区域不会包含任何数值,因此我们会忽略填充区域,并在输出的红色显示区域中填入4个数值。
接下来我们来看第2个数值,也就是1,每个过滤器的元素乘1。因为我们使用了步长为2,因此输出中的方格区域会向右移动两格,同样忽略填充区域,需要复制的数值区域只有这个绿色的阴影区域。你可能注意到在我们复制过滤器的红色区域中,与绿色区域之间存在一些重叠,因此我们不能简单的把绿色部分的纸复制到红色部分的值上,而是把红色区域的值和绿色区域的值相加。
我们计算下一个:
计算最后一个:
你可能想知道为什么要这么处理。虽然有很多方法都可以把小的输入值变成较大的输出值,转置卷积是最有效的。
12 u-net 结构灵感
现在我们知道了转置卷积的时限,我们可以深入探讨一下U-Eet架构的细节了。
这是一张关于图像分割神经网络架构的粗略示意图:
对于该神经网络的前半部分,采用普通卷积。这部分神经网络会对输入图像进行压缩,经过这样的作用后,可以演变成相当小的图像,从而会丧失许多空间信息,因为维度变小了,但是却更深了。在该神经网络的后半部分,采用转置卷积,把压缩图像再放大到原始输入图像的大小。
事实证明,对该神经网络的架构进行修改是很有必要的,这样可以使它工作得更好,这就是U-Net架构由来的原因。转置卷积可以获得上一层的高层次空间的复杂信息,而因为缺少了图片的详细空间信息,只有较低的空间分辨率。