目标检测学习总结之YOLO

YOLOv1
  1. 输入信息预处理(将输入图片resize为,这样相比较之前的的图片保证了更多的输入信息)
  2. 模型预测(只运行一个CNN,one-stage,速度更快)
  3. 对预测结果进行限制(NMS,非最大值抑制)

补充对NMS的解释:NMS,Non Maximum Suppression,非最大值抑制。NMS的作用是保证预测阶段输出框没有重合,其实现流程如下:

  1. 先找出预测结果中所有不重合的类别
  2. 针对每种类别进行如下操作:
    1. 找出当前类别对应的所有的box信息;
    2. 按照confidence进行降序排序;
    3. 依次计算序列的头与后面所有元素的IOU值,去掉IOU值大于一定阈值的box(就是将IOU值大于阈值的box的confidence置为0,在去掉这些confidence为0的box)
      具体代码实现如下:假设二维数据image_pred_class是经过confidence排序后的box信息(每一行代表box的具体信息,而且前面已经筛选过一次保证这些box都是含有object的)
idx = image_pred_class.size(0)
for i in range(idx):
    try:
        ious = bbox_iou(image_pred_class[i].unsuqeeze(0), image_pred_class[i+1:])
    catch IndexError:  # image_pred_class[i]可能返回IndexError
        break
    catch ValueError:  #image_pred_class[i+1:]可能返回空值而导致ValueError
    iou_mask = (ious < nms_conf).float().unsqueeze(1)
    image_pred_class[i+1:] *= iou_mask
    non_zero_ind = torch.nonzero(image_pred_class[:, 4].squeeze())
    image_pred_class = image_pred_class[non_zero_ind].view(-1, 7) 

  v1的模型设计借鉴了Inceptionv1,整个模型由24个卷积层和2个全连接层组成。输入是448*448的图片,输出是的tensor。表示原图像的信息被划分成个区域,每个grid负责原图像中这样一块区域的预测。预测信息体现在grid对应的tensor的第2个维度上(从第0维度开始),也就是这样一个一维向量。表示该grid要生成个预测框,每个预测框包含5个信息(框的中心坐标x、y,框的宽和高w、h,框中存在object的置信度confidence),测表示该grid的object的类别(C是一个向量,是类别one-hot后的形式)。训练中的细节有:

  1. 利用ImageNet的训练模型的前20层(加上一个平均池化层和全连接层),再固定这20层卷积层,后接4个卷积层,2个全连接层,并对这新加的6层进行fine-tuning;
  2. 将输入图片精度有提高到;
  3. 将框的宽和高按照图片的size进行归一化,将框的中心点坐标的零点定在其所在grid的左上角;
  4. 除了最后一层用线性激活函数,其它层均用leaky ReLU。

  YOLO v1的关键在于loss function的设计(毕竟一个模型棒不棒,loss的设计是要占很大比例的)。作者选择用sum-squared error,因为它很容易优化,但是有几个问题:一是将定位误差和分类误差等同是不合理的(在不同误差前面加上权重,增加定位误差重要性,降低分类误差重要性。毕竟要先定位准确,然后再谈分类);二是预测极度不平衡,一张图片中绝大部分的grid都是不包含object,此时不包含object的grid对loss的影响会远大于包含object的grid对loss的影响,因此可能会导致一些object没有检测到(因为模型为了降低loss肯定会优先考虑对loss影响更大的部分,导致很多grid会被预测为没有object,也许这其中有1、2个grid是有object的,此时的解决自然还是加权重);三是如果单纯用表示定位误差中宽高造成的loss会导致小的box预测不准确。因为大的box对loss的影响更大,模型更加专注于大的box的w和h的回归,从而疏忽了对小的box的优化(解决办法是对w和h开方后再计算定位误差,也就是,可稍微降低大的box对loss的影响)。YOLO v1的loss function完整公式如下:\begin{align} loss= & \lambda_{coord}\sum_{i=0}^{S^2}\sum_{j=0}^B[(x_i-\hat{x}_i)^2+(y_i-\hat{y}_i)^2] \\ & +\lambda_{coord}\sum_{i=0}^{S^2}\sum_{j=0}^{B}1_{ij}^{obj}[(w_i-\hat{w}_i)^2+(h_i-\hat{h}_i)^2] \\ & +\sum_{i=0}^{S^2}\sum_{j=0}^{B}1_{ij}^{obj}(C_i-\hat{C}_i)^2 \\ & +\lambda_{noobj}\sum_{i=0}^{S^2}\sum_{j=0}^{B}1_{ij}^{noobj}(C_i-\hat{C}_i)^2 \\ & +\sum_{i=0}^{S^2}1_i^{obj}\sum_{C \in classes}(p_i(C)-\hat{p}_i(C))^2 \end{align}其中权重关系是。第1、2项是定位误差,,第3、4项是置信误差,置信度,每次前向运算结束后对一个grid对应的2个box计算IOU值并判断用哪个box来参与loss的计算,同时我们注意到负样本grid的置信误差权重是最小的,前面已经分析了要抑制这部分的loss,不然会影响召回率,第5项是分类误差。YOLO v1的缺点如下:

  1. 检测和定位精度不高(毕竟每个grid才预测2个box)
  2. 对小物体的召回不好
YOLO v2

  针对于YOLO v1的不足,v2着重于改善recall和localization。一是借鉴了Faster RCNN中的anchor box机制。YOLO v1中每个grid只是预测2个box,然后利用反向传播让box的中心和宽高不断偏向ground truth。而v2则是定好一些anchor box,然后模型预测这些anchor box的中心和宽高的变化,也就是说预测方式由直接预测框的信息改为间接预测框的信息的变化量(预测变化量肯定更好一些,因为变化量的变动更小,模型更易预测且不易崩溃)。而YOLO v2中anchor box的选择也和Faster RCNN不同,Faster RCNN是利用先验设计了9种不同的anchor box,提高召回率的同时也降低了速度,但是YOLO v2则是对训练集中的ground truth进行了kmeans聚类,在精度和速度的调和中确定anchor box的数量和尺寸。
  二是预测的变化。正如上面写的,预测方式由直接预测改为间接预测,所以框的位置信息也做一定的变化,具体为:其中,是模型的直接输出,是对应grid的左上角坐标,是sigmoid函数(预测是相对于grid左上角的偏移,这个偏移必须在0到1之间,不然中心点就偏到其他grid中,因此用sigmoid函数将输出限制到0到1之间),是anchor box的宽高。利用PyTorch实现的代码如下:

# c_x, c_y
grid = np.arange(grid_size)
a, b = np.meshgrid(grid, grid)
x_offset = torch.FloatTensor(a).view[-1, 1]
y_offset = torch.FloatTensor(b).view[-1, 1]
# x_y_offset维度是[1, grid_size * grid_size * num_anchors, 2]
x_y_offset = torch.cat((x_offset, y_offset), 1).repeat(1, num_anchors).view(-1, 2).unsqueeze(0)  
# p_w, p_h
# 下面代码中右边的anchors的维度是[num_anchors],左边的anchors的维度是[1, grid_size * grid_size * num_anchors, 1]
anchors = anchors.repeat(grid_size * grid_size, 1).unsqueeze(0)

YOLO v2其他的改进还有:

  1. 自己基于VGG重新设计了网络的卷积部分(Darknet-19),加入了BN层,大量使用的卷积核,每次经过pooling层后就利用的卷积核加深channel维度(pooling层会造成信息丢失,因此需要利用卷积核提取更多的特征,保证模型的准确性),再利用的卷积核减少channel维度(对特征进行融合,并控制着模型中数据的维度变化)。下面截取了Dartnet-19的部分网络层表示
  2. 提出了一种联合训练机制(WordTree),利用分类数据学习分类,利用检测数据学习box、confidence和分类。论文中WordTree示意图如下:
    YOLOv2-WordTree.png

    个人感觉这种结构和word2vec中的分层softmax很像,分层softmax构建的霍夫曼树是二叉的,而这里WordTree是多叉的。个人认为这种结构增加了模型预测的鲁棒性,因为如果直接对,比如说一千个类,进行softmax预测,有些类别对应的样本可能比较少而导致预测也不够准确,但是如果像WordTree这样对每张图片进行重新labeling,那么每个图片就有好几个类别,而每个类别也会对应更多的样本,这样对比较少见的图片进行分类预测时,即使不能准确预测其具体类别,也可以很好地预测其所属大类。
    TODO:还不太清楚WordTree是如何利用Wordnet来构建的,等后续看了YOLO的源码再来填坑。

YOLO v3

改进之处:

  1. 新设计了用于特征提取的卷积网络部分(Darknet-53),加入了残差结构;
  2. 多标签分类预测,其实就是将最后输出层的softmax激活函数改为sigmoid激活函数;
  3. 多尺度预测,借鉴了SSD的多尺度特征图的预测机制,利用3个不同尺度的特征图来预测(为了更好地检测小的box)。

YOLO v3网络结构图如下:
YOLOv3网络结构图.png

你可能感兴趣的:(目标检测学习总结之YOLO)