Deep Learning Note: 4-7 检测算法
1. 目标定位
前文主要讨论了图像分类问题,即判断图像中对象的类型,如图 1 中左图,给出一张图片,识别它是一张汽车的图片。而对于分类和定位问题,不仅要判断图像中是否存在目标对象,还要找到该对象的位置,如图 1 中间的图,不仅要识别出图中的汽车,还要找到汽车的位置。以上两个问题都只针对一个目标,目标检测问题则更进一步,需要识别和定位图像中存在的全部目标,这些目标还可能属于不同的分类,如图 1 中右图,图片中有两辆汽车,都需要识别和定位出来。
对于分类和定位问题,网络结构如图 2 所示。
对于一张输入图像,首先经过一个普通的网络,该网络的输出有两部分,一部分通过 Softmax 给出分类预测,例如我们想要找到图片中的行人、汽车、摩托车,则有四个分类:
- 行人
- 汽车
- 摩托车
- 背景(没有以上三种目标)
此时图 2 中 Softmax 的输出为一个 $4 \times 1$ 的向量。
另外,图 2 中的网络也会输出所检测目标的位置,使用 $b_x$、$b_y$、$b_h$、$b_w$ 表示,这里 $b_x$ 和 $b_y$ 为目标中心在图片中的位置,$b_h$ 和 $b_w$ 表示目标的宽度和高度,这四个值可以定位一个方框,即目标的位置。令图片左上角坐标为 $(0, 0)$,右下角坐标为 $(1, 1)$,则对于图 2 中的汽车图片,约有 $b_x = 0.5$,$b_y = 0.7$,$b_h = 0.3$,$b_w = 0.4$。
在分类和定位问题中,网络要输出 $b_x$、$b_y$、$b_h$、$b_w$ 和分类,此时样本标签的结构为:
\begin{equation}
y = \begin{bmatrix}p_c \\ b_x \\ b_y \\ b_h \\ b_w \\ c_1 \\ c_2 \\ c_3\end{bmatrix} \tag{1}
\end{equation}
式 (1) 中,$p_c$ 表示图像中是否有所关心的目标,如果有目标(行人/汽车/摩托车),则 $p_c = 1$;如果没有目标(背景),则 $p_c = 0$。$b_x$、$b_y$、$b_h$、$b_w$ 为目标位置。如果有目标,即 $p_c = 1$ 时,$c_1$、$c_2$、$c_3$ 表示图像中是否有对应分类(行人/汽车/摩托车)的目标,分类和定位问题中,图像里最多只有一个对象,此时 $c_1$、$c_2$、$c_3$ 最多有一个是 1,其余都是 0。
举例来说,对于图 2 中的输入数据,其标签为:
\begin{equation}
y = \begin{bmatrix}1 \\ 0.5 \\ 0.7 \\ 0.3 \\ 0.45 \\ 0 \\ 1 \\ 0\end{bmatrix}
\end{equation}
再例如图 3 所示的图片,其中没有所关心的目标:
其标签如下(其中的 ? 表示不关心):
\begin{equation}
y = \begin{bmatrix}0 \\ ? \\ ? \\ ? \\ ? \\ ? \\ ? \\ ?\end{bmatrix}
\end{equation}
训练网络使用的损失函数为:
\begin{equation}
L(\hat{y}, y) = \begin{cases}
\sum\limits_{i=1}^8 (\hat{y}_i – y_i)^2 &if \; y_1 = 1 \\
(\hat{y}_1 – y_1)^2 & if \; y_1 = 0\end{cases} \tag{2}
\end{equation}
当 $y_1 = 1$,即图像中有目标时,分别计算 $\hat{y}$ 和 $y$ 中所有项带来的损失;当 $y_1 = 0$,即图像中没有目标时,只计算 $\hat{y}$ 和 $y$ 中第一个元素,即 $p_c$ 所带来的损失。注意这里为了方便描述,使用平方误差来计算 $y$ 中所有项的损失,实际中,要根据实际情况选择合适的计算方式:如使用对数似然(Log Likelihood)误差计算 Softmax 输出的 $c_1$、$c_2$、$c_3$ 的损失,使用平方误差计算与位置和距离相关的 $b_x$、$b_y$、$b_h$、$b_w$ 的损失,使用逻辑回归的损失函数计算 $p_c$ 的损失。
2. Landmark 检测
在上面的分类和定位问题中,网络输出 $b_x$、$b_y$、$b_h$、$b_w$,即目标的位置的大小。有时候我们只关心图像中关键点(即 Lamdmark)的位置,此时网络只需输出 Landmark 的坐标 x 和 y,称为 Landmark 检测(Landmark Detection)。
例如对于一个人脸识别的应用,想要找出人脸、眼睛、鼻子、嘴巴的轮廓等共计 64 个关键点的位置,则网络输出为:
\begin{equation}
y = \begin{bmatrix}p_c \\ l_{1x} \\ l_{1y} \\ l_{2x} \\ l_{2y} \\ … \\ \\ l_{64x} \\ l_{64y}\end{bmatrix} \tag{2}
\end{equation}
式 (2) 中 $l_{ix}$ 和 $l_{iy}$ 表示第 $i$ 个 Lamdmark 的坐标。在标记数据时,需要手工标记以上 64 个关键点的位置,并且确保所有样本标签中坐标与关键点的对应关系保持一致,例如规定第 1 个关键点 $(l_{1x}, l_{1y})$ 为右眼右眼角的位置,则在所有样本的标签中,$(l_{1x}, l_{1y})$ 都必须是右眼右眼角的位置。
3. 对象检测
滑窗检测(Sliding Window Detection)算法是一种对象检测算法,首先训练一个仅用于识别目标的算法,然后使用一个窗口逐步滑过图像,使用识别算法判断窗口下的图像是否有检测目标,如果有,则判定该窗口位置上有目标。
例如要检测图像中的汽车的位置,则首先训练一个识别汽车的网络,训练数据为沿汽车边缘裁剪的汽车图片,标签为图片是否为汽车,如图 4。
然后使用一个小窗口,逐步划过整个图像,对于每个被窗口截取下来的图像,使用前面训练的识别汽车的网络,检测其中是否有汽车,如图 5 所示。注意图中窗口滑动的步长比较大,实际中会使用较小的步长。
窗口滑动并检测过整张图像后,增大窗口的尺寸,再进行一遍滑动检测,如图 6 左图。因为增大了窗口的尺寸,需要将窗口截取下图片的尺寸进行缩放,以匹配汽车识别网络的输入要求。完成第二遍滑动检测后,还可以继续增大窗口,如图 6 右图。
如果在滑窗检测的过程中,在某一个窗口下识别到了目标物体,则窗口位置即为目标物体的位置。
滑窗检测的一大缺点是计算量很大。如果滑动的步长很小,则需要计算大量的窗口,带来很大的计算量;如果增大滑动的步长,计算量会减小,但检测的精度也会下降。在神经网络兴起之前,分类器还比较简单,每个窗口的计算量不大,可以应用滑窗检测;而对于现代的卷积网络,进行单次预测的计算量大大增加,滑窗检测也就不再适宜了。
4. 滑窗的卷积实现
图 8 展示了一个普通的卷积网络,网络输入为一张 $14 \times 14 \times 3$ 的 RGB 图片,经过一个卷积层、一个池化层和两个全连接层,通过 Softmax 输出 4 个值,分别表示图像中是否有行人、汽车、摩托车,或者以上三者都没有。
图 8 所示网络中的两个全连接层也可以表现为卷积层的形式,如图 9。
第一个全连接层相当于是将输入的 $5 \times 5 \times 16$ 的数据与 400 个 $5 \times 5 \times 16$ 的过滤器相卷积,结果的大小为 $1 \times 1 \times 400$;第二个全连接层相当于是将输入的 $1 \times 1 \times 400$ 的数据与 400 个 $1 \times 1 \times 400$ 的过滤器相卷积,结果的大小为 $1 \times 1 \times 400$。最后通过一层 $1 \times 1$ 的卷积得到 $1 \times 1 \times 4$ 的数据,再由 Softmax 输出预测。
OverFeat 一文给出了通过卷积来实现滑窗的方法,通过在计算滑窗时共享重复的计算结果,降低计算量。以图 9 所示的网络为例,将它画为图 10 的形式,注意图 10 中只画了数据的截面,没有画出各个通道。
通过图 10 中的网络,我们可以检测一张 $14 \times 14 \times 3$ 的图片中是否有行人、汽车、摩托车,或者以上三者都没有(这里为方便说明,使用的数据尺寸很小,实际中会使用更大的尺寸)。对于一张 $16 \times 16 \times 3$ 的图片,我们想知道其中是否有所关心的对象(行人、汽车、摩托车)及其位置,传统的滑窗的方法是使用 $14 \times 14$ 的窗口,以一定步长,在 $16 \times 16 \times 3$ 的图片上滑动,识别各个位置窗口下的 $14 \times 14 \times 3$ 的图片中是否有所关心的对象,如图 11。
可以看到,对于图 11 中的 4 个窗口,在使用图 10 中网络通过前向传播进行识别时,有很多计算是重复的,这些计算可以在多个窗口的计算中共享,如图 12 所示。
图 12 中的网络结构与图 10 相同,但它直接使用 $16 \times 16 \times 3$ 作为输入,最终输出的大小为 $2 \times 2 \times 4$,其中每个位置的值(即每个 $1 \times 1 \times 4$ 的值)就对应了图 11 中每个窗口的结果,如原 $16 \times 16 \times 3$ 图片中蓝色部分的内容,经过一系列计算,最终输出在 $2 \times 2 \times 4$ 的结果的左上角。
通过卷积的形式实现滑窗,仅通过一次前向传播就可以检测多个窗口的位置,各个窗口的计算过程中复用了很多公共部分的计算结果,相比于对每个窗口单独计算前向传播,极大地降低了计算量。
再看一个例子,假设输入图片的大小为 $28 \times 28 \times 3$,则其计算过程如图 13 所示,最终结果的大小为 $8 \times 8 \times 4$,相当于在原 $28 \times 28$ 的图片上使用 $14 \times 14$ 的窗口进行滑动检测。这里窗口移动的步长为 2,是因为网路中使用了 $2 \times 2$ 的池化层。
回到前面的问题,对于图 2 中的图片,通过卷积滑窗,最终可以找到一个窗口,在其中识别出了汽车,由此就找到了汽车的位置,如图 14。