YoloV1

论文地址

https://arxiv.org/pdf/1506.02640.pdf

论文思想

YOLO把目标检测看作一个回归问题,直接用一个网络进行分类和框回归。
具体做法是:将image划分为SS个网格,每个网格预测B个bbox的位置yolo算法原理 - 图1、置信度(confidence为交并比)、类别概率。输出维度为SS(B5+C),C为类别数。无论网格中包含多少个boxes,每个网格只预测一组类概率。测试时,将条件类概率和预测框的置信度乘起来,表示每个box包含某类物体的置信度,这个分数可以将box中的类别可能性和预测精确度同时表示出来。

网络架构

image.png
网络模型受到GoogleNet的激发设计的,但是没有使用inception模块。而是交替使用1x1和3x3卷积层。卷积层负责提取图像特征,全连接层负责类别预测和框参数回归。整个网络共有24个卷积层和2个全连接层。再Fast Yolo中是9个卷积层,没个卷积层使用个数更少的卷积器。其他参数与Yolo一样。

网络架构源码

  1. net = tf.pad(images, np.array([[0, 0], [3, 3], [3, 3], [0, 0]]),name='pad_1')
  2. net = slim.conv2d(net, 64, 7, 2, padding='VALID', scope='conv_2')
  3. net = slim.max_pool2d(net, 2, padding='SAME', scope='pool_3')
  4. net = slim.conv2d(net, 192, 3, scope='conv_4')
  5. net = slim.max_pool2d(net, 2, padding='SAME', scope='pool_5')
  6. net = slim.conv2d(net, 128, 1, scope='conv_6')
  7. net = slim.conv2d(net, 256, 3, scope='conv_7')
  8. net = slim.conv2d(net, 256, 1, scope='conv_8')
  9. net = slim.conv2d(net, 512, 3, scope='conv_9')
  10. net = slim.max_pool2d(net, 2, padding='SAME', scope='pool_10')
  11. net = slim.conv2d(net, 256, 1, scope='conv_11')
  12. net = slim.conv2d(net, 512, 3, scope='conv_12')
  13. net = slim.conv2d(net, 256, 1, scope='conv_13')
  14. net = slim.conv2d(net, 512, 3, scope='conv_14')
  15. net = slim.conv2d(net, 256, 1, scope='conv_15')
  16. net = slim.conv2d(net, 512, 3, scope='conv_16')
  17. net = slim.conv2d(net, 256, 1, scope='conv_17')
  18. net = slim.conv2d(net, 512, 3, scope='conv_18')
  19. net = slim.conv2d(net, 512, 1, scope='conv_19')
  20. net = slim.conv2d(net, 1024, 3, scope='conv_20')
  21. net = slim.max_pool2d(net, 2, padding='SAME', scope='pool_21')
  22. net = slim.conv2d(net, 512, 1, scope='conv_22')
  23. net = slim.conv2d(net, 1024, 3, scope='conv_23')
  24. net = slim.conv2d(net, 512, 1, scope='conv_24')
  25. net = slim.conv2d(net, 1024, 3, scope='conv_25')
  26. net = slim.conv2d(net, 1024, 3, scope='conv_26')
  27. net = tf.pad(net, np.array([[0, 0], [1, 1], [1, 1], [0, 0]]),name='pad_27')
  28. net = slim.conv2d(net, 1024, 3, 2, padding='VALID', scope='conv_28')
  29. net = slim.conv2d(net, 1024, 3, scope='conv_29')
  30. net = slim.conv2d(net, 1024, 3, scope='conv_30')
  31. net = tf.transpose(net, [0, 3, 1, 2], name='trans_31')
  32. net = slim.flatten(net, scope='flat_32')
  33. net = slim.fully_connected(net, 512, scope='fc_33')
  34. net = slim.fully_connected(net, 4096, scope='fc_34')
  35. net = slim.dropout(net, keep_prob=keep_prob, is_training=is_training,scope='dropout_35')
  36. net = slim.fully_connected(net, num_outputs, activation_fn=None, scope='fc_36')

目标损失函数

image.png
对输出采用平方和进行优化,因为它更容易操作,但是:
(1)它认为定位误差和分类误差的权重相等,而每个图像中许多网格不包含任何物体,这会使得这些网格的置信度为0从而压倒那些包含物体的网格的梯度,导致模型不稳定。为了解决这个问题,我们提高框回归预测的损失,降低那些不含物体的boxes的损失,使用2个参数调节,其中 yolo算法原理 - 图4,yolo算法原理 - 图5
(2)它认为大boxes和小boxes的loss也有同样的权重,在我们的网格设计中,很明显大boxes的loss比小boxes的loss重要的多。为了解决这个问题,预测边界框的时候,不是直接使用宽/高,而是使用宽/高的平方根。
每个网格可以预测到多个bounding boxes,训练时指定一个和真值有最高IoU的box,来负责预测这个目标,这会使每个predictor在预测特定大小、长宽比、对象类别方面做的更好。
损失函数定义为(预测框中心位置x,y损失 + 预测框宽高w,h损失 + 置信度confidence损失 + 分类损失):
并不是网络的所有输出都要计算loss:

  • 有物体中心落入的cell,需要计算分类损失,
  • 两个predictor都要计算置信度损失,
  • 预测的bounding box与groud truth IOU较大的那个predictor需要计算xywh损失。
  • 最关键的部分,没有物体中心落入的cell,只需要计算置信度(confidence)损失。

yolo算法原理 - 图6

损失函数计算源码

  1. # class_loss
  2. class_delta = response * (predict_classes - classes)
  3. class_loss = tf.reduce_mean(
  4. tf.reduce_sum(tf.square(class_delta), axis=[1, 2, 3]),
  5. name='class_loss') * self.class_scale
  6. # object_loss
  7. object_delta = object_mask * (predict_scales - iou_predict_truth)
  8. object_loss = tf.reduce_mean(
  9. tf.reduce_sum(tf.square(object_delta), axis=[1, 2, 3]),
  10. name='object_loss') * self.object_scale
  11. # noobject_loss
  12. noobject_delta = noobject_mask * predict_scales
  13. noobject_loss = tf.reduce_mean(
  14. tf.reduce_sum(tf.square(noobject_delta), axis=[1, 2, 3]),
  15. name='noobject_loss') * self.noobject_scale
  16. # coord_loss
  17. coord_mask = tf.expand_dims(object_mask, 4)
  18. boxes_delta = coord_mask * (predict_boxes - boxes_tran)
  19. coord_loss = tf.reduce_mean(
  20. tf.reduce_sum(tf.square(boxes_delta), axis=[1, 2, 3, 4]),
  21. name='coord_loss') * self.coord_scale

超参数设定

batch_size = 64,momentum = 0.9,weight decay = 0.0005
first epochs,learning rate从0.001慢慢增加到0.01,如果从高的学习率开始,可能会由于梯度不稳定,导致模型diverges。再用0.01的learning rate训练75个迭代,再用0.001训练30个迭代,再用0.0001训练30个迭代。
为了防止过拟合,采用dropout和数据增强,dropout比例为0.5

Yolo-V1优缺点

YOLO1优点

(1)速度快。因为我们把它看作一个回归问题,而不需要复杂的pipeline,测试时,只需要把新图像放入神经网络中运行即可。它可以达到实时的效果,mAP也更高。
(2)对图像有全局的理解。不像是基于滑动窗口和region proposal的技术,YOLO会隐式地编码目标所属类别及其外观的上下文信息,而Fast RCNN不能看到更大的上下文信息。YOLO用整个图像的特征去预测每个bounding box,同时预测图像中所有类别的bounding box,也就是说,对图像有着全局的理解。
(3)对目标的学习更具有一般性。
(4)精确度高且能快速定位图像中的目标和位置,即使是很小的目标。
(5)网格单元的设计方案,可以减轻对同一对象多次检测的问题。
(6)提供了更少的bounding boxes,每个图像仅98个,而selective search大约2000个。
(7)将这些单独的组件组合成一个单一的联合优化的模型。
(8)YOLO是一个更通用的检测器,可以同时检测多种物体。

YOLO1缺点

(1)由于每个网格只预测2个bounding boxes,这限制了模型可以预测的物体的数量
(2)多次使用下采样,所以预测模型边界框使用的是相对粗糙的特征