YOLOv8白皮书-第Y9周:重要模块解读

本文为365天深度学习训练营中的学习记录博客
原作者:K同学啊|接辅导、项目定制

文件路径: …\ultralytics-main\ultralytics\nn\modules \ ***
该文件夹下的文件与YOLOv5中的 common.py 是起到相同作用的,是实现YOLOv8算法中各个模块的地方,如果我们需要修改某一模块(例如C3),那么就需要修改这个文件夹中相应文件中对应模块的的定义。这里仅仅介绍YOLOv8中涉及的主要模块,未讲解到的可查看之前YOLOv5中的介绍。由于YOLOv8版本问题,同一个模块你可能会看到不同的版本,这都是正常的,以官网为主即可。

以文件 …\ultralytics-main\ultralytics\nn\modules\conv.py 为例,开头列举了该文件中定义的所有模型,如果你需要新加一个模块,记得在该文件开头这里将其名称加入。(这是YOLOv8新增的一个类似声明的内容)

import math

import numpy as np
import torch
import torch.nn as nn

__all__ = (
    "Conv",
    "Conv2",
    "LightConv",
    "DWConv",
    "DWConvTranspose2d",
    "ConvTranspose",
    "Focus",
    "GhostConv",
    "ChannelAttention",
    "SpatialAttention",
    "CBAM",
    "Concat",
    "RepConv",
)

在这里插入图片描述
1、autopad
模块定义文件路径: …\ultralytics-main\ultralytics\nn\modules\conv.py

  • 功能:返回pad的大小,使得padding后输出张量的大小不变。

  • 参数说明:

    • k:卷积核(kernel)的大小。可以是单个整数 int,也可以是整数列表(对于不同维度的卷积核)。

    • p:填充(padding)大小。如果未提供,即默认为None,函数将自动计算。

    • d:膨胀率(dilation rate),默认为1。普通卷积的扩张率为1,空洞卷积的扩张率大于1。

    autopad 函数在实现卷积神经网络时非常有用,特别是在需要保持特征图尺寸不变的情况下。通过自动计算填充大小,它简化了卷积层的实现过程。

def autopad(k, p=None, d=1):  # kernel, padding, dilation
    """Pad to 'same' shape outputs."""
    if d > 1:
        k = d * (k - 1) + 1 if isinstance(k, int) else [d * (x - 1) + 1 for x in k]  # actual kernel-size
    if p is None:
        p = k // 2 if isinstance(k, int) else [x // 2 for x in k]  # auto-pad
    return p

2、Conv
模块定义文件路径: …\ultralytics-main\ultralytics\nn\modules\conv.py

  • ·功能:标准卷积模块
  • 参数:输入通道数( c1 ),输出通道数( c2 ),卷积核大小( k,默认是 1 ),步长( s,默认是 1 ),填充( p,默认为 None),组( g,默认为 1), 扩张率( d,默认为 1 ),是否采用激活函数( act,默认为True,且采用SiLU为激活函数)
class Conv(nn.Module):
    """Standard convolution with args(ch_in, ch_out, kernel, stride, padding, groups, dilation, activation)."""

    default_act = nn.SiLU()  # default activation

    def __init__(self, c1, c2, k=1, s=1, p=None, g=1, d=1, act=True):
        """Initialize Conv layer with given arguments including activation."""
        super().__init__()
        self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p, d), groups=g, dilation=d, bias=False)
        self.bn = nn.BatchNorm2d(c2)
        self.act = self.default_act if act is True else act if isinstance(act, nn.Module) else nn.Identity()

    def forward(self, x):
        """Apply convolution, batch normalization and activation to input tensor."""
        return self.act(self.bn(self.conv(x)))

    def forward_fuse(self, x):
        """Perform transposed convolution of 2D data."""
        return self.act(self.conv(x))

Conv 类,继承自 nn.Module 。它实现了标准的卷积操作,具有一些参数( ch_in、ch_out、kernel、stride、padding、groups、dilation、activation)来定义卷积层的行为。

1.在conv 类的初始化方法__init__中,首先调用了父类 nn.Module的初始化方法 super().init ()。

2.使用 nn.conv2d 创建了一个卷积层 self.conv,其中包括输入通道数 c1、输出通道数 c2、卷积核大小 k、步长 s、填充 p、分组数 g、膨胀率 d、偏置 bias 等参数。
3.创建了批归一化层 self.bn,用于对卷积结果进行归一化处理。
4.根据 act 参数的类型,确定激活函数 self.act,默认为 nn.siLu()。

在前向传播方法 forward 中,首先对输入张量 x 进行卷积操作 self.conv(x),然后对卷积结果进行批归一化 self.bn ,最后使用激活函数 self.act进行激活,并返回结果。
forward_fuse 方法用于执行转置卷积操作。它对输入张量 x 执行卷积操作 self.conv(x),然后使用激活函数 self.act 进行激活,并返回结果。

3、Focus
模块定义文件路径: …\ultralytics-main\ultralytics\nn\modules\conv.py
Focus模块是作者自己设计出来,为了减少浮点数和提高速度,而不是增加feature map的,本质就是将图像进行切片,类似于下采样取值,将原图像的宽高信息切分,聚合到channel通道中。结构如下所示:
在这里插入图片描述

class Focus(nn.Module):
    """Focus wh information into c-space."""

    def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True):    #ch_in(输入通道数),ch_out(输出通道数),卷积核大小,步长,填充,分组数
        """Initializes Focus object with user defined channel, convolution, padding, group and activation values."""
        super().__init__()
        self.conv = Conv(c1 * 4, c2, k, s, p, g, act=act)
        # self.contract = Contract(gain=2)    # 降维模块(可选)

    def forward(self, x):    # x(b,c,w,h) -> y(b,4c,w/2,h/2)(输入x的维度为:批大小,通道数,宽度,高度;输出y的维度为:批大小,4倍通道数,宽度的一半,高度的一半)
        """
        Applies convolution to concatenated tensor and returns the output.

        Input shape is (b,c,w,h) and output shape is (b,4c,w/2,h/2).
        """
        return self.conv(torch.cat((x[..., ::2, ::2], x[..., 1::2, ::2], x[..., ::2, 1::2], x[..., 1::2, 1::2]), 1))
        #通过将输入张量x沿通道维度拼接四次得到新的输入,然后经过卷积层self.conv处理
        
        #如果启用降维模块:
        # return self.conv(self.contract(x))

4、C2f
模块定义文件路径: …\ultralytics-main\ultralytics\nn\modules\block.py

在这里插入图片描述

class C2f(nn.Module):
    """Faster Implementation of CSP Bottleneck with 2 convolutions."""
	"""C2f层,快速实现带有2个卷积的CSP Bottleneck。"""
	
    def __init__(self, c1, c2, n=1, shortcut=False, g=1, e=0.5):
        """Initialize CSP bottleneck layer with two convolutions with arguments ch_in, ch_out, number, shortcut, groups,
        expansion.
        """
        super().__init__()
        self.c = int(c2 * e)  # hidden channels  隐藏通道数
        self.cv1 = Conv(c1, 2 * self.c, 1, 1)    #第一个卷积层,用于将输入通道转换为2倍的隐藏通道数
        self.cv2 = Conv((2 + n) * self.c, c2, 1)  # optional act=FReLU(c2)   第二个卷积层,用于将隐藏通道数转换为输出通道数;也可选使用激活函数FReLU(c2)
        self.m = nn.ModuleList(Bottleneck(self.c, self.c, shortcut, g, k=((3, 3), (3, 3)), e=1.0) for _ in range(n))     #创建包含n个Bottleneck块的ModuleList

    def forward(self, x):
        """Forward pass through C2f layer."""
        """通过C2f层进行前向传播。"""
        y = list(self.cv1(x).chunk(2, 1))    #将cv1的输出按通道分为两部分
        y.extend(m(y[-1]) for m in self.m)   #将y的最后一个部分输入n个Bottleneck块中,得到一系列的输出
        return self.cv2(torch.cat(y, 1))    #将这些输出连接起来并输入到cv2中进行最终的输出

    def forward_split(self, x):
        """Forward pass using split() instead of chunk()."""
        """使用split()而不是chunk()进行前向传播。"""
        y = list(self.cv1(x).split((self.c, self.c), 1))   #使用split函数将cv1的输出按指定大小分割
        y.extend(m(y[-1]) for m in self.m)    # 将y的最后一个部分输入n个Bottleneck块中,得到一系列的输出
        return self.cv2(torch.cat(y, 1))    #将这些输出连接起来并输入到cv2中进行最终的输出

该模块包含了两个卷积层和一些 Bottleneck 模块的组合,下面是该类的主要成员和功能:

  • __ init__(self,c1,c2,n=1,shortcut=False,g=1,e=0.5):初始化函数,接受输入通道数 c1、输出通道数 c2、重复次数 n、是否使用 shortcut 连接
    shortcut 、分组卷积的组数g、扩展因子 e 等参数。在初始化过程中创建了包含了两个卷积层和一些 Bottleneck 模块的组合。

  • forward(self,x):前向传播函数,接受输入张量 x 。在前向传播过程中,首先通过一个卷积层 self.cv1 对输入进行卷积操作,然后将输出分成两部分。接下来,通过一系列的 Bottleneck 模块 self.m 对其中一部分进行处理,并将处理后的结果与另一部分进行拼接。最后,通过另一个卷积层 self.cv2 对拼接后的结果进行卷积操作,并返回输出张量。

  • forward_split(self,x):与 forward(self,x) 类似的前向传播函数,但在处理输入分成两部分时,使用了 split() 方法代替了 chunk() 方法。其余部分的功能与 forward(self, x) 相同。

5、总结
学习了YOLOv8的重要模块,对修改模块有一定的掌握。

  • 20
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值