# 第三周 目标检测（Object detection）

## 3.1 目标定位（Object localization）

![](https://github.com/fengdu78/deeplearning_ai_books/raw/master/images/0107af10b33fcb955cc3c588dfb78d49.png)

定位分类问题：不仅要用算法判断图片中是不是一辆汽车，还要在图片中标记出它的位置，用边框或红色方框把汽车圈起来，“定位”的意思是判断汽车在图片中的具体位置

定位分类问题通常只有一个较大的对象位于图片中间位置，对它进行识别和定位。对象检测问题中图片可以含有多个对象，甚至单张图片中会有多个不同分类的对象 ![](https://github.com/fengdu78/deeplearning_ai_books/raw/master/images/d4a47c2041807f891c0a606d246330c5.png)

构建汽车自动驾驶系统，对象可能包括以下几类：行人、汽车、摩托车和背景

![](https://github.com/fengdu78/deeplearning_ai_books/raw/master/images/6461ff27c00dff4205688de4cf9d8803.png)

定位图片中汽车的位置：让神经网络输出一个边界框，标记为$$b\_{x}$$,$$b\_{y}$$,$$b\_{h}$$和$$b\_{w}$$，是被检测对象的边界框的参数化表示

红色方框的中心点表示为($$b\_{x}$$,$$b\_{y}$$)，边界框的高度为$$b\_{h}$$，宽度为$$b\_{w}$$。训练集不仅包含神经网络要预测的对象分类标签，还要包含表示边界框的这四个数字，接着采用监督学习算法，输出一个分类标签，还有四个参数值，从而给出检测对象的边框位置 ![](https://github.com/fengdu78/deeplearning_ai_books/raw/master/images/21b37dcb413e7c86464f88484796420c.png)

如何为监督学习任务定义目标标签 $$y$$：

![](https://github.com/fengdu78/deeplearning_ai_books/raw/master/images/02d85ab36285cd21b5df4d1c253df57e.png)

目标标签$$y$$的定义：$$y= \begin{bmatrix} p\_{c} \ b\_{x} \ b\_{y}\ b\_{h}\ b\_{w} \ c\_{1}\ c\_{2}\ c\_{3} \end{bmatrix}$$

$$p\_{c}$$表示是否含有对象，如果对象属于前三类（行人、汽车、摩托车），则$$p\_{c}= 1$$，如果是背景，则$$p\_{c} =0$$。$$p\_{c}$$表示被检测对象属于某一分类的概率，背景分类除外

如果检测到对象，就输出被检测对象的边界框参数$$b\_{x}$$、$$b\_{y}$$、$$b\_{h}$$和$$b\_{w}$$。$$p\_{c}=1$$，同时输出$$c\_{1}$$、$$c\_{2}$$和$$c\_{3}$$，表示该对象属于行人，汽车还是摩托车

![](https://github.com/fengdu78/deeplearning_ai_books/raw/master/images/fd37e4750b64a07cc1f29880c9b97261.png)

如果图片中没有检测对象:

[![](https://github.com/fengdu78/deeplearning_ai_books/raw/master/images/131239883224f03709ddc66d9481c3c7.png)](https://github.com/fengdu78/deeplearning_ai_books/blob/master/images/131239883224f03709ddc66d9481c3c7.png)

$$p\_{c} =0$$，$$y$$的其它参数全部写成问号，表示“毫无意义”的参数

神经网络的损失函数，如果采用平方误差策略：

$$
L\left(\hat{y},y \right) = \left( \hat{y\_1} - y\_{1} \right)^{2} + \left(\hat{y\_2} - y\_{2}\right)^{2} + \ldots+\left( \hat{y\_8} - y\_{8}\right)^{2}
$$

损失值等于每个元素相应差值的平方和

[![](https://github.com/fengdu78/deeplearning_ai_books/raw/master/images/d50ae3ee809da4c728837fee2d055f00.png)](https://github.com/fengdu78/deeplearning_ai_books/blob/master/images/d50ae3ee809da4c728837fee2d055f00.png)

如果图片中存在定位对象，$$y\_{1} =p\_{c}=1$$，损失值是不同元素的平方和

$$y\_{1}= p\_{c} = 0$$，损失值是$$\left(\hat{y\_1} - y\_{1}\right)^{2}$$，只需要关注神经网络输出$$p\_{c}$$的准确度

这里用平方误差简化了描述过程。实际应用中可以不对$$c\_{1}$$、$$c\_{2}$$、$$c\_{3}$$和**softmax**激活函数应用对数损失函数，并输出其中一个元素值，通常做法是对边界框坐标应用平方差，对$$p\_{c}$$应用逻辑回归函数，甚至采用平方预测误差

## 3.2 特征点检测（Landmark detection）

仅对目标的关键特征点坐标进行定位，这些关键点被称为landmarks

[![](https://baozou.gitbooks.io/neural-networks-and-deep-learning/content/assets/1231import.png)](https://github.com/fengdu78/deeplearning_ai_books/blob/master/images/100b265aefc4b0170fb39ed339e5181a.png)

选定特征点个数，并生成包含特征点的标签训练集，利用神经网络输出脸部关键特征点的位置

具体做法:准备一个卷积网络和一些特征集，将人脸图片输入卷积网络，输出1表示有人脸，0表示没有人脸，然后输出（$$l\_{1x}$$，$$l\_{1y}$$）……直到（$$l\_{64x}$$，$$l\_{64y}$$），$$l$$代表一个特征，即该网络模型共检测人脸上64处特征点，加上是否为face的标志位，输出label共有64x2+1=129个值，即有129个输出单元，由此实现对图片的人脸检测和定位

检测人体姿势动作：

![](https://baozou.gitbooks.io/neural-networks-and-deep-learning/content/assets/1232import.png)

特征点的特性在所有图片中必须保持一致

## 3.3 目标检测（Object detection）

通过卷积网络进行对象检测，采用的是基于滑动窗口的目标检测算法

[![](https://github.com/fengdu78/deeplearning_ai_books/raw/master/images/2f4e567978bb62fcbec093887de37783.png)](https://github.com/fengdu78/deeplearning_ai_books/blob/master/images/2f4e567978bb62fcbec093887de37783.png)

构建汽车检测算法步骤：

1. 首先创建一个标签训练集，$$x$$和$$y$$表示适当剪切的汽车图片样本，一开始可以使用适当剪切的图片，就是整张图片$$x$$几乎都被汽车占据，使汽车居于中间位置，并基本占据整张图片
2. 开始训练卷积网络，输入这些适当剪切过的图片（编号6），卷积网络输出$$y$$，0或1表示图片中有汽车或没有汽车

训练完这个卷积网络，用它来实现滑动窗口目标检测，具体步骤如下：

1.首先选定一个特定大小的窗口，将红色小方块输入卷积神经网络，卷积网络开始判断红色方框内有没有汽车

[\
![](https://github.com/fengdu78/deeplearning_ai_books/raw/master/images/2ac2ab6dcdcc0fe26a9833ff9da49bd2.png)](https://legacy.gitbook.com/book/baozou/neural-networks-and-deep-learning/edit)

2.滑动窗口目标检测算法继续处理第二个图像，红色方框稍向右滑动之后的区域，并输入给卷积网络，再次运行卷积网络，然后处理第三个图像，依次重复操作，直到这个窗口滑过图像的每一个角落

[\
![](https://github.com/fengdu78/deeplearning_ai_books/raw/master/images/c55f22f302899d5f9d77bef958465660.png)](https://legacy.gitbook.com/book/baozou/neural-networks-and-deep-learning/edit)

思路是以固定步幅移动窗口，遍历图像的每个区域，把这些剪切后的小图像输入卷积网络，对每个位置按0或1进行分类

3.重复上述操作，选择一个更大的窗口，截取更大的区域，并输入给卷积神经网络处理，输出0或1

[\
![](https://github.com/fengdu78/deeplearning_ai_books/raw/master/images/34507c03fbda16049faeb3caf075fe50.png)](https://legacy.gitbook.com/book/baozou/neural-networks-and-deep-learning/edit)

4.再以某个固定步幅滑动窗口，重复以上操作，遍历整个图像，输出结果

[![](https://github.com/fengdu78/deeplearning_ai_books/raw/master/images/f2b6d5bfedc5298160bc2628544e315c.png)](https://github.com/fengdu78/deeplearning_ai_books/blob/master/images/f2b6d5bfedc5298160bc2628544e315c.png)

5.第三次重复操作，选用更大的窗口

[![](https://github.com/fengdu78/deeplearning_ai_books/raw/master/images/c14524aa0534ed78c433e1cd0a8dff50.png)](https://github.com/fengdu78/deeplearning_ai_books/blob/master/images/c14524aa0534ed78c433e1cd0a8dff50.png)

这样不论汽车在图片的什么位置，总有一个窗口可以检测到

这种算法叫作滑动窗口目标检测：以某个步幅滑动这些方框窗口遍历整张图片，对这些方形区域进行分类，判断里面有没有汽车

[![](https://github.com/fengdu78/deeplearning_ai_books/raw/master/images/ef8afff4e50fc1c50a46b8443f1d6976.png)](https://github.com/fengdu78/deeplearning_ai_books/blob/master/images/ef8afff4e50fc1c50a46b8443f1d6976.png)

滑动窗口目标检测算法缺点：**计算成本**

* 如果选用的步幅很大，会减少输入卷积网络的窗口个数，粗糙间隔尺寸可能会影响性能
* 如果采用小粒度或小步幅，传递给卷积网络的小窗口会特别多，这意味着超高的计算成本

## 3.4 卷积的滑动窗口实现（Convolutional implementation of sliding windows）

### 把神经网络的全连接层转化成卷积层

[![](https://github.com/fengdu78/deeplearning_ai_books/raw/master/images/38be387e37d131e44aff9d7fc9e3488a.png)](https://github.com/fengdu78/deeplearning_ai_books/blob/master/images/38be387e37d131e44aff9d7fc9e3488a.png)

前几层和之前的一样，下一层全连接层用5×5×16的过滤器来实现，数量是400个（编号1），输入图像大小为5×5×16，输出维度是1×1×400，这400个节点中每个节点都是上一层5×5×16激活值经过某个任意线性函数的输出结果

再添加另外一个卷积层（编号2），用1×1卷积，假设有400个1×1的过滤器，在这400个过滤器的作用下，下一层的维度是1×1×400，是上个网络中的这一全连接层经由1×1过滤器的处理，得到一个**softmax**激活值，通过卷积网络，最终得到1×1×4的输出层，而不是这4个数字（编号3）

以上就是用卷积层代替全连接层的过程，结果这几个单元集变成了1×1×400和1×1×4的维度

### 通过卷积实现滑动窗口对象检测算法

假设向滑动窗口卷积网络输入14×14×3的图片，神经网络最后的输出层，即**softmax**单元的输出是1×1×4

[![](https://github.com/fengdu78/deeplearning_ai_books/raw/master/images/00c4fb1a1af9b50f0fd0bcf5eacca6ff.png)](https://github.com/fengdu78/deeplearning_ai_books/blob/master/images/00c4fb1a1af9b50f0fd0bcf5eacca6ff.png)

假设测试集图片是16×16×3，给输入图片加上黄色条块，在最初的滑动窗口算法中，把蓝色区域输入卷积网络（红色笔标记）生成0或1分类。接着滑动窗口，步幅为2个像素，向右滑动2个像素，将绿框区域输入给卷积网络，运行整个卷积网络，得到另外一个标签0或1。继续将这个橘色区域输入给卷积网络，卷积后得到另一个标签，最后对右下方的紫色区域进行最后一次卷积操作。在这个16×16×3的小图像上滑动窗口，卷积网络运行了4次，于是输出了了4个标签

[![](https://github.com/fengdu78/deeplearning_ai_books/raw/master/images/2a8750d733379aebf58f4354203153f2.png)](https://github.com/fengdu78/deeplearning_ai_books/blob/master/images/2a8750d733379aebf58f4354203153f2.png)

这4次卷积操作中很多计算都是重复的。执行滑动窗口的卷积时使得卷积网络在这4次前向传播过程中共享很多计算，尤其是在编号1，卷积网络运行同样的参数，使用相同的5×5×16过滤器进行卷积操作，得到12×12×16的输出层。然后执行同样的最大池化（编号2），输出结果6×6×16。照旧应用400个5×5的过滤器（编号3），得到一个2×2×400的输出层，现在输出层为2×2×400，应用1×1过滤器（编号4）得到另一个2×2×400的输出层。再做一次全连接的操作（编号5），最终得到2×2×4的输出层，在输出层4个子方块中，蓝色的是图像左上部分14×14的输出（红色箭头标识），右上角方块是图像右上部分（绿色箭头标识）的对应输出，左下角方块是输入层左下角（橘色箭头标识），右下角是卷积网络处理输入层右下角14×14区域(紫色箭头标识)的结果

[![](https://github.com/fengdu78/deeplearning_ai_books/raw/master/images/ad1743ff113f9d30080f63a16c74ed64.png)](https://github.com/fengdu78/deeplearning_ai_books/blob/master/images/ad1743ff113f9d30080f63a16c74ed64.png)

具体的计算步骤：以绿色方块为例，假设剪切出这块区域（编号1），传递给卷积网络，第一层的激活值就是这块区域（编号2），最大池化后的下一层的激活值是这块区域（编号3），这块区域对应着后面几层输出的右上角方块（编号4，5，6）

该卷积操作的原理是不需要把输入图像分割成四个子集，分别执行前向传播，而是把它们作为一张图片输入给卷积网络进行计算，其中的公共区域可以共享很多计算

假如对一个28×28×3的图片应用滑动窗口操作，以14×14区域滑动窗口，以大小为2的步幅不断地向右移动窗口，直到第8个单元格，得到输出层的第一行。然后向图片下方移动，最终输出8×8×4的结果

[![](https://github.com/fengdu78/deeplearning_ai_books/raw/master/images/5fd2f8d039a3bfc5187dfe33f5276235.png)](https://github.com/fengdu78/deeplearning_ai_books/blob/master/images/5fd2f8d039a3bfc5187dfe33f5276235.png)

总结滑动窗口的实现过程：

在图片上剪切出一块区域，假设大小是14×14，把它输入到卷积网络。继续输入下一块区域，大小同样是14×14，重复操作，直到某个区域识别到汽车

[![](https://github.com/fengdu78/deeplearning_ai_books/raw/master/images/84a6a0505acc165c6600d4b6f03d5e3c.png)](https://github.com/fengdu78/deeplearning_ai_books/blob/master/images/84a6a0505acc165c6600d4b6f03d5e3c.png)

但是不能依靠连续的卷积操作来识别图片中的汽车，可以对大小为28×28的整张图片进行卷积操作，一次得到所有预测值，如果足够幸运，神经网络便可以识别出汽车的位置

[![](https://github.com/fengdu78/deeplearning_ai_books/raw/master/images/447080411189a0a4544747c2380fbda4.png)](https://github.com/fengdu78/deeplearning_ai_books/blob/master/images/447080411189a0a4544747c2380fbda4.png)

在卷积层上应用滑动窗口算法提高了整个算法的效率，缺点是边界框的位置可能不够准确

## 3.5 Bounding Box预测（Bounding box predictions）

滑动窗口法的卷积实现算法效率很高，但不能输出最精准的边界框

[![](https://github.com/fengdu78/deeplearning_ai_books/raw/master/images/cd3e263bf279739afe62eb8730b4e167.png)](https://github.com/fengdu78/deeplearning_ai_books/blob/master/images/cd3e263bf279739afe62eb8730b4e167.png)

输入图像是100×100的，用3×3网格，实际实现时会用更精细的网格（19×19）。使用图像分类和定位算法

[![](https://github.com/fengdu78/deeplearning_ai_books/raw/master/images/e4bebc707829a1610572f43f8e0995c9.png)](https://github.com/fengdu78/deeplearning_ai_books/blob/master/images/e4bebc707829a1610572f43f8e0995c9.png)

编号1什么也没有，左上格子的标签向量$$y$$是$$\begin{bmatrix}0\ ?\ ?\ ?\ ?\ ?\ ?\ ? \end{bmatrix}$$。其他什么也没有的格子都一样

图中有两个对象，**YOLO**算法做的是取两个对象的中点，将对象分配给包含对象中点的格子。即使中心格子（编号5）同时有两辆车的一部分，分类标签$$y$$也为$$y= \begin{bmatrix}0\ ?\ ?\ ?\ ?\ ?\ ?\ ? \end{bmatrix}$$。编号4目标标签$$y= \begin{bmatrix} 1\ b\_{x}\ b\_{y}\ b\_{h}\ b\_{w}\ 0\ 1\ 0 \end{bmatrix}$$，编号6类似

[![](https://github.com/fengdu78/deeplearning_ai_books/raw/master/images/fb08477cd3937f7df0deddc1de1d2920.png)](https://github.com/fengdu78/deeplearning_ai_books/blob/master/images/fb08477cd3937f7df0deddc1de1d2920.png)

3×3中9个格子都对应一个8维输出目标向量$$y$$，其中一些值可以是**dont care-s**（即？）所以总的目标输出尺寸就是3×3×8

[![](https://github.com/fengdu78/deeplearning_ai_books/raw/master/images/98633e9df22fd06cfc21af2e7d39bbb6.png)](https://github.com/fengdu78/deeplearning_ai_books/blob/master/images/98633e9df22fd06cfc21af2e7d39bbb6.png)

如果要训练一个输入为100×100×3的神经网络，输入图像通过普通的卷积网络，卷积层，最大池化层等等，最后映射到一个3×3×8输出尺寸。然后用反向传播训练神经网络，将任意输入$$x$$映射到输出向量$$y$$

[![](https://github.com/fengdu78/deeplearning_ai_books/raw/master/images/404fdcba2685b830ae3718d348ab1d75.png)](https://github.com/fengdu78/deeplearning_ai_books/blob/master/images/404fdcba2685b830ae3718d348ab1d75.png)

这个算法的优点在于神经网络可以输出精确的边界框，测试的时候有要做的是喂入输入图像$$x$$，然后跑正向传播，直到得到输出$$y$$。然后3×3位置对应的9个输出，只要每个格子中对象数目没有超过1个，这个算法应该是没问题的。但实践中会使用更精细的19×19网格，输出就是19×19×8，多个对象分配到同一个格子得概率就小得多

[![](https://github.com/fengdu78/deeplearning_ai_books/raw/master/images/a6d32959543c502ee18765cf20495bc2.png)](https://github.com/fengdu78/deeplearning_ai_books/blob/master/images/a6d32959543c502ee18765cf20495bc2.png)

即使对象可以横跨多个格子，也只会被分配到9个格子其中之一，或者19×19网络的其中一个格子。在19×19网格中，两个对象的中点（图中蓝色点所示）处于同一个格子的概率就会更低。

[![](https://github.com/fengdu78/deeplearning_ai_books/raw/master/images/b6b6ca6167596a180c7bab7296ea850c.png)](https://github.com/fengdu78/deeplearning_ai_books/blob/master/images/b6b6ca6167596a180c7bab7296ea850c.png)

优点：

* 显式地输出边界框坐标，可以具有任意宽高比，并且能输出更精确的坐标，不会受到滑动窗口分类器的步长大小限制
* 并没有在3×3网格上跑9次算法，而是单次卷积实现，但在处理这3×3计算中很多计算步骤是共享的，所以这个算法效率很高
* 因为是卷积实现，运行速度非常快，可以达到实时识别

如何编码这些边界框$$b\_{x}$$、$$b\_{y}$$、$$b\_{h}$$和$$b\_{w}$$：

在**YOLO**算法中，编号1约定左上点是$$(0,0)$$，右下点是$$(1,1)$$，橙色中点的位置$$b\_{x}$$大概是0.4，$$b\_{y}$$大概是0.3，$$b\_{w}$$是0.9，$$b\_{h}$$是0.5。$$b\_{x}$$、$$b\_{y}$$、$$b\_{h}$$和$$b\_{w}$$单位是相对于格子尺寸的比例，所以$$b\_{x}$$和$$b\_{y}$$必须在0和1之间，因为从定义上看，橙色点位于对象分配到格子的范围内，如果它不在0和1之间，即它在方块外，那么这个对象就应该分配到另一个格子上。这个值（$$b\_{h}$$和$$b\_{w}$$）可能会大于1，特别是如果有一辆汽车的边界框是这样的（编号3所示），那么边界框的宽度和高度有可能大于1

[![](https://github.com/fengdu78/deeplearning_ai_books/raw/master/images/0d7ee9b9f455338a8724520841223b11.png)](https://github.com/fengdu78/deeplearning_ai_books/blob/master/images/0d7ee9b9f455338a8724520841223b11.png)

## 3.6 交并比（Intersection over union）

并交比函数可以用来评价对象检测算法

[![](https://github.com/fengdu78/deeplearning_ai_books/raw/master/images/38eea69baa46091d516a0b7a33e5379e.png)](https://github.com/fengdu78/deeplearning_ai_books/blob/master/images/38eea69baa46091d516a0b7a33e5379e.png)

交并比（**loU**）函数是计算两个边界框交集和并集之比。两个边界框的并集是两个边界框绿色阴影区域，而交集是这个橙色阴影区域，交并比就是交集的大小（橙色阴影面积）除以绿色阴影的并集面积

一般约定，在计算机检测任务中，如果loU≥0.5，就说检测正确，如果预测器和实际边界框完美重叠，**loU**就是1，因为交集就等于并集

## 3.7 非极大值抑制（Non-max suppression）

对象检测中的一个问题是算法可能对同一个对象做出多次检测，非极大值抑制可以确保算法对每个对象只检测一次

[![](https://github.com/fengdu78/deeplearning_ai_books/raw/master/images/a86a2edbb89014e193ab613a162cff58.png)](https://github.com/fengdu78/deeplearning_ai_books/blob/master/images/a86a2edbb89014e193ab613a162cff58.png)

实践中当运行对象分类和定位算法时，对于每个格子都运行一次，编号1、2、3可能会认为这辆车中点应该在格子内部

[![](https://github.com/fengdu78/deeplearning_ai_books/raw/master/images/78f2b2a2efdbd6aebe034ce30cda440b.png)](https://github.com/fengdu78/deeplearning_ai_books/blob/master/images/78f2b2a2efdbd6aebe034ce30cda440b.png)

这个算法做的是：

1.首先看哪个检测结果相关的概率$$p\_{c}$$（实际上是$$p\_{c}$$乘以$$c\_{1}$$、$$c\_{2}$$或$$c\_{3}$$）概率最大，右边车辆中是0.9，即最可靠的检测，用高亮标记，之后非极大值抑制逐一审视剩下的矩形，所有和这个最大的边框有很高交并比，高度重叠的其他边界框输出就会被抑制

[![](https://github.com/fengdu78/deeplearning_ai_books/raw/master/images/074beeacfd9d400fc580171b09a6f3e9.png)](https://github.com/fengdu78/deeplearning_ai_books/blob/master/images/074beeacfd9d400fc580171b09a6f3e9.png)

2.逐一审视剩下的矩形，找出概率$$p\_{c}$$最高的一个，在这种情况下是0.8，就认为检测出一辆车（左边车辆），然后非极大值抑制算法就会去掉其他**loU**值很高的矩形。现在每个矩形都会被高亮显示或者变暗，如果直接抛弃变暗的矩形，就剩下高亮显示的那些是最后得到的两个预测结果

非最大值意味着只输出概率最大的分类结果，但抑制很接近，不是最大的其他预测结果

算法的细节：

首先在19×19网格上执行算法，会得到19×19×8的输出尺寸。简化成只做汽车检测，会得到输出预测概率（$$p\_{c}$$）和边界框参数（$$b\_{x}$$、$$b\_{y}$$、$$b\_{h}$$和$$b\_{w}$$）

[![](https://github.com/fengdu78/deeplearning_ai_books/raw/master/images/514cfeb2d7315eba2b6a29f68eae2879.png)](https://github.com/fengdu78/deeplearning_ai_books/blob/master/images/514cfeb2d7315eba2b6a29f68eae2879.png)

1.将所有的预测值$$p\_{c}$$小于或等于某个阈值，如$$p\_{c}\le 0.6$$的边界框去掉

[![](https://github.com/fengdu78/deeplearning_ai_books/raw/master/images/6d0fa2073b280cd0bb111485ee1639e5.png)](https://github.com/fengdu78/deeplearning_ai_books/blob/master/images/6d0fa2073b280cd0bb111485ee1639e5.png)

2.剩下的边界框就一直选择概率$$p\_{c}$$最高的边界框，把它输出成预测结果，取一个边界框，让它高亮显示，就可以确定输出有一辆车的预测

[![](https://github.com/fengdu78/deeplearning_ai_books/raw/master/images/549430cf442163c7f44ae648e625ca10.png)](https://github.com/fengdu78/deeplearning_ai_books/blob/master/images/549430cf442163c7f44ae648e625ca10.png)

3.去掉所有剩下的边界框

如果同时检测三个对象，比如说行人、汽车、摩托，输出向量就会有三个额外的分量。正确的做法是独立进行三次非极大值抑制，对每个输出类别都做一次

## 3.8 Anchor Boxes

对象检测存在的一个问题是每个格子只能检测出一个对象，如果想让一个格子检测出多个对象，可以使用**anchor box**

[![](https://github.com/fengdu78/deeplearning_ai_books/raw/master/images/49b7d68a17e89dd109f96efecc223f5a.png)](https://github.com/fengdu78/deeplearning_ai_books/blob/master/images/49b7d68a17e89dd109f96efecc223f5a.png)

> 行人的中点和汽车的中点都落入到同一个格子中

[![](https://github.com/fengdu78/deeplearning_ai_books/raw/master/images/e001f5f3d2afa76a1c3710bd60bcad00.png)](https://github.com/fengdu78/deeplearning_ai_books/blob/master/images/e001f5f3d2afa76a1c3710bd60bcad00.png)

**anchor box**的思路是：预先定义两个不同形状的**anchor box**，把预测结果和这两个**anchor box**关联起来

[![](https://github.com/fengdu78/deeplearning_ai_books/raw/master/images/2e357b5b92122660c550dcfb0901519c.png)](https://github.com/fengdu78/deeplearning_ai_books/blob/master/images/2e357b5b92122660c550dcfb0901519c.png)

定义类别标签：

$$
y= \begin{bmatrix} 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} \end{bmatrix}^{T}
$$

前面的$$p\_{c},b\_{x},b\_{y},b\_{h},b\_{w},c\_{1},c\_{2},c\_{3}$$（绿色方框标记的参数）是和**anchor box 1**关联的8个参数，后面的8个参数（橙色方框标记的元素）是和**anchor box 2**相关联

行人：$$p\_{c}= 1,b\_{x},b\_{y},b\_{h},b\_{w},c\_{1} = 1,c\_{2} = 0,c\_{3} = 0$$

车子的边界框更像**anchor box 2**，($$p\_{c}= 1,b\_{x},b\_{y},b\_{h},b\_{w},c\_{1} = 0,c\_{2} = 1,c\_{3} = 0$$)

[![](https://github.com/fengdu78/deeplearning_ai_books/raw/master/images/e94aa7ea75300ea4692682b179834bb4.png)](https://github.com/fengdu78/deeplearning_ai_books/blob/master/images/e94aa7ea75300ea4692682b179834bb4.png)

现在每个对象都分配到对象中点所在的格子中，以及分配到和对象形状交并比最高的**anchor box**中。然后观察哪个**anchor box**和实际边界框（编号1，红色框）的交并比更高

编号1对应同时有车和行人，编号3对应只有车：

[![](https://github.com/fengdu78/deeplearning_ai_books/raw/master/images/322b15fe615c739ebd1d36b669748618.png)](https://github.com/fengdu78/deeplearning_ai_books/blob/master/images/322b15fe615c739ebd1d36b669748618.png):

**anchor box**是为了处理两个对象出现在同一个格子的情况，实践中这种情况很少发生，特别用的是19×19网格

怎么选择**anchor box：**

* 一般手工指定**anchor box**形状，可以选择5到10个**anchor box**形状，覆盖到想要检测的对象的各种形状
* 更高级的是使用**k-平均算法**，将两类对象形状聚类，选择最具有代表性的一组**anchor box**

## 3.9 YOLO 算法（Putting it together: YOLO algorithm）

假设要在图片中检测行人、汽车，同时使用两种不同的Anchor box

**训练集：**

* 输入X：同样大小的完整图片
* 目标Y：使用$$3\times3$$网格划分，输出大小$$3\times3\times2\times8$$，或者$$3\times3\times16$$
* 对不同格子中的小图，定义目标输出向量Y

[\
![](https://github.com/fengdu78/deeplearning_ai_books/raw/master/images/36ff927836cfcd7fee9413e2d34757d8.png)](https://legacy.gitbook.com/book/baozou/neural-networks-and-deep-learning/edit)

编号2目标向量$$y =\begin{bmatrix} 0 & ? & ? & ? & ? & ? & ? & ? & 1 & b\_{x} & b\_{y} & b\_{h} \&b\_{w} & 0 & 1 & 0 \end{bmatrix}^{T}$$，假设训练集中对于车子有一个边界框（编号3），水平方向更长一点，红框和**anchor box 2**的交并比更高，车子和向量的下半部分相关

**模型预测：**

输入与训练集中相同大小的图片，然后训练一个卷积网络，遍历9个格子，得到每个格子中不同的输出结果：$$3\times3\times2\times8$$

[\
![](https://github.com/fengdu78/deeplearning_ai_books/raw/master/images/e23084f4a75246f08ea4cedef55f60ab.png)](https://legacy.gitbook.com/book/baozou/neural-networks-and-deep-learning/edit)

**运行非最大值抑制（NMS）：**

1. 假设使用了2个Anchor box，每一个网格都会得到预测输出的2个bounding boxes，其中一个$$P\_{c}$$比较高
2. 抛弃概率$$P\_{c}$$值低的预测bounding boxes
3. 对每个对象分别使用NMS算法得到最终的预测边界框

[![](https://github.com/fengdu78/deeplearning_ai_books/raw/master/images/23256c4b7b28d62d34a744f5fb5e9c3b.png)](https://legacy.gitbook.com/book/baozou/neural-networks-and-deep-learning/edit)

[\
![](https://github.com/fengdu78/deeplearning_ai_books/raw/master/images/66f8cf8e55eadc1ac01f773515bfbc45.png)](https://legacy.gitbook.com/book/baozou/neural-networks-and-deep-learning/edit)

如果有三个对象检测类别，希望检测行人，汽车和摩托车：对于每个类别单独运行非极大值抑制，处理预测结果所属类别的边界框，用非极大值抑制来处理行人类别、车子类别、摩托车类别，运行三次来得到最终的预测结果

## 3.10 候选区域（选修）（Region proposals (Optional)）

滑动窗法会对原始图片的每个区域都进行扫描，即使是一些空白的或明显没有目标的区域，这样会降低算法运行效率，耗费时间

[![](https://github.com/fengdu78/deeplearning_ai_books/raw/master/images/838a6aeb35865f9cfecac8dc593b565b.png)](https://github.com/fengdu78/deeplearning_ai_books/blob/master/images/838a6aeb35865f9cfecac8dc593b565b.png)

**R-CNN**算法，即带区域的卷积网络，或者带区域的**CNN**。这个算法尝试选出一些区域，在少数窗口上运行卷积网络分类器

选出候选区域的方法是运行图像分割算法，找出各个尺度的色块，然后在色块上运行分类器，即首先得到候选区域，然后再分类

[![](https://github.com/fengdu78/deeplearning_ai_books/raw/master/images/e78e4465af892d0965e2b0863263ef8c.png)](https://github.com/fengdu78/deeplearning_ai_books/blob/master/images/e78e4465af892d0965e2b0863263ef8c.png)

**R-CNN**算法很慢，基本的**R-CNN**算法是使用某种算法求出候选区域，然后对每个候选区域运行一下分类器，每个区域会输出一个标签，有没有车子、行人、摩托车？并输出一个边界框，就能在确实存在对象的区域得到一个精确的边界框

**R-CNN**算法不会直接信任输入的边界框，也会输出一个边界框$$b\_{x}$$，$$b\_{y}$$，$$b\_{h}$$和$$b\_{w}$$，这样得到的边界框比较精确，比单纯使用图像分割算法给出的色块边界要好

**Fast R-CNN**算法基本上是**R-CNN**算法，最初的算法是逐一对区域分类，快速**R-CNN**用的是滑动窗法的一个卷积实现，和**3.4 卷积的滑动窗口实现**的相似，显著提升了**R-CNN**的速度，问题是得到候选区域的聚类步骤仍然非常缓慢

更快的**R-CNN**算法（**Faster R-CNN**），使用的是卷积神经网络，而不是更传统的分割算法来获得候选区域色块，比**Fast R-CNN**算法快得多

[![](https://github.com/fengdu78/deeplearning_ai_books/raw/master/images/e6ed1aa3263107d4e189dd75adc060b4.png)](https://github.com/fengdu78/deeplearning_ai_books/blob/master/images/e6ed1aa3263107d4e189dd75adc060b4.png)

不过大多数更快**R-CNN**的算法实现还是比**YOLO**算法慢很多
