A Practical Guide to Object Detection using the Popular YOLO Framework – Part3翻译

原文链接:https://www.analyticsvidhya.com/blog/2018/12/practical-guide-object-detection-yolo-framewor-python/?utm_source=blog&utm_medium=a-step-by-step-introduction-to-the-basic-object-detection-algorithms-part-1

介绍

如果我们采用一个已经设计好的框架,执行它,并得到预期的结果,我们的生活会有多简单?最小的努力,最大的回报。这不正是我们在任何职业中所追求的吗?

作为我们机器学习社区的一员,我感到无比幸运,在这个社区里,即使是顶尖的科技巨头也愿意接受开源技术。当然,在具体实现之前,理解和掌握概念是很重要的,但当顶级行业数据科学家和研究人员为你奠定基础时,这总是很有帮助的。

这对于像计算机视觉这样的深度学习领域尤其如此。不是每个人都有从头开始构建深度学习模型的计算资源。这就是预定义的框架和预定义的模型派上用场的地方。在本文中,我们将研究一个这样的目标检测框架-YOLO。这是一个非常快速和准确的框架,正如我们很快就会看到的。


到目前为止,在我们详细介绍目标检测的一系列文章(下方有链接)中,我们已经看到了各种算法,以及如何使用R-CNN家族的算法检测图像中的目标并预测边界框。我们还研究了更快RCNN在Python中的实现。

在这里的第3部分中,我们将学习:是什么使得YOLO发挥作用,为什么你应该使用它而不是其他对象检测算法,以及YOLO使用的不同技术。一旦我们完全理解了这个概念,我们将在Python中实现它。这是获得宝贵知识并实际应用的理想指南。

我强烈建议在深入阅读本指南之前先阅读前两部分:

A Step-by-Step Introduction to the Basic Object Detection Algorithms (Part 1)
原文链接:https://www.analyticsvidhya.com/blog/2018/10/a-step-by-step-introduction-to-the-basic-object-detection-algorithms-part-1/
翻译链接:https://blog.csdn.net/Stella_CYT/article/details/114298515

A Practical Implementation of the Faster R-CNN Algorithm for Object Detection (Part 2)
原文链接:https://www.analyticsvidhya.com/blog/2018/11/implementation-faster-r-cnn-python-object-detection/
翻译链接:https://blog.csdn.net/Stella_CYT/article/details/114359219

 

目录
1.什么是YOLO以及YOLO为什么有用?
2.YOLO框架如何工作?
3.如何确定边界框?
4.交并比和非最大抑制
5.Anchor Boxes
6.结合以上方法
7.在Python中实现YOLO

 

什么是YOLO以及YOLO为什么有用?

我们在第1部分中看到的R-CNN技术主要使用区域来定位图像中的对象。该网络不会查看整个图像,只关注图像中有较高概率包含对象的部分。

另一方面,YOLO框架(You Only Look Once)以不同的方式处理目标检测。它在单个实例中获取整个图像,并预测边界框坐标和类概率。使用YOLO的最大优势是它的超高速——它的速度惊人,每秒可以处理45帧。YOLO也理解广义对象表示。

这是最好的目标检测算法之一,并且显示出与R-CNN算法相似的性能。在接下来的部分中,我们将学习YOLO算法中使用的不同技术。以下内容的灵感来自于Andrew NG的目标检测课程https://www.coursera.org/learn/convolutional-neural-networks,这对我理解YOLO有很大帮助。

 

YOLO框架如何工作?

既然我们已经理解了为什么YOLO是一个如此有用的框架,那么让我们开始讨论它是如何工作的。在本节中,我将提到YOLO在检测给定图像中的对象时所遵循的步骤。

1.YOLO首先获得一幅输入图像:
2.YOLO把输入图像划分为3x3的网格:

3.在每个网格上进行图像分类和定位。然后,YOLO预测对象的边界框及其对应的类概率(当然,如果找到了任何对象的话)。

很简单,不是吗?让我们把每一步都分解一下,以便对我们刚刚学到的内容有一个更细致的理解。

我们需要将标记好的数据传递给模型,以便对其进行训练。假设我们把图像分成一个3×3大小的网格,我们想把对象分为3类。假设这些类分别是行人、汽车和摩托车。因此,对于每个网格单元,y将是一个八维向量:


pc表示一个对象是否存在于网格中(它是概率)
bx,by,bh,bw指定边界框(如果有目标)
c1、c2、c3代表类别。所以,如果对象是一辆汽车,c2将是1,c1和c3将是0,依此类推。

假设我们选择了以上图片的第一格:

这一格图像里没有目标,pc为0,这一格的y向量为:

在这里,’?'意味着bx、by、bh、bw、c1、c2和c3包含什么并不重要,因为网格中没有目标对象。让我们换一个有车的格子(c2=1):


在我们为这格写y向量之前,首先要了解YOLO是如何决定网格中是否确实存在目标的。在上图中,有两个目标对象(两辆车),所以YOLO将取这两个对象的中心点,这些对象将被指定给包含这些对象中心点的网格。含有车的中间一行左侧网格的y向量为:


因为这个网格中有一个对象,所以pc等于1。bx,by,bh,bw将相对于我们正在处理的特定网格单元进行计算。因为汽车是第二类,c2=1,c1和c3=0。所以,对于9个网格中的每一个,我们都有一个8维的输出向量。此输出的形状为3 X 3 X 8。

现在我们有了一个输入图像和它对应的向量。使用上述示例(输入图像:100 X 100 X 3,输出:3 X 3 X 8),我们的模型将按以下方式进行训练:


我们将运行前向传播和后向传播来训练我们的模型。在测试阶段,我们将图像传递给模型,并向前传播,直到得到输出y。为了简单,我在这里使用了3×3网格来解释这一点,但在现实场景中,我们采用较大的网格(可能是19 X 19)。

即使对象跨越多个网格,它也只能被指定给其中心点所在的单个网格。通过增加更多的网格数量(例如19 X 19),我们可以减少多个对象出现在同一网格单元中的概率。

 

如何确定边界框?

如前所述,bx、by、bh和bw是相对于我们正在处理的网格单元计算的。让我们用一个例子来理解这个概念。考虑包含一辆汽车的中间一行右侧网格:

因此,bx、by、bh和bw将仅相对于该网格计算。此网格的y标签将是:

因为这个网格中有一个对象,所以pc=1,而且对象是一辆汽车,c2=1。现在,让我们看看如何决定bx、by、bh和bw。在YOLO中,分配给所有网格的坐标为:

bx、 by是对象中心点相对于该栅格的x和y坐标。在这种情况下,(大约)bx=0.4,by=0.3:


bh是边界框(上例中的红框)的高度与相应网格单元的高度之比,在我们的例子中约为0.9。所以,bh=0.9。bw是边界框宽度与网格单元宽度的比值。因此,bw=0.5(近似值)。此网格的y向量将是:
注意这里的bx和by总是在0和1之间,因为中心点总是位于网格内。而当边界框的尺寸大于网格的尺寸时,bh和bw可以大于1。

在下一节中,我们将研究更多的方法,这些方法有可能帮助我们提高算法的性能。

 

交并比和非最大抑制

这里有一些值得思考的东西——我们如何确定预测的边界框是否给了我们一个好的结果(或者一个坏的结果)?这就是交并比发挥作用的地方。它计算实际边界框和预测的边界框的交集比上并集。考虑汽车的实际和预测边界框,如下所示:

在这里,红色框是实际的边界框,蓝色框是预测的边界框。我们怎样才能决定这是否是一个好的预测呢?IoU,或交并比,将计算这两个框的交集面积和并集面积之比。该区域将是:

IoU=交集面积/并集面积
IoU=黄色区域面积/绿色区域面积

如果IoU大于0.5,我们可以说预测是足够好的。0.5是我们在这里采用的任意阈值,它的值可以根据具体问题进行更改。一般,阈值越高,预测就变得越好。

还有一种技术可以显著提高YOLO的输出——非最大值抑制。

目标检测算法最常见的一个问题是,它们可能多次检测到同一目标,而不是只检测一次。请看下图:


在这里,这些车被多次识别。非最大抑制技术解决了这一点,因此我们能对每个对象只进行一次检测。让我们看看这个方法是如何工作的。

1.它首先查看与每个检测相关的概率,并取最大的一个。在上图中,0.9是最高概率,因此将首先选择概率为0.9的框:


2.现在,它查看图像中的所有其他框。与当前框具有高IoU的框被抑制。因此,在我们的示例中,概率为0.6和0.7的框将被抑制:

3.在这些框被抑制后,从所有概率最高的框中选择下一个框,在我们的例子中为0.8:

4.再次查看此边界框与其余边界框的交并比,抑制高交并比的边界框:

5.重复这些步骤,直到所有的边界框要么被选中,要么被抑制。至此,我们得到最终的边界框:

这就是非最大抑制的意义所在。我们取具有最大概率的边界框,并抑制具有非最大概率的邻近边界框。让我们快速总结一下我们在本节中看到的关于非最大抑制算法的重点:

1.丢弃概率小于或等于预定义阈值(例如,0.5)的所有框

2.对于其余框:
(1)选取概率最大的框作为输出预测
(2)丢弃与上述输出框的交并比大于阈值的其它边界框。

3.重复步骤2,直到所有框都作为输出或被丢弃。

我们还可以使用另一种方法来改进YOLO算法的性能——让我们来看看吧!

 

Anchor Boxes

我们已经看到,每个网格只能识别一个对象。但是如果一个网格中有多个对象呢?现实中常常如此。这就引出了Anchor Boxes的概念。考虑以下图像,分为3 X 3网格:

还记得我们是如何将一个对象分配给网格的吗?我们取物体的中点,根据其位置,将物体分配到相应的网格中。在上面的示例中,两个对象的中点位于同一网格中。这就是对象的实际边界框:


我们只会得到两个边界框中的一个,不管是车的还是人的。但是如果我们使用Anchor Boxes,我们可能可以同时输出这两个框!我们该怎么做?首先,我们预先定义了两种不同的形状,称为anchor boxes或anchor box shapes。现在,对于每个网格,我们将有两个输出,而不是一个输出。我们也可以增加anchor boxes的数量。为了让这个概念更容易理解,我在这里用2个anchor boxes:

不采用anchor box时,y向量是这样的:


如果我们有两个anchor box,你认为y向量会是什么样子?在进一步阅读之前,我想让你花点时间思考一下。知道了?y向量将是:

前8行属于anchor box1,其余8行属于anchor box2。根据边界框和anchor box形状的相似性,将对象指定给anchor box。由于anchor box1的形状类似于人的边界框,因此后者将被指定给anchor box1,而车辆将被指定给anchor box2。在本例中,输出不是3x3x8(使用3x3网格和3个类),而是3x3x16(因为我们使用2个anchor box)。

因此,对于每个网格,我们可以根据anchor box的数量检测两个或多个对象。让我们结合所有我们已经讨论过的想法,并将它们集成到YOLO框架中。

 

结合以上方法

在本节中,我们将首先了解如何训练YOLO模型,然后了解如何对一个新的、没有看见过的图像进行预测。

1.训练
显然,训练模型所需的输入是图像和他们对应的y向量。让我们来看一幅图像并确定它的y向量:

考虑这样一个场景:我们使用一个3x3网格,每个网格有两个anchor box,并且对象有3个不同的类。所以相应的y向量的形状是3x3x16。现在,假设我们每个网格使用5个anchor box,类的数量增加到5个。所以目标是3x3x10x5=3x3x50。训练过程:获得一个特定形状的图像,并将其与一个3 X 3 X 16的目标进行映射(这可能会根据网格大小、anchor box的数量和类的数量而改变)。

2.测试

新的图像将被划分成与训练时期相同数量的网格。对于每个网格,模型将预测形状为3 X 3 X 16的输出(假设这是训练期间目标的形状)。此预测中的16个值将与训练中y向量的格式相同。前8个值将对应于anchor box1,其中第一个值将是该网格中有某个对象的概率。值2~5将是该对象的边界框坐标,最后三个值将告诉我们该对象属于哪个类。接下来的8个值将用于anchor box2,格式相同,即首先是概率,然后是边界框坐标,最后是类。

最后,将非最大值抑制技术应用于预测框,以获得每个对象的单个预测。

这就结束了理解YOLO算法工作原理的理论部分,从训练模型开始,然后为对象生成预测框。下面是YOLO算法所遵循的步骤:

(1)获取输入图像,尺寸为(608,608,3)

(2)将此图像传递给卷积神经网络(CNN),后者返回(19,19,5,85)维输出

(3)将上述输出的最后两个维度展平,得到(19,19,425)的输出:
在这里,19x19网格的每个单元格返回425个数字
425=5*85,其中5是每个网格的anchor box数量
85=5+80,其中5是(pc,bx,by,bh,bw),80是我们要检测的类的数量

(4)最后,我们进行IoU和非最大值抑制,以避免选择重叠框

 

在Python中实现YOLO

该是时候启动我们的Jupyter notebook(或IDE),最后以代码的形式实现我们的学习!这就是我们迄今为止一直在努力的,所以让我们开始吧!

我们在本节中看到的实现YOLO的代码,从AndrewNG的GitHub深度学习存储库中获取https://github.com/enggen/Deep-Learning-Coursera。你还需要下载运行此代码所需的预先调整好的权重。https://pjreddie.com/darknet/yolo/

首先,我们定义函数,这些函数将帮助我们选择高于某个阈值的框,确定IoU,并对它们应用非最大抑制。但是,在其他所有内容之前,我们将首先导入所需的库:

import os
import matplotlib.pyplot as plt
from matplotlib.pyplot import imshow
import scipy.io
import scipy.misc
import numpy as np
import pandas as pd
import PIL
import tensorflow as tf
from skimage.transform import resize
from keras import backend as K
from keras.layers import Input, Lambda, Conv2D
from keras.models import load_model, Model
from yolo_utils import read_classes, read_anchors, generate_colors, preprocess_image, draw_boxes, scale_boxes
from yad2k.models.keras_yolo import yolo_head, yolo_boxes_to_corners, preprocess_true_boxes, yolo_loss, yolo_body

%matplotlib inline

让我们定义一个函数,用来根据边界框的概率和阈值进行筛选:

def yolo_filter_boxes(box_confidence, boxes, box_class_probs, threshold = .6):
    box_scores = box_confidence*box_class_probs
    box_classes = K.argmax(box_scores,-1)
    box_class_scores = K.max(box_scores,-1)
    filtering_mask = box_class_scores>threshold
    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

接着,我们定义一个函数来计算两个边界框之间的IoU:

def iou(box1, box2):
    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 = (yi2-yi1)*(xi2-xi1)
    box1_area = (box1[3]-box1[1])*(box1[2]-box1[0])
    box2_area = (box2[3]-box2[1])*(box2[2]-box2[0])
    union_area = box1_area+box2_area-inter_area
    iou = inter_area/union_area
 
    return iou

定义一个函数用于非最大值抑制:

def yolo_non_max_suppression(scores, boxes, classes, max_boxes = 10, iou_threshold = 0.5):
    max_boxes_tensor = K.variable(max_boxes, dtype='int32')
    K.get_session().run(tf.variables_initializer([max_boxes_tensor]))
    nms_indices = tf.image.non_max_suppression(boxes,scores,max_boxes,iou_threshold)
    scores = K.gather(scores,nms_indices)
    boxes = K.gather(boxes,nms_indices)
    classes = K.gather(classes,nms_indices)

    return scores, boxes, classes

我们现在有了计算IoU和执行非最大抑制的函数。我们得到形状为(19,19,5,85)的CNN的输出。因此,我们将创建一个大小为(19,19,5,85)随机数,然后预测边界框:

yolo_outputs = (tf.random_normal([19, 19, 5, 1], mean=1, stddev=4, seed = 1),
                   tf.random_normal([19, 19, 5, 2], mean=1, stddev=4, seed = 1),
                   tf.random_normal([19, 19, 5, 2], mean=1, stddev=4, seed = 1),
                   tf.random_normal([19, 19, 5, 80], mean=1, stddev=4, seed = 1))

最后,我们将定义一个函数,该函数将CNN的输出作为输入并返回抑制后的边界框:

def yolo_eval(yolo_outputs, image_shape = (720., 1280.), max_boxes=10, score_threshold=.6, iou_threshold=.5):
    box_confidence, box_xy, box_wh, box_class_probs = yolo_outputs
    boxes = yolo_boxes_to_corners(box_xy, box_wh)
    scores, boxes, classes = yolo_filter_boxes(box_confidence, boxes, box_class_probs, threshold = score_threshold)
    boxes = scale_boxes(boxes, image_shape)
    scores, boxes, classes = yolo_non_max_suppression(scores, boxes, classes, max_boxes, iou_threshold)

    return scores, boxes, classes

让我们看看如何使用yolo_eval函数进行预测:

scores, boxes, classes = yolo_eval(yolo_outputs)

结果看起来怎么样:

with tf.Session() as test_b:
    print("scores[2] = " + str(scores[2].eval()))
    print("boxes[2] = " + str(boxes[2].eval()))
    print("classes[2] = " + str(classes[2].eval()))


“scores”表示对象出现的可能性。“boxes”返回检测到的对象的(x1,y1,x2,y2)坐标。“classes”是对象的类。

现在,让我们在新图像上使用预训练的YOLO算法,看看它是如何工作的:

sess = K.get_session()
class_names = read_classes("model_data/coco_classes.txt")
anchors = read_anchors("model_data/yolo_anchors.txt")

yolo_model = load_model("model_data/yolo.h5")

在有了类和预训练模型之后,让我们使用上面定义的函数来获取yolo_outputs。

yolo_outputs = yolo_head(yolo_model.output, anchors, len(class_names))

现在,我们将定义一个函数来预测边界框并保存包含这些边界框的图像:

def predict(sess, image_file):
    image, image_data = preprocess_image("images/" + image_file, model_image_size = (608, 608))
    out_scores, out_boxes, out_classes = sess.run([scores, boxes, classes], feed_dict={yolo_model.input: image_data, K.learning_phase(): 0})

    print('Found {} boxes for {}'.format(len(out_boxes), image_file))

    # Generate colors for drawing bounding boxes.
    colors = generate_colors(class_names)

    # Draw bounding boxes on the image file
    draw_boxes(image, out_scores, out_boxes, out_classes, class_names, colors)

    # Save the predicted bounding box on the image
    image.save(os.path.join("out", image_file), quality=90)

    # Display the results in the notebook
    output_image = scipy.misc.imread(os.path.join("out", image_file))

    plt.figure(figsize=(12,12))
    imshow(output_image)

    return out_scores, out_boxes, out_classes

接下来让我们读取图像并作出预测:

img = plt.imread('images/img.jpg')
image_shape = float(img.shape[0]), float(img.shape[1])
scores, boxes, classes = yolo_eval(yolo_outputs, image_shape)

最后让我们看看结果:

out_scores, out_boxes, out_classes = predict(sess, "img.jpg")



 

总结

以下是我们在本指南中所涵盖和实施的内容的简要总结:

1.YOLO是一种先进的目标检测算法,它的速度和精度令人难以置信。
2.我们发送一个输入图像到CNN,CNN有一个19×19×5×85维的输出。
3.在这里,网格大小是19 X 19,每个网格包含5个anchor boxes。

4.我们使用非最大值抑制对所有的框进行筛选,只保留精确的框,并且消除重叠的。

YOLO是我一直以来最喜欢的框架之一,我相信一旦你在自己的机器上实现了代码,你就会明白为什么了。这是一个很好的、让你开始着手学习计算机视觉算法的方法。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
damo-yolo是一个关于实时物体检测设计的报告。物体检测是计算机视觉中的重要任务之一,它可以识别图像或视频中的各种物体,并对其进行分类和定位。damo-yolo是基于YOLO(You Only Look Once)算法的改进版本,旨在提高实时性能和准确性。 YOLO算法是一种基于深度学习的物体检测算法,其核心思想是将物体检测任务转化为一个回归问题,同时使用卷积神经网络进行端到端的训练。YOLO的优点是具有较高的处理速度,可以在实时场景中进行物体检测。 damo-yoloYOLO算法的基础上进行了优化和改进。首先,对YOLO的网络结构进行了调整,引入了新的特征提取模块和上采样模块,以提高特征表示的能力。其次,优化了损失函数的计算方法,使其更加准确地度量物体检测结果与真实标注的差距。此外,damo-yolo还引入了多尺度处理和先验框的改进方法,以提高检测结果的准确性和鲁棒性。 在实验结果部分,报告给出了在常见的物体检测数据集上的性能评估。实验结果显示,damo-yolo相比于传统的YOLO算法,在保持实时性能的情况下,能够取得更好的检测精度。具体而言,报告给出了不同物体类别的AP(Average Precision)值和mAP(mean Average Precision)值进行对比分析,证明了damo-yolo在物体检测任务中的优越性。 最后,在总结部分,报告指出了damo-yolo设计的优点和存在的不足之处。同时,报告还提出了未来进一步改进的方向,如进一步优化网络结构、改进损失函数和增强数据扩充等。通过这些工作,可以进一步提升damo-yolo的性能和应用场景的拓展。 综上所述,damo-yolo是一个关于实时物体检测设计的报告,通过对YOLO算法的改进,提高了实时性能和准确性,并且具有一定的应用前景和改进空间。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值