淘先锋技术网

首页 1 2 3 4 5 6 7

思想和特点

之前的目标检测算法均需要多个步骤实现目标的分类和定位。如RCNN系列,首先需要进行region proposal,RCNN到Faster RCNN模块逐步将其他任务整合到网络,最终将region proposal也用网络来实现,但是仍然是分步骤实现的。分步骤实现的缺点是实现复杂,运行速度慢。

YOLO的核心思想就是利用整张图作为网络的输入,直接在输出层回归bounding box的位置和bounding box所属的类别。

而YOLO采用回归的方法将定位,分类等步骤统一到了一个网络,比之前RCNN系列的网络简洁。YOLO最突出的特点速度飞快,能够达到实时的效果。

网络结构分析

首先放一张论文YOLO-v1原图

下面的序号 1.   2.   3.   ⋯ 1.\ 2.\ 3.\ \cdots 1. 2. 3. 表示总层数, C 1 ,   C 2 , ⋯ C1,\ C2, \cdots C1, C2,表示第几个卷积层, 64 @ 7 × 7 × 3 64@7\times7\times3 64@7×7×3表示有64个这样的卷积核,没有写出参数默认 s t r i d e = 1 stride=1 stride=1,卷积层 p a d = f i l t e r S i z e − 1 2 pad = \frac {filterSize - 1}{2} pad=2filterSize1

  1. INPUT: i m a g e = 448 × 448 × 3 image=448\times448\times3 image=448×448×3

  2. C1: i n p u t = 448 × 448 × 3 , f i l t e r s = 64 @ 7 × 7 × 3 , s t r i d e = 2 , p a d = 3 → L e a k y   R e L U , o u t p u t = 224 × 224 × 64 input=448\times448\times3, filters=64@7\times7\times3, stride=2, pad=3 \rightarrow Leaky\ ReLU, output=224\times224\times64 input=448×448×3,filters=64@7×7×3,stride=2,pad=3Leaky ReLU,output=224×224×64

  3. MAX_POOl1: i n p u t = 224 × 224 × 64 , w i n d o w = 2 × 2 , s t r i d e = 2 , o u t p u t = 112 × 112 × 64 input=224 \times 224 \times 64, window=2 \times 2, stride=2,output=112 \times 112 \times 64 input=224×224×64,window=2×2,stride=2output=112×112×64

  4. C2: i n p u t = 112 × 112 × 64 , f i l t e r s = 192 @ 3 × 3 × 64 → L e a k y   R e L U , o u t p u t = 112 × 112 × 192 input=112 \times 112 \times 64, filters=192@3 \times 3 \times 64 \rightarrow Leaky\ ReLU,output=112 \times 112 \times 192 input=112×112×64,filters=192@3×3×64Leaky ReLUoutput=112×112×192

  5. MAX_POOL2: i n p u t = 112 × 112 × 192 , w i n d o w = 2 × 2 , s t r i d e = 2 , o u t p u t = 56 × 56 × 192 input=112 \times 112 \times 192, window=2 \times 2, stride=2,output=56 \times 56 \times 192 input=112×112×192,window=2×2,stride=2output=56×56×192

  6. C3: i n p u t = 56 × 56 × 192 , f i l t e r s = 128 @ 1 × 1 × 192 → L e a k y   R e L U , o u t p u t = 56 × 56 × 128 input=56 \times 56 \times 192, filters=128@1 \times 1 \times 192 \rightarrow Leaky\ ReLU, output=56 \times 56 \times 128 input=56×56×192,filters=128@1×1×192Leaky ReLU,output=56×56×128

  7. C4: i n p u t = 56 × 56 × 128 , f i l t e r s = 256 @ 3 × 3 × 128 → L e a k y   R e L U , o u t p u t = 56 × 56 × 256 input=56 \times 56 \times 128, filters=256@3\times3\times128 \rightarrow Leaky\ ReLU, output=56\times56\times256 input=56×56×128,filters=256@3×3×128Leaky ReLU,output=56×56×256

  8. C5: i n p u t = 56 × 56 × 256 , f i l t e r s = 256 @ 1 × 1 × 256 → L e a k y   R e L U , o u t p u t = 56 × 56 × 256 input=56\times56\times256, filters=256@1\times1\times256\rightarrow Leaky\ ReLU,output=56\times 56\times256 input=56×56×256,filters=256@1×1×256Leaky ReLU,output=56×56×256

  9. C6: i n p u t = 56 × 56 × 256 , f i l t e r s = 512 @ 3 × 3 × 256 → L e a k y   R e L U , o u t p u t = 56 × 56 × 512 input=56\times 56\times 256, filters=512@3\times3\times256\rightarrow Leaky\ ReLU, output=56\times 56\times512 input=56×56×256,filters=512@3×3×256Leaky ReLU,output=56×56×512

  10. MAX_POOL3: i n p u t = 56 × 56 × 512 , w i n d o w = 2 × 2 , s t r i d e = 2 , o u t p u t = 28 × 28 × 512 input= 56 \times 56 \times 512, window=2 \times 2, stride=2, output=28 \times 28 \times 512 input=56×56×512,window=2×2,stride=2,output=28×28×512

  11. C7: i n p u t = 28 × 28 × 512 , f i l t e r s = 256 @ 1 × 1 × 512 → L e a k y   R e L U , o u t p u t = 28 × 28 × 256 input=28\times28\times512,filters=256@1\times1\times512 \rightarrow Leaky\ ReLU, output=28\times28\times256 input=28×28×512,filters=256@1×1×512Leaky ReLU,output=28×28×256

  12. C8: i n p u t = 28 × 28 × 256 , f i l t e r s = 512 @ 3 × 3 × 256 → L e a k y   R e L U , o u t p u t = 28 × 28 × 512 input=28\times28\times256,filters=512@3\times3\times256 \rightarrow Leaky\ ReLU, output=28\times28\times512 input=28×28×256,filters=512@3×3×256Leaky ReLU,output=28×28×512

  13. C9: i n p u t = 28 × 28 × 512 , f i l t e r s = 256 @ 1 × 1 × 512 → L e a k y   R e L U , o u t p u t = 28 × 28 × 256 input=28\times28\times512,filters=256@1\times1\times512 \rightarrow Leaky\ ReLU, output=28\times28\times256 input=28×28×512,filters=256@1×1×512Leaky ReLU,output=28×28×256

  14. C10: i n p u t = 28 × 28 × 256 , f i l t e r s = 512 @ 3 × 3 × 256 → L e a k y   R e L U , o u t p u t = 28 × 28 × 512 input=28\times28\times256,filters=512@3\times3\times256 \rightarrow Leaky\ ReLU, output=28\times28\times512 input=28×28×256,filters=512@3×3×256Leaky ReLU,output=28×28×512

  15. C11: i n p u t = 28 × 28 × 512 , f i l t e r s = 256 @ 1 × 1 × 512 → L e a k y   R e L U , o u t p u t = 28 × 28 × 256 input=28 \times 28 \times 512, filters=256@ 1 \times 1 \times 512 \rightarrow Leaky\ ReLU, output=28 \times 28 \times 256 input=28×28×512,filters=256@1×1×512Leaky ReLU,output=28×28×256

  16. C12: i n p u t = 28 × 28 × 256 , f i l t e r s = 512 @ 3 × 3 × 256 → L e a k y   R e L U , o u t p u t = 28 × 28 × 512 input=28 \times 28 \times 256, filters=512@ 3 \times 3 \times 256 \rightarrow Leaky\ ReLU, output=28 \times 28 \times 512 input=28×28×256,filters=512@3×3×256Leaky ReLU,output=28×28×512

  17. C13: i n p u t = 28 × 28 × 512 , f i l t e r s = 256 @ 1 × 1 × 512 → L e a k y   R e L U , o u t p u t = 28 × 28 × 256 input=28 \times 28 \times 512, filters=256@ 1 \times 1 \times 512 \rightarrow Leaky\ ReLU, output=28 \times 28 \times 256 input=28×28×512,filters=256@1×1×512Leaky ReLU,output=28×28×256

  18. C14: i n p u t = 28 × 28 × 256 , f i l t e r s = 512 @ 3 × 3 × 256 → L e a k y   R e L U , o u t p u t = 28 × 28 × 512 input=28 \times 28 \times 256, filters=512@ 3 \times 3 \times 256 \rightarrow Leaky\ ReLU, output=28 \times 28 \times 512 input=28×28×256,filters=512@3×3×256Leaky ReLU,output=28×28×512

  19. C15: i n p u t = 28 × 28 × 512 , f i l t e r s = 256 @ 1 × 1 × 512 → L e a k y   R e L U , o u t p u t = 28 × 28 × 256 input=28 \times 28 \times 512, filters=256@ 1 \times 1 \times 512 \rightarrow Leaky\ ReLU, output=28 \times 28 \times 256 input=28×28×512,filters=256@1×1×512Leaky ReLU,output=28×28×256

  20. C16: i n p u t = 28 × 28 × 256 , f i l t e r s = 1024 @ 3 × 3 × 256 → L e a k y   R e L U , o u t p u t = 28 × 28 × 1024 input=28 \times 28 \times 256, filters=1024@ 3 \times 3 \times 256 \rightarrow Leaky\ ReLU, output=28 \times 28 \times 1024 input=28×28×256,filters=1024@3×3×256Leaky ReLU,output=28×28×1024

  21. MAX_POOL4: i n p u t = 28 × 28 × 1024 , w i n d o w = 2 × 2 , s t r i d e = 2 , o u t p u t = 14 × 14 × 1024 input= 28 \times 28 \times 1024, window=2 \times 2, stride=2, output=14 \times 14 \times 1024 input=28×28×1024,window=2×2,stride=2,output=14×14×1024

  22. C17: i n p u t = 14 × 14 × 1024 , f i l t e r s = 512 @ 1 × 1 × 1024 → L e a k y   R e L U , o u t p u t = 14 × 14 × 512 input=14 \times 14 \times 1024, filters=512@ 1 \times 1 \times 1024 \rightarrow Leaky\ ReLU, output=14 \times 14 \times 512 input=14×14×1024,filters=512@1×1×1024Leaky ReLU,output=14×14×512

  23. C18: i n p u t = 14 × 14 × 512 , f i l t e r s = 1024 @ 3 × 3 × 512 → L e a k y   R e L U , o u t p u t = 14 × 14 × 1024 input=14 \times 14 \times 512, filters=1024@ 3 \times 3 \times 512 \rightarrow Leaky\ ReLU, output=14 \times 14 \times 1024 input=14×14×512,filters=1024@3×3×512Leaky ReLU,output=14×14×1024

  24. C19: i n p u t = 14 × 14 × 1024 , f i l t e r s = 512 @ 1 × 1 × 1024 → L e a k y   R e L U , o u t p u t = 14 × 14 × 512 input=14 \times 14 \times 1024, filters=512@ 1 \times 1 \times 1024 \rightarrow Leaky\ ReLU, output=14 \times 14 \times 512 input=14×14×1024,filters=512@1×1×1024Leaky ReLU,output=14×14×512

  25. C20: i n p u t = 14 × 14 × 512 , f i l t e r s = 1024 @ 3 × 3 × 512 → L e a k y   R e L U , o u t p u t = 14 × 14 × 1024 input=14 \times 14 \times 512, filters=1024@ 3 \times 3 \times 512 \rightarrow Leaky\ ReLU, output=14 \times 14 \times 1024 input=14×14×512,filters=1024@3×3×512Leaky ReLU,output=14×14×1024

  26. C21: i n p u t = 14 × 14 × 1024 , f i l t e r s = 1024 @ 3 × 3 × 1024 → L e a k y   R e L U , o u t p u t = 14 × 14 × 1024 input=14 \times 14 \times 1024, filters=1024@ 3 \times 3 \times 1024 \rightarrow Leaky\ ReLU, output=14 \times 14 \times 1024 input=14×14×1024,filters=1024@3×3×1024Leaky ReLU,output=14×14×1024

  27. C22: i n p u t = 14 × 14 × 1024 , f i l t e r s = 1024 @ 3 × 3 × 1024 , s t r i d e = 2 → L e a k y   R e L U , o u t p u t = 7 × 7 × 1024 input=14 \times 14 \times 1024, filters=1024@ 3 \times 3 \times 1024, stride=2\rightarrow Leaky\ ReLU, output=7 \times 7 \times 1024 input=14×14×1024,filters=1024@3×3×1024,stride=2Leaky ReLU,output=7×7×1024

  28. C23: i n p u t = 7 × 7 × 1024 , f i l t e r s = 1024 @ 3 × 3 × 1024 → L e a k y   R e L U , o u t p u t = 7 × 7 × 1024 input=7 \times 7 \times 1024, filters=1024@ 3 \times 3 \times 1024 \rightarrow Leaky\ ReLU, output=7 \times 7 \times 1024 input=7×7×1024,filters=1024@3×3×1024Leaky ReLU,output=7×7×1024

  29. C24: i n p u t = 7 × 7 × 1024 , f i l t e r s = 1024 @ 3 × 3 × 1024 → L e a k y   R e L U , o u t p u t = 7 × 7 × 1024 input=7 \times 7 \times 1024, filters=1024@ 3 \times 3 \times 1024 \rightarrow Leaky\ ReLU, output=7 \times 7 \times 1024 input=7×7×1024,filters=1024@3×3×1024Leaky ReLU,output=7×7×1024

  30. FC1: i n p u t = 7 × 7 × 1024 = 50176 , w e i g h t = 512 × 50176 → L e a k y   R e L U , o u t p u t = 512 input = 7 \times 7 \times 1024 = 50176, weight = 512\times 50176 \rightarrow Leaky\ ReLU, output=512 input=7×7×1024=50176,weight=512×50176Leaky ReLU,output=512

  31. FC2: i n p u t = 512 , w e i g h t = 4096 × 512 , d r o p _ p r o b = 0.5 → L e a k y   R e L U , o u t p u t = 4096 input = 512, weight = 4096\times 512, drop\_prob = 0.5 \rightarrow Leaky\ ReLU, output=4096 input=512,weight=4096×512,drop_prob=0.5Leaky ReLU,output=4096

  32. OUTPUT: i n p u t = ? d r o p _ d i m s , o u t p u t = 7 × 7 × 30 input=?drop\_dims, output = 7\times 7 \times 30 input=?drop_dims,output=7×7×30

可以发现,YOLO运用了24个卷积层,4个最大池化层,2个全连接层。 3 × 3 3\times 3 3×3卷积层用于提取特征, 1 × 1 1\times 1 1×1卷积层是为了跨通道信息整合,池化层用于缩小特征图 ( w i d t h , h e i g t ) (width,heigt) width,heigt两个维度,全连接层用于预测物体的位置和类别概率。

另外,YOLO-v1中采用的激活函数是Leaky ReLU,公式如下: ϕ ( x ) = { x ,  if  x > 0 0.1 x ,  otherwise \phi(x)=\begin{cases} x, & \text{ if } x>0\\ 0.1x, & \text{ otherwise} \end{cases} ϕ(x)={x,0.1x, if x>0 otherwise画一下,长这样

import matplotlib.pyplot as plt
import numpy as np

def leaky_relu(x):
    return np.where(x > 0, x, 0.1*x)

x = np.linspace(-10, 10)
plt.plot(x, leaky_relu(x))

在这里插入图片描述

详细分析

网络输出

将输入图像分成 S × S S\times S S×S的格子,一个物体的中心点落在哪个格子,这个格子就负责检测该物体。每个格子有B个Bounding Box(后面称Bbox),每个Bbox有5个值 ( x , y , w i d t h , h e i g h t , c o n f i d e n c e ) (x,y,width,height,confidence) (x,y,width,height,confidence),下面逐一解释这五个值的含义:

  1. ( x , y ) ∈ [ 0 , 1 ] (x, y) \in [0, 1] (x,y)[0,1]表示Bbox中心点相对该格子左上角的坐标(相对于格子高宽归一化之后的坐标);

  2. ( h e i g h t , w i d t h ) ∈ [ 0 , 1 ] (height, width) \in [0, 1] (height,width)[0,1]表示相对于整张图片高宽归一化之后的高宽;

  3. c o n f i d e n c e confidence confidence是置信度,描述了该Bbox含有物体的确信程度和该Bbox包含物体的精准程度,公式为 c o n f i d e n c e = P r ( O b j e c t ) ∗ I O U p r e d t r u t h confidence = Pr(Object)*IOU_{pred}^{truth} confidence=Pr(Object)IOUpredtruth当有物体存在时 P r ( O b j e c t ) = 1 Pr(Object)=1 Pr(Object)=1,此时 c o n f i d e n c e = I O U p r e d t r u t h = p r e d ∩ t r u t h p r e d ∪ t r u t h confidence = IOU_{pred}^{truth}= \frac {pred\cap truth}{pred\cup truth} confidence=IOUpredtruth=predtruthpredtruth,即预测框和真实框的重合比例;当没有物体时 P r ( O b j e c t ) = 0 Pr(Object)=0 Pr(Object)=0,即 c o n f i d e n c e = 0 confidence = 0 confidence=0

每一个框还要预测C个类别出现在该格子中的条件概率 P r ( C l a s s i ∣ O b j e c t ) Pr(Class_i|Object) Pr(ClassiObject),并且一个格子只负责预测一个物体而不是B个。

现在让我们来统计一下一张图片经过网络最终的输出有哪些。首先有 S × S S\times S S×S个格子,每个格子有B个Bounding Box,每个Bounding Box包含上述 ( x , y , w i d t h , h e i g h t , c o n f i d e n c e ) (x,y,width,height,confidence) (x,y,width,height,confidence)这样5个参数,在加上每个格子包含C个含有物体的条件概率,所以总共输出为 S × S × ( B × 5 + C ) S\times S \times (B\times 5 + C) S×S×(B×5+C)。论文中 S = 7 , B = 2 , C = 20 S=7,B=2,C=20 S=7,B=2,C=20,所以输出是一个 7 × 7 × ( 2 × 5 + 20 ) = 7 × 7 × 30 7\times 7 \times (2\times 5 + 20) = 7\times 7 \times 30 7×7×(2×5+20)=7×7×30的张量。

训练

训练过程

  1. 预训练。使用 ImageNet 1000 类数据训练YOLO网络的前20个卷积层+1个average池化层+1个全连接层。训练图像分辨率resize到224x224。
  2. 用步骤1.得到的前20个卷积层网络参数来初始化YOLO模型前20个卷积层的网络参数,然后用 VOC 20 类标注数据进行YOLO模型训练。检测通常需要有细密纹理的视觉信息,所以为提高图像精度,在训练检测模型时,将输入图像分辨率从224 × 224 resize到448x448。

损失函数

训练主要围绕损失函数展开讨论,下面是损失函数

l o s s = λ c o o r d ∑ i = 0 S 2 ∑ j = 0 B 1 i j o b j [ ( x i − x ^ i ) 2 + y i − y ^ i ) 2 ] + λ c o o r d ∑ i = 0 S 2 ∑ j = 0 B 1 i j o b j [ ( w i − w ^ i ) 2 + h i − h ^ i ) 2 ] + ∑ i = 0 S 2 ∑ j = 0 B 1 i j o b j ( C i − C ^ i ) 2 + λ n o o b j ∑ i = 0 S 2 ∑ j = 0 B 1 i j n o o b j ( C i − C ^ i ) 2 + ∑ i = 0 S 2 1 i o b j ∑ c ∈ c l a s s e s ( p i ( c ) − p ^ i ( c ) ) 2 \begin{aligned} loss &= \lambda_{coord}\sum_{i=0}^{S^2}\sum_{j=0}^B \mathbb{1}_{ij}^{obj}\left [(x_i - \hat{x}_i)^2 + y_i - \hat{y}_i)^2\right ]\\ &+ \lambda_{coord}\sum_{i=0}^{S^2}\sum_{j=0}^B \mathbb{1}_{ij}^{obj}\left [(\sqrt{w_i} - \sqrt{\hat{w}_i})^2 + \sqrt{h_i} - \sqrt{\hat{h}_i})^2\right ] \\ &+ \sum_{i=0}^{S^2}\sum_{j=0}^B \mathbb{1}_{ij}^{obj}(C_i -\hat{C}_i)^2\\ &+ \lambda_{noobj}\sum_{i=0}^{S^2}\sum_{j=0}^B \mathbb{1}_{ij}^{noobj}(C_i -\hat{C}_i)^2\\ &+ \sum_{i=0}^{S^2}\mathbb{1}_{i}^{obj} \sum_{c \in classes}(p_i(c)-\hat{p}_i(c))^2 \end{aligned} loss=λcoordi=0S2j=0B1ijobj[xix^i2+yiy^i2]+λcoordi=0S2j=0B1ijobj[wi w^i 2+hi h^i 2]+i=0S2j=0B1ijobj(CiC^i)2+λnoobji=0S2j=0B1ijnoobj(CiC^i)2+i=0S21iobjcclasses(pi(c)p^i(c))2

为了便于分析,下面将损失函数各部分解释标注在图上

  • 损失函数采用的是误差平方和的形式,这样便于优化,主要由三部分组成:坐标,置信度,类别。所以YOLO能够用一个网络同时进行定位和识别。

  • ① YOLO-v1使用误差平方和作为损失函数,但是直接把定位误差平方和与分类误差平方等权值相加显然不合理,同时还考虑到在很多的格子里根本没有物体,这将导致没有物体的这些格子的置信度分数为0,这将会压制包含对象的单元格的梯度,这将导致在训练前期容易发散。为了修正这两个问题我们在定位误差项前面乘以 λ c o o r d = 5 \lambda_{coord}=5 λcoord=5,在没有物体的置信度误差项前面乘以系数 λ n o o b j = 0.5 \lambda_{noobj}=0.5 λnoobj=0.5

  • ② 为什么要在 w i d t h , h e i g h t width,height width,height上加根号?原文是想反映大的Bbox中的小偏差比小Bbox中小。画个图可以解释:

x = np.linspace(0,5)
plt.plot(x,x)
plt.plot(x,np.sqrt(x))

在这里插入图片描述
从加根号可以看出,在 w i d t h , h e i g h t width,height width,height较大时,根号具有缓解增长的作用。

  • 1 i j o b j \mathbb{1}_{ij}^{obj} 1ijobj i i i个格子的第 j j j个Bbox有负责的Object, 所以坐标惩罚项实际惩罚的是有物体的那些Bbox,如果该Bbox没有负责某一个物体,则该部分损失值为0。

  • 1 i j n o o b j \mathbb{1}_{ij}^{noobj} 1ijnoobj表示第 i i i个格子的第 j j j个Bbox没有负责的Object, 在置信度惩罚项中我们对有没有物体的Bbox都要惩罚,但是没有物体的项乘以了系数 λ n o o b j \lambda_{noobj} λnoobj来降低它的权重。

  • 1 i o b j \mathbb{1}_{i}^{obj} 1iobj表示第 i i i个格子中有Object,这个时候需要分别计算属于各个类的概率。

其他细节

  • 在训练时采用的是小批迭代动量梯度下降。动量mc=0.9,衰减率是0.0005。学习速率在需要各个阶段动态调整,如果在初期迭代学习率过高将导致梯度不稳定而发散。

  • 为了防止过拟合,仍然采用了dropout正则化技术(第一个全连接层后面,drop_prob=0.5)和数据增强(尺度缩放,图像变换,调节曝光度和饱和度等)。

预测

经过网络,输出是 7 × 7 × 30 7\times 7\times 30 7×7×30,其中 30 = ( x , y , w i d t h , h e i g h t , c o n f i d e n c e ) × 2 + 20 个 类 别 的 条 件 概 率 30 = (x, y, width, height, confidence)\times2 + 20个类别的条件概率 30=(x,y,width,height,confidence)×2+20

For c i c_i ci in C:

  1. c i c_i ci的98个bbox按置信度分数降序排列。
  2. 选择 c i c_i ci预测框中置信度最大(排序后为第一个)的那个bbox然后挨个计算其与剩余bbox的IOU,如果IOU值大于一定阈值(如0.5),则重合度过高,就将该类别置信度值置为0。
  3. 重复2.直到处理完 c i c_i ci的所有检测框。