【YOLOv5-6.x】网络模型源码解析

news/2025/2/22 15:47:46/

文章目录

    • 前言
    • 整体网络结构
      • v5.x网络结构
      • v6.x网络结构
    • 各部分源码解析
      • Conv
      • Focus
      • Bottleneck
      • C3
      • SPP
      • SPPF
    • Reference

前言

YOLOv5是Ultralytics公司的开源项目,GitHub地址:https://github.com/ultralytics/yolov5,更新速度非常快,最新版的v6.1于2022年2月22日发布,目前star数22.7k。

YOLOv5更新日志:

  • 2020年6月26日发布v1.0
  • … … …
  • 2021年4月12日发布v5.0
  • 2021年10月12日发布v6.0
  • 2022年2月22日发布v6.1

下面对v6.x版本的网络模型及各个组件,结合源码和网络框图进行解析。

整体网络结构

v5.x网络结构

在这里插入图片描述

v6.x网络结构

在这里插入图片描述

可以看出,相比于之前v5.x,最新版的v6.x网络结构更加精简(以提高速度和推理性能),主要有以下更新:

  • Conv(k=6, s=2, p=2) 替换Focus,便于导出其他框架(for improved exportability)
  • SPPF代替SPP,并且将SPPF放在主干最后一层(for reduced ops)
  • 主干中的C3层重复次数从9次减小到6次(for reduced ops)
  • 主干中最后一个C3层引入shortcut

各部分源码解析

YOLOv5网络搭建的各个组件主要在model/common.py文件中

Conv

网络中的标准卷积层,有2D卷积+BN层+激活函数(SiLU)组成,在之后的Bottleneck、C3、SPPF等结构中都会被调用。
在这里插入图片描述

源码:

# 标准卷积操作:conv2D+BN+SiLU
# 在Focus、Bottleneck、BottleneckCSP、C3、SPP、DWConv、TransformerBloc等模块中调用
class Conv(nn.Module):# Standard convolutiondef __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True):  # ch_in, ch_out, kernel, stride, padding, groupssuper().__init__()self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p), groups=g, bias=False)self.bn = nn.BatchNorm2d(c2)# 这里的nn.Identity()不改变input,直接return inputself.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)))# 前向加速推理模块# 用于Model类的fuse函数,融合conv+bn 加速推理 一般用于测试/验证阶段def forward_fuse(self, x):return self.act(self.conv(x))

Focus

Focus模块是作者自己设计出来,为了减少浮点数和提高速度,而不是增加featuremap的,本质就是将图像进行切片,类似于下采样取值,将原图像的宽高信息切分,聚合到channel通道中。
在这里插入图片描述
源码:

class Focus(nn.Module):# Focus wh information into c-space"""理论:从高分辨率图像中,周期性的抽出像素点重构到低分辨率图像中,即将图像相邻的四个位置进行堆叠,聚焦wh维度信息到c通道中,增大每个点的感受野,减少原始信息的丢失,该模块的设计主要是减少计算量加快速度Focus wh information into c-space 把宽度w和高度h的信息整合到c空间中1. 先做4个slice 再concat 最后再做Conv2. slice后 (b,c1,w,h) -> 分成4个slice 每个slice(b,c1,w/2,h/2)3. concat(dim=1)后 4个slice(b,c1,w/2,h/2)) -> (b,4c1,w/2,h/2)4. conv后 (b,4c1,w/2,h/2) -> (b,c2,w/2,h/2)"""def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True):  # ch_in, ch_out, kernel, stride, padding, groupssuper().__init__()self.conv = Conv(c1 * 4, c2, k, s, p, g, act)# self.contract = Contract(gain=2)def forward(self, x):  # x(b,c,w,h) -> y(b,4c,w/2,h/2)# 假设x = [1,2,3,4,5,6,7,8,9] x[::2] = [1,3,5,7,9] 间隔2个取样# x[1::2] = [2, 4, 6, 8] 从第二个数据开始,间隔2个取样return self.conv(torch.cat([x[..., ::2, ::2], x[..., 1::2, ::2], x[..., ::2, 1::2], x[..., 1::2, 1::2]], 1))# return self.conv(self.contract(x))

Bottleneck

标准的bottleneck模块,用在构建BottleneckCSP和C3等模块中,包含shortcut,起到加深网络的作用。
在这里插入图片描述

源码:

class Bottleneck(nn.Module):# Standard bottleneckdef __init__(self, c1, c2, shortcut=True, g=1, e=0.5):  # ch_in, ch_out, shortcut, groups, expansionsuper().__init__()c_ = int(c2 * e)  # hidden channelsself.cv1 = Conv(c1, c_, 1, 1)self.cv2 = Conv(c_, c2, 3, 1, g=g)self.add = shortcut and c1 == c2def forward(self, x):return x + self.cv2(self.cv1(x)) if self.add else self.cv2(self.cv1(x))

C3

C3模块其实是简化版的BottleneckCSP,该部分除了Bottleneck之外,只有3个卷积模块,可以减少参数,所以取名C3,作者用意为:C3() is an improved version of CSPBottleneck(). It is simpler, faster and and lighter with similar performance and better fuse characteristics.
在这里插入图片描述
源码:

class C3(nn.Module):# C3() is an improved version of CSPBottleneck()# It is simpler, faster and lighter with similar performance and better fuse characteristics# CSP Bottleneck with 3 convolutionsdef __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5):  # ch_in, ch_out, number, shortcut, groups, expansionsuper().__init__()c_ = int(c2 * e)  # hidden channelsself.cv1 = Conv(c1, c_, 1, 1)self.cv2 = Conv(c1, c_, 1, 1)self.cv3 = Conv(2 * c_, c2, 1)  # act=FReLU(c2)self.m = nn.Sequential(*(Bottleneck(c_, c_, shortcut, g, e=1.0) for _ in range(n)))# self.m = nn.Sequential(*[CrossConv(c_, c_, 3, 1, g, 1.0, shortcut) for _ in range(n)])def forward(self, x):return self.cv3(torch.cat((self.m(self.cv1(x)), self.cv2(x)), dim=1))

SPP

Spatial Pyramid Pooling (SPP) layer https://arxiv.org/abs/1406.4729
SPP层将更多不同分辨率的特征进行融合,在送入网络neck之前能够得到更多的信息。
在这里插入图片描述
源码:

class SPP(nn.Module):# Spatial Pyramid Pooling (SPP) layer https://arxiv.org/abs/1406.4729def __init__(self, c1, c2, k=(5, 9, 13)):super().__init__()c_ = c1 // 2  # hidden channelsself.cv1 = Conv(c1, c_, 1, 1)# cv2的输入channel数,等于c_乘以4(4个不同的分辨率的feature map进行融合)self.cv2 = Conv(c_ * (len(k) + 1), c2, 1, 1)self.m = nn.ModuleList([nn.MaxPool2d(kernel_size=x, stride=1, padding=x // 2) for x in k])def forward(self, x):x = self.cv1(x)with warnings.catch_warnings():warnings.simplefilter('ignore')  # suppress torch 1.9.0 max_pool2d() warningreturn self.cv2(torch.cat([x] + [m(x) for m in self.m], 1))

SPPF

Spatial Pyramid Pooling - Fast (SPPF) layer for YOLOv5 by Glenn Jocher
SPP-Fast顾名思义就是为了保证准确率相似的条件下爱,减少计算量,以提高速度,使用3个5×5的最大池化,代替原来的5×5、9×9、13×13最大池化。
在这里插入图片描述
源码:

class SPPF(nn.Module):# Spatial Pyramid Pooling - Fast (SPPF) layer for YOLOv5 by Glenn Jocherdef __init__(self, c1, c2, k=5):  # equivalent to SPP(k=(5, 9, 13))super().__init__()c_ = c1 // 2  # hidden channelsself.cv1 = Conv(c1, c_, 1, 1)self.cv2 = Conv(c_ * 4, c2, 1, 1)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')  # suppress torch 1.9.0 max_pool2d() warningy1 = self.m(x)y2 = self.m(y1)return self.cv2(torch.cat([x, y1, y2, self.m(y2)], 1))

Reference

  • 【YOLOV5-5.x 源码解读】common.py
  • yolov5s-6.0网络模型结构图
  • YOLOv5 v6.0 release 改动速览

http://www.ppmy.cn/news/266426.html

相关文章

x的x分之一次方极限x趋于0_x分之e的x次方减一的极限

求极限X趋近于0时 E的2X次方减1分之ln(1-X)等于? 应用洛必达法则,上下求导,得到1/(x-1)*(2e^2x),该式X趋近于0时极限为-1/2 lim(x趋于0)3x分之e的x次方-1,求极限 建议用无穷小代换法,因为无穷小代入法有两个好处,一是运用起来比较方便,而是经常运用这个方法可以增加对数学的感…

gdb x 命令详解

>examine命令 x &#xff1a;查看内存地址中的值 格式&#xff1a;x/<n/f/u> <addr> n:是正整数&#xff0c;表示需要显示的内存单元的个数&#xff0c;即从当前地址向后显示n个内存单元的内容&#xff0c;一个内存单元的大小由第三个参数u定义。 f:表示addr…

Z=X+Y型概率密度的求解

###ZXY型概率密度的求解### (概率论) Z g ( X , Y ) Z g(X,Y) Zg(X,Y) 总结过一次&#xff0c;一般方法是可以由分布函数再求导得到概率密度&#xff0c;计算一定更要小心才能得到正确的解。 F Z ( z ) P ( Z ≤ z ) P ( g ( X , Y ) ≤ z ) ∫ ∫ g ( x , y ) ≤ z f ( …

pytorch relu6

tf代码是: relu6 = min(max(features, 0), 6) 结果是把小于0的变成0,大于6的取6,y= torch.clamp(x,0,6)计算结果一样的。 缺点:这个训练收敛比较快,但是收敛比较好后,目标检测网络回归框不太准。 import torch import torchvisionimport torch import torch.nn as nn#…

CentOS6.x升级到7

资料&#xff1a; Centos 6.x 升级到 7CentOS 6.5升级至CentOS 7 centos6.x如何更新 风险&#xff1a; 系统&#xff1a; ssh、yum不可用&#xff0c;需按文末步骤安装 数据&#xff1a; 从实验来看&#xff0c;不会清空 /opt、/home、/var 目录下的用户数据&#xff0c;部…

python分段函数输入x的值求y的值,根据以下分段函数计算y的值,要求x的值由键盘输入,...

求大神,在线等.编程计算分段函数,根据键盘输入的x值,在屏幕输出y值. #include#includevoid main(){float x,y;scanf("%f",&a 计算分段函数的值.根据输入的x值计算下列表达式中y的值.是c语言程序设计题. #includeintmain(){\x09floatx,y;\x09printf("请输入x…

python语句x 3 3执行_已知 x = 3,那么执行语句 x *= 6 之后,x的值为_学小易找答案

【填空题】Python内置函数__用来返回序列中的最小元素 【填空题】表达式 list(range(5)) 的值为 【填空题】表达式 int(4**0.5) 的值为 【填空题】表达式 3 or 5 的值为 【填空题】表达式 min([‘11’, ‘2’, ‘3’]) 的值为 【填空题】已知 x = [1, 2, 3, 2, 3],执行语句 x.p…

DDR4、GDDR5、GDDR6内存的区别

计算机内存主要有两种类型&#xff1a;主内存&#xff08;RAM&#xff09;和图形内存&#xff08;VRAM&#xff09;&#xff0c;前者利用 DDR4&#xff08;很快还会有 DDR5&#xff09;&#xff0c;而后者利用 GDDR5&#xff08;和 GDDR6&#xff09;标准。但这两者有什么区别&…