Ultralytics框架之conv.py代码精读

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

这段代码定义了一个名为 autopad 的函数,其主要功能是计算卷积操作的填充(padding)量,以确保输入和输出的形状一致,即“same”卷积。

  1. 函数定义

    def autopad(k, p=None, d=1):  # kernel, padding, dilation
    
    • k:卷积核的大小(kernel size),可以是整数或列表(即多个维度的卷积核大小)。
    • p:填充量(padding),默认值为 None,这意味着如果未提供填充量,函数将根据卷积核的大小自动计算填充量。
    • d:膨胀率(dilation),默认为1,表示没有进行膨胀卷积。
  2. 调整卷积核大小

    if d > 1:
        k = d * (k - 1) + 1 if isinstance(k, int) else [d * (x - 1) + 1 for x in k]  # actual kernel-size
    
    • 如果膨胀率 d 大于1,函数会根据膨胀率调整卷积核的实际大小。如果 k 是一个整数,则直接计算 d * (k - 1) + 1,如果 k 是列表,则使用列表推导式遍历每个元素进行相同的计算。
  3. 自动计算填充量

    if p is None:
        p = k // 2 if isinstance(k, int) else [x // 2 for x in k]  # auto-pad
    
    • 如果用户未提供填充量 p,则根据卷积核的大小自动计算填充量。
    • 对于单个维度的卷积核(整数形式),填充量为 k // 2;对于多维卷积核(列表形式),填充量为每个维度的大小的一半。
  4. 返回填充量

    return p
    
    • 函数返回计算得到的填充量 p,这通常用于确保卷积操作的输入输出形状保持一致。

autopad 函数用于自动计算卷积操作所需的填充量,以确保输入和输出的尺寸能保持一致。它可以根据卷积核的大小和膨胀率动态调整填充量,并在用户未提供填充量时给予自动填充的便利。这种功能在构建深度学习模型时非常重要,尤其是在处理卷积神经网络(CNN)时,以防止信息损失和保持空间特征的对齐。

2. Conv

深入浅出之CBR模块、CBL模块、CBM和CBS模块(YOLO)_yolo cbl-CSDN博客文章浏览阅读1.3k次,点赞28次,收藏34次。CBM和CBL作为YOLOv4网络结构中的基本组件,各自具有独特的激活函数,分别用于增强网络的非线性能力和防止神经元死亡。它们在YOLOv4的网络中相互配合,共同构成了强大的特征提取和学习能力。在实际应用中,这些组件的选择和优化对于提升YOLOv4的性能至关重要。_yolo cblhttps://blog.csdn.net/a8039974/article/details/142340798?sharetype=blogdetail&sharerId=142340798&sharerefer=PC&sharesource=a8039974&spm=1011.2480.3001.8118

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 的卷积层类,该类继承自 torch.nn.Module,是 PyTorch 中用于构建神经网络的基础模块。以下是对代码的逐步分解和详细解释:

1. 类定义和 docstring

class Conv(nn.Module):
    """Standard convolution with args(ch_in, ch_out, kernel, stride, padding, groups, dilation, activation)."""
  • Conv 类是一个标准的卷积层,接收多个参数以配置卷积行为。

  • docstring 提供了参数的简要说明。

2. 默认激活函数

default_act = nn.SiLU()  # default activation
  • default_act 是该类的默认激活函数,使用的是 SiLU(Sigmoid Linear Unit)。

3. 构造函数 __init__

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__()
  • 构造函数接收几个参数:

    • c1:输入通道数。

    • c2:输出通道数。

    • k:卷积核的大小(默认为1)。

    • s:步幅(默认为1)。

    • p:填充(默认为None)。

    • g:组数(默认为1,表示普通卷积)。

    • d:扩张率(默认为1)。

    • act:指定是否使用激活函数或自定义的激活函数。

self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p, d), groups=g, dilation=d, bias=False)
  • 使用 nn.Conv2d 创建一个二维卷积层,参数根据输入的配置进行初始化。

  • autopad(k, p, d) 用于计算填充,使输出尺寸与输入尺寸相匹配(即相同的空间尺寸输出)。

self.bn = nn.BatchNorm2d(c2)
  • 创建批归一化层,用于改善训练稳定性,减少内部协变量偏移。

self.act = self.default_act if act is True else act if isinstance(act, nn.Module) else nn.Identity()

这段代码是一个Python语句,通常出现在一个类的初始化方法(如__init__)中,用于设置一个名为act的属性。这个属性是一个激活函数(activation function),用于神经网络中的非线性变换。下面是对这段代码的详细解释:

  1. self.act:这是类的实例属性,用于存储激活函数。

  2. self.default_act:这是类的另一个属性,通常在类的初始化方法中定义,表示默认的激活函数。

  3. act is True:这是一个条件判断,检查传入的参数act是否为布尔值True

  4. self.default_act if act is True else ...:如果actTrue,则self.act被设置为self.default_act,即默认的激活函数。

  5. act if isinstance(act, nn.Module) else ...isinstance(act, nn.Module)检查act是否是一个nn.Module的实例,即是否是一个PyTorch的模块(如一个自定义的激活函数)。如果是,则self.act被设置为act

  6. nn.Identity():如果act既不是True也不是一个nn.Module实例,那么self.act被设置为nn.Identity(),这是一个特殊的激活函数,它不做任何变换,直接返回输入。

用途
这段代码的目的是根据传入的参数act来设置激活函数。如果actTrue,则使用默认的激活函数;如果act是一个自定义的激活函数模块,则使用这个模块;否则,使用nn.Identity()作为激活函数。

注意事项

  • nn.Module是PyTorch中的一个基类,用于定义神经网络中的各种模块,包括激活函数。

  • nn.Identity()是一个特殊的激活函数,它不做任何变换,直接返回输入,通常用于占位或调试。

  • 这段代码假设self.default_act已经在类的初始化方法中定义,并且是一个激活函数模块。

4. 前向传播方法 forward

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

这行代码是深度学习模型中常见的一种操作,通常用于卷积神经网络(CNN)中的卷积层之后。它涉及三个主要操作:卷积(Convolution)、批量归一化(Batch Normalization)和激活函数(Activation Function)。下面是对每个操作的详细解释:

  1. 卷积(Convolution, self.conv(x)

    • 实现原理:卷积操作用于提取输入数据(通常是图像)中的特征。卷积核(或滤波器)在输入数据上滑动,计算局部区域的加权和,加上一个偏置项,生成输出特征图。

    • 用途:卷积层能够捕捉到输入数据中的空间特征,如边缘、角点等。

    • 注意事项:卷积核的大小、步长、填充方式等参数会影响特征提取的效果。

  2. 批量归一化(Batch Normalization, self.bn(...)

    • 实现原理:批量归一化是一种加速神经网络训练的技术,通过在训练过程中对每一批数据进行标准化处理,使得每一层的输入保持稳定的分布,从而加速收敛并提高模型的稳定性。

    • 用途:减少内部协变量偏移,加速训练过程,提高模型泛化能力。

    • 注意事项:批量归一化需要足够的批量大小,否则效果可能不佳。

  3. 激活函数(Activation Function, self.act(...)

    • 实现原理:激活函数引入非线性,使得神经网络能够学习复杂的模式。常见的激活函数有ReLU、Sigmoid、Tanh等。

    • 用途:增加网络的非线性表达能力,使得网络能够拟合更复杂的函数。

    • 注意事项:选择合适的激活函数,考虑其在不同任务中的表现。

拆开写

def forward(self, x):  
    # Step 1: Convolution  
    conv_result = self.conv(x)  
      
    # Step 2: Batch Normalization  
    bn_result = self.bn(conv_result)  
      
    # Step 3: Activation  
    activation_result = self.act(bn_result)  
      
    # 返回最终结果  
    return activation_result

综合起来,这行代码的含义是:首先对输入数据进行卷积操作,提取特征;然后对卷积后的特征进行批量归一化,稳定数据分布;最后通过激活函数引入非线性,使得网络能够学习更复杂的特征。这种操作顺序在卷积神经网络中非常常见,有助于提高模型的性能和训练效率。

5. 融合前向传播方法 forward_fuse

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

这行代码是一个深度学习模型中常见的前向传播操作。我们可以逐步分解并详细解释这行代码的组成部分。

  1. self.conv:

    • 这是一个卷积层(nn.Conv2d 类的实例)。卷积层的作用是对输入张量(通常是图像)执行卷积操作,从而提取特征。

    • 在卷积操作中,会使用设定好的卷积核(滤波器)来卷积输入数据,生成特征图(feature map)。

  2. x:

    • 这是输入张量,通常是一个包含多个通道(例如颜色通道)的图像数据,格式为 (batch_size, channels, height, width)

    • 这行代码中的 x 会传入卷积层进行处理。

  3. self.conv(x):

    • 这里的代码将输入张量 x 传递给卷积层 self.conv。这会执行卷积操作,生成经过卷积处理的输出张量。

    • 输出张量的形状和数量由卷积层的参数(如输入通道数、输出通道数、卷积核大小等)决定。

  4. self.act:

    • 这是一个激活函数(例如 nn.ReLU()nn.SiLU(),或其他激活函数)的实例。激活函数的主要作用是引入非线性,使得模型能够学习更复杂的特征。

    • 在深度学习中,激活函数通常跟随在卷积层之后。

  5. self.act(self.conv(x)):

    • 这整行代码的作用是首先通过 self.conv(x) 计算卷积层的输出,然后将该输出传递给激活函数 self.act,进行非线性变换。

    • 通过这种方式,每一次前向传播都能让模型从数据中提取出更加复杂和高阶的特征。

这行代码 self.act(self.conv(x)) 是深度学习模型中的一个基本前向传播步骤。其主要功能是先利用卷积层 self.conv 对输入数据 x 进行卷积操作,生成特征图,然后将特征图输入到激活函数 self.act 中,以增加模型的非线性特性。这种结构帮助神经网络更好地捕捉输入数据中的复杂模式和特征。

总结

Conv 类实现了一个标准的卷积层,结合了卷积、批归一化和激活功能。它允许通过多种参数自定义卷积操作,如输入输出通道数、卷积核大小、步幅、填充、组卷积以及扩张。同时,类还提供了两种前向传播方式,使其在训练和推理阶段具有灵活性和效率。

3. RepConv

class RepConv(nn.Module):
    """
    RepConv is a basic rep-style block, including training and deploy status.

    This module is used in RT-DETR.
    Based on https://github.com/DingXiaoH/RepVGG/blob/main/repvgg.py
    """

    default_act = nn.SiLU()  # default activation

    def __init__(self, c1, c2, k=3, s=1, p=1, g=1, d=1, act=True, bn=False, deploy=False):
        """Initializes Light Convolution layer with inputs, outputs & optional activation function."""
        super().__init__()
        assert k == 3 and p == 1
        self.g = g
        self.c1 = c1
        self.c2 = c2
        self.act = self.default_act if act is True else act if isinstance(act, nn.Module) else nn.Identity()

        self.bn = nn.BatchNorm2d(num_features=c1) if bn and c2 == c1 and s == 1 else None
        self.conv1 = Conv(c1, c2, k, s, p=p, g=g, act=False)
        self.conv2 = Conv(c1, c2, 1, s, p=(p - k // 2), g=g, act=False)

    def forward_fuse(self, x):
        """Forward process."""
        return self.act(self.conv(x))

    def forward(self, x):
        """Forward process."""
        id_out = 0 if self.bn is None else self.bn(x)
        return self.act(self.conv1(x) + self.conv2(x) + id_out)

    def get_equivalent_kernel_bias(self):
        """Returns equivalent kernel and bias by adding 3x3 kernel, 1x1 kernel and identity kernel with their biases."""
        kernel3x3, bias3x3 = self._fuse_bn_tensor(self.conv1)
        kernel1x1, bias1x1 = self._fuse_bn_tensor(self.conv2)
        kernelid, biasid = self._fuse_bn_tensor(self.bn)
        return kernel3x3 + self._pad_1x1_to_3x3_tensor(kernel1x1) + kernelid, bias3x3 + bias1x1 + biasid

    @staticmethod
    def _pad_1x1_to_3x3_tensor(kernel1x1):
        """Pads a 1x1 tensor to a 3x3 tensor."""
        if kernel1x1 is None:
            return 0
        else:
            return torch.nn.functional.pad(kernel1x1, [1, 1, 1, 1])

    def _fuse_bn_tensor(self, branch):
        """Generates appropriate kernels and biases for convolution by fusing branches of the neural network."""
        if branch is None:
            return 0, 0
        if isinstance(branch, Conv):
            kernel = branch.conv.weight
            running_mean = branch.bn.running_mean
            running_var = branch.bn.running_var
            gamma = branch.bn.weight
            beta = branch.bn.bias
            eps = branch.bn.eps
        elif isinstance(branch, nn.BatchNorm2d):
            if not hasattr(self, "id_tensor"):
                input_dim = self.c1 // self.g
                kernel_value = np.zeros((self.c1, input_dim, 3, 3), dtype=np.float32)
                for i in range(self.c1):
                    kernel_value[i, i % input_dim, 1, 1] = 1
                self.id_tensor = torch.from_numpy(kernel_value).to(branch.weight.device)
            kernel = self.id_tensor
            running_mean = branch.running_mean
            running_var = branch.running_var
            gamma = branch.weight
            beta = branch.bias
            eps = branch.eps
        std = (running_var + eps).sqrt()
        t = (gamma / std).reshape(-1, 1, 1, 1)
        return kernel * t, beta - running_mean * gamma / std

    def fuse_convs(self):
        """Combines two convolution layers into a single layer and removes unused attributes from the class."""
        if hasattr(self, "conv"):
            return
        kernel, bias = self.get_equivalent_kernel_bias()
        self.conv = nn.Conv2d(
            in_channels=self.conv1.conv.in_channels,
            out_channels=self.conv1.conv.out_channels,
            kernel_size=self.conv1.conv.kernel_size,
            stride=self.conv1.conv.stride,
            padding=self.conv1.conv.padding,
            dilation=self.conv1.conv.dilation,
            groups=self.conv1.conv.groups,
            bias=True,
        ).requires_grad_(False)
        self.conv.weight.data = kernel
        self.conv.bias.data = bias
        for para in self.parameters():
            para.detach_()
        self.__delattr__("conv1")
        self.__delattr__("conv2")
        if hasattr(self, "nm"):
            self.__delattr__("nm")
        if hasattr(self, "bn"):
            self.__delattr__("bn")
        if hasattr(self, "id_tensor"):
            self.__delattr__("id_tensor")

这是一个名为 RepConv 的类,它是一个用于卷积神经网络的模块,主要用于实现轻量级的卷积操作。此类继承自 nn.Module,用于在训练和推理阶段执行不同的操作。它的设计灵感来自于 RepVGG 模型,旨在提高网络的性能并减少推理时间。

1. 定义与初始化

class RepConv(nn.Module):
    default_act = nn.SiLU()  # 默认激活函数

    def __init__(self, c1, c2, k=3, s=1, p=1, g=1, d=1, act=True, bn=False, deploy=False):
        ...
        assert k == 3 and p == 1  # 确保卷积核大小为3并且填充为1
        self.g = g
        self.c1 = c1
        self.c2 = c2
        self.act = self.default_act if act is True else act if isinstance(act, nn.Module) else nn.Identity()

        self.bn = nn.BatchNorm2d(num_features=c1) if bn and c2 == c1 and s == 1 else None  # 条件性批量归一化
        self.conv1 = Conv(c1, c2, k, s, p=p, g=g, act=False)  # 第一个卷积
        self.conv2 = Conv(c1, c2, 1, s, p=(p - k // 2), g=g, act=False)  # 第二个卷积
  • 默认激活函数:使用 SiLU(Sigmoid Linear Unit)作为默认激活函数。

  • 构造函数参数

    • c1:输入通道数。

    • c2:输出通道数。

    • kspgd:卷积参数,其中 k 为卷积核大小,s 为步幅,p 为填充,g 为分组数,d 为扩张卷积。

    • act:激活函数,默认为 True 使用默认激活。

    • bn:是否应用批量归一化。

    • deploy:标识是否为部署模式。

2. 前向传播

def forward(self, x):
    """Forward process."""
    id_out = 0 if self.bn is None else self.bn(x)  # 如果存在批归一化,则重新标记
    return self.act(self.conv1(x) + self.conv2(x) + id_out)  # 通过两个卷积的结果与 ID 映射相加

这段代码定义了一个名为 forward 的方法,通常用于神经网络中的前向传播过程。下面是对这段代码的详细解释:

def forward(self, x):
  • forward 是一个方法,通常在类中定义,用于实现前向传播逻辑。

  • self 是类的实例,指向调用该方法的对象。

  • x 是输入数据,通常是一个张量(Tensor),代表输入的特征或数据。

id_out = 0 if self.bn is None else self.bn(x)
  • 这行代码根据 self.bn 是否为 None 来决定 id_out 的值。

  • 如果 self.bn 是 None,则 id_out 被赋值为 0

  • 如果 self.bn 不是 None,则 id_out 被赋值为 self.bn(x),即对输入 x 进行批量归一化(Batch Normalization)处理后的结果。

return self.act(self.conv1(x) + self.conv2(x) + id_out)
  • self.conv1(x) 和 self.conv2(x) 分别对输入 x 进行卷积操作。

  • self.conv1(x) + self.conv2(x) 将两个卷积操作的输出相加。

  • id_out 是可选的,如果 self.bn 不是 None,则会被加到卷积结果上。

  • self.act(...) 对上述结果进行激活函数(Activation Function)操作。

  • 最终返回激活函数处理后的结果。

  1. 批量归一化(Batch Normalization):批量归一化是一种加速神经网络训练的技术,通过规范化每一层的输入,使得网络更容易训练。

  2. 卷积操作:卷积操作是卷积神经网络(Convolutional Neural Network, CNN)的核心,用于提取输入数据中的特征。

  3. 激活函数:激活函数用于引入非线性,使得神经网络能够学习复杂的模式。

这段代码通常用于定义神经网络中的某个层(Layer)的前向传播逻辑,例如卷积层、批归一化层和激活函数的组合。在前向传播过程中,输入数据会经过这些层进行处理,最终得到输出结果。

3. 卷积合并与参数获取

def fuse_convs(self):
    """Combines two convolution layers into a single layer and removes unused attributes from the class."""
    ...
    self.conv.weight.data = kernel
    self.conv.bias.data = bias

  • fuse_convs 方法是将两个卷积层(conv1 和 conv2)合并为一个单一的卷积层。这可以减少模型的复杂性和推理时间,适用于推理阶段。

4. 获取等效卷积核和偏置

def get_equivalent_kernel_bias(self):
    """Returns equivalent kernel and bias by adding 3x3 kernel, 1x1 kernel and identity kernel with their biases."""
    ...
    return kernel3x3 + self._pad_1x1_to_3x3_tensor(kernel1x1) + kernelid, bias3x3 + bias1x1 + biasid

这段代码定义了一个名为 get_equivalent_kernel_bias 的方法,用于获取等效的卷积核和偏置。这个方法通常用于神经网络中的卷积层,特别是那些使用了批量归一化(Batch Normalization, BN)的卷积层。具体来说,它将一个3x3卷积层、一个1x1卷积层和一个批量归一化层融合成一个等效的卷积层,并返回其卷积核和偏置。

实现原理

  1. 融合卷积核和偏置:通过调用 _fuse_bn_tensor 方法,将卷积层和其后的批量归一化层融合成一个等效的卷积核和偏置。这个方法通常会将卷积核与批量归一化层的缩放因子和偏置相乘,并加上批量归一化层的均值和方差。

  2. 处理1x1卷积核:由于1x1卷积核的尺寸较小,不能直接与3x3卷积核和身份卷积核相加,因此需要通过 _pad_1x1_to_3x3_tensor 方法将其扩展为3x3尺寸。

  3. 计算等效卷积核和偏置:将融合后的3x3卷积核、扩展后的1x1卷积核和身份卷积核相加,以及它们的偏置相加,得到等效的卷积核和偏置。

用途

这个方法的主要用途是在神经网络中简化计算,特别是在使用深度可分离卷积(Depthwise Separable Convolution)时。通过将多个卷积层和批量归一化层融合成一个等效的卷积层,可以减少计算量和参数数量,从而提高模型的效率。

注意事项

  1. 批量归一化层的融合:在融合卷积核和偏置时,需要确保批量归一化层的均值和方差是正确的。通常,这些值是在训练过程中计算的,因此在推理阶段需要使用训练集的均值和方差。

  2. 1x1卷积核的扩展:由于1x1卷积核的尺寸较小,扩展为3x3尺寸时,需要填充额外的零。这可能会引入一些数值误差,因此在实际应用中需要谨慎处理。

  3. 模型兼容性:在使用这种方法时,需要确保模型的其他部分能够处理融合后的卷积核和偏置。例如,某些深度学习框架可能需要特定的数据格式或操作来支持这种融合。

5. 静态方法

 @staticmethod
    def _pad_1x1_to_3x3_tensor(kernel1x1):
        """Pads a 1x1 tensor to a 3x3 tensor."""
        if kernel1x1 is None:
            return 0
        else:
            return torch.nn.functional.pad(kernel1x1, [1, 1, 1, 1])

这段Python代码定义了一个名为_pad_1x1_to_3x3_tensor的函数,用于将一个1x1的tensor(张量)填充(padding)成一个3x3的tensor。这个函数使用了PyTorch库中的torch.nn.functional.pad函数来实现填充操作。

实现原理

  1. 函数定义:函数接受一个参数kernel1x1,这个参数是一个1x1的tensor。

  2. 检查参数:函数首先检查kernel1x1是否为None。如果是None,则返回0。

  3. 填充操作:如果kernel1x1不是None,则使用torch.nn.functional.pad函数对其进行填充。torch.nn.functional.pad函数的参数[1, 1, 1, 1]表示在tensor的四个方向(上、下、左、右)各填充1个元素。这样,一个1x1的tensor就会被填充成一个3x3的tensor。

用途

这个函数的主要用途是将1x1的卷积核(kernel)扩展为3x3的卷积核,这在某些深度学习模型中可能是有用的。例如,在卷积神经网络(CNN)中,有时需要将小的卷积核(如1x1)扩展为更大的卷积核(如3x3),以便更好地捕捉特征。

注意事项

  1. 输入检查:函数在处理之前会检查输入的kernel1x1是否为None,这是为了防止后续操作中出现NoneType错误。

  2. 填充方式:函数使用的是均匀填充(即在每个方向上填充相同的元素),这在某些情况下可能不是最优的。在实际应用中,可能需要根据具体需求调整填充方式。

  3. 依赖库:这个函数依赖于PyTorch库,因此需要在安装了PyTorch的环境中运行。

总结

RepConv 类是一个用于实现高效轻量级卷积操作的模块,其结构设计允许快速合并卷积层,以减少计算量和加快推理速度。通过支持可选的批量归一化和激活函数,它能够在训练和推理期间灵活地调整行为。这种方法通常用于提高卷积神经网络的性能,尤其是像 RT-DETR 等需要快速推理的应用场景。通过将卷积层合并,该模块能够保持模型精度的同时显著提高推理效率。

4. Conv2

class Conv2(Conv):
    """Simplified RepConv module with Conv fusing."""

    def __init__(self, c1, c2, k=3, s=1, p=None, g=1, d=1, act=True):
        """Initialize Conv layer with given arguments including activation."""
        super().__init__(c1, c2, k, s, p, g=g, d=d, act=act)
        self.cv2 = nn.Conv2d(c1, c2, 1, s, autopad(1, p, d), groups=g, dilation=d, bias=False)  # add 1x1 conv

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

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

    def fuse_convs(self):
        """Fuse parallel convolutions."""
        w = torch.zeros_like(self.conv.weight.data)
        i = [x // 2 for x in w.shape[2:]]
        w[:, :, i[0] : i[0] + 1, i[1] : i[1] + 1] = self.cv2.weight.data.clone()
        self.conv.weight.data += w
        self.__delattr__("cv2")
        self.forward = self.forward_fuse

类定义

class Conv2(Conv):
    """Simplified RepConv module with Conv fusing."""
  • Conv2 类继承自 Conv 类,目的是实现一个简化的重复卷积模块,带有卷积融合的功能。

初始化方法

def __init__(self, c1, c2, k=3, s=1, p=None, g=1, d=1, act=True):
    """Initialize Conv layer with given arguments including activation."""
    super().__init__(c1, c2, k, s, p, g=g, d=d, act=act)
    self.cv2 = nn.Conv2d(c1, c2, 1, s, autopad(1, p, d), groups=g, dilation=d, bias=False)  # add 1x1 conv
  • 参数解释

    • c1:输入通道数。

    • c2:输出通道数。

    • k:卷积核大小(默认3)。

    • s:步幅(默认1)。

    • p:零填充量(可以默认计算)。

    • g:分组卷积的组数(默认1)。

    • d:膨胀率(默认1)。

    • act:是否应用激活函数(默认是)。

  • 功能

    • 调用父类 Conv 的初始化方法。

    • 添加一个 1x1 卷积 cv2 用于在通道层面融合信息,并使用 autopad 计算填充。

前向传播方法

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

    • 计算两个卷积(self.conv 和 self.cv2)的输出并相加。

    • 将结果传入批量归一化层 (self.bn) 和激活函数 (self.act),输出处理后的张量。

拆开写:

def forward(self, x):  
    # Step 1: 第一个卷积操作  
    conv1_result = self.conv(x)  
      
    # Step 2: 第二个卷积或变换操作  
    conv2_result = self.cv2(x)  
      
    # Step 3: 计算两个卷积输出的和  
    sum_result = conv1_result + conv2_result  
      
    # Step 4: 批量归一化  
    bn_result = self.bn(sum_result)  
      
    # Step 5: 激活函数  
    activation_result = self.act(bn_result)  
      
    # 返回最终结果  
    return activation_result

融合前向传播方法

def forward_fuse(self, x):
    """Apply fused convolution, batch normalization and activation to input tensor."""
    return self.act(self.bn(self.conv(x)))
  • 功能

    • 该方法在融合了卷积后直接使用。它只计算主卷积的结果,减少计算量。

卷积融合方法

def fuse_convs(self):
    """Fuse parallel convolutions."""
    w = torch.zeros_like(self.conv.weight.data)
    i = [x // 2 for x in w.shape[2:]]
    w[:, :, i[0] : i[0] + 1, i[1] : i[1] + 1] = self.cv2.weight.data.clone()
    self.conv.weight.data += w
    self.__delattr__("cv2")
    self.forward = self.forward_fuse
  • 功能

    • 创建与主卷积权重相同形状的全零张量 w

    • 计算该张量的中心位置,并将 cv2 的权重拷贝到中心位置。

    • 将 cv2 的权重添加到主卷积的权重中,实现权重的融合。

    • 删除 cv2 属性以避免在后续操作中重复,并将 forward 方法替换为 forward_fuse,减少计算量及复杂性。

Conv2 类是一个卷积模块,旨在通过卷积融合技术减少卷积操作的计算量和复杂性它结合了标准卷积和额外的 1x1 卷积,以提高特征提取的效率。该模块提供了常规的前向传播方法,以及一个优化的融合方法,以便在不牺牲表现的情况下提升推理速度。此外,通过 fuse_convs 方法可以在训练阶段进行卷积融合,进一步提升模型的运行效率。

5. DWConv

class DWConv(Conv):
    """Depth-wise convolution."""

    def __init__(self, c1, c2, k=1, s=1, d=1, act=True):  # ch_in, ch_out, kernel, stride, dilation, activation
        """Initialize Depth-wise convolution with given parameters."""
        super().__init__(c1, c2, k, s, g=math.gcd(c1, c2), d=d, act=act)
class DWConv(Conv):
    """Depth-wise convolution."""
  • 这一行定义了一个名为 DWConv 的类,并且该类继承自 Conv 类。DWConv 代表深度可分离卷积(Depth-wise Convolution)。这是一种卷积操作,其中每个输入通道分别进行卷积,这有助于降低计算复杂度和参数数量。
    def __init__(self, c1, c2, k=1, s=1, d=1, act=True):  # ch_in, ch_out, kernel, stride, dilation, activation
  • 这是 DWConv 类的构造函数(初始化方法)。它接受多个参数:
    • c1:输入通道数(ch_in)。
    • c2:输出通道数(ch_out)。
    • k:卷积核大小(kernel size),默认为1。
    • s:步幅(stride),默认值为1。
    • d:扩张率(dilation),默认值为1。
    • act:是否使用激活函数,默认为 True
        """Initialize Depth-wise convolution with given parameters."""
        super().__init__(c1, c2, k, s, g=math.gcd(c1, c2), d=d, act=act)
  • 这里的文档字符串解释了构造函数的功能。接下来,调用父类 Conv 的构造函数 super().__init__(),并传递参数:
    • c1:输入通道数。
    • c2:输出通道数。
    • k:卷积核大小。
    • s:步幅。
    • g=math.gcd(c1, c2):组卷积的组数为输入通道数和输出通道数的最大公约数(gcd)。这使得 DWConv 类实现了深度可分离卷积。
    • d:扩张率。
    • act:激活函数的选择。

DWConv 类是用于执行深度可分离卷积的神经网络层。它通过继承自 Conv 类,重用卷积的基本功能,同时调整参数以实现分离卷积的特性。

深度可分离卷积有助于减少计算量和参数量,相较于常规卷积,它能够在保持较高性能的前提下提高模型的效率,非常适用于轻量级神经网络,比如在手机或嵌入式设备上使用的模型。通过此类,可以方便地创建深度可分离卷积层,并可选择是否应用激活函数。

 6. focus

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):
        """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):
        """
        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))
        # return self.conv(self.contract(x))

这段代码定义了一个名为 Focus 的类,它是 PyTorch 中 nn.Module 的一个子类,主要用于在卷积神经网络中聚焦空间信息。下面逐步分解并详细解释这段代码:

  1. 类定义

    class Focus(nn.Module):
        """Focus wh information into c-space."""
    
    • 定义了一个 Focus 类,继承自 nn.Module。注释说明这个类的作用是将宽高(wh)信息聚焦到通道空间(c-space)。
  2. 构造函数 __init__

    def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True):
        """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)
    
    • 构造函数接受多个参数,其中:
      • c1: 输入通道数。
      • c2: 输出通道数。
      • k: 卷积核的大小(默认值为1)。
      • s: 步幅(默认值为1)。
      • p: 填充大小(默认值为None)。
      • g: 分组卷积的组数(默认值为1)。
      • act: 激活函数(默认值为True,表示使用默认激活)。
    • super().__init__() 调用基类的构造函数以初始化 nn.Module
    • self.conv: 初始化了一个 Conv 对象,用于处理输入的4倍通道数(即 c1 * 4),将其卷积输出到 c2 通道。
  3. 前向传播函数 forward

    def forward(self, x):
        """
        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))
        # return self.conv(self.contract(x))
    
    • 该方法实现了前向传播过程,接受一个输入张量 x
    • 输入张量的形状为 (b, c, w, h) 其中 b 是批量大小,c 是通道数,w 是宽度,h 是高度。
    • 这里使用了 torch.cat() 方法将 x 的四个分块进行拼接:
      • x[..., ::2, ::2]: 选择偶数行和偶数列的元素。
      • x[..., 1::2, ::2]: 选择奇数行和偶数列的元素。
      • x[..., ::2, 1::2]: 选择偶数行和奇数列的元素。
      • x[..., 1::2, 1::2]: 选择奇数行和奇数列的元素。
    • 拼接后得到的张量形状为 (b, 4c, w/2, h/2),即通道数为原来的四倍,宽度和高度减半,然后将此张量输入到 self.conv 中进行卷积操作。

Focus 类的主要功能是将输入张量的空间信息聚焦到通道空间。这通过选择不同的像素块并将其拼接来实现,从而将输入的宽高信息压缩到通道中。最终,该类通过卷积层输出具有更多通道信息(c2)和减小尺寸的特征图,适用于图像处理和计算机视觉中的特征提取任务。

7. GhostConv

class GhostConv(nn.Module):
    """Ghost Convolution https://github.com/huawei-noah/ghostnet."""

    def __init__(self, c1, c2, k=1, s=1, g=1, act=True):
        """Initializes Ghost Convolution module with primary and cheap operations for efficient feature learning."""
        super().__init__()
        c_ = c2 // 2  # hidden channels
        self.cv1 = Conv(c1, c_, k, s, None, g, act=act)
        self.cv2 = Conv(c_, c_, 5, 1, None, c_, act=act)

    def forward(self, x):
        """Forward propagation through a Ghost Bottleneck layer with skip connection."""
        y = self.cv1(x)
        return torch.cat((y, self.cv2(y)), 1)

1. 类定义

class GhostConv(nn.Module):
    """Ghost Convolution https://github.com/huawei-noah/ghostnet."""
  • GhostConv 类继承自 nn.Module,这是 PyTorch 中所有神经网络模块的基类。该类实现了“Ghost 卷积”模块,这是一种高效的卷积操作,旨在减少模型的计算负担,同时保持特征学习的准确性。

2. 初始化方法

def __init__(self, c1, c2, k=1, s=1, g=1, act=True):
    """Initializes Ghost Convolution module with primary and cheap operations for efficient feature learning."""
    super().__init__()
    c_ = c2 // 2  # hidden channels
    self.cv1 = Conv(c1, c_, k, s, None, g, act=act)
    self.cv2 = Conv(c_, c_, 5, 1, None, c_, act=act)
  • __init__ 方法用于初始化 GhostConv 模块的实例。

  • c1:输入通道数。

  • c2:输出通道数。

  • k:卷积核的大小,默认为1。

  • s:卷积的步长,默认为1。

  • g:组卷积的组数,默认为1。

  • act:是否使用激活函数,默认为True。

主要逻辑

  • c_ = c2 // 2:定义隐含通道数为输出通道数的一半,这为后续的计算做准备。

  • self.cv1:创建一个常规卷积层,将输入通道数 c1 变换为隐含通道数 c_

  • self.cv2:创建第二个卷积层,使用5x5的卷积核,将隐含通道数 c_ 转换为 c_(相同数量的输出通道),这可以提取更复杂的特征。

3. 前向传播方法

def forward(self, x):
    """Forward propagation through a Ghost Bottleneck layer with skip connection."""
    y = self.cv1(x)
    return torch.cat((y, self.cv2(y)), 1)
  • forward 方法定义了数据如何通过网络流动。

  • x:输入张量,通常形状为 (batch_size, channels, height, width)

主要逻辑

  • y = self.cv1(x):通过第一个卷积层处理输入,返回中特征图。

  • return torch.cat((y, self.cv2(y)), 1):将第一个卷积层的输出 y 与通过第二个卷积层处理的 y 拼接,拼接的维度为1(即通道维度)。这样,输出将包含来自两个卷积层的特征图,增强了模型的表达能力。

GhostConv 类实现了“Ghost 卷积”模块,该模块通过引入主卷积和廉价卷积的组合,有效地学习特征。初始化方法中定义了两个卷积层,分别负责处理输入通道和生成特征。前向传播方法则将这两个层的输出拼接在一起,形成了最终的输出。这种设计旨在提高计算效率,同时保持模型性能。

 8. lightConv

class LightConv(nn.Module):
    """
    Light convolution with args(ch_in, ch_out, kernel).

    https://github.com/PaddlePaddle/PaddleDetection/blob/develop/ppdet/modeling/backbones/hgnet_v2.py
    """

    def __init__(self, c1, c2, k=1, act=nn.ReLU()):
        """Initialize Conv layer with given arguments including activation."""
        super().__init__()
        self.conv1 = Conv(c1, c2, 1, act=False)
        self.conv2 = DWConv(c2, c2, k, act=act)

    def forward(self, x):
        """Apply 2 convolutions to input tensor."""
        return self.conv2(self.conv1(x))

这段代码定义了一个名为 LightConv 的类,该类是 PyTorch 的 nn.Module 的一个子类。以下是该代码的逐步分解及详细解释:

类定义

class LightConv(nn.Module):
  • 该类继承自 nn.Module,这意味着 LightConv 是一个可训练的神经网络模块。

文档字符串

"""
Light convolution with args(ch_in, ch_out, kernel).
https://github.com/PaddlePaddle/PaddleDetection/blob/develop/ppdet/modeling/backbones/hgnet_v2.py
"""
  • 提供了一个简短的描述,说明这是一个轻量级卷积的实现,接受输入通道数(ch_in)、输出通道数(ch_out)和卷积核大小(kernel)作为参数。

  • 还提供了一个指向相关实现的链接。

初始化方法

def __init__(self, c1, c2, k=1, act=nn.ReLU()):
  • __init__ 是类的构造方法,用于初始化实例。

  • c1:输入通道数。

  • c2:输出通道数。

  • k:卷积核的大小,默认为 1。

  • act:激活函数,默认为 ReLU。

初始化主要组件

super().__init__()
self.conv1 = Conv(c1, c2, 1, act=False)
self.conv2 = DWConv(c2, c2, k, act=act)
  • super().__init__() 调用父类的构造方法,以确保父类正确初始化。

  • self.conv1 是一个标准的卷积层(Conv),它使用 1x1 的卷积核,将输入的通道数从 c1 转换为 c2,且不使用激活函数(act=False)。

  • self.conv2 是一个深度卷积层(DWConv),它使用指定大小的卷积核(k),将通道数从 c2 转换为 c2,并且使用传入的激活函数。

前向传播方法

def forward(self, x):
  • forward 方法定义了如何通过该模块进行前向传播,即如何处理输入数据 x

处理输入张量

return self.conv2(self.conv1(x))
  • 先通过 self.conv1 对输入张量 x 进行处理,得到中间结果,然后将该中间结果传递给 self.conv2 进行进一步处理。

  • 最终返回的结果就是经过两次卷积处理后的输出张量。

LightConv 是一个轻量级的卷积模块,旨在以高效的方式对输入数据进行处理。它首先使用 1x1 的标准卷积将输入通道数映射到输出通道数,然后通过深度卷积进一步处理,能够减少模型参数和计算量。此模块广泛应用于需要高效特征提取的深度学习网络中,尤其是在计算资源有限的情况下。

 9. ChannelAttention

class ChannelAttention(nn.Module):
    """Channel-attention module https://github.com/open-mmlab/mmdetection/tree/v3.0.0rc1/configs/rtmdet."""

    def __init__(self, channels: int) -> None:
        """Initializes the class and sets the basic configurations and instance variables required."""
        super().__init__()
        self.pool = nn.AdaptiveAvgPool2d(1)
        self.fc = nn.Conv2d(channels, channels, 1, 1, 0, bias=True)
        self.act = nn.Sigmoid()

    def forward(self, x: torch.Tensor) -> torch.Tensor:
        """Applies forward pass using activation on convolutions of the input, optionally using batch normalization."""
        return x * self.act(self.fc(self.pool(x)))

  1. 类定义:

    class ChannelAttention(nn.Module):
    

    这里定义了一个名为 ChannelAttention 的类,继承自 PyTorch 的 nn.Module。这是一个用于实现通道注意力机制的模块。

  2. 文档字符串:

    """Channel-attention module https://github.com/open-mmlab/mmdetection/tree/v3.0.0rc1/configs/rtmdet."""
    

    文档字符串提供了该模块的简要说明及相关链接,这里提到了使用的来源。

  3. 初始化方法:

    def __init__(self, channels: int) -> None:
    

    初始化方法接受一个参数 channels,表示输入张量的通道数。

  4. 父类初始化:

    super().__init__()
    

    调用父类的初始化方法,以便正确初始化继承自 nn.Module 的部分。

  5. 自适应平均池化层:

    self.pool = nn.AdaptiveAvgPool2d(1)
    

    创建一个自适应平均池化层,输出大小为 1×1。这意味着输入张量的每个通道都会通过平均池化被压缩为一个单一的数值。

  6. 全连接层(卷积):

    self.fc = nn.Conv2d(channels, channels, 1, 1, 0, bias=True)
    

    创建一个 1x1 的卷积层,输入通道和输出通道均为 channels。这个卷积层相当于一个全连接层,可以用来对每个通道进行变换。

  7. 激活函数:

    self.act = nn.Sigmoid()
    

    使用 Sigmoid 激活函数,这个函数的输出范围在 0 到 1 之间。

  8. 前向传播方法:

    def forward(self, x: torch.Tensor) -> torch.Tensor:
    

    定义前向传播方法,接受一个输入张量 x

  9. 计算过程:

    return x * self.act(self.fc(self.pool(x)))
    
    • 首先,通过自适应平均池化对输入 x 进行处理,得到一个 1×1 的张量,表示输入每个通道的平均值。
    • 然后通过卷积层 self.fc 对这个 1×1 的结果进行处理,得到一个通道的权重向量。
    • 最后,通过 Sigmoid 激活函数将得到的权重映射到 0 到 1 之间。
    • 最终的输出是输入 x 和计算得到的权重的逐通道相乘结果,这样可以使得每个通道的特征进行加权,强调重要的特征。

ChannelAttention 类实现了一个通道注意力机制,主要用于突出输入特征图中的重要通道。通过首先对输入特征进行自适应平均池化,然后使用 1x1 卷积层和 Sigmoid 激活函数来计算每个通道的权重,最终通过按通道相乘的方式返回加权后的特征图。这个模块在深度学习中常用于提高模型的表现,特别是在目标检测和图像分类等任务中。

10. SpatialAttention

class SpatialAttention(nn.Module):
    """Spatial-attention module."""

    def __init__(self, kernel_size=7):
        """Initialize Spatial-attention module with kernel size argument."""
        super().__init__()
        assert kernel_size in {3, 7}, "kernel size must be 3 or 7"
        padding = 3 if kernel_size == 7 else 1
        self.cv1 = nn.Conv2d(2, 1, kernel_size, padding=padding, bias=False)
        self.act = nn.Sigmoid()

    def forward(self, x):
        """Apply channel and spatial attention on input for feature recalibration."""
        return x * self.act(self.cv1(torch.cat([torch.mean(x, 1, keepdim=True), torch.max(x, 1, keepdim=True)[0]], 1)))

1. 类定义

class SpatialAttention(nn.Module):
    """Spatial-attention module."""
  • 这是一个名为 SpatialAttention 的类,它继承自 torch.nn.Module。这个类实现的是空间注意力机制,通常用于提升特征图的表示能力。

2. 构造函数

def __init__(self, kernel_size=7):
    """Initialize Spatial-attention module with kernel size argument."""
    super().__init__()
  • __init__ 是构造函数,它在类实例化时调用。这里,kernel_size 参数的默认值为 7。

  • super().__init__() 调用父类(nn.Module)的构造函数,以确保模块的正确初始化。

3. 参数检查

assert kernel_size in {3, 7}, "kernel size must be 3 or 7"
  • 通过断言语句检查 kernel_size 是否为 3 或 7。若不是,将抛出错误,并提示用户输入有效的卷积核大小。

4. 填充和卷积层定义

padding = 3 if kernel_size == 7 else 1
self.cv1 = nn.Conv2d(2, 1, kernel_size, padding=padding, bias=False)
  • 根据 kernel_size 的值设置填充(padding)。如果卷积核大小为 7,则填充为 3;否则,填充为 1。

  • self.cv1 定义了一个二维卷积层,其输入通道数为 2,输出通道数为 1,卷积核的大小取决于 kernel_size

5. 激活函数

self.act = nn.Sigmoid()
  • 这里定义了一个 Sigmoid 激活函数,将用于后续计算中,以便对卷积输出进行激活,映射到(0, 1)之间。

6. 前向传播函数

def forward(self, x):
    """Apply channel and spatial attention on input for feature recalibration."""
  • forward 方法定义了如何通过这个模块传输输入 x。它是网络向前传播时必定调用的方法。

7. 计算空间注意力

return x * self.act(self.cv1(torch.cat([torch.mean(x, 1, keepdim=True), torch.max(x, 1, keepdim=True)[0]], 1)))
  • torch.mean(x, 1, keepdim=True):计算输入 x 在通道维上的均值,也就是对于每个空间位置取通道上的平均值。

  • torch.max(x, 1, keepdim=True)[0]:计算输入 x 在通道维上的最大值。

  • torch.cat(..., 1):在通道维上连接均值和最大值的特征图,形成一个具有 2 个通道的张量。

  • self.cv1(...):将连接后的张量输入到卷积层中,生成一个新的特征图。

  • self.act(...):使用 Sigmoid 激活函数对卷积输出进行激活,从而产生空间注意力的权重图。

  • x * ...:最后,将输入 x 的特征图与该权重图相乘,从而完成空间注意力的应用,突出重要特征。

SpatialAttention 类实现了空间注意力机制。该机制通过对输入特征图计算通道均值和最大值,生成空间注意力权重。然后,通过一个卷积层和激活函数处理这些权重,再与输入特征图相乘,重新校准特征图中的重要信息,增强模型对重要区域的关注能力,从而提升模型性能。

11. CBAM

class CBAM(nn.Module):
    """Convolutional Block Attention Module."""

    def __init__(self, c1, kernel_size=7):
        """Initialize CBAM with given input channel (c1) and kernel size."""
        super().__init__()
        self.channel_attention = ChannelAttention(c1)
        self.spatial_attention = SpatialAttention(kernel_size)

    def forward(self, x):
        """Applies the forward pass through C1 module."""
        return self.spatial_attention(self.channel_attention(x))

这段代码定义了一个名为 CBAM 的类,代表“卷积块注意力模块”(Convolutional Block Attention Module)。该模块结合了通道注意力和空间注意力机制,以增强特征的表达能力。下面是对代码的逐步分解和详细解释:

  1. 类定义

    class CBAM(nn.Module):
        """Convolutional Block Attention Module."""
    

    这里定义了一个名为 CBAM 的类,继承自 torch.nn.Module,使其成为一个可以集成到 PyTorch 模型中的神经网络模块。

  2. 初始化方法 (__init__)

    def __init__(self, c1, kernel_size=7):
        """Initialize CBAM with given input channel (c1) and kernel size."""
        super().__init__()
        self.channel_attention = ChannelAttention(c1)
        self.spatial_attention = SpatialAttention(kernel_size)
    
    • 参数
      • c1: 输入特征图的通道数。
      • kernel_size: 用于空间注意力的卷积核大小,默认为 7。
    • 功能
      • 调用父类的初始化方法 super().__init__()
      • 创建一个通道注意力模块 ChannelAttention 的实例,并将输入通道数 c1 传递给它。
      • 创建一个空间注意力模块 SpatialAttention 的实例,并传递 kernel_size
  3. 前向传播方法 (forward)

    def forward(self, x):
        """Applies the forward pass through C1 module."""
        return self.spatial_attention(self.channel_attention(x))
    
    • 参数
      • x: 输入张量,通常是特征图。
    • 功能
      • 先通过通道注意力模块处理输入 x,生成加权后的特征图。
      • 然后,将通道注意力模块的输出传递给空间注意力模块,进行进一步处理。
      • 最终返回经过通道和空间注意力加权的特征图。

该代码实现的 CBAM 模块旨在通过结合通道注意力和空间注意力机制,提升特征图的表达能力。其主要功能是:

  • 通道注意力:对特征图的每个通道进行加权,以突出重要通道,抑制不重要的通道。
  • 空间注意力:在特征图的宽高维度上进行加权,强调图像中重要的空间区域。

通过这种双重注意力机制,CBAM 模块能够帮助模型更有效地学习到有用的特征,从而提高任务性能,特别是在图像分类、目标检测等视觉任务中。

12. Concat

class Concat(nn.Module):
    """Concatenate a list of tensors along dimension."""

    def __init__(self, dimension=1):
        """Concatenates a list of tensors along a specified dimension."""
        super().__init__()
        self.d = dimension

    def forward(self, x):
        """Forward pass for the YOLOv8 mask Proto module."""
        return torch.cat(x, self.d)

这段代码定义了一个名为 Concat 的 PyTorch 模块,主要用于在指定维度上连接多个张量。下面是对代码的逐步分解和详细解释:

  1. 导入依赖:

    import torch
    import torch.nn as nn
    

    依赖于 torch 和 torch.nn 模块,前者是 PyTorch 的核心库,后者包含神经网络相关的功能和模块。

  2. 类定义:

    class Concat(nn.Module):
    

    定义了一个名为 Concat 的类,继承自 nn.Module。继承该类配合 PyTorch 的神经网络模型定义。

  3. 文档字符串:

    """Concatenate a list of tensors along dimension."""
    

    该字符串描述了该类的功能,即沿着指定维度连接多个张量。

  4. 初始化方法:

    def __init__(self, dimension=1):
    

    初始化方法接受一个参数 dimension,默认值为 1,指明要沿哪个维度连接。

    • super().__init__() 调用父类的初始化方法,以确保模块的基类被正确初始化。

    • self.d = dimension 保存传入的维度参数,供后续使用。

  5. 前向传播方法:

    def forward(self, x):
    

    定义了前向传播方法 forward,该方法在调用此模块时执行。

    • x 是输入,通常是一个包含多个张量的列表或元组。

    • return torch.cat(x, self.d)使用 torch.cat 方法将所有输入张量在指定的维度 self.d 上进行连接。

该 Concat 类的主要功能是沿着指定的维度连接一个张量列表。其设计能够适用于多种输入组合,使得在神经网络中可灵活地组合特征图或其他张量。在 YOLOv8 的上下文中,这可能用于特征融合或连接不同层的输出,以便后续的处理。

在实际应用中,可以根据需要指定连接的维度,这样在处理多通道数据或多层特征时,可以灵活配置结果的形状。

13. ConvTranspose

class ConvTranspose(nn.Module):
    """Convolution transpose 2d layer."""

    default_act = nn.SiLU()  # default activation

    def __init__(self, c1, c2, k=2, s=2, p=0, bn=True, act=True):
        """Initialize ConvTranspose2d layer with batch normalization and activation function."""
        super().__init__()
        self.conv_transpose = nn.ConvTranspose2d(c1, c2, k, s, p, bias=not bn)
        self.bn = nn.BatchNorm2d(c2) if bn else nn.Identity()
        self.act = self.default_act if act is True else act if isinstance(act, nn.Module) else nn.Identity()

    def forward(self, x):
        """Applies transposed convolutions, batch normalization and activation to input."""
        return self.act(self.bn(self.conv_transpose(x)))

    def forward_fuse(self, x):
        """Applies activation and convolution transpose operation to input."""
        return self.act(self.conv_transpose(x))

这段代码定义了一个名为 ConvTranspose 的类,它实现了一个转置卷积(或反卷积)层。下面逐步分解并详细解释这段代码:

类定义

class ConvTranspose(nn.Module):
    """Convolution transpose 2d layer."""
  • 该类继承自 torch.nn.Module,表明它是一个神经网络模块。

  • 它的主要功能是进行二维转置卷积操作,通常用于图像生成或上采样任务。

默认激活函数

default_act = nn.SiLU()  # default activation
  • 定义了一个默认的激活函数,这里使用的是 SiLU(Sigmoid Linear Unit),这是一个常见的激活函数。

初始化方法

def __init__(self, c1, c2, k=2, s=2, p=0, bn=True, act=True):
    """Initialize ConvTranspose2d layer with batch normalization and activation function."""
    super().__init__()
  • __init__ 函数是初始化方法,在实例化这个类时会被调用。

  • 参数说明:

    • c1:输入通道数。

    • c2:输出通道数。

    • k:卷积核的大小(默认为 2)。

    • s:步幅(默认为 2),控制输出特征图的尺寸。

    • p:填充(默认为 0),用于卷积操作的额外填充。

    • bn:布尔值,决定是否在卷积后使用批量归一化。

    • act:布尔值,决定是否使用激活函数。

self.conv_transpose = nn.ConvTranspose2d(c1, c2, k, s, p, bias=not bn)
  • 创建一个转置卷积层 self.conv_transpose,该层将输入的特征图进行上采样。

  • bias=not bn:如果使用批量归一化,则不使用偏置。

self.bn = nn.BatchNorm2d(c2) if bn else nn.Identity()
  • 根据参数 bn 决定是否使用批量归一化。如果 bn 为真,将使用批量归一化层;否则,使用身份(即不做任何操作)。

self.act = self.default_act if act is True else act if isinstance(act, nn.Module) else nn.Identity()
  • 根据 act 参数初始化激活函数。如果 act 为 True,使用默认的 SiLU 函数;如果 act 是一个 nn.Module 实例,则直接使用它;否则,使用身份函数。

前向传播方法

def forward(self, x):
    """Applies transposed convolutions, batch normalization and activation to input."""
    return self.act(self.bn(self.conv_transpose(x)))
  • 该方法实现了前向传播。

  • 输入张量 x 经过转置卷积层、批量归一化(如果使用),最后经过激活函数。这一过程综合了卷积操作、归一化和激活的效果。

融合前向传播方法

def forward_fuse(self, x):
    """Applies activation and convolution transpose operation to input."""
    return self.act(self.conv_transpose(x))
  • 该方法提供了一种优化的前向传播方式,省略了批量归一化的步骤,只进行转置卷积和激活。

  • 适用于推理阶段,通常用来减少计算时间和提高性能。

ConvTranspose 类实现了一个转置卷积层,配备了批量归一化和激活函数选项。其主要功能是将输入特征图进行上采样,常用于图像生成或传递特征到更高分辨率的层中。类定义了两种前向传播方法,以支持训练和推理阶段的不同需求。

 14.DWConvTranspose2d

class DWConvTranspose2d(nn.ConvTranspose2d):
    """Depth-wise transpose convolution."""

    def __init__(self, c1, c2, k=1, s=1, p1=0, p2=0):  # ch_in, ch_out, kernel, stride, padding, padding_out
        """Initialize DWConvTranspose2d class with given parameters."""
        super().__init__(c1, c2, k, s, p1, p2, groups=math.gcd(c1, c2))
  1. 类定义:

    class DWConvTranspose2d(nn.ConvTranspose2d):
    
    • 该行定义了一个名为 DWConvTranspose2d 的新类,它继承自 nn.ConvTranspose2d。这意味着 DWConvTranspose2d 将具备 nn.ConvTranspose2d 的所有功能,并可以在其基础上进行扩展。
  2. 类文档字符串:

    """Depth-wise transpose convolution."""
    
    • 这是一个文档字符串,简单描述了这个类的功能,即“深度逐通道的转置卷积”。
  3. 初始化方法:

    def __init__(self, c1, c2, k=1, s=1, p1=0, p2=0):
    
    • 定义了初始化方法 __init__,这是一个构造函数,用于创建类的实例。它接受参数如下:
      • c1: 输入通道数。
      • c2: 输出通道数。
      • k: 卷积核的大小,默认为1。
      • s: 步幅,默认为1。
      • p1 和 p2: 填充参数,分别代表输入和输出的填充量,默认为0。
  4. 调用父类初始化方法:

    super().__init__(c1, c2, k, s, p1, p2, groups=math.gcd(c1, c2))
    
    • 使用 super().__init__() 调用父类 nn.ConvTranspose2d 的初始化方法。传递给父类的参数包括:
      • c1: 输入通道数。
      • c2: 输出通道数。
      • k: 卷积核大小。
      • s: 步幅。
      • p1: 输入填充量。
      • p2: 输出填充量。
      • groups: 分组数,这里使用 math.gcd(c1, c2) 计算输入和输出通道数的最大公约数,以实现深度卷积的特性。

DWConvTranspose2d 类实现了深度逐通道转置卷积(Depth-wise Transpose Convolution),它用于在神经网络中进行转置卷积操作。这个类继承自 PyTorch 的 nn.ConvTranspose2d,在初始化时将输入和输出通道数、卷积核大小、步幅和填充等参数传递给父类。通过利用最大公约数来设定分组数,实现了深度卷积的特性,使其在处理输入数据时具有更高效的参数利用率,适合处理图像等多通道数据。

猜你喜欢

转载自blog.csdn.net/a8039974/article/details/143169904