首发于目标检测
重温yolo v2

重温yolo v2

近来在研究6D pose estimation,其中有用到yolo v2作为基础框架,所以这里整理一下yolo v2,后续会把6D pose estimation也整理一下。如果有理解不对的地方欢迎指正。

本文主要分为四个部分讲解:

  1. 骨架网络
  2. 网络的输出
  3. 网络的预测
  4. 网络的训练

如果对yolo v1不熟悉的,可以看我的另外一篇文章:

stone:你真的读懂yolo了吗?zhuanlan.zhihu.com图标

下面,首先讲解骨架网络。

一、骨架网络

YOLO v2用的骨架网络是作者自己设计。网络结构直接看图:

图片来自:ethereon.github.io/nets

关于骨架网络的设计,有以下特点:

  1. 网络抛弃了全连接,采用全卷积FCN的架构,因此可以输入任意大小的图片。
  2. 在每个卷积层之后都使用了BN。BN的作用是为了是网络更容易收敛,除此之外还有正则化的作用,可以防止过拟合。
  3. 使用了跨层连接,这个借鉴了ResNet的identity mapping思想。跨层连接的一个大好处是使梯度更容易前传,也就是说可以让网络训练变得更容易。但是,这个跨层连接有点别致,一般的跨层连接,会通过求和或者通道连接进行特征融合,但是yolov2在融合之前还添加了一个reorganization的操作。经过这样的操作,实际上已经把feature map的排布重整了,直觉上觉得这么做不太好,但事实证明它是可行的。不过这么做的一个好处就是将所有的信息都传递到后面的层,并没有因为下采样等操作导致损失信息,因此获得了更多细粒度的特征。

那什么是reorganization层?其实很简单,就是将大分辨率的feature map进行重新排布得到分辨率更小的feature map,相应的通道数增加。举例来说,如果网络的输入维度是3x416x416,那么conv13_512的维度则是512x26x26,将其进行重新排布之后则变成2048x13x13。这个重新排布如图:

实际上就是将一个feature map变成了更小的feature map,但是通道数变多了。

二、网络的输出

假设网络图片的输入大小是[416,416],那么经过骨架网络(或者说特征提取网络)之后,由于存在步长为32的分辨率降低,这样网络的输出是[13,13,1024]。要将其转化为预测,使用一个1x1的卷积将通道数压缩到1024→(num_anchor x (4+1+num_class),如下图所示)这个维度就可以了,这里的num_anchor表示feature map上每个点对应的anchor数目,4表示xywh,1表示confidence,num_class表示预测的类别数,注意这里的类别数是不包括背景的。

实际上,这个还不是真正预测的输出结果,这个输出结果需要进行一定的转换,在介绍转换之前,需要讲解anchor,因为转换是基于anchor来进行的。

三、网络的预测

1. yolo v2中的anchor

我们知道,yolo v1中是没有使用到anchor的,这使得每个网格中的每个cell只能预测一个物体。因此yolo v2借鉴了faster RCNN中anchor的思想,这样实际上使得grid的每个cell可以预测多个尺度的不同物体。yolo v1中grid的大小是7x7,但是yolo v2的grid变成了13x13,grid中的每个cell都对应这5个不同尺寸的anchor,如下图:

我们知道,faster RCNN是事先固定几个长宽比和大小的anchor,但yolo v2不同,yolo v2设置的5种anchor是通过维度聚类得到的。5种anchor的宽高,分别如下:

# 宽高
[0.57273, 0.677385], 
[1.87446, 2.06253],
[3.33843, 5.47434],
[7.88282, 3.52778],
[9.77052, 9.16828].

注意,这个宽高是在Grid的尺度下的,不是在原图尺度上,在原图尺度上的话还要乘以步长32。

2. Anchor的预测

每个anchor的预测的维度为 (4+1+num_class)。也就是说每个anchor的预测包括xywh,confidence,class。上文已经讲到,这些输出并不是真正的网络预测结果,要得到真正的网络预测结果,需要进行一些转换。

对预测结果转换如下:

center_x=grid_x+sigmoid(x)
center_y=grid_x+sigmoid(y)
w=exp(w)*anchor_w
h=exp(h)*anchor_h
confidence=sigmoid(confidence)
cls1=sigmoid(cls1)
cls2=sigmoid(cls1)

这里解释一下转换的意义:

  1. 对于预测的bbox的中心,需要压缩到0-1之间,再加上anchor相对于grid在x和y方向上的偏移。这一点,和yolo v1是一致的。
  2. 对于预测的bbox的宽高,这个和faster RCNN一样,是相对于anchor宽高的一个放缩。exp(w)和exp(h)分别对应了宽高的放缩因子。
  3. 对于预测的bbox的置信度,则需要用sigmoid压缩到0-1之间。这个很合理,因为置信度就是要0-1之间。
  4. 对于预测的每个类别,也是用你sigmoid压缩到0-1之间。这是因为类别概率是在0-1之间。

经过以上变换之后,网络预测就都有了实际的意义。

以上得到的结果,实际上还不是最终的预测结果,以上得到的center_x,center_y,w,h都是在Grid这个尺度上做的,所以要乘上步长32就可以得到在原图尺度上的预测结果。

3. 后处理

以上得到的anchor的预测结果是很多的,因此需要进行后处理,即通过非极大值抑制(NMS)和confidence滤除不包含物体的预测,得到最终的预测结果。

四、网络的训练

1. 给Anchor打label

我们已经知道了Anchor是如何进行预测的,但更重要的是,我们要知道如何训练这些anchor来进行这些预测的。所以首先要知道怎么给这些anchor打label的。

首先,对于一个物体的bbox,我们得到它的中心,看这个中心落在grid中的哪一个cell,那么这个cell就负责预测这个物体。但是,需要注意的是,每个cell中实际上有5个anchor,并不是每个anchor的会预测这个物体,我们只会选择一个长宽和这个bbox最匹配的anchor来负责预测这个物体。那么什么叫长宽最为匹配?这个实际上就是将anchor移动到图像的右上角,bbox也移动到图像的左上角,然后去计算它们的iou,iou最大的其中一个anchor负责预测这个物体,如下图所示。

因为anchor和bbox都移动到了图像左上角,那么这个时候计算出来的iou最大就意味着是宽高最为匹配,这个和不转移到图像左上角进行计算IOU还是有差别的。我个人觉得这种做法只是为了方便处理,anchor和bbox不转移到图像左上角的做法也是可行的。

2. 损失函数

给anchor打完label,那么就可以定义损失函数了,yolo v2的损失函数还是比较复杂的。先上损失函数的定义公式:

损失函数分为5项,下面分别解释:

第一项:负责预测物体的anchor的xywh损失。如果anchor负责预测物体,那么需要计算坐标的L2损失。

第二项:不负责预测物体的anchor的xywh损失。如果anchor不负责预测物体,那么需要在迭代的初期(比如iteration<12800)去计算坐标的L2损失。问题的关键是,anchor都不负责预测物体,那么它的预测目标是什么呢?答:预测目标是anchor的xywh。为什么要这么做?我的理解是,这么做可以让所有anchor的预测都接近anchor自身的xywh,这样当它有物体落入这个anchor的时候,anchor的预测不至于和目标差别太大,相应的损失也会比较小,训练起来会更加容易。

第三项:负责预测物体的anchor的confidence损失。负责预测物体的anchor需要计算confidence损失,confidence的目标就是预测的bbox和真实bbox的iou。

第四项:不负责预测物体的anchor的confidece损失。对那些不负责预测gt的anchor,需要计算每个anchor和所有gt box的IOU。如果算出来的最大IOU<0.6,相应的 \lambda^{conf}_{noobj}=1 并且confidence的label就是0。但是,如果这个值大于0.6,相应的 \lambda^{conf}_{noobj}=0 ,也就是说,这个时候是不算这个anchor的confidence损失的。为什么要这么做呢?我的理解是,当anchor不负责预测物体的时候,如果它预测出来的结果和真实值差别很大的话,那代表它是没有物体的,那么这个时候就希望它的预测的confidence接近0。但是如果预测的结果和真实值比较接近的话,则不计算损失。

第五项:负责预测物体的anchor的类别损失。每个类别的输出概率0-1之间,计算的是L2损失。也就是说分类问题也把它当做了回归问题。另外需要注意的是,类别预测中是不需要预测背景的,因为confidence实际上就已经代表是否存在物体,类别就没必要去预测背景。

3. 多尺度训练

yolo v2中还有一个多尺度训练的方法。因为骨架网络是一个全卷积的网络,因此可以输入任意大小的图片,这个时候网络输出的grid大小就不是固定的,如果是416x416的图片输入,那么网络的输出的grid是13x13大小的,但图片大小变化的时候,那么grid大小也会相应的变化,这时候,anchor的数量也会相应的发生变化。下图显示了三种不同尺度的输入图像:[320,320],[416,416]和[512,512],对应的grid大小分别为[10,10], [13,13], [16,16]。在实际训练过程中,每10个batch就会从320×320, 352×352, … 608×608 (步长32)中选择一种大小的图片作为输入进行训练。这种训练方式可以强制网络去学习预测多种尺度的图片。

参考:

  1. github.com/leetenki/YOL
  2. towardsdatascience.com/
  3. medium.com/@jonathan_hu
编辑于 2018-08-30

文章被以下专栏收录