一、目标检测
1.1 目标检测概念
目标检测(object detection)是在给定的图片中精确找到物体所在位置,并标注出物体的类别。物体的尺寸变化范围很大,摆放物体的角度、姿态不确定,而且可以出现在图片任何地方,同时物体也可是多个类别的。
目标检测在多个领域中被广泛使用。例如,在无人驾驶领域,系统需要通过识别拍摄到的视频图像中车辆、行人、道路和障碍的位置来规划行进路线;在安保领域,系统需要检测异常目标,如歹徒或者危险品。
目标检测在目标定位基础上进一步开发,其与图片分类、目标定位的主要区别如下:
Image Classification | Classification with Localization | Object Detection | |
---|---|---|---|
图片特点 | 包含比较大的单个物体 | 包含比较大的单个物体 | 包含多类物体 |
处理方法 | 将图片输入到多层卷积神经网络中 | 在图片分类基础上,使神经网络多输出4个单元用来表示物体的边界框(如红框所示) | 在分类定位基础上,使神经网络多输出n个单元,代表物体是否属于该类别的物体 |
输出结果 | 是/否属于该类别 | 是/否属于该类别+该物体的位置信息 | 每个物体是否属于该类别+该物体的位置+是否属于n个类别 |
具体结果 | 1个代表属于某类别的值 | 1个代表属于某类别的值+4个代表边框的值 | 1个代表物体存在的值+n个属于某类别的值+4个代表边框的值 |
1.2 目标检测原理
1.2.1 基本原理
目标检测通常采用滑动窗口来进行,即使用一个小窗口,窗口截取到图片上的区域,将该区域输入到卷积神经网络,输出1或0代表该区域内是否有目标,并按照一定的步长滑动窗口,直到遍历整张图片。
这种方法相当于对每个窗口的图片做了一个图片分类,但带来的是低计算成本和高精度难以同时满足的现实问题。
1.2.2 滑动窗口卷积实现
滑动窗口的卷积实现即在卷积层上应用这个算法。首先把神经网络的全连接层转化成卷积层, 全连接层可看作是进行一次卷积操作,但在把全连接层转化成卷积层之后,每个窗口截取到的区域存在共享的部分,将神经网络每层所有窗口共享的部分重叠在一起,相当于将整张图片输入神经网络得到的结果。
所以,不必将图片每个区域分别输入神经网络进行检测,直接将整张图片输入进行卷积操作,神经网络就可以识别出对象的位置。
1.3 目标检测算法改善
1.3.1 交并比
交并比(IoU:Intersection over Union)函数是用于计算两个边界框交集和并集之比,即下图中S(绿色)/S(蓝色+绿色+黄色)的数值,常用来评价目标检测算法的精度。
一般来说,IoU大于等于0.5时说明结果可以接受,即检测结果可接受。如果预测器和实际边界框完美重叠,loU就是1,因为交集就等于并集。通常规定0.5是阈值(threshold),用来判断预测的边界框是否正确,loU越高,边界框越精确。
1.3.2 非极大值抑制
当目标检测窗口格子划分较小时,会出现同时有几个格子里检测到有目标的情况。即图中的一辆汽车可能被检测到多次:
可以采用非极大值抑制(Non-max suppression)的方法解决此问题。首先比较所有格子输出结果中检测到物体的概率,由大到小排序,保留概率最大的预测框,然后依次与比它小的预测框求交并比,若交并比很大,则说明这两个预测框很有可能检测的是同一个物体,于是把存在物体概率较低的那个预测框抑制掉。
下图显示的是抑制后的结果:
1.3.3 锚框
目标检测中存在一个问题就是每个格子只能预测一个对象,如果想让一个格子检测出多个对象,就要使用到锚框(Anchor Box)。
如上图所示,我们使用3×3的网格,可以观察到人和汽车的几何中心几乎在同一个网格,然而传统方法中一个格子只能预测一个对象,而且对于y输出的向量可以检测这三个类别:人、汽车和摩托车,他将无法输出检测结果,所以我必须从两个检测结果中选择一个,这便影响了模型性能,导致一些对象被丢弃无法检测出来。
而引入锚框后,预先定义两个不同形状的锚框,把预测结果和这两个锚框关联起来:
因此,定义类别标签时用的向量不再是:
而是重复两次:
前面8个是和Anchor box1相关联,后面8个是和Anchor box2相关联。行人一般符合anchor box1形状,所以用Anchor box1来预测行人回达到很好的效果,这么编码𝑝𝑐 = 1,代表有个行人,用𝑏𝑥, 𝑏𝑦, 𝑏ℎ和𝑏𝑤来编码包住行人的边界框,然后用𝑐1, 𝑐2, 𝑐3(𝑐1 = 1, 𝑐2 = 0, 𝑐3 = 0)来说明这个对象是行人。 汽车一般符合Anchor box2形状,所以用Anchor box2来预测汽车会有很好的效果。
1.4 目标检测程序实现
为说明目标检测基本原理,我们通过一个案例加以阐述。假设有如下一张图(左边是一只狗,右边是一只猫),他们共同构成了图像里的两个主要目标,我们需要对这两个目标进行识别并进行标注:
首先导入必要的包和模块:
%matplotlib inline
from PIL import Image
import sys
sys.path.append("..")
import d2lzh_pytorch as d2l
d2l.set_figsize()
img = Image.open('img/catdog.jpg') d2l.plt.imshow(img);
# 加分号只显示图
1.4.1 边界框的实现
在目标检测中,我们使用边界框(bounding box)来描述目标位置。边界框通常是一个矩形框,可以由矩形左上角的(x, y)坐标与右下角的(x, y)坐标确定。我们可以根据图中的坐标信息来定义图中猫和狗的边界框。图中坐标原点在图像左上角,原点往右和往下分别定义为x轴和y轴的正方向:
dog_bbox, cat_bbox = [60, 45, 378, 516], [400, 112, 655, 493]
我们可以在图中将边界框画出来检测其是否准确。我们定义一个辅助函数bbox_to_rect,通过其将边界框表示成matplotlib的边界框格式:
def bbox_to_rect(bbox, color):
# 将边界框(左上x, 左上y, 右下x, 右下y)格式转换成matplotlib格式:
# ((左上x, 左上y), 宽, 高)
return d2l.plt.Rectangle(
xy=(bbox[0], bbox[1]), width=bbox[2]-bbox[0],
height=bbox[3]-bbox[1], fill=False, edgecolor=color, linewidth=2
)
我们将边界框加载在图像上:
fig = d2l.plt.imshow(img)
fig.axes.add_patch(bbox_to_rect(dog_bbox, 'blue'))
fig.axes.add_patch(bbox_to_rect(cat_bbox, 'red'))
从输出结果可看出,猫和狗两个主要目标的轮廓都在边界框内。
1.4.2 锚框的实现
目标检测算法通常会在输入图像中采样大量区域,然后判断这些区域是否包含我们所要检测的目标,并调整区域边缘从而更准确地预测目标的真实边界框(ground-truth bounding box)。
不同模型使用的区域采样方法可能不同,若以每个像素为中心生成多个大小和宽高比(aspect ratio)不同的边界框,这些边界框就被称为锚框(anchor box)。
先导入相关包和库:
%matplotlib inline
from PIL import Image
import numpy as np
import math
import torch
import sys sys.path.append("..")
import d2lzh_pytorch as d2l
假设输入图像高为h,宽为w。我们分别以图像的每个像素为中心生成不同形状的锚框。设大小为s∈(0,1]且宽高比为r >0,那么锚框的宽和高将分别 为𝑤𝑠𝑟^0.5 和h𝑠𝑟^0.5。当中心位置给定时,已知宽和高的锚框是确定的。
下面我们分别设定好一组大小s1,...,sn和一组宽高比r1,...,rm。如果以每个像素为中心时使用所有的大小与宽高比的组合,输入图像将一共得到 w*h*n*m个锚框。虽然这些锚框可能覆盖了所有的真实边界框,但计算复杂度容易过高。因此,以相同像素为中心的锚框的数量为n+m−1。对于整个输入图像,我们将一共生成w*h(n+m−1)个锚框。
以上生成锚框的方法通过下述的MultiBoxPrior函数实现。当制定输入一组大小和一组宽高比时,该函数将返回输入的所有锚框:
d2l.set_figsize()
img = Image.open('img/catdog.jpg')
w, h = img.size
print("w = %d, h = %d" % (w, h)) # w = 728, h = 561
def MultiBoxPrior(
feature_map, sizes=[0.75, 0.5, 0.25], ratios=[1, 2, 0.5])
pairs = [] # pair of (size, sqrt(ration))
for r in ratios:
pairs.append([sizes[0], math.sqrt(r)])
for s in sizes[1:]:
pairs.append([s, math.sqrt(ratios[0])])
pairs = np.array(pairs)
ss1 = pairs[:, 0] * pairs[:, 1] # size * sqrt(ration)
ss2 = pairs[:, 0] / pairs[:, 1] # size / sqrt(ration)
base_anchors = np.stack([-ss1, -ss2, ss1, ss2], axis=1) / 2
h, w = feature_map.shape[-2:]
shifts_x = np.arange(0, w) / w
shifts_y = np.arange(0, h) / h
shift_x, shift_y = np.meshgrid(shifts_x, shifts_y)
shift_x = shift_x.reshape(-1)
shift_y = shift_y.reshape(-1)
shifts_x和shifts_y是将宽高进行归一化处理然后用meshgrid函数生成一个向量矩阵, 最后reshape成一行向量。
shifts = np.stack((shift_x, shift_y, shift_x, shift_y), axis=1)
anchors = shifts.reshape(
(-1, 1, 4)) + base_anchors.reshape((1, -1, 4))
return torch.tensor(anchors, dtype=torch.float32).view(1, -1, 4)
X = torch.Tensor(1, 3, h, w) # 构造输入数据
Y = MultiBoxPrior(X, sizes=[0.75, 0.5, 0.25], ratios=[1, 2, 0.5])
Y.shape # torch.Size([1, 2042040, 4])
将reshape之后的向量进行stack操作,之后将得到的shift与原始的base_anchors相加从而自动生成所有的anchor。
下面的例子里 我们访问以(250,250)为中心的第一个锚框。它有4个元素,分别是锚框 左上角的x和y轴坐标和右下角的x和y轴坐标,其中x和y轴的坐标值分别已除 以图像的宽和高,因此值域均为0和1之间。
boxes = Y.reshape((h, w, 5, 4))
boxes[250, 250, 0, :]# * torch.tensor([w, h, w, h],
dtype=torch.float32)
输出如下:
tensor([-0.0316, 0.0706, 0.7184, 0.8206])
为了描绘图像中以某个像素为中心的所有锚框,我们先定义show_bboxes函 数以便在图像上画出多个边界框:
def show_bboxes(axes, bboxes, labels=None, colors=None):
def _make_list(obj, default_values=None):
if obj is None:
obj = default_values
elif not isinstance(obj, (list, tuple)):
obj = [obj]
return obj
labels = _make_list(labels)
colors = _make_list(colors, ['b', 'g', 'r', 'm', 'c'])
为了描绘图像中以某个像素为中心的所有锚框,我们先定义show_bboxes函 数以便在图像上画出多个边界框:
for i, bbox in enumerate(bboxes):
color = colors[i % len(colors)]
rect = d2l.bbox_to_rect(bbox.detach().cpu().numpy(), color)#画出边界框
axes.add_patch(rect)
if labels and len(labels) > i:
text_color = 'k' if color == 'w' else 'w'
axes.text(
rect.xy[0], rect.xy[1], labels[i],
va='center', ha='center', fontsize=6, color=text_color,
bbox=dict(facecolor=color, lw=0)
)
变量boxes中xx和yy轴的坐标值分别已除以图像的宽和高。在 绘图时,我们需要恢复锚框的原始坐标值,并因此定义了变量bbox_scale,我们可以画出图像中以(250, 250)为中心的所有锚框了。可以看到,大小为 0.75且宽高比为1的锚框较好地覆盖了图像中的狗:
d2l.set_figsize()
fig = d2l.plt.imshow(img)
bbox_scale = torch.tensor([[x, y, w, h]], dtype=torch.float32)
show_bboxes(fig.axes, boxes[250, 250, :, :] * bbox_scale,['s=0.75, r=1', 's=0.75, r=2', 's=0.55,r=0.5', 's=0.5, r=1', 's=0.25, r=1'])
输出如下:
二、YOLO算法
2.1 YOLO算法简述
YOLO(You Only Look Once)是一种基于深度学习的目标检测算法,由Joseph Redmon等人在2015年提出,其最新版本为YOLOv5。
与传统目标检测算法相比,YOLO算法具有以下优点:
- 速度快:YOLO算法采用全卷积神经网络实现,可以实现实时目标检测;
- 准确率高:YOLO算法采用单个网络结构,能够同时检测多个目标并获得更准确的边界框;
- 应用广泛:YOLO算法可处理各种尺寸的物体,不需要对图像进行缩放和裁剪,能够处理任意大小的物体。
YOLO算法的基本思路是将输入图像分割成多个网格,然后对每个网格预测物体的类别和位置。具体来说,YOLO算法采用单个卷积神经网络,在图像的全局信息和局部信息之间进行平衡,并直接预测出每个物体的边界框和类别。
YOLO算法的主要步骤如下:
- 将输入图像分成S×S个网格;
- 对于每个网格,预测该网格中是否包含物体,以及该物体的边界框和类别;
- 计算每个预测边界框与真实边界框之间的损失,更新网络参数;
- 在测试阶段,将所有预测边界框进行筛选,得到最终的检测结果。
虽然YOLO算法具有很高的速度和准确率,但其也存在一些缺点,如对小物体的检测效果较差,对于密集目标的检测效果也不尽如人意。此外,YOLO算法的训练过程也较为复杂,需要大量的训练数据和计算资源。
2.2 YOLO v1算法
学习该算法前,首先要分清预测阶段与训练阶段。预测阶段是用已经训练好的、现成的网络,去对图片做预测,即做目标检测;训练阶段是利用梯度下降和反向传播来迭代地微调神经元中的权重,并使损失函数最小化,来训练得到一个预测效果更好的模型。
2.2.1 预测阶段
预测阶段使用训练好的卷积神经网络结构如下:
输入 | 卷积层(24层) | 全连接层(2层) | 输出 |
---|---|---|---|
448×448×3的图像 | 与7×7的过滤器、3×3的过滤器做卷积,最终得到7×7×1024的特征图 | 拉平填充输入4096个神经元中,再输入到1470个神经元中 | 将全连接层的输出重塑为7×7×30的张量 |
最后输出的7×7×30的张量中,7×7的原因是yolo将输入的图片划分为7×7的网格,每一个网格需要输出的是一个1×30维的信息,所以最后的输出为7×7×30,输出可视化如下图:
YOLO v1是一个单阶段的、端到端的算法,7×7×30的输出包括所有目标的置信度、预测框坐标、类别,上图中以框的粗细代表置信度的高低。 对于每个网格,它都会产生两个预测框,这两个预测框的中心点都落在该网格中,所以YOLO v1最后一共会产生98个预测框。
对于这98个预测框,并不是所有预测框都会被保留,需要进行一系列后处理,将最终结果表现为上图的结果那样。后处理步骤主要包括:置信度过滤(去掉低置信度的预测框)和非极大值抑制(去掉对同一个物体重复检测的预测框)。
首先是置信度过滤,它指的是置信度×每个类别的概率。对于这98个1×20维向量来说,每个向量中同一个位置的值都代表该预测框预测到某种类别的概率,我们可以设定一个阈值,小于这个阈值的全部设为0。
其次是非极大值抑制,当得到的每个预测框对某些种类预测的置信度都比较高时,对于某一种类,我们将该种类所在位置的概率从高到低排,再对排序之后的结果进行非极大值抑制。
具体步骤为:除去最高概率,剩下的每一个值代表的预测框都与最高值的预测框计算IoU,如果IoU大于我们设定的阈值,我们就认为这两个框检测的是同一个目标,那么就将较低的概率值置0,否则保留。
第一轮比较完成后,除去最高的概率和第二高的概率,剩下概率代表的预测框与第二高的概率的预测框计算IoU,重复上述步骤,直至到达最后一个概率。
对于每个类别都重复上面步骤,完成所有输出的后处理并可视化在图上,即为目标检测的结果。
2.2.2 训练阶段
在训练阶段,每个网格会产生出两个预测框,我们将与ground truth中IoU较大的预测框作为负责拟合ground truth的框,与ground truth的IoU较小的预测框的置信度越低越好。
然后设计一个损失函数,来使负责拟合ground truth的框作为损失函数的最大组成,另一个框的让它的影响尽量的小。损失函数主要由三大部分、五小部分组成:坐标回归误差(主预测框中心点坐标误差+主预测框宽高误差)+置信度回归误差(主预测框置信度误差+另一预测框置信度误差)+类别预测误差(主预测框分类误差)。文章来源:https://www.toymoban.com/news/detail-763677.html
2.2.3 优缺点分析
YOLO v1的优缺点主要如下:文章来源地址https://www.toymoban.com/news/detail-763677.html
优点 | 缺点 |
---|---|
单阶段模型,速度很快 | 输入图像分辨率低,准确率低,定位性能差 |
能获取全图信息,更好辨别前景和背景 | 每个网络只能预测一个物体 |
捕获全图信息,学习能力强 | 所有网格只能预测7×7=49个物体,小目标和密集目标识别性能差 |
到了这里,关于深度学习|目标检测与YOLO算法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!