yolo系列论文看过,源码包调过,抽点时间把论文理解和源码做个一一对应,加深理解,论文
1 |
|
yolov3 network
darknet53一共53层卷积,除去最后一个FC总共52个卷积用于当做主体网络,主体网络被分成三个stage,结构类似FPN,1-26层卷积为stage1,27-43层卷积为stage2,44-52层卷积为stage3,低层卷积(26)感受野更小,负责检测小目标,深层卷积(52)感受野大,容易检测出大目标,整体网络的graph如下
边框预测
$$
b_x = \rho(t_x)+c_x
\ b_y = \rho(t_y)+c_y
\ b_w = p_we^t_w
\ b_h = p_he^t_h
$$
预测的中心坐标是相对于左上角的一个0-1之间的一个值,$p_w, p_h$是anchor的高宽,在anchor的基础上乘以一个比例。
loss
$\lambda {coord} \sum{i=0}^{s^2} \sum_{j=0}^{B} \pmb {1}_{ij}^{obj} [(x_i- \hat x_i)^2 + (y_i -\hat {y_i})^2]$+
$\lambda {coord} \sum{i=0}^{s^2} \sum_{j=0}^{B} \pmb {1}_{ij}^{obj} [(\sqrt{w_i}- \sqrt{\hat w_i)^2} + (\sqrt {h_i} - \sqrt{\hat {h_i}})^2]$+
$\sum_{i=0}^{s^2} \sum_{j=0}^{B} \pmb {1}_{ij}^{obj} (C_i- \hat C_i)^2 + \lambda_{coord}\sum_{i=0}^{s^2} \sum_{j=0}^{B} \pmb {1}_{ij}^{noobj} (C_i- \hat C_i)^2$+
$\sum_i^{s2} \pmb {1}i^{obj} \sum{c} (p_i(c)-\hat{p}_i(c))^2$
整体思路为:每个cell的每个anchor和label做loss,根据label会有一个mask,中心点,scale有物体的cell,anchor才有loss,其他位置被0mask值忽略,每个cell,anchor有没有物体的置信度都都被用来做loss,有物体的cell才会做分类loss,依次对应上面的数学公式;针对某个cell,某个类被预测,则为1,该cell如果有物体,那这个位置肯定为1
如果某个cell的某个anchor不负责检测某个ground truth,那只有置信度的loss,位置,高宽,分类loss全部没有
anchors
1 | anchors = [[10, 13, 16, 30, 33, 23], [30, 61, 62, 45, 59, 119], [116, 90, 156, 198, 373, 326]], |
这个应该是相对于416的宽和高,相对于416,320,608训练的时候是等比例调整得,同样等比例调整了的应该还有label值
yolov3的anchor和faster-rcnn的 anchor有如下区别
- yolov3的anchor是聚类生成的,faster-rcnn是三个尺度,单个大小固定生成的
- 预测的时候yolov3多坐标是相对于目标像素左上角的,faster-rcnn是相对于全图的
- yolov3是三个尺度每个尺度分配3个anchor,faster-rcnn是每个像素分配9个anchor
yolov3与yolov2的区别
一个区别是v3采用fpn的多尺度,增加检测的准确性,另一个是分类网络没有使用soft而是针对每个类别做一个二分类,20类的pascal voc就有20个二分类器
yolov3 summary
1 | layer filters size input output |
YOLOOutputV3
从tip卷积套件relu输出开始,到推理的reshape成detection结束。
针对最后一个尺度:
卷积输出24=(1+4+3)3,3是类别,4代表一个box,1代表是否有物体,最后的3=6/2,anchor两个一组,一组分别代表高和宽。
yolo3.py->YOLOOutputV3->123行->
pred->24x169 (1+4+3)x3x13x13<-->(置信度+坐标+类别)xanchor数量x高x宽
pred->169x3x8 列代表特征位置,横代表anchor的index,通道分别是置信度,位置,类别
raw_box_centers->169x3x2 每个格子,每个anchor相对的中心点
raw_box_scales->169x3x2 每个格子,每个anchor的伸缩比例
objness->169x3x1 每个格子,每个anchor的置信度
class_pred->169x3x3 每个格子,每个anchor的类别概率
box_centers->169x3x2 每个格子,每个anchor对应box相对原图的中心点,加了offset
box_scales->169x3x2 每个格子,每个anchor对应box相对原图高宽,它由raw_box_scales先按元素计算以 e(2.71)为底的幂,再和anchor相乘
class_score->169x3x3 每个格子,每个anchor每个类别的得分乘以置信度,分类与置信度联合做loss
bbox->169x3x4 每个格子,每个anchor对应box的坐标,左上角,右下角
offsets->169x1x2 ,每个网格相对偏移,x(0->12),y(0->12),每个网格中心点加上其左上角的相对位置偏移,再乘以stride(32),坐标中心从相对变为绝对
anchor->[[116,90],[156,198],[373,326]],每个anchor的比例,最后一个尺度(13-->13)的三个anchor,相对于定义,anchor被颠倒,高纬用于检测大物体,yolo3定义的三组anchors:1
如果是训练,返回```bbox(1,507,4),raw_box_centers(1x169x3x2),raw_box_scales(1x169x3x2),bojness(1x169x3x1),clas_pred(1x169x3),anchor(1x1x3x2),offset(1x169x1x2)
针对其他两个尺度
针对其他两个尺度分别返回1
```bbox(1,8112,4),raw_box_centers(1x2704x3x2),raw_box_scales(1x2704x3x2),bojness(1x2704x3x1),clas_pred(1x2704x3),anchor(1x1x3x2),offset(1x2704x1x2)
训练的时候前向计算的1
```all_box_centers,(1x507x2) con (1x2028x2) con (1x8112x1)->(1x10647x2)
1 | ```all_class_pred (1x507x3) con (1x2028x3) con (1x8112x3)->(1x10647x3) |
与构造好的label做loss更新参数,所有的cell长宽以及anchor数量糅合到一维
YOLODetectionBlockV3
接在特征提取后面,介于特征提取和输出pred之间,用作特征转换,降维等,源码在yolo3.py,类名YOLODetectionBlockV3,每一个stage之后都接一个YOLODetectionBlock,channel设置为[512,256,128],所以每个YOLODetectionBlock最后输出的通道数依次减少,[512,1024,512,1024,512,1024],[256,512,256,512,256,512], [128,256,128,256,128,256],每一组一个6个卷积,最后一个卷积的输出(tip)进入output用于检测,第5个卷积的输出进入transitions层后和对应的stage concate后进入下一个YOLODetectionBlockV3。
<img src=”/Users/alpha/Documents/pic/yolodetectionblock.png”, width=”400px”, height=”200px”/>
YOLODetectionBlockV3之间transition,就一个卷积,卷积后分别在特征图高和宽的维度各做一次repeat使得上采样,然后做一次slice_like使得YOLODetectionBlockV3的输出和route的一模一样以便concate