下面介绍的是 YOLO V2 的内容
V2 使用 Batch Normalization 对网络进行优化,通过对每一个卷积层增加 BN 处理,最终使得 V2 的 mAP 提高了 2%
在 V2 之前的业界标准检测方法都是先把分类器(即卷积分类网络)放在 ImageNet 上进行预训练,这样卷积网络对物体更敏感。在预训练的基础上对网络进行改进与进一步训练。
大多数的分类器都运行在小于 256×256 的图片上,因为一般是预训练的 ImageNet。而现在 YOLO 从 224×224 增加到了 448×448(V1 就是 448x448),这就意味着网络需要适应新的输入分辨率。
为了适应新的分辨率,V2 的分类网络以 448×448 的分辨率先在 ImageNet 上进行微调,微调 10 个 epochs. 这样可以让网络有时间去调整卷积层,以更好地运行在高分辨率图片上。之后,作者还微调了用于检测的 resulting network. 最终,通过使用高分辨率分类器,mAP 提升了 4%
V1 最后采用的是全连接层直接对边界框进行预测,其中边界框的宽与高是相对整张图片大小的,而由于图片中存在不同尺度和长宽比(scales and ratios)的物体,V1 在训练过程中学习适应不同物体的形状是比较困难的,这也导致 V1 在精确定位方面表现较差(召回率低)。
V2 借鉴了Faster R-CNN 中RPN 网络的 anchor boxes 策略。
RPN 对 CNN 特征提取器得到的特征图进行卷积来预测每个位置的 box 以及置信度(前景得分),并且各个位置设置不同尺度和比例的 anchor boxes,所以 RPN 预测的是 bounding box 相对于 anchor boxes 的偏移值,这样使得模型更容易学习。
所以,YOLO V2 移除了 V1 中的全连接层而采用了卷积和 anchor boxes 来预测 bounding box
为了使检测所用的特征图具有更高的分辨率,作者先移除了一个 pooling 层。另外,作者将
448x448 的输入改成了 416x416 的输入。这样做是因为作者想要在特征图的定位上得到一些奇数,这样每个 bounding box 就只有唯一的一个中心网格。同时,作者还认为,对于那些较大的物体,它们更倾向于分布在图片的中心位置,于是,利用一个单独的、位于物体中心的位置来预测这些物体是不错的选择。
V2 使用 anchor boxes 之后,将分类预测和空间定位分离开了。对每个 anchor box,分别预测其类属性和一套 objectness(作者对 objectness 的解释是:同 V1,objectness prediction 包括 box 和 ground truth 的 IoU、box 的回归以及存在物体时的类条件概率)。
使用 anchor box 会让 mAP 稍微下降(降低0.3),但用了它能让 V2 预测出大于一千个框,同时 recall 上升到 88%
我们知道在 Faster R-CNN 中 anchor box 的大小和比例是按经验设定的,然后网络会在训练过程中调整 anchor box 的尺寸。但是如果一开始就能选择到合适尺寸的 anchor box,那肯定可以帮助网络越好地预测。
于是,作者所以作者采用 k-means 的方式对训练集的 bounding boxes 做聚类,试图找到合适的 anchor box
另外,作者也发现如果采用欧式距离的 k-means,在 box 的尺寸比较大的时候其误差也较大。但是我们希望的是误差和 box 的尺寸没有直接的关系,我们真正关注的是IoU值。所以,作者通过 IoU 定义了如下的距离函数,使得误差和 box 的大小无关:
d ( b o x , c e n t r i o d ) = 1 − I O U ( b o x , c e n t r i o d ) \begin{aligned}d(box, centriod)=1-IOU(box, centriod)\end{aligned} d(box,centriod)=1−IOU(box,centriod)
如下图 ,左边是聚类的簇个数好和 IoU 的关系,两条曲线分别代表两个不同的数据集。在分析了聚类的结果并平衡了模型复杂度与召回率,作者选择了 K=5,这也就是图中右边的示意图是选出来的 5 个 box 的大小,这里蓝色和黑色分别表示两个不同的数据集,可以看出它们的基本形状是类似的。同时,还可以发现聚类的结果和手动设置的 anchor box 大小差别显著。聚类的结果中多是高瘦的 box,而矮胖的 box 数量较少。
作者发现,anchor box 的引入使模型变得不稳定,尤其是在最开始的几次迭代。大多数的不稳定都产生在预测 box 的 ( x , y ) (x, y) (x,y)位置的时候。
在 RPN 中,中心坐标的计算公式为
x = ( t x ∗ w a ) − x a , y = ( t y ∗ h a ) − y a \begin{aligned}x=(t_x*w_a)-x_a, y = (t_y*h_a)-y_a\end{aligned} x=(tx∗wa)−xa,y=(ty∗ha)−ya
RPN 负责预测 t x t_x tx和 t y t_y ty
但是呢,上面的两个公式是无约束的,任意一个 anchor box 很有可能在图片上的任意位置停下,而无视 box 的预测位置。同时,随机的初始化会使得模型需要很长的时间才能稳定地进行预测。
于是,作者放弃了RPN中的方法,而沿用 V1 中的方法:预测 bounding box 中心相对于中心网格的偏移。同样使用了 Sigmod 来限制输出在 ( 0 , 1 ) (0, 1) (0,1)
网络预测特征图中每个网格的5个 boxes,每个 box 包括 ( t x , t y , t w , t h , t o ) (t_x, t_y, t_w, t_h, t_o) (tx,ty,tw,th,to). 如果网格在图像上的左上角偏移为 ( c x , c y ) (c_x,c_y) (cx,cy),bounding box 先验的宽度和高度为 ( p w , p h ) (p_w,p_h) (pw,ph),于是对应的预测即为:
b x = σ ( t x ) + c x b y = σ ( t y ) + c y b w = p w e t w b h = p h e t h P r ( object ) ∗ I O U ( b , object ) = σ ( t o ) b_x = \sigma(t_x) + c_x \\ b_y = \sigma(t_y) + c_y\\ b_w = p_w e^{t_w}\\ b_h = p_h e^{t_h}\\ Pr(\text{object}) * IOU(b, \text{object}) = \sigma(t_o) bx=σ(tx)+cxby=σ(ty)+cybw=pwetwbh=phethPr(object)∗IOU(b,object)=σ(to)
由于限制了位置的预测,参数变得更容易学习,网络也变得相对更加稳定了。
通过维度聚类 + 直接预测 bounding box 中心位置,V2 比直接使用使用 anchor box 的版本提高了近5%
好像前面忘记说 V2 的输出了 ε=ε=ε=(~ ̄▽ ̄)~,这里补一句,V2 卷积层中的下采样因子是 32, 于是对于 416x416 的输入,最终得到的特征图就是 13x13
虽然这个大小的特征图对大物体的检测来说是足够了,但是作者又从细粒度特征上剽了一点想法过来。Faster R-CNN、SSD 都使用了多尺寸的特征图来进行预测,这样可以获得不同的分辨率。
不同于Faster R-CNN、SSD,作者直接在 V2 中加入了一个 passthrough layer, 这样就可以从前面的层(26x26 的分辨率) 中提取特征。
passthrough layer 与 ResNet 网络的 shortcut 类似,以前面更高分辨率的特征图为输入,然后将其连接到后面的低分辨率特征图上。
前面的特征图维度是后面的特征图的 2 倍,passthrough layer 将相邻的特征堆叠到不同的通道上。于是,26x26x512 的特征图经过 passthough layer 之后就变成了 13x13x2048 的特征图(特征图大小降低4倍,而channles增加4倍),这样就可以和后面的 13x13x1024 特征图连在一起形成 13x13x3072 的特征图了。
另外,作者在后期的实现中借鉴了 ResNet,不是直接对高分辨特征图处理,而是增加了一个中间卷积层,先采用 64 个 1×1 的卷积核进行卷积,然后再进行 passthrough 处理。
在这一节,作者想要 V2 可以稳定地运行在不同尺寸的图片上,又 V2 只使用了卷积和池化,这样在网络中及时地调整输入输出的大小是很方便的。于是,在训练模型的时候作者加入了一些操作:
他们没有固定输入图像的大小,而是让 V2 每隔 10 个 bathches 就随机选择一个新的图片大小。又下采样因子是 32,所以图片的大小只能是 32 的倍数,如 320、352、…、608, 调整之后继续训练。
由于这样的操作,V2 在小尺寸的网络上运行得更快,在大尺寸的网络上能得到更高的精度。于是,V2 便提供了一个在速度和精度上权衡。
作者在 V2 的基础上使用了一个新的 backbone,即 Darknet-19
Darknet-19 还是主要使用 3x3 的卷积核,池化后通道数也变为原来的 2 倍。与 NIN 一样,采用了 global avg pooling,在 3x3 卷积之后直接用 1x1 的卷积压缩特征。Darknet-19 的详细信息如下:
Darknet-19 包含 19 个卷积层和 5 个max pooling ,而 V1 采用的是 GooLeNet,包含 24 个卷积层和 2 个全连接层,因此 Darknet-19 整体上的卷积操作相比于 V1 的 GoogLeNet 要少,这是计算量减少的关键。
预训练都是在 ImageNet 上进行预训练,主要分两步:
在高分辨率的情况下,网络的 top-1到达了 76.5%,top-5 达到了 93.3%
之前 training for classification的操作相当于是预训练,只是简单地进行分类,没有检测的过程。所以,迁移到检测的网络上时需要对 backbone 做一些修改。
作者去掉最后一个卷积,取而代之的是 3 个 3×3×1024 的卷积再加 1 个 1
x1 的卷积(卷积个数取决于最终检测的输出,在 VOC中,每个网格预测 5 个 boxes,每个 box有 5 个坐标和 20 个类别,所以有 5x(5+25) = 125 个滤波器)。最后,作者 还从最后的 3×3×512 layer 到 倒数第二个卷积层之间添加了个 passthough layer
V2 的训练主要包括三个阶段。
第一阶段:先在 ImageNet 分类数据集上预训练 Darknet-19,此时模型输入为 224*224,共训练160 epoch
第二阶段:将网络的输入调整为 448*448,继续在 ImageNet 数据集上 fine tune 分类模型,训练10 epoch
第三个阶段:修改Darknet-19分类模型为检测模型,并在检测数据集上继续 fine tune 网络
在 VOC 中,最终的预测矩阵 T ( b a c t h _ s i z e , 13 , 13 , 125 ) T(bacth\_size, 13,13, 125) T(bacth_size,13,13,125),调整一下 T T T的形状 ( b a t c h _ s i z e , 13 , 13 , 5 , 25 ) (batch\_size,13, 13, 5, 25) (batch_size,13,13,5,25)
于是, T [ : , : , : , : , 0 : 4 ] T[:,:,:,:, 0:4] T[:,:,:,:,0:4] 是 bounding box 的 ( t x , t y , t w , t h ) (t_x, t_y, t_w, t_h) (tx,ty,tw,th), T [ : , : , : , : , 4 ] T[:,:,:,:, 4] T[:,:,:,:,4] 是 box 的置信度 t o t_o to, T [ : , : , : , : , 5 : ] T[:,:,:,:, 5:] T[:,:,:,:,5:] 是类别预测值
但是,在论文中,作者并没有给出 V2 训练过程中 anchor box 的匹配和训练的损失函数,难怪Ng说YOLO论文很难懂 ━━∑( ̄□ ̄*|||━━
不过默认按照 V1 的方式也是可以处理,YOLO V2 在 TensorFlow上 的实现确实也就是如此:
和 V1 一样,对于图片中某个物体的 ground truth,若其中心点落在哪个网格内,然后计算这个网格对应的 5 个 anchor boxes 与 groud truth 的 IoU,取 IoU 值最大的 anchor box 与 ground truth 匹配,之后就用该 anchor box 对应的 bounding box 来进行预测,而剩余的 4 个 anchor box 都不与 ground truth 匹配。
V2 同样需要假定每个网格至多含有一个 grounth truth,而在实际上基本不会出现多于 1 个的情况。通过与 ground truth 匹配的 anchor box 计算坐标误差、置信度误差以及分类误差,而其它的 box 只计算置信度误差。
V2 和 V1 的损失函数大部分是类同的。但是 V2 的处理比原来 V1 的版本更加复杂。
我们先给出 loss func 的计算公式,下面再逐条分析其所指的内容:
W , H W, H W,H分别表示特征图的宽和高(即 13x13), A A A表示 需要 anchor box 的个数(即为 5)
对于第一项,计算的是背景的置信度误差,那怎么知道哪些 box 是预测背景的呢?这里就再次需要 bounding box 和所有 groud truth 的 IoU值,记录最大的 IoU,如果该值小于一定的阈值,我们就将这个bounding box 标记为预测背景的,第一分项的示性函数也说明了这点。同 V1, λ n o o b j \lambda_{noobj} λnoobj是为了调节背景和前景不平衡而引入的。
对于第二项,计算的是 anchor boxes 和 bounding box 的坐标误差。但是由第一分项可知,仅在迭代的前 12800 次计算这一项损失。
对于剩下的几项,将视为一个部分,计算的是和 groud truth 匹配的 bounding box 的损失,包括坐标误差、置信度损失和分类误差。
[注]
上面关于anchor box 匹配和 loss func 的内容如果实在看不懂,就不要硬刚了,anchor box 匹配可以参考下 V3 里面的内容 摘记 - YOLO V3,至于 loss func 是从源码中对应出来的,所以佛性理解吧 o(╥﹏╥)o
下面介绍的是 YOLO9000 的内容
ImageNet 的标签名字是来自于一个叫 WordNet 的语言库,wordNet 采用的结构是有向图,但是由于原因的复杂性,有向图用起来可能并不是那么的方便。如,狗狗 U•ェ•*U,既可以是犬科的子集,也可以是家畜的子集,而犬科、家畜在 WordNet 中被视为同义词,这样有向图使用起来可能就不是特别的方便。
于是,作者放弃了使用完整的图结构,而是根据 ImageNet 中包含的概念来建立一个分层树。
为了建立这个分层树,首先检查 ImagenNet 中出现的名词,然后在 WordNet 中找到这些名词。同时,再找到这些名词到达他们根节点的路径(在这里设所有的根节点为实体对象)。在 WordNet 中,大多数同义词只有一个路径,所以首先把这条路径中的词全部都加到分层树中。然后,再接着迭代地检查剩下的名词,把他们添加到分层树上,但是要让生长树尽可能小。比如,一个概念两条路径到达根节点,一条路径会添加 3 条边,而另一条仅添加 1 条边,这时我们就选择添加路径最短的加入到树中。
这样最终就得到了一个 WordTree. 为了使用 WordTree 进行分类,我们预测每个节点的条件概率,以得到同义词集合中每个每个下义词的概率,如
P r ( Norfolk terrier ∣ terrier ) P r ( Yorkshire terrier ∣ terrier ) P r ( Bedlington terrier ∣ terrier ) … Pr(\text{Norfolk terrier} | \text{terrier}) \\ Pr(\text{Yorkshire terrier} | \text{terrier}) \\ Pr(\text{Bedlington terrier} | \text{terrier})\\ …\\ Pr(Norfolk terrier∣terrier)Pr(Yorkshire terrier∣terrier)Pr(Bedlington terrier∣terrier)…
如果我们要计算某一节点的绝对概率,我们只需要沿着树上到达根节点的路径,使所有条件概率相乘,就搞定啦。如,我们想知道一张图片是否是 Norfolk terrier,我们计算
P r ( Norfolk terrier ) = P r ( Norfolk terrier ∣ terrier ) ∗ P r ( terrier ∣ hunting dog ) ∗ … ∗ ∗ P r ( mammal ∣ P r ( animal ) ∗ P r ( animal ∣ physical object ) Pr(\text{Norfolk terrier}) = Pr(\text{Norfolk terrier} | \text{terrier})\\ * Pr(\text{terrier} | \text{hunting dog}) \\ * \ldots * \\ *Pr(\text{mammal} | Pr(\text{animal})\\ * Pr(\text{animal} | \text{physical object}) Pr(Norfolk terrier)=Pr(Norfolk terrier∣terrier)∗Pr(terrier∣hunting dog)∗…∗∗Pr(mammal∣Pr(animal)∗Pr(animal∣physical object)
[注]
论文上给出的即是这个公式,但是倒数第二项 P r ( mammal ∣ P r ( animal ) Pr(\text{mammal} | Pr(\text{animal}) Pr(mammal∣Pr(animal) 是几个意思没太懂,要不是编辑的时候码错了 (* ̄︿ ̄)
为了达到分类目的,作者假定图像包含一个目标: P r ( physical object ) = 1 Pr(\text{physical object}) = 1 Pr(physical object)=1
为了验证这种方法,作者在 1000 类 ImageNet 构建的 WordTree 上训练 Darknet-19
为了能构建出 WordTree1k,作者添加了一些中间节点,将标签空间从 1000 扩展到 1369. 在训练过程中,作者将真实标签的传播方式设为沿树向上面传播,以便如果某图片被标记为Norfolk terrier,则它也将被标记为 dog 和 mammal 等。为了计算条件概率,模型预测了一个1369 的向量。之前的 ImageNet 分类是使用一个大 softmax 进行分类。而现在,WordTree 只需要对同一概念下的同义词进行 softmax 分类就可以啦
这种方法的好处就在于:对未知或者新的物体进行分类时,性能降低得不会太明显。比如看到一个狗的照片,但不知道是哪种种类的狗,那么就模型将会以一个较高的置信度来预测是 “狗”,但是在其下义词之间,如 “哈士奇”、“牛头梗”、“金毛”等的置信度则会较低。
这种方法同样可以用到检测上:我们将不再假定每张图片都包含一个目标( P r ( physical object ) = 1 Pr(\text{physical object})=1 Pr(physical object)=1),而是通过 V2 objectness predictor 去预测 P r ( physical object ) Pr(\text{physical object}) Pr(physical object). 用于检测的 predictor 会预测对应的 bounding box 和 概率树。这时,我们沿树向下搜索,选取每个子集中置信度最高路径,直达达到某一设定的阈值,这时我们进可以预测物体类别了。
有了 WordTree 就可以以一种合理的方式将多个数据集组合在一起了:只需要将数据集中的类别映射到 WordTree 的某一同义词下
作者对于 YOLO9000 的目的是:训练一个 Extremely Large Scale 的检测器。所以训练的时候使用 WordTree 混合了 COCO 检测数据集与 ImageNet 中的 Top9000 类,混合后的数据集对应的 WordTree 有 9418 个类。另一方面,由于 ImageNet 数据集太大了,作者为了平衡一下两个数据集之间的数据量,于是对 COCO 进行了 oversampling,使 ImageNet 数据集只以 4:1 的比例大于 COCO数据集
YOLO9000 的训练是基于 YOLO V2 的构架,但是使用 3 anchor boxes 而不是 5 来限制输出。当网络遇到检测数据集中的图片时,则正常地反方向传播。对于分类损失,我们只反向传播那些等于或高于相应 level 的标签的损失。例如,如果标签是狗狗U•ェ•*U,我们只有在沿着 WordTree 向下的预测时,是 “德牧” 还是 “金毛”,这样做预测时我们才会记录误差,因为对于 “德牧” 或是 “金毛” 我们缺少相关的信息。当遇到分类数据集图片的时候,只反向传播分类对应的损失。要做到这一点,只需找到预测该类别概率最高的bounding box ,然后计算其预测树上的损失。同时,作者假设 IOU 最少为 0.3,并根据次假设进行 objectness loss 的反向传播。
使用联合训练法,YOLO9000 使用 COCO 检测数据集学习检测图片中的物体的位置,使用 ImageNet 分类数据集学习如何对大量的类别进行分类。