YOLOv5中SPP/SPPF结构源码详析(内含注释分析)

让我详细讲解一下“YOLOv5中SPP/SPPF结构源码详析(内含注释分析)”的完整攻略,过程中将包含两个示例说明。

首先,让我们回顾一下SPP(Spatial Pyramid Pooling)结构的定义。SPP结构是一种特殊的池化层,目的是在不同尺度下对图像进行池化(Pooling)。这种结构可以在不同尺寸的特征图上利用ROI池化不同尺度下的特征信息,提高模型的精度和效率。

在YOLOv5的实现中,SPP结构主要包含两个版本,分别为SPP和SPPF。其中,SPP代表“Spatial Pyramid Pooling”,而SPPF则代表“Fast Spatial Pyramid Pooling”。

接下来,让我们详细讲解这两个版本的SPP结构的源码实现及其注释分析。

SPP结构源码详析

以下是SPP结构的python代码实现及其注释:

class SPP(nn.Module):
    def __init__(self, c1, c2, k=(5, 9, 13)):
        super(SPP, self).__init__()
        c_ = int(c1 / 2)
        self.cv1 = Conv(c1, c_, 1, 1)
        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)
        x = torch.cat([x] + [m(x) for m in self.m], 1)
        x = self.cv2(x)
        return x

在上面的代码实现中,我们可以看到SPP结构的主要实现流程。SPP结构主要包括三个部分:第一个是输入通道数和输出通道数的设置;第二个是池化核大小的设置;第三个是正向传播函数的实现。

具体地:

  • 在第一部分中,输入通道数和输出通道数分别为c1和c2,我们将输入通道数c1除以2,得到的结果c_表示输入的通道数下降一半。然后,我们将c_分别乘以池化核的个数再加1,即c_ * (len(k) + 1),得到的结果即为输出的通道数c2。

  • 在第二部分中,我们通过设置池化核的大小,定义了一个最大池化层的列表,其数字大小在k中指定。这些最大池化层将在SPP模块的池化子层中使用。

  • 在第三部分中,我们用一个卷积操作将输入进行压缩,接着将压缩后的结果与多个不同尺度的池化层进行拼接,然后再进行一次卷积操作,最终得到SPP结构的输出结果。

需要注意的是,在YOLOv5的实现中,SPP结构中的卷积层采用了Conv模块,而不是普通的nn.Conv2d。为了更好地理解Conv模块的实现原理,我们需要进一步了解它。

Conv模块源码详析

以下是Conv模块的python代码实现及其注释:

class Conv(nn.Module):
    def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True):
        super(Conv, self).__init__()
        if isinstance(k, int):  # kernel size: kxk
            k = (k, k)
        if isinstance(s, int):  # stride: sxs
            s = (s, s)
        if isinstance(p, int):  # padding: p
            p = (p, p)
        self.conv = nn.Conv2d(c1, c2, kernel_size=k, stride=s,
                              padding=p, groups=g, bias=False)
        self.bn = nn.BatchNorm2d(c2)
        self.act = nn.LeakyReLU(0.1, inplace=True) if act else None

    def forward(self, x):
        x = self.conv(x)
        x = self.bn(x)
        if self.act is not None:
            x = self.act(x)
        return x

在上面的代码实现中,我们可以看到Conv模块的主要实现流程。Conv模块主要包括四个部分:输入通道数和输出通道数的设置;卷积核大小和步长的设置;批归一化层的添加;激活函数的添加。

具体地:

  • 在第一部分中,输入通道数c1表示卷积层输入数据张量中的通道数,c2表示卷积层输出数据张量中的通道数。

  • 在第二部分中,卷积核大小k和步长s均设置为可选参数。可以通过传递一个整数设置kxk大小的卷积核。也可以通过传递元组设置kxk大小的卷积核和sxs的步长。p是padding参数,如果不设置,将自动设置。g参数表示分组卷积的数量。

  • 在第三部分中,我们通过添加批归一化层来防止梯度消失。这里我们使用pytorch内置的BatchNorm2d层。

  • 在第四部分中,我们可以选择在卷积操作后添加一个激活函数,这里我们使用了LeakyReLU激活函数。

通过以上对SPP和Conv模块源码的详细讲解,我们已经可以更好地理解这两个模块的使用方式和实现原理。接下来,我们将看一下两个实际的示例。

示例1:在Backbone中的使用

下面是在Backbone中使用SPP结构的示例代码:

# SPP 结构
class SPPCSP(nn.Module):
    def __init__(self, c1, c2, n=3, k=(5, 9, 13)):
        super(SPPCSP, self).__init__()
        c_ = int(c2 * 0.5)  # hidden channels
        self.cv1 = Conv(c1, c_, 1, 1)
        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])

        self.cv3 = Conv(c_, c_, 1)
        self.cv4 = Conv(c2, c_, 1)
        self.cv5 = Conv(c_ * n, c2, 1)
        self.act = nn.LeakyReLU(0.1, inplace=True)

    def forward(self, x):
        y = self.cv1(x)
        y = torch.cat([y] + [m(y) for m in self.m], 1)
        y = self.cv2(y)

        x = self.cv3(y)
        y = self.cv4(y)
        y = self.act(y + F.interpolate(x, size=[y.shape[2], y.shape[3]], mode='nearest'))

        y = torch.cat([y] * self.m, 1)
        y = self.cv5(y)
        return y

在上面的代码实现中,我们可以看到SPP结构被应用在了CSP网络中。输入数据包括特征图x。然后,我们将其送入SPP网络中,按照上述讲解进行卷积池化等操作。最终,得到输出特征图y。

示例2:在Detection Head中的使用

下面是在Detection Head中使用SPPF结构的示例代码:

# SPPF 结构
class SPPF(nn.Module):
    def __init__(self, c, k=(5, 9, 13)):
        super(SPPF, self).__init__()
        c_ = int(c / 2)
        self.cv1 = Conv(c, c_, 1, 1)
        self.cv2 = Conv(c_ * (len(k) + 1), c, 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)
        x = torch.cat([x] + [m(x) for m in self.m], 1)
        x = self.cv2(x)
        return x

在上面的代码实现中,我们将SPPF结构应用在了YOLOv5的Detection Head中。输入数据包括特征图x。然后,我们将其送入SPPF网络中,按照上述讲解进行卷积池化等操作。最终,得到输出特征图y。

通过以上的两个示例,我们可以看到,SPP(SPPF)结构在YOLOv5目标检测模型的各个部分中均有应用。在实际使用中,我们可以根据需要进行不同的处理和组合,以便更好地满足目标检测任务的需求。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:YOLOv5中SPP/SPPF结构源码详析(内含注释分析) - Python技术站

(0)
上一篇 2023年5月15日
下一篇 2023年5月15日

相关文章

  • 3*3卷积核实例

    3×3 convolution kernels with online demo Which are the most used 3×3 convolution kernels/matrices? Which kernel is used for averaging, applying blur or smooth effect, do sharpening…

    2023年4月8日
    00
  • 卷积神经网络之卷积的物理意义

      图像中的卷积,是离散的,这不同于我们数学中的卷积公式,数学中的卷积公式大部分都是连续的,但是也有离散的卷积公式,学过数字信号处理的应该都知道。这一点是我之前不明白的地方。      正如上图所示,大的方框表示原图像的像素,中间小的3*3的方框为卷积模板,最右边的方框是做完卷积之后的输出图像。   那么,为什么要对图像做卷积呢?卷积的物理意义是什么呢?经过…

    2023年4月6日
    00
  • [DeeplearningAI笔记]卷积神经网络3.6-3.9交并比/非极大值抑制/Anchor boxes/YOLO算法

    觉得有用的话,欢迎一起讨论相互学习~ 吴恩达老师课程原地址 3.6交并比intersection over union 交并比函数(loU)可以用来评价对象检测算法,可以被用来进一步改善对象检测算法的性能。 如何评价一个算法的好坏,即如图中假设红色框线表示 真实的对象所在边界框,紫色框线表示 模型预测的对象所在边界框.通过计算两个边界框交集和并集的比用于评价…

    2023年4月8日
    00
  • CNN中卷积层 池化层反向传播

    参考:https://blog.csdn.net/kyang624823/article/details/78633897 卷积层 池化层反向传播: 1,CNN的前向传播 a)对于卷积层,卷积核与输入矩阵对应位置求积再求和,作为输出矩阵对应位置的值。如果输入矩阵inputX为M*N大小,卷积核为a*b大小,那么输出Y为(M-a+1)*(N-b+1)大小。  …

    2023年4月8日
    00
  • 全卷积网络FCN详解

    http://www.cnblogs.com/gujianhan/p/6030639.html CNN能够对图片进行分类,可是怎么样才能识别图片中特定部分的物体? (图像语义分割) FCN(Fully Convolutional Networks)对图像进行像素级的分类,从而解决了语义级别的图像分割(semantic segmentation)问题。与经典的…

    2023年4月8日
    00
  • 深度学习原理与框架-卷积网络细节-网络设计技巧 1. 3个3*3替换7*7卷积核 2. 1*1 和 3*3 替换 3*3卷积核

    感受野:对于第一次卷积,如果卷积核是3*3,那么卷积的感受野就是3*3,如果在此卷积上,再进行一次卷积的话,那么这次的卷积的感受野就是5*5  因为5*5的区域,卷积核为3*3, 卷积后每一个点的感受野是3*3,卷积后的区域为3*3 第二次卷积还用用3*3的卷积的话,第二次卷积的结果就变成了1*1,因此每一个点的感受野是5*5   对应于3次卷积的结果,每一…

    2023年4月8日
    00
  • 卷积层channel数量变化过程

      卷积神经网络的总体架构是金字塔型,如下图。 CNNs架构图 可以看到,每一层的channel数量是变化的。如上图中,左边的第一层只有R、G、B三个channel,第二层有16个channel,第三、四层分别有64、256个。 那么这些channel数量是如何变化的呢?   基本过程: 对于输入图片的每一个patch(下图中的绿色部分),运行一个具有K个输…

    2023年4月6日
    00
  • CNN中卷积的意义

      在传统的神经网络中,比如多层感知机(MLP),其输入通常是一个特征向量。需要人工设计特征,然后将用这些特征计算的值组成特征向量。在过去几十年的经验来看,人工找的特征并不总是好用。有时多了,有时少了,有时选的特征根本就不起作用(真正起作用的特征在浩瀚的未知里)。这就是为啥过去几十年神经网络一直被SVM等完虐的原因。  如果有人说,任何特征都是从图像中提取的…

    2023年4月5日
    00
合作推广
合作推广
分享本页
返回顶部