根据Ng视频内容和章节总结。
CNN-目标检测
3.1目标定位
让神经网络多输出几个单元,输出一个边界框,具体说就是让神经网络再多输出4个数字,标记为bx、by、bh和bw,这四个数字是被检测对象的边界框的参数化表示。
图片左上角为(0,0),右下角(1,1),中心点用(bx,by)表示, 边界框的高度为bh,边界框的高度为bh,训练集不仅包括神经网络要预测的对象分类标签,神经网络要预测的对象分类标签,接着采用监督学习算法,输出一个分类标签,还有这四个参数值,从而给出被检测对象的边界框位置。
目标标签定义如下:(假设分4类,人、车、自行车、背景)
pc表示被检测对象属于某一分类的概率,如果对象属于前三类则Pc=1,如果是背景,则图片中没有要检测的对象,Pc=0。
--如果检测到对象,就输出被检测对象的边界框参数bx、by、bh、bw,如果存在某个对象,那么Pc=1,同时输出c1、c2、c3,表示该对象属于1-3中的哪一类,这些数据最终定义了训练集。
(1)
y
=
[
p
c
b
x
b
y
b
h
b
w
c
1
c
2
c
3
]
y= \begin{bmatrix} p_{c} \\ \hline b_{x} \\ b_{y} \\ b_{h}\\ b_{w} \\ \hline c_{1} \\ c_{2} \\ c_{3}\\ \end{bmatrix} \tag{1}
y=⎣⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎡pcbxbybhbwc1c2c3⎦⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎤(1)
损失函数
通常做法是对边界框坐标参数bx、by、bh、bw应用平方误差或类似方法;对Pc应用逻辑回归函数,甚至采用平方预测误差也是可以的。
利用神经网络输出批量实数来识别图片中的对象是个非常有用的算法。下一课介绍,把神经网络输出的实数集作为一个回归任务,这个思想也被应用于计算机视觉的其它领域。
3.4卷积滑动窗口实现
3.4.1需要的基本操作
将全连接层改为卷积操作,中间输出
5
×
5
×
16
5\times5\times16
5×5×16,添加400个
5
×
5
×
16
5\times5\times16
5×5×16的filter,卷积输出为
1
×
1
×
400
1\times1\times400
1×1×400。这里不再把它看作一个含有400个神经元(节点)的集合,而是一个
1
×
1
×
400
1\times1\times400
1×1×400的输出层。再添加另外一个卷积层,这里用的是
1
×
1
1\times1
1×1卷积,假设有400个
1
×
1
1\times1
1×1的过滤器,则下一层的维度是
1
×
1
×
400
1\times1\times400
1×1×400,它其实就是上个网络中的这一全连接层。最后经由4个
1
×
1
1\times1
1×1过滤器的处理得到一个softmax激活值,为
1
×
1
×
4
1\times1\times4
1×1×4的输出层。
3.4.2用卷积实现滑动窗口
3.5 bounding box predictions
YOLO算法
基本思路是使用图像分类和定位算法,然后将算法逐一应用到9个格子上。
具体是:对于9个格子中的每一个,指定一个标签y,y是8维向量。 这张图有两个对象,YOLO算法做的就是取两个对象的中点,然后将这个对象分配给包含对象中点的格子。所以对于这里9个格子中任何一个,都会得到一个8维输出向量。因为这里有3×3格子,然后对于每个格子都有一个8维向量y,所以目标输出尺寸是3×3×8。
所以对于这3×3中每一个位置而言,每个都对应一个8维输出目标向量y。所以总的目标输出标签尺寸就是3×3×8。
这个算法的优点:
1.精确边框线:神经网络可以输出精确的边界框,实际中用到19×19格子。任意高宽比,输出更精确的坐标,不会受到滑动窗法分类器的步长大小限制。
2.效率高:并不在19×19网格中跑361次算法,仅仅是单次卷积实现,使用了一个卷积网络,有很多共享计算步骤,效率高。运行速度非常快,可达实时效果。
如何指定边界,编码bx、by、bh、bw
bx、by是相对格子尺寸的比例,所以bx和by必须在0和1之间。bh、bw边界线的高和宽,也是相对一个格子尺寸比例,可能会>1。
在YOLO的研究论文中,还有其他更高级的参数化方式,可能效果会更好。涉及到sigmoid函数确保这个值介于0和1之间,然后使用指数参数化来确保非负数。
3.6 交并比(IoU)
交并比函数可以用来评价对象检测算法,计算两个边界框交集和并集之比,那么交并比就是计算 交集的大小/并集的大小。
一般约定:
在计算机检测任务中如果IoU大于或等于0.5就说检测正确。
人们定义IoU这个概念是为了评价你的对象定位算法是否精准,但更一般地说,IoU衡量了两个边界框重叠的相对大小。
3.7非最大值抑制(non-max suppression)
非最大值抑制这个方法可以确保算法对每个对象只检测一次。
找到最大的pc,这个例子中是0.9,然后就指定这是最可靠的检测,非最大值抑制就会逐一审视剩下的矩形,所有和这个最大的边界框有很高交并比(高度重叠的其他边界框),那么这些输出就会被抑制,非最大值抑制算法就会去掉其他IoU值很高的矩形。
交并比定义(IoU):
算法步骤:(检测一个对象为例)
- 去掉 ≤ \leq ≤ 阈值 的边界框
- While 剩余保留的boxes:
–选择概率最高的box并作为输出预测结果
–去掉和输出边界框高交并比的所有框
同时检测三个对象时,输出向量就会有三个额外的分量,独立进行三次非最大值抑制,对每个输出类别都做一次。
3.8 anchor boxes
我把他称为 锚定框
使用anchor box这个概念,让一个格子检测出多个对象。
用多个anchor box:
因为行人的形状更类似于anchor box1,可以用这个8个数值,汽车类似,一共用两组数据表示边框和检测结果。
3.9 YOLO算法
Training
预测
非最大抑制输出
- 每个格子两个预测边框(有的框H、W可超过格子大小)
- 去掉低概率边框
- 对每个分类单独运行非最大值抑制
3.10 候选区域(region proposals)
滑动窗口:用训练过的分类器在窗口中跑一遍,然后运行检测器检测是否有对象。
卷积算法缺点:在没有对象的区域浪费时间。
3.10.1 带区域的卷积网络(R-CNN (regions with CNN))
这个算法尝试选出一些 运行卷积网络分类器有意义的 区域。
原理:
这里不再针对每个滑动窗跑检测算法,在少数窗口上运行卷积网络分类器。
选出候选区域的方法是运行图像分割算法,在分块中跑分类器,减少了需要处理的块,可以减少卷积网络分类器运行时间,比在图像所有位置跑一遍分类器要快。
所以基本的R-CNN算法是使用某种算法求出候选区域,然后对每个候选区域跑一下分类器,每个区域会输出一个标签,并输出一个边界框,在确实存在对象的区域得到一个精确的边界框。R-CNN算法不会直接信任输入的边界框,它也会输出一个边界框bx、by、bh、bw,这样得到的边界框比较精确,比单纯使用图像分割算法给出的色块边界要好。
3.10.2 fast R-CNN
原理
fast R-CNN用的是滑动窗法的一个卷积实现,这显著提升了R-CNN的速度。
缺点
得到候选区域的聚类步骤仍然非常缓慢。
3.10.3 faster R-CNN
使用的是卷积神经网络,而不是更传统的分割算法来获得候选区域色块,结果比fast R-CNN算法快得多,但是还是比YOLO算法慢很多。
0.0 细节解释
图片标定:
如果您希望YOLO识别出80个类,则可以将类标签c表示为1到80之间的整数,或者表示为80维向量(具有80个数字),其中一个元素为1,其余是0。
该算法在图像中"only looks once",因为它只需要一次前向传播通过网络进行预测。 在非最大抑制之后,然后将识别的对象与边界框一起输出。
模型细节
- 输入: 假设输入图像数据为 (m, 608, 608, 3)
- 输出: 包含(pc,bx,by,bh,bw,c),如果为80分类,则输出维度为5+80=85
假设用5个anchor boxes,YOLO结构可简单表示为IMAGE (m, 608, 608, 3) -> DEEP CNN -> ENCODING (m, 19, 19, 5, 85),具体如下:
由于我们使用5个anchor boxes,因此19个x19单元中的每一个cell都包含5个anchor boxes坐标信息(仅由cell宽度和高度定义)。为了简化方便使用,将最后两维展开由(19, 19, 5, 85)变成(19, 19, 425)。如下:
计算
对于每个单元格,我们将计算以下元素乘积,并提取该框包含某个类的概率:
以下是一种可视化Yolo在图像上预测的方法:
- 对于每个19x19网格单元,找到概率最大值(在5个锚定框和不同类中取最大值)
- 根据网格单元认为最可能的对象,为网格单元着色如左图。也可以画边框如右图。
YOLO算法过滤对象多余边框(使用了anchor boxes)
- 1.在类预测上应用阈值过滤
def yolo_filter_boxes(box_confidence, boxes, box_class_probs, threshold=.6):
"""Filters YOLO boxes by thresholding on object and class confidence.
Arguments:
box_confidence -- tensor of shape (19, 19, 5, 1)
boxes -- tensor of shape (19, 19, 5, 4)
box_class_probs -- tensor of shape (19, 19, 5, 80)
threshold -- real value, if [ highest class probability score < threshold], then get rid of the corresponding box
Returns:
scores -- tensor of shape (None,), containing the class probability score for selected boxes
boxes -- tensor of shape (None, 4), containing (b_x, b_y, b_h, b_w) coordinates of selected boxes
classes -- tensor of shape (None,), containing the index of the class detected by the selected boxes
Note: "None" is here because you don't know the exact number of selected boxes, as it depends on the threshold.
For example, the actual output size of scores would be (10,) if there are 10 boxes."""
# box_confidence - (19, 19, 5, 1) (xx, xx, xx, 1)cell内有对象的概率是0.几
# boxes - (19, 19, 5, 4) (xx, xx, xx,) 某个锚定框的四个位置参数向量 4个元素[bx, by, bh, bw]
# box_class_probs - (19, 19, 5, 80) (xx, xx, xx,)某个锚定框所属类的概率向量 80个元素 [0.1, 0.02, 0.6,...]
# Step 1: Compute box scores
box_scores = box_confidence * box_class_probs
# Step 2: Find the box_classes thanks to the max box_scores, keep track of the corresponding score
box_classes = K.argmax(box_scores, axis=-1) # 一个锚定框只包含一个类,需要挑出最大概率所在的类
box_class_scores = K.max(box_scores, axis=-1) # 记录每个锚定框的所属类别的概率的最大值
# Step 3: Create a filtering mask based on "box_class_scores" by using "threshold". The mask should have the
# same dimension as box_class_scores, and be True for the boxes you want to keep (with probability >= threshold)
# 创建筛子,(去掉cell中低概率的锚定框 [尽管在该预测中是最大的值],用剩下的锚定框组成筛子(True, False,...))
filtering_mask = (box_class_scores >= threshold)
# Step 4: Apply the mask to scores, boxes and classes 利用筛子各种筛选
scores = tf.boolean_mask(box_class_scores, filtering_mask)
boxes = tf.boolean_mask(boxes, filtering_mask)
classes = tf.boolean_mask(box_classes, filtering_mask)
return scores, boxes, classes
尽管在类预测上应用阈值过滤,但对象还是存在冗余边框,需要用到前面介绍的非最大值抑制算法(NMS)。
- 2.运用非最大值抑制
- 计算交并比
def iou(box1, box2): """Implement the intersection over union (IoU) between box1 and box2 Arguments: box1 -- first box, list object with coordinates (x1, y1, x2, y2) box2 -- second box, list object with coordinates (x1, y1, x2, y2) """ xi1 = max(box1[0], box2[0]) yi1 = max(box1[1], box2[1]) xi2 = min(box1[2], box2[2]) yi2 = min(box1[3], box2[3]) inter_area = (xi2 - xi1) * (yi2 - yi1) box1_area = (box1[2] - box1[0]) * (box1[3] - box1[1]) box2_area = (box2[2] - box2[0]) * (box2[3] - box2[1]) union_area = box1_area + box2_area - inter_area return inter_area / union_area
- 非极大值抑制算法步骤(TensorFlow自带tf.image.non_max_suppression())
–(1)选择最大预测值的边框
–(2)计算它与所有其他框的重叠程度IoU,并删除超过IoU阈值的框
–(3)返回到步骤(1)并迭代,直到没有比当前所选框预测值更低的框
def yolo_non_max_suppression(scores, boxes, classes, max_boxes=10, iou_threshold=0.5):
"""
Applies Non-max suppression (NMS) to set of boxes
Arguments:
scores -- tensor of shape (None,), output of yolo_filter_boxes()
boxes -- tensor of shape (None, 4), output of yolo_filter_boxes() that have been scaled to the image size (see later)
classes -- tensor of shape (None,), output of yolo_filter_boxes()
max_boxes -- integer, maximum number of predicted boxes you'd like
iou_threshold -- real value, "intersection over union" threshold used for NMS filtering
Returns:
scores -- tensor of shape (, None), predicted score for each box
boxes -- tensor of shape (4, None), predicted box coordinates
classes -- tensor of shape (, None), predicted class for each box
Note: The "None" dimension of the output tensors has obviously to be less than max_boxes. Note also that this
function will transpose the shapes of scores, boxes, classes. This is made for convenience.
"""
max_boxes_tensor = K.variable(max_boxes, dtype='int32') # tensor to be used in tf.image.non_max_suppression()
K.get_session().run(tf.variables_initializer([max_boxes_tensor])) # initialize variable max_boxes_tensor
# Use tf.image.non_max_suppression() to get the list of indices corresponding to boxes you keep
nms_indices = tf.image.non_max_suppression(boxes, scores, max_boxes_tensor, iou_threshold=iou_threshold)
# Use K.gather() to select only nms_indices from scores, boxes and classes
scores = K.gather(scores, nms_indices)
boxes = K.gather(boxes, nms_indices)
classes = K.gather(classes, nms_indices)
return scores, boxes, classes
将前面的函数组合到一起
def yolo_eval(yolo_outputs, image_shape=(720., 1280.), max_boxes=10, score_threshold=.6, iou_threshold=.5):
"""
Converts the output of YOLO encoding (a lot of boxes) to your predicted boxes along with their scores, box coordinates and classes.
Arguments:
yolo_outputs -- output of the encoding model (for image_shape of (608, 608, 3)), contains 4 tensors:
box_confidence: tensor of shape (None, 19, 19, 5, 1)
box_xy: tensor of shape (None, 19, 19, 5, 2)
box_wh: tensor of shape (None, 19, 19, 5, 2)
box_class_probs: tensor of shape (None, 19, 19, 5, 80)
image_shape -- tensor of shape (2,) containing the input shape, in this notebook we use (608., 608.) (has to be float32 dtype)
max_boxes -- integer, maximum number of predicted boxes you'd like
score_threshold -- real value, if [ highest class probability score < threshold], then get rid of the corresponding box
iou_threshold -- real value, "intersection over union" threshold used for NMS filtering
Returns:
scores -- tensor of shape (None, ), predicted score for each box
boxes -- tensor of shape (None, 4), predicted box coordinates
classes -- tensor of shape (None,), predicted class for each box
"""
# Retrieve outputs of the YOLO model (≈1 line)
box_confidence, box_xy, box_wh, box_class_probs = yolo_outputs
# Convert boxes to be ready for filtering functions
boxes = yolo_boxes_to_corners(box_xy, box_wh)
# Use one of the functions you've implemented to perform Score-filtering with a threshold of score_threshold (≈1 line)
scores, boxes, classes = yolo_filter_boxes(box_confidence, boxes, box_class_probs, threshold=score_threshold)
# Scale boxes back to original image shape.
boxes = scale_boxes(boxes, image_shape)
# Use one of the functions you've implemented to perform Non-max suppression with a threshold of iou_threshold (≈1 line)
scores, boxes, classes = yolo_non_max_suppression(scores, boxes, classes, max_boxes=max_boxes, iou_threshold=iou_threshold)
return scores, boxes, classes