神经网络与深度学习笔记四

目标检测

预备知识

基本原理:

\qquad 很多时候图像里有多个我们感兴趣的目标,我们不仅想知道它们的类别,还想得到它们在图像中的具体位置。在计算机视觉里,我们将这类任务称为目标检测(object detection)或物体检测。

\qquad 目标检测在多个领域中被广泛使用。例如,在无人驾驶里,我们需要通过识别拍摄到的视频图像里的车辆、行人、道路和障碍的位置来规划行进线路。机器人也常通过该任务来检测感兴趣的目标。安防领域则需要检测异常目标,如歹徒或者炸弹。

边界框:

在目标检测里,我们通常使用边界框(bounding box)来描述目标位置。边界框是一个矩形框,可以由矩形左上角的 x x x y y y轴坐标与右下角的 x x x y y y轴坐标确定。我们根据下面的图的坐标信息来定义图中狗和猫的边界框。图中的坐标原点在图像的左上角,原点往右和往下分别为 x x x轴和 y y y轴的正方向。

锚框:

目标检测算法通常会在输入图像中采样大量的区域,然后判断这些区域中是否包含我们感兴趣的目标,并调整区域边缘从而更准确地预测目标的真实边界框( ground truth bounding box)。
法:它以每个像素为中心生成多个大小和宽高比(aspect ratio)不同的边界框,这些边界框被称为锚框(anchor box)。

交并比:

Jaccard 系数(Jaccard index)可以衡量两个集合的相似度。给定集合 A 和 B ,它们的 Jaccard 系数即二者交集大小除以二者并集大小:
J ( A , B ) = ∣ A ∩ B ∣ ∣ A ∪ B ∣ (1) J(A,B)=\frac{|\mathcal{A}\cap\mathcal{B}|}{|\mathcal{A}\cup\mathcal{B}|}\tag{1} J(A,B)=ABAB(1)
非极大值抑制:
目标检测窗口格子划分较小时,同一目标可能被检测到多次,此时可以采用非极大值抑制(Non-max suppression)的方法解决。首先比较所有格子输出结果中检测到物体的概率,由大到小排序,保留概率最大的预测框,然后依次与比它小的预测框求交并比,若交并比很大,则把存在物体概率较低的那个预测框抑制掉。

目标检测实现过程

首先导入相关包和库:

%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 h h,宽为 w w w。我们分别以图像的每个像素为中心生成不同形状的锚框。设大小为 s ∈ ( 0 , 1 ] s\in(0,1] s(0,1]且宽高比为 r > 0 r >0 r>0,那么锚框的宽和高将分别 为 w s r ws\sqrt{r} wsr h s r hs\sqrt{r} hsr 。当中心位置给定时,已知宽和高的锚框是确定的。

下面我们分别设定好一组大小s1, ⋯ \cdots ,sn和一组宽高比r1, ⋯ \cdots ,rm。如果以每个像素为中心时使用所有的大小与宽高比的组合,输入图像将一共得到 whn*m个锚框。虽然这些锚框可能覆盖了所有的真实边界框,但计算复杂度容易过高。因此,我们通常只对包含s1或r1的大小与宽高比的组合感兴趣,即
( s 1 , r 1 ) , ( s 1 , r 2 ) , ⋯   , ( s 1 , r m ) , ( s 2 , r 1 ) , ( s 3 , r 1 ) , ⋯   , ( s n , r 1 ) (2) (s_{1},r_{1}),(s_{1},r_{2}),\cdots,(s_{1},r_{m}),(s_{2},r_{1}),(s_{3},r_{1}),\cdots,(s_{n},r_{1})\tag{2} (s1,r1),(s1,r2),,(s1,rm),(s2,r1),(s3,r1),,(sn,r1)(2)

生成锚框的方法通过下述的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])

返回锚框变量y 的形状为(1,锚框个数 4)。将锚框变量 y 的形状变为(图像高,图像宽,以相同像素为中心的锚框个数,4)后,我们就可以通过指定像素位置来获取所有以该像素为中心的锚框了。下面的例子里我们访问以(250 250)为中心的第一个锚框。它有 4 个元素,分别是锚框左上角的 x x x y y y轴坐标和右下角的 x x x y y y轴坐标,其中 x x x y y 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'])
    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'])

输出如下:
在这里插入图片描述

图1 目标检测结果

YOLO算法

YOLO算法简述

YOLO作为一种非常具有代表性的一步算法,也继承了其主要特点,即无需像RCNN一样生成候选框,可以直接预测得到结果。这使得YOLO具有两步法所不具备的快速性。由于YOLO所具有的优异的性能,自从其被提出以来,研究员们开发出了大量的变种,并应用到了各类领域,其主要分支见图2-3。随着版本的迭代YOLO的性能也逐渐增强。
在这里插入图片描述

图2 YOLO发展历程

在这里插入图片描述
在这里插入图片描述

图3 YOLO性能

一步法的基本思想是将目标检测问题转化成回归和分类问题。需要将图像分成若干个网格单元(grid cell),再预测出每个网格中潜在的目标的大小和位置,最后通过非极大值抑制等方法对包围框进行筛选,网格划分及目标预测,

问题1:有一个框里有多个,有个多个框里有一个,怎么办?
多个框里有一个目标,取目标中心点所在框;一个框里有多个,暂不能解决。
问题2:多类目标怎么办?
使用独热编码扩展类别数。
在这里插入图片描述

图4 独热编码扩展类别数

问题3:小目标怎么办?
使用单独网络拟合小目标,即设置多个bounding box。
在这里插入图片描述

图5 设置多个bounding box

YOLO网络结构

YOLO的结构如图6所示并对应图7的概略图,网络结构包含24 个卷积层和 2 个全连接层;其中前 20 个卷积层用来做预训练,后面 4 个是随机初始化的卷积层,和 2 个全连接层。

在这里插入图片描述

图6 YOLO结构

在这里插入图片描述
在这里插入图片描述

图7 YOLO结构概略图

YOLO的输入:YOLO v1在PASCAL VOC数据集上进行训练,因此输入图片为 448 × 448 × 3 448\times448\times3 448×448×3。实际应用中若需要使用其它尺寸,则需要resize或切割成要求尺寸。
  YOLO模型处理:将图片分割为 S 2 S^{2} S2 个grid( S = 7 S = 7 S=7),每个网格单元(grid cell)的大小都是相等的,如图8
;每个网格单元都可以检测是否包含目标;YOLO v1中,每个网格单元只能检测出一种物体(大小可以不同)。
在这里插入图片描述

图8 YOLO图像划分

YOLO网络输出是一个 7 × 7 × 30 7\times7\times30 7×7×30的张量。对应 7 × 7 7\times7 7×7个网格单元。每个网格单元对应2个包围框(bounding box),预测不同大小和宽高比,对应检测不同目标。每个包围框包含5个分量,分别是物体的中心位置 ( x , y ) (x, y) (x,y)和它的高( h h h ) 、宽($ w$ ) ,以及这次预测的置信度($ c$ ) 。图9中,每个框代表1个预测的包围框,框的粗细代表不同的置信度,框越粗代表置信度越高。
在这里插入图片描述

图9 YOLO输出

例中,图片被分成了49个单元格,每个单元格预测2个包围框,因此图10中共包含98个包围框。
在这里插入图片描述

图10 YOLO输出

包围框与置信度

YOLO的包围框

设共有 S 2 S^{2} S2个网格单元,每个网格单元的包围框个数为𝐵,分类器可以识别出𝐶种不同的物体,那么所有整个ground truth的长度为 S × S × ( B × 5 + C ) S\times S\times(B \times 5 + C) S×S×(B×5+C)。YOLO v1中,这个数量是30;YOLO v2和以后版本使用了自聚类的anchor box为包围框, v2版本为 B = 5 B = 5 B=5, YOLO v3中 B = 9 B = 9 B=9

归一化

四个关于位置的值,分别是$ x, y, h 和 和 w$,均为整数,实际预测中收敛慢。因此,YOLO对数据进行了归一化,使其限定在在0-1的范围内。

置信度

置信度计算公式如下:
C = P r ( o b j ) ∗ I O U t r u t h p r e d (3) C=Pr(obj)*IOU^{pred}_{truth}\tag{3} C=Pr(obj)IOUtruthpred(3)
其中: P r ( o b j ) Pr(obj) Pr(obj)是一个网格单元存在物体的概率; I O U t r u t h p r e d IOU_{truth}^{pred} IOUtruthpred是预测的包围框和真实物体位置包围框的交集面积与并集面积之比。

训练值(ground truth)

P r ( o b j ) Pr(obj) Pr(obj)的ground truth如图11所示,三个目标中点对应格子为1,其它为0。
在这里插入图片描述

图11 训练值

YOLO的训练数据与网络输出结构

YOLO的训练数据与网络输出结构如图12。
在这里插入图片描述

图12 YOLO的训练数据与网络输出结构

损失函数

YOLO的损失函数如下:
L = λ c o o r d ∑ i = 0 S 2 ∑ j = 0 B 1 i j o b j [ ( x i − x ^ i ) 2 + ( y i − y ^ i ) 2 ] + λ c o o r d ∑ i = 0 S 2 ∑ j = 0 B 1 i j o b j [ ( w i − w ^ i ) 2 + ( y i − y ^ i ) 2 ] + ∑ i = 0 S 2 ∑ j = 0 B 1 i j o b j ( C i − C ^ i ) 2 + λ n o o b j ∑ i = 0 S 2 ∑ j = 0 B 1 i j n o o b j ( C i − C ^ i ) 2 + ∑ i = 0 S 2 1 i o b j ∑ c ∈ c l a s s e s ( p i ( c ) − p ^ i ( c ) ) 2 (4) \begin{array}{l} L=\lambda_{coord}\sum\limits_{i=0}^{S^{2}}\sum\limits_{j=0}^{B}1_{ij}^{obj}[(x_{i}-\hat{x}_{i})^2+(y_{i}-\hat{y}_{i})^{2}]\\ \qquad+\lambda_{coord}\sum\limits_{i=0}^{S^{2}}\sum\limits_{j=0}^{B}1_{ij}^{obj}[(\sqrt{w_{i}}-\sqrt{\hat{w}_{i}})^2+(\sqrt{y_{i}}-\sqrt{\hat{y}_{i}})^{2}]\\ \qquad+\sum\limits_{i=0}^{S^{2}}\sum\limits_{j=0}^{B}1_{ij}^{obj}(C_{i}-\hat{C}_{i})^2\\ \qquad+\lambda_{noobj}\sum\limits_{i=0}^{S^{2}}\sum\limits_{j=0}^{B}1_{ij}^{noobj}(C_{i}-\hat{C}_{i})^2\\ \qquad+\sum\limits_{i=0}^{S^{2}}1_{i}^{obj}\sum\limits_{c\in classes}(p_{i}(c)-\hat{p}_{i}(c))^{2}\\ \end{array} \tag{4} L=λcoordi=0S2j=0B1ijobj[(xix^i)2+(yiy^i)2]+λcoordi=0S2j=0B1ijobj[(wi w^i )2+(yi y^i )2]+i=0S2j=0B1ijobj(CiC^i)2+λnoobji=0S2j=0B1ijnoobj(CiC^i)2+i=0S21iobjcclasses(pi(c)p^i(c))2(4)

损失本别为边界框中心点的损失、边界框宽高损失、置信度损失(包括物体)、置信度损失(不包括物体)、类别损失。

训练与NMS

预测中一个物体可能被多个边界框包围,而实际物体只对应一个边界框,此时使用NMS解决。

NMS 核心思想是:选择得分最高的作为输出,与该输出重叠的去掉,不断重复这一过程直到所有备选处理完。

NMS算法要点

1 ◯ \textcircled{1} 1首先丢弃概率小于预定 IOU 阈值(例如 0.5 )的所有边界框;对于剩余的边界框;
2 ◯ \textcircled{2} 2选择具有最高概率的边界框并将其作为输出预测;
3 ◯ \textcircled{3} 3计算 “作为输出预测的边界框”,与其他边界框的相关联 IoU值;舍去 IoU 大于阈值的边界框;其实就是舍弃与“作为输出预测的边界框” 很相近的框框;
4 ◯ \textcircled{4} 4重复步骤 2 ,直到所有边界框都被视为输出预测或被舍弃;

预训练与训练

∙ \bullet YOLO 先使用 ImageNet 数据集对前 20 层卷积网络进行预训练,然后使用完整的网络,在 PASCAL VOC 数据集上进行对象识别和定位的训练和预测;
∙ \bullet 训练中采用了 drop out 和数据增强来防止过拟合;
∙ \bullet YOLO 的最后一层采用线性激活函数 因为要回归 bb 位置 )),其它层都是采用 Leaky ReLU 激活函数:
Φ ( x ) = { x , i f x > 0 0.1 x , o t h e r w i s e (5) \begin{array}{l} \varPhi(x)= \begin{cases} x,& if\enspace x >0\\ 0.1x,& otherwise \end{cases} \end{array} \tag{5} Φ(x)={x,0.1x,ifx>0otherwise(5)

语义分割

与其它问题区别

语义分割:找到同一画面中的不同类型目标区域;
实例分割:同一类型目标要分出来具体实例(谁是谁);
目标检测:标出来外包围矩形;

发展历程

深度学习图像分割算法发展历程如图13
在这里插入图片描述

图13 图像分割算法发展历程

基本思想

语义分割的目标为对图中每一个像素进行分类,得到对应标签。其基本思想为滑动窗口。为加快计算,可以采用FCN,其结构如图14
在这里插入图片描述

图14 FCN网络结构
网络结构分为两个部分:全卷积部分和反卷积部分。全卷积部分借用了一些经典的CNN网络,并把最后的全连接层换成卷积,用于提取特征,形成热点图;反卷积部分则是将小尺寸的热点图上采样得到原尺寸的语义分割图像。 # 反卷积与反池化

1 × 1 1\times 1 1×1卷积的操作如图15所示
在这里插入图片描述

图15 1×1卷积操作

上池化(反池化)操作如图16所示:
在这里插入图片描述

图16 反池化操作

FCN具体实现

FCN卷积部分如下图所示:
在这里插入图片描述

图17 FCN卷积部分

FCN中第6、7、8层都是通过 1 × 1 1\times1 1×1卷积得到的,第6层的输出是 4096 × 7 × 7 4096\times7\times7 4096×7×7,第7层的输出是 4096 × 7 × 7 , 4096\times7\times7, 4096×7×7第8层的输出是 1000 × 7 × 7 1000\times7\times7 1000×7×7即1000个大小是 7 × 7 7\times7 7×7的特征图(称为heatmap)。

反卷积部分如图18所示:
在这里插入图片描述

图18 FCN反卷积部分

其中跳级结构如图19所示:
在这里插入图片描述

图19 FCN跳级结构

评价指标

常见语义分割评价指标包括:
Pixel Accuracy(Global Acc): ∑ i n i i ∑ i t i \displaystyle{\frac{\sum_{i}n_{ii}}{\sum_{i}t_{i}}} itiinii
mean Accuracy: 1 n c l s ∑ i n i i t i \displaystyle{\frac{1}{n_{cls}}\sum_{i}\frac{n_{ii}}{t_{i}}} ncls1itinii
mean IoU: 1 n c l s ∑ i n i i t i + ∑ j n i j − n i i \displaystyle{\frac{1}{n_{cls}}\sum_{i}\frac{n_{ii}}{t_{i}+\sum_{j}n_{ij}-n_{ii}}} ncls1iti+jnijniinii
其中: n i j n_{ij} nij为leibie1 i i i被预测成类别 j j j的像素个数, n c l s n_{cls} ncls为目标类别个数(包含背景), t i = ∑ j n i j t_{i}=\sum_{j}n_{ij} ti=jnij为目标类别 i i i的总像素个数。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值