目录
1 网络结构
1.1 整体网络结构参考
yolov5 6.0版本 参考
https://blog.csdn.net/qq_37541097/article/details/123594351
1.2 backbone C3结构
可以看出yolov5- 5.0后面的版本主干主要由CSP模块变成了C3模块,yolov5-5.0之前的版本主干还是和yolov4类似的CSP结果,可参考
YOLOV5网络结构_Laughing-q的博客-CSDN博客_yolov5结构图
CSP和C3区别如下:
之前讲yolov4 yolov4原理_xd_MrCheng的博客-CSDN博客
时CSP结构如下:
一般来说CBM1只起到下采样2倍,真正意义上的CSP结构如下,把CBM1不要(因为CBM1只是为了下采样2倍)
其中CBM结构都是卷积核1x1且步长为1的卷积层
残差模组Resunit则是一个1x1的卷积加一个3x3的卷积,在相加
而C3结构和CSP结构有些不一样,C3结构如下:
其中CBM换成了CBS, 表示激活函数有Mish换成了SiLu
并且相对CSP,C3结构经过残差模组Resunit后少了一个卷积层, 直接连到了Concat,正好只有3个CBS,或者说只有3个卷积,可能才叫C3,并且C3中的残差模组,有的地方也叫BottleNeck1
单纯的C3结构是不会进行下采样的,每次下采样都是C3前面会接一个3x3且步长为2的卷积
1.3 Neck
1.3.1 SPPF
在Neck部分的变化还是相对较大的,首先是将SPP换成成了SPPF(Glenn Jocher自己设计的),两者的作用是一样的,但后者效率更高。SPP结构如下图所示,是将输入并行通过多个不同大小的MaxPool,然后做进一步融合,能在一定程度上解决目标多尺度问题。
SPP结构
SPPF结构
而SPPF
结构是将输入串行通过多个5x5
大小的MaxPool
层,这里需要注意的是串行两个5x5
大小的MaxPool
层是和一个9x9
大小的MaxPool
层计算结果是一样的,串行三个5x5
大小的MaxPool
层是和一个13x13
大小的MaxPool
层计算结果是一样的。
也就说用两个串联的5x5的MaxPool层替代一个9x9的maxPool层,因为两个5x5的串联的池化层效果就是9x9的池化层.
用3个串联的
5x5的MaxPool层替代一个13x13的maxPool层, 以此减小计算时间。二者效果基本是一样的。但计算时间SPPF比SPP减半了
这和用2个3x3的卷积来替代5x5的卷积一样,减小计算量
1.3.2 带C3结构的FPN-PAN
在YOLOv4中,Neck的PFN和PAN
结构是没有引入CSP
结构的,但在YOLOv5中作者在FPN和PAN
结构中加入了C3结构,但注意,Neck中C3中用到的叫bottleneck2, 和backbone中的bottleneck1(即残差模组resunit)是不一样的,bottleneck2没有残差连接,如下图:
Neck中的C3结构:
yolov5-Neck
YoloV5-Neck
1.4 Head
yolov5的head和yolov4,yolov3一样
2 损失函数
参考YOLOv5网络详解_太阳花的小绿豆的博客-CSDN博客_yolov5网络结构详解
3 消除Grid敏感度
继续参考YOLOv5网络详解_太阳花的小绿豆的博客-CSDN博客_yolov5网络结构详解
4 正负样本分配
4.1 匹配正样本(Build Targets)
还是参考 YOLOv5网络详解_太阳花的小绿豆的博客-CSDN博客_yolov5网络结构详解
yolov3是GT中心点G落在那个格子,那个格子对应的Anchor就负责预测这个GT
比如上图,只有A这个格子回去预测GT,那现在由于网络预测目标中心点相对gird cell左上角的偏移调整到了-0.5-1.5,所以只要gird cell左上角点距离GT中心点在(-0.5,1.5)范围内它们对应的Anchor都能回归到GT的位置处,比如C点, 距离GT中心点x方向距离明显<0.5 , y方向的距离明<1.5, 所以C这个单元格满足, 同理B也是, 满足这样就扩充了正样本数量
更详细的介绍,参考【YOLOv5】正样本分配详解_mjiansun的博客-CSDN博客
具体如下:
4.2 正样本采样
Yolov5
算法使用如下3种方式增加正样本个数:
如上图,绿色框是GT,假设中心点为绿色的点G, 红色实线锚框是1这个gird单元格对应的锚框,其中心点为A,也就是1单元格中心那个黑色的点,而网络预测的x,y偏移量其实就是想让虚线 红色实线锚框上下左右平移,使得中心点变为G,即让中心点与GT重合, 如红色虚线锚框(假设红色虚线锚框中心点是G),之前这个平移量范围是0-1之间的,现在变成了-0.5-1.5, 所以2和3这个单元格对应的anchor通过平移也能和GT的中心点重合,(在缩放宽度和高度,就能让anchor和GT完全重合,所以是一个平移+缩放的过程,这里只讨论平移)
debug 代码
上述正样本采样过程在yolov5
通过函数build_targets
实现,为了方便理解上述代码,对每一步进行debug,具体如
def build_targets(self, p, targets):
# Build targets for compute_loss(), input targets(image,class,x,y,w,h)
na, nt = self.na, targets.shape[0] # number of anchors, targets
tcls, tbox, indices, anch = [], [], [], []
gain = torch.ones(7, device=targets.device) # normalized to gridspace gain
## 前置处理
# same as .repeat_interleave(nt)
ai = torch.arange(na, device=targets.device).float().view(na, 1).repeat(1, nt)
targets = torch.cat((targets.repeat(na, 1, 1), ai[:, :, None]), 2) # append anchor indices
g = 0.5 # bias
off = torch.tensor([[0, 0],
[1, 0], [0, 1], [-1, 0], [0, -1], # j,k,l,m
# [1, 1], [1, -1], [-1, 1], [-1, -1], # jk,jm,lk,lm
], device=targets.device).float() * g # offsets
for i in range(self.nl):
## target映射到当前层的尺度
anchors = self.anchors[i]
gain[2:6] = torch.tensor(p[i].shape)[[3, 2, 3, 2]] # xyxy gain
# Match targets to anchors
t = targets * gain
if nt:
# Matches
r = t[:, :, 4:6] / anchors[:, None] # wh ratio
j = torch.max(r, 1 / r).max(2)[0] < self.hyp['anchor_t'] # compare
t = t[j] # filter
# Offsets
gxy = t[:, 2:4] # grid xy
gxi = gain[[2, 3]] - gxy # inverse
j, k = ((gxy % 1 < g) & (gxy > 1)).T
l, m = ((gxi % 1 < g) & (gxi > 1)).T
j = torch.stack((torch.ones_like(j), j, k, l, m))
t = t.repeat((5, 1, 1))[j]
offsets = (torch.zeros_like(gxy)[None] + off[:, None])[j]
else:
t = targets[0]
offsets = 0
# Define
b, c = t[:, :2].long().T # image, class
gxy = t[:, 2:4] # grid xy
gwh = t[:, 4:6] # grid wh
gij = (gxy - offsets).long()
gi, gj = gij.T # grid xy indices
# Append
a = t[:, 6].long() # anchor indices
indices.append((b, a, gj.clamp_(0, gain[3] - 1), gi.clamp_(0, gain[2] - 1))) # image, anchor, grid indices
tbox.append(torch.cat((gxy - gij, gwh), 1)) # box
anch.append(anchors[a]) # anchors
tcls.append(c) # class
return tcls, tbox, indices, anch