主要改变是取消了region proposal,提出一个新的网络region proposal network(RPN)来生成待检测区域。
因为faster r-cnn的细节较多,这里单列一个小节来着重讲解。
RPN
RPN在feature map上先进行3 x 3的滑动窗口卷积且output_channels = 256,之后在分别进行两个1 x 1的卷积 ,第一个卷积是输出cls,输出channel为2 * k(2是二分类,判断anchor是前景还是背景,即判断这个anchor里有没有目标,k是anchaor数量,文中设置为9);第二个卷积是输出reg,输出channel为4 * k(4是anchor的4个坐标偏移量[x, y, w, h],k同上)。
文中为每个位置预先设定好了k=9个长宽比与面积的先验框,这9个先验框包含三种面积(128 x128,256 x 256, 512 x 512),每种面积又包含三种长宽比(1:1,1:2, 2:1) 。
anchor的分类采用softmaxLoss进行训练,那么anchor的label是什么呢?文中做出了如下定义:如果一个anchor与ground truth的IoU在0.7以上,那这个anchor就算前景(positive)。类似地,如果这个anchor与ground truth的IoU在0.3以下,那么这个anchor就算背景(negative)。在作者进行RPN网络训练的时候,只使用了上述两类anchor,与ground truth的IoU介于0.3和0.7的anchor没有使用。而由于一张图生成的anchor数量比较多(对于40 x 60的特征图,有40 x 60 x 9 = 21600个),因此随机抽取128个前景anchor与128个背景anchor进行训练。
anchor的回归主要是训练anchor的修正值[t_x, t_y, t_w, t_htx,ty,tw,th],这四个值的意思是修正后的anchor在原来anchor基础上x和y方向上的偏移(由t_x, t_ytx,ty决定),并且长宽放大一定倍数(由t_w, t_htw,th决定)。让我们看看[t_x, t_y, t_w, t_htx,ty,tw,th]的公式定义:
t_x = (x - x_a) / w_a, \quad t_x^* = (x^* - x_a) / w_a \\ t_y = (y - y_a) / h_a, \quad t_y^* = (y^* - y_a) / h_a \\ t_w = log(w/w_a), \quad t_w^* = log(w^*/w_a) \\ t_h = log(h/h_a), \quad t_h^* = log(h^*/h_a)tx=(x−xa)/wa,tx∗=(x∗−xa)/waty=(y−ya)/ha,ty∗=(y∗−ya)/hatw=log(w/wa),tw∗=log(w∗/wa)th=log(h/ha),th∗=log(h∗/ha)
x, y, w, h分别代表anchor的中心点坐标和宽高。x代表预测的anchor,x_axa代表事先设置的先验anchor,x^*x∗代表ground truth的anchor(对于y, w, h都同理)。
anchor的回归损失函数采用smooth l1函数,需要注意,只对有物体(前景)的anchor,即只对positive的anchor进行边框修正。
smooth_{L_1}(x) = \left\{ \begin{aligned} 0.5x^2 , if \left|x \right| < 1 \\ \left|x \right| - 0.5, otherwise \end{aligned} \right.smoothL1(x)={0.5x2,if∣x∣<1∣x∣−0.5,otherwise
L({p_i},{t_i}) = \frac{1}{N_{cls}}\sum_i L_{cls}(p_i, p_i^*) + \lambda \frac{1}{N_{reg}}\sum_i p^*L_{reg}(t_i, t_i^*)L(pi,ti)=Ncls1i∑Lcls(pi,pi∗)+λNreg1i∑p∗Lreg(ti,ti∗)
其中第一个loss即为anchor分类loss(softmaxLoss),第二个loss为anchor回归loss(smooth l1 loss),为了保持两部分loss均衡,N_{cls}Ncls为mini-batch的数量=256,N_{reg}Nreg为anchor的location数量$\approx2400,将2400,将\lambda$设置为10能保持两部分均衡。
ROI pooling
得到RPN提出的region后,将其映射到对应的feature map的patch上,然后通过该层将特征转化成一样的大小**(6 x 6)**。
Classifier
此部分就是Fast R-CNN的分类器和RoI边框修正训练。分类器主要是分这个提取的RoI具体是什么类别(人,车,马等等),一共C+1类(包含一类背景)。RoI边框修正和RPN中的anchor边框修正原理一样,同样也是SmoothL1 Loss,值得注意的是,RoI边框修正也是对于非背景的RoI进行修正,对于类别标签为背景的RoI,则不进行RoI边框修正的参数训练。
训练方式
对于Faster R-CNN的训练方式有三种,可以被描述如下:
RPN和Fast R-CNN交替训练,这种方式也是作者采用的方式。
近似联合RPN和Fast R-CNN的训练,在训练时忽略掉了RoI边框修正的误差,也就是说只对anchor做了边框修订,这也是为什么叫"近似联合"的原因。
联合RPN和Fast R-CNN的训练。
对于作者采用的交替训练的方式,步骤如下:
使用在ImageNet上预训练的模型初始化共享卷积层并训练RPN。
使用上一步得到的RPN参数生成RoI proposal。再使用ImageNet上预训练的模型初始化共享卷积层,训练Fast R-CNN部分(分类器和RoI边框修订)。
将训练后的共享卷积层参数固定,同时将Fast R-CNN的参数固定,训练RPN。(从这一步开始,共享卷积层的参数真正被两大块网络共享)
同样将共享卷积层参数固定,并将RPN的参数固定,训练Fast R-CNN部分。
YOLO首先会把输入图片分成S x S个grid cell(文中S = 7),若某个物体的中心点落到某个格子中,则该格子负责预测该物体。
对于每个格子,YOLO会预测出B个(文中B = 2)bounding box(bbox),而对于每个bbox,会预测出5个值,分别是4个位置值[x, y, w, h]和1个置信度confidence。
YOLO还会为每个格子进行分类,一共有C类(在VOC上C = 20),为每个grid cell预测一组条件概率:P_r(class_i|object)Pr(classi∣object),grid cell中的B个bbox共享这个概率值。
除最后一层外,每一层都用的是leaky ReLU激活函数。
7 x 7 x 30的输出是怎么来的呢?首先被划分为S x S个格子,S = 7,然后每个格子有B个bbox,每个bbox有4个位置值和1个confidence,同时还有C个类别。因此总数为B x (4 + 1) + C = 2 x 5 + 20 = 30。
loss:loss是通过和gt的sum-squared error进行计算的,主要分为以下几个部分:
在测试的时候:
输入一张图到网络,得到7 x 7 x 30的结果,计算一下每个bbox的class-specific confidence score:
Pr(Class_i|object) \cdot Pr(object) \cdot IOU_{Pred}^{Truth} = Pr(Class_i) \cdot IOU_{Pred}^{Truth}Pr(Classi∣object)⋅Pr(object)⋅IOUPredTruth=Pr(Classi)⋅IOUPredTruth
则对于7 x 7 x B个bbox我们可以得到98个score,然后对这98个bbox根据score进行NMS,最后得到结果。
这篇文章实际介绍了两个模型:YOLOv2和YOLO9000
在当时来看没啥大的缺点,不如SSD算一个?
采用了BN来加快模型收敛,而且可以起到正则化的作用,防止模型过拟合,并且不再使用dropout,使用Batch Normalization后,YOLOv2的mAP提升了2.4%。
YOLOv1在采用224 x 224分类模型预训练后,直接将分辨率增加至448 x 448在检测数据集上fine-tune,但是直接切换分辨率,检测模型可能难以快速适应高分辨率,所以YOLOv2增加了在ImageNet数据集上使用448 x 488输入来finetune分类网络这一中间过程(10 epochs),这可以使得模型在检测数据集上finetune之前已经适用高分辨率输入。使用高分辨率分类器后,YOLOv2的mAP提升了约4%。不过值得强调的是,**YOLOv2采用的是416 x 416的输入。**因为YOLOv2模型下采样的总步长为32,对于416 x 416的图片,最后得到的特征图大小为13 x 13。
YOLOv2借鉴了Faster R-CNN中RPN网络的先验框(anchor boxes,prior boxes,SSD也采用了先验框)策略,所以YOLOv2移除了YOLOv1中的全连接层而采用了卷积和anchor boxes来预测边界框。
YOLOv2使用了anchor boxes之后,每个位置的各个anchor box都单独预测一套分类概率值,在YOLOv1中,每个cell预测一个分类概率值供所有box共享。
在Faster R-CNN和SSD中,先验框的维度(长和宽)都是手动设定的,带有一定的主观性。如果选取的先验框维度比较合适,那么模型更容易学习,从而做出更好的预测。因此,YOLOv2采用k-means聚类方法对训练集中的边界框做了聚类分析,聚类分析时选用box与聚类中心box之间的IOU值作为距离指标:
d(box, centroid) = 1 - IOU(box, centroid)d(box,centroid)=1−IOU(box,centroid)
随着聚类中心数目的增加,平均IOU值(各个边界框与聚类中心的IOU的平均值)是增加的,但是综合考虑模型复杂度和召回率,作者最终选取5个聚类中心作为先验框。
YOLOv2也像Faster R-CNN那样预测anchor boxes的偏移。anchor的实际中心点位置为(x, y)需要根据预测的坐标偏移值(t_xtx, t_yty),先验框的宽高(w_a, w_hwa,wh)及中心点坐标(x_a, y_axa,ya)来计算。
x = (t_x \cdot w_a) - x_a \\ y = (t_y \cdot w_h) - y_ax=(tx⋅wa)−xay=(ty⋅wh)−ya
但是上面的公式是无约束的,预测的边界框很容易向任何方向偏移。所以,YOLOv2弃用了这种预测方式,而是沿用YOLOv1的方法,就是预测边界框中心点相对于对应cell左上角位置的相对偏移值,为了将边界框中心点约束在当前cell中,使用sigmoid函数处理偏移值,这样预测的偏移值在(0,1)范围内(每个cell的尺度看做1)。总结来看,根据边界框预测的4个offsets t_x, t_y, t_h, t_wtx,ty,th,tw ,可以按如下公式计算出边界框实际位置和大小:
b_x = \sigma(t_x) + c_x \\ b_y = \sigma(t_y) + c_y \\ b_w = p_we^{t_w} \\ b_h = p_he^{t_h}bx=σ(tx)+cxby=σ(ty)+cybw=pwetwbh=pheth
其中c_x, c_ycx,cy代表对应cell的左上角坐标,p_w, p_hpw,ph代表先验框的宽高,值是相对于特征图大小的。在这里我们记特征图的大小为(W, H)。则我们可以算出anchor相对于整个特征图的位置:
b_x = (\sigma(t_x) + c_x) / W \\ b_y = (\sigma(t_y) + c_y) / H \\ b_w = (p_we^{t_w}) / W \\ b_h = (p_he^{t_h}) / Wbx=(σ(tx)+cx)/Wby=(σ(ty)+cy)/Hbw=(pwetw)/Wbh=(pheth)/W
如果再将上面的4个值分别乘以原图片的宽度和长度就可以得到边界框的最终位置和大小了。
YOLOv2的输入图片大小是416 x 416,经过32倍下采样得到的feature map大小为13 x 13,该大小的特征图对于检测大物体够了,**但是对于检测小物体还需要更精细一点的特征图(Fine-Grained Features)。**YOLOv2提出了一种passthrough层来利用更精细的特征图,具体地是利用最后一层池化前的输入特征图,该Fine-Grained Features大小为26 x 26 x 512,passthrough层抽取前面层的每个2 x 2的局部区域,然后将其转化为channel维度。具体做法如下图所示:
经过passthrough层,26 x 26 x 512的特征就变为13 x 13 x2048的特征,再与后面的13 x 13 x 1024拼接成13 x 13 x 3072的特征图,然后在此基础上做卷积预测。
另外,作者在后期的实现中借鉴了ResNet网络,不是直接对高分辨特征图处理,而是增加了一个中间卷积层,先采用64个1 x 1卷积核进行卷积,然后再进行passthrough处理,这样26 x 26 x 512的特征图得到13 x 13 x 256的特征图。这算是实现上的一个小细节。使用Fine-Grained Features之后YOLOv2的性能有1%的提升。
由于YOLOv2模型中只有卷积层和池化层,所以YOLOv2的输入可以不限于 416 x 416 大小的图片。为了增强模型的鲁棒性,YOLOv2采用了多尺度输入训练策略,具体来说就是在训练过程中每间隔一定的iterations之后改变模型的输入图片大小。由于YOLOv2的下采样总步长为32,输入图片大小选择一系列为32倍数的值:**{320, 352,…, 608} **,输入图片最小为320 x 320 ,此时对应的特征图大小为 10 x 10,而输入图片最大为 608 x 608 ,对应的特征图大小为 19 x 19 。在训练过程,每隔10个iterations随机选择一种输入图片大小,然后只需要修改对最后检测层的处理就可以重新训练。采用Multi-Scale Training策略,YOLOv2可以适应不同大小的图片,并且预测出很好的结果。
关于loss:
和YOLOv1一样,对于训练图片中的ground truth,若其中心点落在某个cell内,那么该cell内的5个先验框所对应的边界框负责预测它,具体是哪个边界框预测它,需要在训练中确定,即由那个与ground truth的IOU最大的边界框预测它,而剩余的4个边界框不与该ground truth匹配。YOLOv2同样需要假定每个cell至多含有一个grounth truth,而在实际上基本不会出现多于1个的情况。与ground truth匹配的先验框计算坐标误差、置信度误差(此时target为1)以及分类误差,而其它的边界框只计算置信度误差(此时target为0)。YOLOv2和YOLOv1的损失函数一样,为均方差函数。
我们来一点点解释,首先W, H分别指的是特征图(13 x 13)的宽与高,而 A 指的是先验框数目(这里是5),各个 \lambdaλ 值是各个loss部分的权重系数。
第一项loss是计算background的置信度误差,需要计算所有预测框,对每个预测框计算它和所有ground truth的IOU值,并且取最大的IOU值记为Max_IOU,如果该值小于一定的阈值(YOLOv2使用的是0.6),那么这个预测框就标记为background,需要计算noobj的置信度误差。
第二项是计算先验框与预测框的坐标误差,但是只在前12800个iterations间计算,这里是所有的预测框都要参与计算。
第三大项计算与某个ground truth匹配的预测框各部分loss值,包括坐标误差、置信度误差以及分类误差。先说一下匹配原则,对于某个ground truth,**首先要确定其中心点要落在哪个cell上,然后计算这个cell的5个先验框与ground truth的IOU值,IOU值最大的那个先验框与ground truth匹配,对应的预测框用来预测这个ground truth。**在计算obj置信度时,target=1,但与YOLOv1一样而增加了一个控制参数rescore,当其为1时,target取预测框与ground truth的真实IOU值(cfg文件中默认采用这种方式)。对于那些没有与ground truth匹配的先验框(与预测框对应),除去那些Max_IOU低于阈值的,其它的就全部忽略,不计算任何误差。
在80类的COCO数据集中,物体的类别都是比较抽象的,例如类别‘dog’并没有精确到具体狗的品种(哈士奇或者柯基等)。而ImageNet中包含的类别则更具体,不仅包含‘dog’类,还包括‘poodle’和‘Corgi’类。我们将COCO数据集的狗的图片放到训练好的ImageNet模型中理论上是能判断出狗的品种的,同理我们将ImageNet中的狗的图片(不管是贵宾犬,还是柯基犬)放任在COCO训练好的检测模型中,理论上是能够检测出来的。但是生硬的使用两个模型是非常愚蠢且低效的。YOLO9000的提出便是巧妙地利用了COCO数据集提供的检测标签和ImageNet强大的分类标签,使得训练出来的模型具有强大的检测和分类的能力。
暂略
YOLOv3没有太多的创新,主要是借鉴一些好的方案融合到YOLO里面。不过效果还是不错的,在保持速度优势的前提下,提升了预测精度,尤其是加强了对小物体的识别能力。
图片输入网络,进行多尺度检测。