<p>今天讲一讲 YOLOv3, 目标检测网络的巅峰之作, 疾如风,快如闪电。</p>

算法背景

假设我们想对下面这张 416 X 416 大小的图片进行预测,把图中 dog、bicycle 和 car 三种物体给框出来,这涉及到以下三个过程:

  • 怎么在图片上找出很多有价值的候选框?
  • 接着判断候选框里有没有物体?
  • 如果有物体的话,那么它属于哪个类别?

听起来就像把大象装进冰箱,分三步走。事实上,目前的 anchor-based 机制算法例如 RCNN、Faster rcnn 以及 YOLO 算法都是这个思想。最早的时候,RCNN 是这么干的,它首先利用 Selective Search 的方法通过图片上像素之间的相似度和纹理特征进行区域合并,然后提出很多候选框并喂给 CNN 网络提取出特征向量 (embeddings),最后利用特征向量训练 SVM 来对目标和背景进行分类。

image

这是最早利用神经网络进行目标检测的开山之作,虽然现在看来有不少瑕疵,例如:

  • Selective Search 会在图片上提取2000个候选区域,每个候选区域都会喂给 CNN 进行特征提取,这个过程太冗余啦,其实这些候选区域之间很多特征其实是可以共享的;
  • 由于 CNN 最后一层是全连接层,因此输入图片的尺寸大小也有限制,只能进行 Crop 或者 Warp,这样一来图片就会扭曲、变形和失真;
  • 在利用 SVM 分类器对候选框进行分类的时候,每个候选框的特征向量都要保留在磁盘上,很浪费空间!

尽管如此,但仍不可否认它具有划时代的意义,至少告诉后人我们是可以利用神经网络进行目标检测的。后面,一些大神们在此基础上提出了很多改进,从 Fast RCNN 到 Faster RCNN 再到 Mask RCNN, 目标检测的 region proposal 过程变得越来越有针对性,并提出了著名的 RPN 网络去学习如何给出高质量的候选框,然后再去判断所属物体的类别。简单说来就是: 提出候选框,然后分类,这就是我们常说的 two-stage 算法。two-stage 算法的好处就是精度较高,但是检测速度满足不了实时性的要求。

在这样的背景下,YOLO 算法横空出世,江湖震惊!

YOLO 算法简介

发展历程

2015 年 Redmon J 等提出 YOLO 网络, 其特点是将生成候选框与分类回归合并成一个步骤, 预测时特征图被分成 7x7 个 cell, 对每个 cell 进行预测, 这就大大降低了计算复杂度, 加快了目标检测的速度, 帧率最高可达 45 fps!

时隔一年,Redmon J 再次提出了YOLOv2, 与前代相比: YOLOv1是利用全连接层直接预测bounding box的坐标,而YOLOv2借鉴了Faster R-CNN的思想,引入anchor。它在VOC2007 测试集上的 mAP 由 67.4% 提高到 78.6%, 然而由于一个 cell 只负责预测一个物体, 面对重叠性的目标的识别得并不够好。

最终在 2018 年 4 月, 作者又发布了第三个版本 YOLOv3,它延续了 YOLOv2 的 anchor 策略,没有太大变化,主要的改变在于融合了多尺度特征。结果在 COCO 数据集上的 mAP-50 由 YOLOv2 的 44.0% 提高到 57.9%, 与 mAP 61.1% 的 RetinaNet 相比, RetinaNet 在输入尺寸 500×500 的情况下检测速度约 98 ms/帧, 而 YOLOv3 在输入尺寸 416×416 时检测速 度可达 29 ms/帧。

上面这张图足以秒杀一切, 说明 YOLOv3 在保证速度的前提下, 也达到了很高的准确率。

基本思想

作者在YOLO算法中把物体检测(object detection)问题处理成回归问题,并将图像分为S×S的网格。如果一个目标的中心落入格子,该格子就负责检测该目标。

If the center of an object falls into a grid cell, that grid cell is responsible for detecting that object.

每个网格都会输出 bounding box,confidence 和 class probability map。其中:

  • bounding box 包含4个值:x,y,w,h,(x,y)代表 box 的中心。(w,h)代表 box 的宽和高;
  • confidence 表示这个预测框中包含物体的概率,其实也是预测框与真实框之间的 iou 值;
  • class probability 表示的是该物体的类别概率,在 YOLOv3 中采用的是二分类的方法。

网络结构

下面这幅图就是 YOLOv3 网络的整体结构,在图中我们可以看到:尺寸为 416X416 的输入图片进入 Darknet-53 网络后得到了 3 个分支,这些分支在经过一系列的卷积、上采样以及合并等操作后最终得到了三个尺寸不一的 feature map,形状分别为 [13, 13, 255]、[26, 26, 255] 和 [52, 52, 255]。

image

讲了这么多,还是不如看代码来得亲切。

12345678910111213141516171819202122232425262728293031323334353637383940
def YOLOv3(input_layer):# 输入层进入 Darknet-53 网络后,得到了三个分支route_1, route_2, conv = backbone.darknet53(input_layer)# 见上图中的橘黄色模块(DBL),一共需要进行5次卷积操作conv = common.convolutional(conv, (1, 1, 1024,  512))conv = common.convolutional(conv, (3, 3,  512, 1024))conv = common.convolutional(conv, (1, 1, 1024,  512))conv = common.convolutional(conv, (3, 3,  512, 1024))conv = common.convolutional(conv, (1, 1, 1024,  512))conv_lobj_branch = common.convolutional(conv, (3, 3, 512, 1024))# conv_lbbox 用于预测大尺寸物体,shape = [None, 13, 13, 255]conv_lbbox = common.convolutional(conv_lobj_branch, (1, 1, 1024, 3*(NUM_CLASS + 5)),activate=False, bn=False)conv = common.convolutional(conv, (1, 1,  512,  256))# 这里的 upsample 使用的是最近邻插值方法,这样的好处在于上采样过程不需要学习,从而减少了网络参数conv = common.upsample(conv)conv = tf.concat([conv, route_2], axis=-1)conv = common.convolutional(conv, (1, 1, 768, 256))conv = common.convolutional(conv, (3, 3, 256, 512))conv = common.convolutional(conv, (1, 1, 512, 256))conv = common.convolutional(conv, (3, 3, 256, 512))conv = common.convolutional(conv, (1, 1, 512, 256))conv_mobj_branch = common.convolutional(conv, (3, 3, 256, 512))# conv_mbbox 用于预测中等尺寸物体,shape = [None, 26, 26, 255]conv_mbbox = common.convolutional(conv_mobj_branch, (1, 1, 512, 3*(NUM_CLASS + 5)),activate=False, bn=False)conv = common.convolutional(conv, (1, 1, 256, 128))conv = common.upsample(conv)conv = tf.concat([conv, route_1], axis=-1)conv = common.convolutional(conv, (1, 1, 384, 128))conv = common.convolutional(conv, (3, 3, 128, 256))conv = common.convolutional(conv, (1, 1, 256, 128))conv = common.convolutional(conv, (3, 3, 128, 256))conv = common.convolutional(conv, (1, 1, 256, 128))

conv_sobj_branch = common.convolutional(conv, (3, 3, 128, 256))# conv_sbbox 用于预测小尺寸物体,shape = [None, 52, 52, 255]conv_sbbox = common.convolutional(conv_sobj_branch, (1, 1, 256, 3*(NUM_CLASS +5)),activate=False, bn=False)return [conv_sbbox, conv_mbbox, conv_lbbox]

Darknet53 结构

Darknet-53 的主体框架如下图所示,它主要由 Convolutional 和 Residual 结构所组成。需要特别注意的是,最后三层 Avgpool、Connected 和 softmax layer 是用于在 Imagenet 数据集上作分类训练用的。当我们用 Darknet-53 层对图片提取特征时,是不会用到这三层的。

Darknet-53 有多牛逼?看看下面这张图,作者进行了比较,得出的结论是 Darknet-53 在精度上可以与最先进的分类器进行媲美,同时它的浮点运算更少,计算速度也最快。和 ReseNet-101 相比,Darknet-53 网络的速度是前者的1.5倍;虽然 ReseNet-152 和它性能相似,但是用时却是它的2倍以上。

此外,Darknet-53 还可以实现每秒最高的测量浮点运算,这就意味着网络结构可以更好地利用 GPU,从而使其测量效率更高,速度也更快。

Convolutional 结构

Convolutional 结构其实很简单,就是普通的卷积层,其实没啥讲的。但是对于 if downsample 的情况,初学者可能觉得有点陌生, ZeroPadding2D 是什么层?

1234567891011121314151617
def convolutional(input_layer, filters_shape, downsample=False, activate=True, bn=True):if downsample:input_layer = tf.keras.layers.ZeroPadding2D(((1, 0), (1, 0)))(input_layer)padding = 'valid'strides = 2else:strides = 1padding = 'same'conv = tf.keras.layers.Conv2D(filters=filters_shape[-1],kernel_size = filters_shape[0],strides=strides, padding=padding, use_bias=not bn,kernel_regularizer=tf.keras.regularizers.l2(0.0005),kernel_initializer=tf.random_normal_initializer(stddev=0.01),bias_initializer=tf.constant_initializer(0.))(input_layer)if bn: conv = BatchNormalization()(conv)if activate == True: conv = tf.nn.leaky_relu(conv, alpha=0.1)return conv

讲到 ZeroPadding2D层,我们得先了解它是什么,为什么有这个层。对于它的定义,Keras 官方给了很好的解释:

keras.layers.convolutional.ZeroPadding2D(padding=(1, 1), data_format=None) 说明: 对2D输入(如图片)的边界填充0,以控制卷积以后特征图的大小

其实就是对图片的上下左右四个边界填充0而已,padding=((top_pad, bottom_pad), (left_pad, right_pad))。 很简单吧,快打开你的 ipython 试试吧!

1234567
In [2]: x=tf.keras.layers.Input([416,416,3])

In [3]: tf.keras.layers.ZeroPadding2D(padding=((1,0),(1,0)))(x)Out[3]: <tf.Tensor 'zero_padding2d/Identity:0' shape=(None, 417, 417, 3) dtype=float32>

In [4]: tf.keras.layers.ZeroPadding2D(padding=((1,1),(1,1)))(x)Out[4]: <tf.Tensor 'zero_padding2d_1/Identity:0' shape=(None, 418, 418, 3) dtype=float32>

Residual 残差模块

残差模块最显著的特点是使用了 short cut 机制(有点类似于电路中的短路机制)来缓解在神经网络中增加深度带来的梯度消失问题,从而使得神经网络变得更容易优化。它通过恒等映射(identity mapping)的方法使得输入和输出之间建立了一条直接的关联通道,从而使得网络集中学习输入和输出之间的残差。

123456
def residual_block(input_layer, input_channel, filter_num1, filter_num2):short_cut = input_layerconv = convolutional(input_layer, filters_shape=(1, 1, input_channel, filter_num1))conv = convolutional(conv       , filters_shape=(3, 3, filter_num1,   filter_num2))residual_output = short_cut + convreturn residual_output

提取特征

要想详细地知道 YOLO 的预测过程,就非常有必要先来了解一下什么是特征映射 (feature map) 和特征向量 (embeddings)。

特征映射

当我们谈及 CNN 网络,总能听到 feature map 这个词。它也叫特征映射,简单说来就是输入图像在与卷积核进行卷积操作后得到图像特征

一般而言,CNN 网络在对图像自底向上提取特征时,feature map 的数量(其实也对应的就是卷积核的数目) 会越来越多,而空间信息会越来越少,其特征也会变得越来越抽象。比如著名的 VGG16 网络,它的 feature map 变化就是这个样子。

feature map 在空间尺寸上越来越小,但在通道尺寸上变得越来越深,这就是 VGG16 的特点。

特征向量

讲到 feature map 哦,就不得不提一下人脸识别领域里经常提到的 embedding. 一般来说,它其实就是 feature map 被最后一层全连接层所提取到特征向量。早在2006年,深度学习鼻祖 hinton 就在《SCIENCE》上发表了一篇论文,首次利用自编码网络对 mnist 手写数字提取出了特征向量(一个2维或3维的向量)。值得一提的是,也是这篇论文揭开了深度学习兴起的序幕。

下面就是上面这张图片里的数字在 CNN 空间里映射后得到的特征向量在2维和3维空间里的样子:

前面我们提到:CNN 网络在对图像自底向上提取特征时,得到的 feature map 一般都是在空间尺寸上越来越小,而在通道尺寸上变得越来越深。 那么,为什么要这么做?

其实,这就与 ROI (感兴趣区域)映射到 Feature Map 有关。在上面这幅图里:原图里的一块 ROI 在 CNN 网络空间里映射后,在 feature map 上空间尺寸会变得更小,甚至是一个点, 但是这个点的通道信息会很丰富,这些通道信息是 ROI 区域里的图片信息在 CNN 网络里映射得到的特征表示。由于图像中各个相邻像素在空间上的联系很紧密,这在空间上造成具有很大的冗余性。因此,我们往往会通过在空间上降维,而在通道上升维的方式来消除这种冗余性,尽量以最小的维度来获得它最本质的特征。

原图左上角红色 ROI 经 CNN 映射后在 feature map 空间上只得到了一个点,但是这个点有85个通道。那么,ROI的维度由原来的 [32, 32, 3] 变成了现在的 85 维,这难道又不是降维打击么?

YOLOv3 算法的一点理解相关推荐

  1. 图论最短路:Bellman-Ford与其优化SPFA算法的一点理解

    文章目录 前言 一.对Bellman-Ford的深入理解 1. Bellman-Ford有什么用? 2. 什么是松弛操作? 3. Bellman-Ford的k次迭代意义? 4. 一个重要定理 5. 对 ...

  2. J-Linkage clustering算法的一点理解

    1.J-Linkage算法的简介 J-Linkage算法是一种自底向上的一种层次聚类的算法,当然还有很多评价每个聚类距离的算法,例如simple linkage, complete linkage a ...

  3. yolov3算法中关于loss={'yolo_loss': lambda y_true, y_pred: y_pred}的理解

    yolov3算法中关于loss={'yolo_loss': lambda y_true, y_pred: y_pred}的理解 参考文献: (1)https://www.jianshu.com/p/7 ...

  4. 重磅MIT开源人工智能算法评估和理解对抗Logit配对的稳健性

    重磅MIT开源人工智能算法评估和理解对抗Logit配对的稳健性摘要:我们评估了对抗性Logit Pairing的稳健性,这是最近针对广告范例提出的防御措施. 我们发现,使用Adversarial Lo ...

  5. DL之Yolov3:基于深度学习Yolov3算法实现视频目标检测之对《我要打篮球》视频段进行实时目标检测

    DL之Yolov3:基于深度学习Yolov3算法实现视频目标检测之对<我要打篮球>视频段进行实时目标检测 目录 输出结果 设计思路 核心代码 相关文章 成功解决AttributeError ...

  6. Mean-shift算法的直观理解

    Mean-shift算法的直观理解 0 前言 暑假的时候参加移动计算竞赛打了下酱油,接触到了Mean-shift算法,用于做目标跟踪.在那段时间也在网上查阅了不少关于这个算法的资料,可是总感觉它们都比 ...

  7. 视觉感知——深度学习之YOLOv3算法

    视觉感知--深度学习之YOLOv3算法 1. 传感器融合 2. 深度学习算法 2.1 卷积神经网络CNN 2.2 YOLO算法 3. YOLO v3算法实践 3.1 官方数据集参考 3.2 环境配置 ...

  8. 国密SM2算法的只求理解不求甚解 (4/5)SM2算法加解密协议

    国密SM2算法的只求理解不求甚解 (1/5)前置数学知识:模运算 国密SM2算法的只求理解不求甚解 (2/5)前置数学知识:平面几何 国密SM2算法的只求理解不求甚解 (3/5)SM2算法数学模型 国 ...

  9. Hamiltonian Monte Carlo抽样算法的初步理解

    Hamiltonian Monte Carlo抽样算法的初步理解 接受拒绝采样算法 MCMC回顾 Hamiltonian dynamics 拉格朗日方程 从牛顿方程出发推导拉格朗日方程 勒让德变换 哈 ...

最新文章

  1. leetcode -- 3 sum
  2. jqury+css实现可弹出伸缩层
  3. DHCP数据抓包分析--wireshark
  4. 目标检测领域还有什么可做的?19 个方向给你建议
  5. 动态库(共享库)的制作和使用
  6. 我的学习工作经历,一个园林专业中专毕业生的IT之路
  7. 学成在线--22.课程营销
  8. Kubernetes 创建pod一直处于ContainerCreating 状态解决过程
  9. 〖经典〗网页特效汇总实例
  10. 基于visual Studio2013解决C语言竞赛题之1067间隔排序
  11. Android移动应用基础教程【广播机制】
  12. 单片机段式LCD驱动教程
  13. 查看执行计划 oracle,查看Oracle执行计划的几种方法
  14. 对数周期天线工作原理
  15. No.8 CA证书和SSH服务
  16. 全加器和半加器的区别
  17. Phyllotaxis算法应用
  18. 拼多多势不可挡的发展|一度智信
  19. 向下取整符号_22. 为什么 Python 中的整除是向下取整?
  20. UML--顺序图绘制

热门文章

  1. hexo搭建Gitcafe博客(专栏)
  2. 卫哲的3+1思考法:测量项目“靠谱程度”
  3. java中关于拼音的处理。
  4. opencl学习(一)
  5. Linux笔记之浅析linux文件的压缩与解压——tar命令
  6. securecrt全屏怎么退回_securecrt快捷键
  7. 《吴军数学通识讲义》读后感
  8. python 调试 pdb_python pdb调试
  9. 15-VMware Horizon 2203 虚拟桌面-Win10 自动桌面池完整克隆浮动(十五)
  10. 配置本地缓存服务器(一)