YOLO,你想知道的都在这


英文原文

推荐CSDN学院课程: YOLOv3目标检测:原理与源码解析


YOLO 的前世今生

YOLOv1

  1. 最早的YOLO,一个grid cell 预测B个bounding boxes 和一组 概率,每个bouding box又预测了四个坐标值和一个confidence。因此最终有 S × S × ( B ∗ 5 + C ) S\times S\times (B*5+C) S×S×(B5+C).重点在,一个格子只会预测一组conditional class probabilities.
  2. 最早的YOLO并不是FCN而是有2层全连接层
  3. 最早的YOLO,anchor boxes没有应用。
  4. 回归的损失乘以0.5权重(5 × \times × 回归框损失),1 × \times × 分类损失,1 × \times × 有物体的confidence损失,0.5 × \times × 没有物体时候的confidence损失,1 × \times × 类别的条件概率损失.

YOlOv1的损失函数

在这里插入图片描述

  1. 只用了传统的 dropout(也要缩放矫正)数据增强,记得矫正GT框防止过拟合

在这里插入图片描述
这里是引用
在这里插入图片描述

  1. 数据增强包括,随机剪裁,旋转,HSV变换shift等
  2. 激活用 Leaky ReLu
  3. YOLOv1在 定位Recall 上表现差!
  4. yolo 224 × 224 224\times224 224×224 训练,用224*2输入,想通过分辨率大的图片提升获取更清晰的特征。

YOLOv2

  • 加入了BN层,加速收敛。减少权重初始化的依赖。防止过拟合舍弃dropout。

  • 不同于上面的8, v2用416*416输入大小,为了让feature map 有个中心网格!比如13*13
    在这里插入图片描述

  • 不同与上面的1,这次,每个anchor box都要预测一组条件类别概率!因此也就是 S × S × B ∗ ( 5 + C ) S\times S\times B*(5+C) S×S×B(5+C)

  • 抛弃全连接层,使用全卷积层FCN

  • 使用了5个Anchor Boxes机制,mAP降低了0.3%,但是recall上升了7%.

在这里插入图片描述

  • 有创造性的是用 K-means算法自动得到anchor box, 不用手动hand-pick. 纵轴为平均IOU
    在这里插入图片描述
  • K-means的距离选择不是欧氏距离,而是1-IOU。因为大的box, 明显会产生较大的误差。例如: ( 100 − 95 ) 2 = 25 , ( 1 − 0.95 ) 2 = 0.0 5 2 (100-95)^2 =25, (1-0.95)^2=0.05^2 (10095)2=25,(10.95)2=0.052
    在这里插入图片描述

这里是引用自传送门
在这里插入图片描述

  • 多尺度训练!每10batches改变输入的大小,由于网络downsample的factor是32,为了方便,就用32的倍数,范围为(320,608)=(10,19)*32
  • 大部分目标检测网络基于VGG16。虽然准确,但是运算量大: 30.69 billions。YOLO基于GoogleNet架构。准确率低了2%,运算量只有 8.52 billions。YOLO2最终模型基础为Darkent-19(19层卷积层)。
    在这里插入图片描述
  • 然后YOLO900论文中有意思的是,Jointly Training!综合检测数据集(框回归,分类),分类数据集(只有类别标签)训练,对应不同的损失部分。分类数据集只考虑分类的损失。

YOLOv3

这里是引用

  • 分类用多标签的独立逻辑斯特回归,损失函数为二分类交叉熵函数 Binary CrossEntropy
  • 这次用三个尺度一共9个anchor boxes!

这里是引用

  • 新的特征提取网络Darkent-53!
    这里没有maxpooling池化层,因为只需要进行卷积就可以实现下采样了,而且不会丢失空间的信息
    在这里插入图片描述
  • 还是比较优秀的。计算量比ResNet大一些。

在这里插入图片描述

  • 成果,虽然RetinaNet各方面领先,但是训练时长要3.8倍于Yolov3。
    在这里插入图片描述

一些指标参数介绍,引用自传送门这里是引用

正负样本是什么?

这里是引用
在这里插入图片描述

YOLOv3 全部都是卷积层,舍弃了全连接层,那么如何转换的呢:

FCN

如下图,上面 是带有全连接层的神经网络,我们需要的预测的是4个类别的概率。

同理我们也可以用 卷积 神经网络 构成一样的结构。

只要通过一个和前一层被卷积张量一样大小的kernel size,就行了。

下图是 5 ×   5 × 16 5 \times\ 5 \times16 5× 5×16输入张量和400 个 5 × 5 × 16 5 \times 5 \times16 5×5×16卷积体卷积后得到 1 × 1 × 400 1\times1\times400 1×1×400张量,也就是和上图的400神经元的全连接层等价。

在这里插入图片描述

卷积stride某种程度上等价于滑动窗口

  1. 以往的滑动窗口目标检测,就是选择一个框大小,然后在原图上从左到右从上到下,一次次滑动,然后得到一次次预测。

  2. 每一次滑动就有一个预测向量(车,人,树…)。我们可以通过预测向量中最大的概率对应的框作为预测框。

滑动框的缺点:

  • 这种方法问题在于你的滑动框定死了
  • 第二个问题: 框之间重复计算了

重复计算,诶? 因此自然而然想到用卷积来操作,因为本身就和卷积操作相似了。

  • 举例
    下图第三行,等价于用第一行的 14 × 14 × 3 14\times14\times3 14×14×3窗口,滑动得到的预测图。
    换句话说,某输入张量矩阵 经过多层卷积层后,得到一个多维的输出张量矩阵。这个输出矩阵,可以看做是对每一个输入张量矩阵中的相同滑动框大小,不同位置的预测值!
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

物体标签框的中心坐标,落在哪个格子里,哪个就负责预测这个物体!

  1. 作为FCN,YOLOv3本是可以改变输入大小的
    无视图片大小。但是,实际上,由于各种问题,我们可能希望保持不变的输入大小,而这些问题只会在实现算法时浮出水面。

  2. Feature map通过最后一层 1 × 1 1\times1 1×1 卷积后得到 Prediction Map(预测图)
    Prediction Map 每一个Cell 预测了固定数目的回归框。

  3. Depth-wise, we have ( B x (4+1 + C) ) entries in the feature map:
    深度方向上,最后的feature map 有 ( B x (5 +C) ) 个元素,每个BOX有5+C个预测值
    在这里插入图片描述

( o b j e c t n e n e s S c o r e + C l a s s e s P r o b a b i l i t y + t x + t y + t w + t h ) ∗ B o u d i n g B o x e s ( objectnenesScore+ClassesProbability+ t_x +t_ y +t_ w +t_h )* BoudingBoxes (objectnenesScore+ClassesProbability+tx+ty+tw+th)BoudingBoxes
o b j e c t n e n e s   S c o r e = c o n f i d e n c e = P ( o b j e c t ) ∗ I O U P r e d T r u t h objectnenes \space Score = confidence =P(object)*IOU_{Pred}^{Truth} objectnenes Score=confidence=P(object)IOUPredTruth

举例如下:

下图大小为13 x 13

标签框中心 落在(7,7),因此这个cell负责预测狗,这个尺度上(13*13尺度)可以预测3个Bouding box。

实际上,yolo有三个尺度图的预测,下图只是一个13*13大小的如同格子一样的预测图,每个预测图的每个格子预测了不同大小的三个框。

检测大尺度(13,13)中尺度 (26,26)检测小尺度(52,52)
小一点的三个固定框10,13, 16,30, 33,23,中等的三个固定框 30,61, 62,45, 59,119,大的三个固定框 116,90, 156,198, 373,326

在这里插入图片描述
总结一下!
我们找到了哪个格子负责预测我们的物体,但是框的大小怎么预测??


Anchor预测

为啥用anchor?

传送门
借用Andrew的动图:

如何一个网格预测多个物体?

在这里插入图片描述
蓝色花括号代表着Anchors,如果里面有目标,则希望对应的部分,objectiveness score=1
在这里插入图片描述

预测边界框的宽度和高度可能是有意义的,但在实践中,这会导致在训练过程中出现不稳定的梯度。相反,大多数现代object detector预测log_space transformation ,或者简单地偏移到预定义的默认包围框(称为锚)。

Then, these transforms are applied to the anchor boxes to obtain the prediction.
YOLO v3 has three anchors, which result in prediction of three bounding boxes per cell.

负责检测狗的框将是和标签框具有最大IOUAnchor框

请再看图:
在这里插入图片描述
这里的
t x , t y , t w , t h t_x ,t_y, t_w, t_h tx,ty,tw,th

这四个坐标并不是最终(绘制)的坐标,而是相对中心的偏离scale坐标!
bx, by, bw, bh are the x,y center co-ordinates, width and height of our prediction. tx, ty, tw, th is what the network outputs. cx and cy are the top-left co-ordinates of the grid. pw and ph are anchors dimensions for the box.
在这里插入图片描述

在这里插入图片描述

bx, by, bw, bh are the x,y center co-ordinates, width and height of our prediction.
注意:
这个 b w , b h b_w,b_h bw,bh是相对于feature map大小的=归一化比例=,比如你的 b w , b h b_w,b_h bw,bh ( 0.3 , 0.8 ) (0.3,0.8) (0.3,0.8),那么你的实际预测框的大小为 ( 13 × 0.3 , 13 × 0.8 ) (13\times0.3,13\times0.8) (13×0.3,13×0.8)

  • 那么为什么要用sigmoid函数?
    使得预测的cell不会偏离中心cell
    the output is passed through a sigmoid function, which squashes the output in a range from 0 to 1, effectively keeping the center in the grid which is predicting.

Objectness Score

学习过后,中心的红框子的概率基本为1,周围的各自概率接近1,边缘的格子为0

Class Confidences

在yolov3之前使用softmax预测类别概率,但是导致的问题就是,如果目标属于某一类,它就不能属于另一类。这在Woman和Person这种分类情况下就不使用。因此就是用sigmoid来预测。

YOLOv3的损失函数

这里是引用
在这里插入图片描述
在这里插入图片描述
YOLOv1是softmax后进行平方差损失
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

跨尺度预测

三个预测尺度:
412 × 412 412\times412 412×412大小的图片输入

检测大尺度(13,13)中尺度 (26,26)检测小尺度(52,52)
32168
在这里插入图片描述

跨尺度说明产生了很多预测框(10647个框),怎么筛选到最终的1个框
3 × ( 13 × 13 ) + 3 × ( 26 × 26 ) + 3 × ( 52 × 52 ) = 10647 3\times(13\times13)+3\times(26\times26)+3\times(52\times52)=10647 3×(13×13)+3×(26×26)+3×(52×52)=10647

  • 通过上面的objectness score,框具有低于阈值的score直接排除忽视掉。
  • NMS非极大值抑制

网络结构图,concatenate目的是把前面的位置信息和后面的语义信息融合这里是引用
在这里插入图片描述
在这里插入图片描述

权重初始化,weight initialization

这里是引用
在这里插入图片描述
在这里插入图片描述

C实现解析

过程

预测和训练
在这里插入图片描述
在这里插入图片描述

cfg文件

这里是引用
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Pytorch 实现

如何计算IOU?

def bbox_iou(box1, box2):
    """
    Returns the IoU of two bounding boxes  
    """
    #Get the coordinates of bounding boxes
    b1_x1, b1_y1, b1_x2, b1_y2 = box1[:,0], box1[:,1], box1[:,2], box1[:,3]
    b2_x1, b2_y1, b2_x2, b2_y2 = box2[:,0], box2[:,1], box2[:,2], box2[:,3]
    
    #get the corrdinates of the intersection rectangle
    inter_rect_x1 =  torch.max(b1_x1, b2_x1)
    inter_rect_y1 =  torch.max(b1_y1, b2_y1)
    inter_rect_x2 =  torch.min(b1_x2, b2_x2)
    inter_rect_y2 =  torch.min(b1_y2, b2_y2)
    
    #Intersection area
    inter_area = torch.clamp(inter_rect_x2 - inter_rect_x1 + 1, min=0) * torch.clamp(inter_rect_y2 - inter_rect_y1 + 1, min=0)
 
    #Union Area
    b1_area = (b1_x2 - b1_x1 + 1)*(b1_y2 - b1_y1 + 1)
    b2_area = (b2_x2 - b2_x1 + 1)*(b2_y2 - b2_y1 + 1)
    
    iou = inter_area / (b1_area + b2_area - inter_area)
    
    return iou

layer     filters    size              input                output
   0 conv     32  3 x 3 / 1   416 x 416 x   3   ->   416 x 416 x  32 0.299 BF
   1 conv     64  3 x 3 / 2   416 x 416 x  32   ->   208 x 208 x  64 1.595 BF
   2 conv     32  1 x 1 / 1   208 x 208 x  64   ->   208 x 208 x  32 0.177 BF
   3 conv     64  3 x 3 / 1   208 x 208 x  32   ->   208 x 208 x  64 1.595 BF
   4 Shortcut Layer: 1
   5 conv    128  3 x 3 / 2   208 x 208 x  64   ->   104 x 104 x 128 1.595 BF
   6 conv     64  1 x 1 / 1   104 x 104 x 128   ->   104 x 104 x  64 0.177 BF
   7 conv    128  3 x 3 / 1   104 x 104 x  64   ->   104 x 104 x 128 1.595 BF
   8 Shortcut Layer: 5
   9 conv     64  1 x 1 / 1   104 x 104 x 128   ->   104 x 104 x  64 0.177 BF
  10 conv    128  3 x 3 / 1   104 x 104 x  64   ->   104 x 104 x 128 1.595 BF
  11 Shortcut Layer: 8
  12 conv    256  3 x 3 / 2   104 x 104 x 128   ->    52 x  52 x 256 1.595 BF
  13 conv    128  1 x 1 / 1    52 x  52 x 256   ->    52 x  52 x 128 0.177 BF
  14 conv    256  3 x 3 / 1    52 x  52 x 128   ->    52 x  52 x 256 1.595 BF
  15 Shortcut Layer: 12
  16 conv    128  1 x 1 / 1    52 x  52 x 256   ->    52 x  52 x 128 0.177 BF
  17 conv    256  3 x 3 / 1    52 x  52 x 128   ->    52 x  52 x 256 1.595 BF
  18 Shortcut Layer: 15
  19 conv    128  1 x 1 / 1    52 x  52 x 256   ->    52 x  52 x 128 0.177 BF
  20 conv    256  3 x 3 / 1    52 x  52 x 128   ->    52 x  52 x 256 1.595 BF
  21 Shortcut Layer: 18
  22 conv    128  1 x 1 / 1    52 x  52 x 256   ->    52 x  52 x 128 0.177 BF
  23 conv    256  3 x 3 / 1    52 x  52 x 128   ->    52 x  52 x 256 1.595 BF
  24 Shortcut Layer: 21
  25 conv    128  1 x 1 / 1    52 x  52 x 256   ->    52 x  52 x 128 0.177 BF
  26 conv    256  3 x 3 / 1    52 x  52 x 128   ->    52 x  52 x 256 1.595 BF
  27 Shortcut Layer: 24
  28 conv    128  1 x 1 / 1    52 x  52 x 256   ->    52 x  52 x 128 0.177 BF
  29 conv    256  3 x 3 / 1    52 x  52 x 128   ->    52 x  52 x 256 1.595 BF
  30 Shortcut Layer: 27
  31 conv    128  1 x 1 / 1    52 x  52 x 256   ->    52 x  52 x 128 0.177 BF
  32 conv    256  3 x 3 / 1    52 x  52 x 128   ->    52 x  52 x 256 1.595 BF
  33 Shortcut Layer: 30
  34 conv    128  1 x 1 / 1    52 x  52 x 256   ->    52 x  52 x 128 0.177 BF
  35 conv    256  3 x 3 / 1    52 x  52 x 128   ->    52 x  52 x 256 1.595 BF
  36 Shortcut Layer: 33
  37 conv    512  3 x 3 / 2    52 x  52 x 256   ->    26 x  26 x 512 1.595 BF
  38 conv    256  1 x 1 / 1    26 x  26 x 512   ->    26 x  26 x 256 0.177 BF
  39 conv    512  3 x 3 / 1    26 x  26 x 256   ->    26 x  26 x 512 1.595 BF
  40 Shortcut Layer: 37
  41 conv    256  1 x 1 / 1    26 x  26 x 512   ->    26 x  26 x 256 0.177 BF
  42 conv    512  3 x 3 / 1    26 x  26 x 256   ->    26 x  26 x 512 1.595 BF
  43 Shortcut Layer: 40
  44 conv    256  1 x 1 / 1    26 x  26 x 512   ->    26 x  26 x 256 0.177 BF
  45 conv    512  3 x 3 / 1    26 x  26 x 256   ->    26 x  26 x 512 1.595 BF
  46 Shortcut Layer: 43
  47 conv    256  1 x 1 / 1    26 x  26 x 512   ->    26 x  26 x 256 0.177 BF
  48 conv    512  3 x 3 / 1    26 x  26 x 256   ->    26 x  26 x 512 1.595 BF
  49 Shortcut Layer: 46
  50 conv    256  1 x 1 / 1    26 x  26 x 512   ->    26 x  26 x 256 0.177 BF
  51 conv    512  3 x 3 / 1    26 x  26 x 256   ->    26 x  26 x 512 1.595 BF
  52 Shortcut Layer: 49
  53 conv    256  1 x 1 / 1    26 x  26 x 512   ->    26 x  26 x 256 0.177 BF
  54 conv    512  3 x 3 / 1    26 x  26 x 256   ->    26 x  26 x 512 1.595 BF
  55 Shortcut Layer: 52
  56 conv    256  1 x 1 / 1    26 x  26 x 512   ->    26 x  26 x 256 0.177 BF
  57 conv    512  3 x 3 / 1    26 x  26 x 256   ->    26 x  26 x 512 1.595 BF
  58 Shortcut Layer: 55
  59 conv    256  1 x 1 / 1    26 x  26 x 512   ->    26 x  26 x 256 0.177 BF
  60 conv    512  3 x 3 / 1    26 x  26 x 256   ->    26 x  26 x 512 1.595 BF
  61 Shortcut Layer: 58
  62 conv   1024  3 x 3 / 2    26 x  26 x 512   ->    13 x  13 x1024 1.595 BF
  63 conv    512  1 x 1 / 1    13 x  13 x1024   ->    13 x  13 x 512 0.177 BF
  64 conv   1024  3 x 3 / 1    13 x  13 x 512   ->    13 x  13 x1024 1.595 BF
  65 Shortcut Layer: 62
  66 conv    512  1 x 1 / 1    13 x  13 x1024   ->    13 x  13 x 512 0.177 BF
  67 conv   1024  3 x 3 / 1    13 x  13 x 512   ->    13 x  13 x1024 1.595 BF
  68 Shortcut Layer: 65
  69 conv    512  1 x 1 / 1    13 x  13 x1024   ->    13 x  13 x 512 0.177 BF
  70 conv   1024  3 x 3 / 1    13 x  13 x 512   ->    13 x  13 x1024 1.595 BF
  71 Shortcut Layer: 68
  72 conv    512  1 x 1 / 1    13 x  13 x1024   ->    13 x  13 x 512 0.177 BF
  73 conv   1024  3 x 3 / 1    13 x  13 x 512   ->    13 x  13 x1024 1.595 BF
  74 Shortcut Layer: 71
  75 conv    512  1 x 1 / 1    13 x  13 x1024   ->    13 x  13 x 512 0.177 BF
  76 conv   1024  3 x 3 / 1    13 x  13 x 512   ->    13 x  13 x1024 1.595 BF
  77 conv    512  1 x 1 / 1    13 x  13 x1024   ->    13 x  13 x 512 0.177 BF
  78 conv   1024  3 x 3 / 1    13 x  13 x 512   ->    13 x  13 x1024 1.595 BF
  79 conv    512  1 x 1 / 1    13 x  13 x1024   ->    13 x  13 x 512 0.177 BF
  80 conv   1024  3 x 3 / 1    13 x  13 x 512   ->    13 x  13 x1024 1.595 BF
  81 conv     18  1 x 1 / 1    13 x  13 x1024   ->    13 x  13 x  18 0.006 BF
  82 yolo
  83 route  79
  84 conv    256  1 x 1 / 1    13 x  13 x 512   ->    13 x  13 x 256 0.044 BF
  85 upsample            2x    13 x  13 x 256   ->    26 x  26 x 256
  86 route  85 61
  87 conv    256  1 x 1 / 1    26 x  26 x 768   ->    26 x  26 x 256 0.266 BF
  88 conv    512  3 x 3 / 1    26 x  26 x 256   ->    26 x  26 x 512 1.595 BF
  89 conv    256  1 x 1 / 1    26 x  26 x 512   ->    26 x  26 x 256 0.177 BF
  90 conv    512  3 x 3 / 1    26 x  26 x 256   ->    26 x  26 x 512 1.595 BF
  91 conv    256  1 x 1 / 1    26 x  26 x 512   ->    26 x  26 x 256 0.177 BF
  92 conv    512  3 x 3 / 1    26 x  26 x 256   ->    26 x  26 x 512 1.595 BF
  93 conv     18  1 x 1 / 1    26 x  26 x 512   ->    26 x  26 x  18 0.012 BF
  94 yolo
  95 route  91
  96 conv    128  1 x 1 / 1    26 x  26 x 256   ->    26 x  26 x 128 0.044 BF
  97 upsample            2x    26 x  26 x 128   ->    52 x  52 x 128
  98 route  97 36
  99 conv    128  1 x 1 / 1    52 x  52 x 384   ->    52 x  52 x 128 0.266 BF
 100 conv    256  3 x 3 / 1    52 x  52 x 128   ->    52 x  52 x 256 1.595 BF
 101 conv    128  1 x 1 / 1    52 x  52 x 256   ->    52 x  52 x 128 0.177 BF
 102 conv    256  3 x 3 / 1    52 x  52 x 128   ->    52 x  52 x 256 1.595 BF
 103 conv    128  1 x 1 / 1    52 x  52 x 256   ->    52 x  52 x 128 0.177 BF
 104 conv    256  3 x 3 / 1    52 x  52 x 128   ->    52 x  52 x 256 1.595 BF
 105 conv     18  1 x 1 / 1    52 x  52 x 256   ->    52 x  52 x  18 0.025 BF
 106 yolo

train.py

  1. 混合精度训练
mixed_precision = True
try:  # Mixed precision training https://github.com/NVIDIA/apex
    from apex import amp
except:
    print('Apex recommended for faster mixed precision training: https://github.com/NVIDIA/apex')
    mixed_precision = False  # not installed

xyxy <==> xywh 坐标转换

def xyxy2xywh(x):
    # Convert nx4 boxes from [x1, y1, x2, y2] to [x, y, w, h] where xy1=top-left, xy2=bottom-right
    # xy1是左上角, xy2是右下角
    y = torch.zeros_like(x) if isinstance(x, torch.Tensor) else np.zeros_like(x)
    y[:, 0] = (x[:, 0] + x[:, 2]) / 2  # x center 
    y[:, 1] = (x[:, 1] + x[:, 3]) / 2  # y center
    y[:, 2] = x[:, 2] - x[:, 0]  # width
    y[:, 3] = x[:, 3] - x[:, 1]  # height
    return y

def xywh2xyxy(x):
    # Convert nx4 boxes from [x, y, w, h] to [x1, y1, x2, y2] where xy1=top-left, xy2=bottom-right
    y = torch.zeros_like(x) if isinstance(x, torch.Tensor) else np.zeros_like(x)
    y[:, 0] = x[:, 0] - x[:, 2] / 2  # top left x
    y[:, 1] = x[:, 1] - x[:, 3] / 2  # top left y
    y[:, 2] = x[:, 0] + x[:, 2] / 2  # bottom right x
    y[:, 3] = x[:, 1] + x[:, 3] / 2  # bottom right y
    return y

图片变换后的框坐标

  1. clip_boards 用来使得坐标在矩形内
  2. 图中的坐标变换
def clip_coords(boxes, img_shape):
    # Clip bounding xyxy bounding boxes to image shape (height, width)
    boxes[:, 0].clamp_(0, img_shape[1])  # x1
    boxes[:, 1].clamp_(0, img_shape[0])  # y1
    boxes[:, 2].clamp_(0, img_shape[1])  # x2
    boxes[:, 3].clamp_(0, img_shape[0])  # y2

def scale_coords(img1_shape, coords, img0_shape, ratio_pad=None):
    # Rescale coords (xyxy) from img1_shape to img0_shape
    if ratio_pad is None:  # calculate from img0_shape
        gain = max(img1_shape) / max(img0_shape)  # gain  = old / new
        pad = (img1_shape[1] - img0_shape[1] * gain) / 2, (img1_shape[0] - img0_shape[0] * gain) / 2  # wh padding
    else:
        gain = ratio_pad[0][0]
        pad = ratio_pad[1]

    coords[:, [0, 2]] -= pad[0]  # x padding
    coords[:, [1, 3]] -= pad[1]  # y padding
    coords[:, :4] /= gain
    clip_coords(coords, img0_shape)
    return coords

mAP

  1. 已知 tp, confidence, pred_cls, target_cls
  2. np.argsort() 返回对数组排序(递增)的索引
  3. np.unique()函数去除其中重复的元素,并排序后返回

YOLOv4

对比yolov3
v4基本上一种技巧上的优化
基本的原理没有太大变化

区别1:

backbone提取特征网络由原来的darknet53改为CSPDarknet53

在这里插入图片描述

  • 首先可以看到是激活函数变化leaky relu -》 mish
    在这里插入图片描述

在这里插入图片描述

  • 然后是残差块resblock_body修改为csp

在原来的block重复组件中添加残差链接

在这里插入图片描述

import torch
import torch.nn.functional as F
import torch.nn as nn
import math
from collections import OrderedDict

#-------------------------------------------------#
#   MISH激活函数
#-------------------------------------------------#
class Mish(nn.Module):
    def __init__(self):
        super(Mish, self).__init__()

    def forward(self, x):
        return x * torch.tanh(F.softplus(x))

#-------------------------------------------------#
#   卷积块
#   CONV+BATCHNORM+MISH
#-------------------------------------------------#
class BasicConv(nn.Module):
    def __init__(self, in_channels, out_channels, kernel_size, stride=1):
        super(BasicConv, self).__init__()

        self.conv = nn.Conv2d(in_channels, out_channels, kernel_size, stride, kernel_size//2, bias=False)
        self.bn = nn.BatchNorm2d(out_channels)
        self.activation = Mish()

    def forward(self, x):
        x = self.conv(x)
        x = self.bn(x)
        x = self.activation(x)
        return x

#---------------------------------------------------#
#   CSPdarknet的结构块的组成部分
#   内部堆叠的残差块
#---------------------------------------------------#
class Resblock(nn.Module):
    def __init__(self, channels, hidden_channels=None, residual_activation=nn.Identity()):
        super(Resblock, self).__init__()

        if hidden_channels is None:
            hidden_channels = channels

        self.block = nn.Sequential(
            BasicConv(channels, hidden_channels, 1),
            BasicConv(hidden_channels, channels, 3)
        )

    def forward(self, x):
        return x+self.block(x)

#---------------------------------------------------#
#   CSPdarknet的结构块
#   存在一个大残差边
#   这个大残差边绕过了很多的残差结构
#---------------------------------------------------#
class Resblock_body(nn.Module):
    def __init__(self, in_channels, out_channels, num_blocks, first):
        super(Resblock_body, self).__init__()

        self.downsample_conv = BasicConv(in_channels, out_channels, 3, stride=2)

        if first:
            self.split_conv0 = BasicConv(out_channels, out_channels, 1)
            self.split_conv1 = BasicConv(out_channels, out_channels, 1)  
            self.blocks_conv = nn.Sequential(
                Resblock(channels=out_channels, hidden_channels=out_channels//2),
                BasicConv(out_channels, out_channels, 1)
            )
            self.concat_conv = BasicConv(out_channels*2, out_channels, 1)
        else:
            self.split_conv0 = BasicConv(out_channels, out_channels//2, 1)
            self.split_conv1 = BasicConv(out_channels, out_channels//2, 1)

            self.blocks_conv = nn.Sequential(
                *[Resblock(out_channels//2) for _ in range(num_blocks)],
                BasicConv(out_channels//2, out_channels//2, 1)
            )
            self.concat_conv = BasicConv(out_channels, out_channels, 1)

    def forward(self, x):
        x = self.downsample_conv(x)

        x0 = self.split_conv0(x)

        x1 = self.split_conv1(x)
        x1 = self.blocks_conv(x1)

        x = torch.cat([x1, x0], dim=1)
        x = self.concat_conv(x)

        return x

class CSPDarkNet(nn.Module):
    def __init__(self, layers):
        super(CSPDarkNet, self).__init__()
        self.inplanes = 32
        self.conv1 = BasicConv(3, self.inplanes, kernel_size=3, stride=1)
        self.feature_channels = [64, 128, 256, 512, 1024]

        self.stages = nn.ModuleList([
            Resblock_body(self.inplanes, self.feature_channels[0], layers[0], first=True),
            Resblock_body(self.feature_channels[0], self.feature_channels[1], layers[1], first=False),
            Resblock_body(self.feature_channels[1], self.feature_channels[2], layers[2], first=False),
            Resblock_body(self.feature_channels[2], self.feature_channels[3], layers[3], first=False),
            Resblock_body(self.feature_channels[3], self.feature_channels[4], layers[4], first=False)
        ])

        self.num_features = 1
        # 进行权值初始化
        for m in self.modules():
            if isinstance(m, nn.Conv2d):
                n = m.kernel_size[0] * m.kernel_size[1] * m.out_channels
                m.weight.data.normal_(0, math.sqrt(2. / n))
            elif isinstance(m, nn.BatchNorm2d):
                m.weight.data.fill_(1)
                m.bias.data.zero_()


    def forward(self, x):
        x = self.conv1(x)

        x = self.stages[0](x)
        x = self.stages[1](x)
        out3 = self.stages[2](x)
        out4 = self.stages[3](out3)
        out5 = self.stages[4](out4)

        return out3, out4, out5

def darknet53(pretrained, **kwargs):
    model = CSPDarkNet([1, 2, 8, 8, 4])
    if pretrained:
        if isinstance(pretrained, str):
            model.load_state_dict(torch.load(pretrained))
        else:
            raise Exception("darknet request a pretrained path. got [{}]".format(pretrained))
    return model

  • 增加了mosaic等数据增强方法
    在这里插入图片描述
  • 标签平滑label smoothing

这里是引用
Smoothing平滑就是将标签进行一个平滑,原始的标签是0、1,在平滑后变成0.005(如果是二分类)、0.995,也就是说对分类准确做了一点惩罚,让模型不可以分类的太准确,太准确容易过拟合。

  • CIOU

IoU是比值的概念,对目标物体的scale是不敏感的。然而常用的BBox的回归损失优化和IoU优化不是完全等价的,寻常的IoU无法直接优化没有重叠的部分。
于是有人提出直接使用IOU作为回归优化loss,CIOU是其中非常优秀的一种想法。
CIOU将目标与anchor之间的距离,重叠率、尺度以及惩罚项都考虑进去,使得目标框回归变得更加稳定,不会像IoU和GIoU一样出现训练过程中发散等问题。而惩罚因子把预测框长宽比拟合目标框的长宽比考虑进去。

这里是引用

  • 学习率余弦退火

未完待续。。。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

万物琴弦光锥之外

给个0.1,恭喜老板发财

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值