YOLOv5-Backbone 模块详解
- 🍨 本文为🔗365天深度学习训练营 中的学习记录博客
- 🍖 原作者:K同学啊
前言:本次实验主要是基于YOLOv5的Backbone模块的深入理解,并将其应用于天气图片的分类任务展开。
文章目录:
文章目录
一、总体结构

图1-1
图片引用自 知乎网站: YOLOv5系列(一) 解析YOLOv5的网络结构(详尽) - 知乎
Yolov5主要由**Backbone,Head,Neck,**组成,主要就Backbone即主干网络进行介绍。

二、 Backbone结构解析
Backbone 主要由Conv,C3(Bottleneck残差模块),SPPF组成。
2.1 Conv (CBS)
Conv是一个标准的卷积层,主要由conv ,BatchNorm,SiLu(激活函数)组成

#Conv模块是卷积神经网络中常用的基础模块,主要由卷积层、BN层和激活函数组成
class Conv(nn.Module):
def __init__(self, c1,c2,k=1,s=1,p=None, g=1,act=True):
super().__init__()
self.conv=nn.Conv2d(c1,c2,k,s,autopad(k,p),groups=1,bias=False)
self.bn=nn.BatchNorm2d(c2)
self.act=nn.SiLU() if act is True else (act if isinstance(act,nn.Module)else nn.Identity())
def forward (self, x):
return self.act(self.bn(self.conv(x)))
2.2 Bottleneck模块
-
残差模块的引入
人们在网络训练的过程中发现,随着网络的深入,模型的准确度开始下降,出现了梯度消失和梯度爆炸的现象,因此,提出了残差网络,主要思想是基于将原来的输入加上经过多层卷积的结果作为输出,进入下一层的输入,相比前面,一定程度保留了更多的原始信息。
-
**Bottleneck **
CSP中的Bottleneck 与resnet类似,前者通过的shortcut是将卷积的输出与初始的输入相加作为最终的输出,是特征图对应位置相加而通道数不变;后者的shortcut则是通过concat实现,同时通道数发生了增加。
class Bottleneck(nn.Module): def __init__(self,c1,c2,shortcut=True,g=1,e=0.5): super().__init__() c_=int(c2*e) self.cv1=Conv(c1,c_,1,1) self.cv2=Conv(c_,c2,3,1,g=g) self.add=shortcut and c1==c2 def forward(self,x): return x +self.cv2(self.cv1(x)) if self.add else self.cv2(self.cv1(x))
2.3 C3/CSP模块
根据shortcut的取值不同可分为CSP1_x,CSP2_x,Backbone中的C3存在shortcut,为CSP1_x,neck中的C3为CSP2_x。这里解释一下,由于Backbone已经承担了主要的特征信息提取的功能,所以在Neck阶段不需要再一味地加深网络,因此采取不带残差的C3模块可能会更合适。
- C3模块主要结构(主要以Backbone为例):
class C3(nn.Module):
def __init__(self,c1,c2,n=1,shortcut=True,g=1,e=0.5):
super().__init__()
c_=int(c2*e)# hidden channels
self.cv1=Conv(c1,c_,1,1)
self.cv2=Conv(c1,c_,1,1)
self.cv3=Conv(2*c_,c2,1)#将通道数扩大为原来的两倍,并拼接为输出通道
self.m=nn.Sequential(*(Bottleneck(c_,c_,shortcut,g,e=1.0) for _ in range(n)))#.m操作是使用nn.Sequential将n个Bottleneck模块串联到网络中
def forward(self,x):
return self.cv3(torch.cat((self.m(self.cv1(x)),self.cv2(x)),dim=1))
2.3 SSPF模块

#SSPF模块,用于特征融合。
class SPPF(nn.Module):
def __init__(self,c1,c2,k=5):
super().__init__()
c_=c1//2 #hidden channel
self.cv1=Conv(c1,c_,1,1)
self.cv2=Conv(c_*4,c2,1,1)#由于后面需要进行拼接操作将维度融合,因此将通道数扩大为4倍
self.m=nn.MaxPool2d(kernel_size=k,stride=1,padding=k//2)
def forward(self,x):
x=self.cv1(x)
with warnings.catch_warnings():
warnings.simplefilter('ignore')
y1=self.m(x)
y2=self