YOLOv7基础 | 手把手教你简化网络结构之yolov7.yaml(包括源码+封装步骤+网络结构图)

发布时间:2024年01月14日

前言:Hello大家好,我是小哥谈。通过下载YOLOv7源码可知,原始的yolov7.yaml文件是拆开写的,比较混乱,也不好理解,并且为后续改进增添了很多困难。基于此种情况,笔者就给大家介绍一种将yolov7.yaml文件简化的方法,并且参数量和计算量和原来是一致的,区别只是yaml文件的写法不同!~🌈??

? ? ?目录

🚀1.背景介绍

🚀2.封装步骤

🚀3.具体方法

💥💥步骤1:common.py文件修改

💥💥步骤2:yolo.py文件修改

💥💥步骤3:创建自定义yaml文件

💥💥步骤4:修改自定义yaml文件

💥💥步骤5:验证是否加入成功

💥💥步骤6:修改默认参数

💥💥步骤7:实际训练测试

🚀1.背景介绍

YOLOv7是一种广泛用于实时目标检测的单阶段算法,其成功的一部分可以归功于灵活的yaml配置文件。然而,随着项目的发展,配置文件可能变得庞大而复杂。在本博文中,我们将学习如何简化YOLOv7的yaml配置文件,以提高可读性可维护性

封装后具体的结构可以参考下列的网络结构图,图中的模块都是和yaml配置文件一一对应的。👇

改进后的代码作者已上传至“下载”中,大家学习的时候可自行下载。?👇


🚀2.封装步骤

针对YOLOv7源码封装,具体步骤如下所示:👇

步骤1:common.py文件修改

步骤2:yolo.py文件修改

步骤3:创建自定义yaml文件

步骤4:修改自定义yaml文件

步骤5:验证是否加入成功

步骤6:修改默认参数

步骤7:实际训练测试


🚀3.具体方法

💥💥步骤1:common.py文件修改

从上述网络结构图上可以看出,我们需要封装的模块分为ELANMP1MP2ELAN_H这几个模块。

common.py中添加ELAN、MP1、MP2、ELAN-H这几个模块的代码,所要添加模块的代码如下所示,将其复制粘贴到common.py文件末尾的位置。

# 需要添加模块的代码
class ELAN(nn.Module):
    def __init__(self, c1, c2,e=0.5):
        '''
        :param c1: 输入通道
        :param c2: 这里给的是中间层的输出通道
        :param flg: 判断是否为backbone的最后一层,因为这里的输出通道数有所改变
        '''
        super(ELAN, self).__init__()
        c_ = int(c1 *e)
        self.conv1 = Conv(c1, c_, k=1, s=1)

        self.conv2 = Conv(c1, c_, k=1, s=1)

        self.conv3 = Conv(c_, c_, k=3, s=1)
        self.conv4 = Conv(c_, c_, k=3, s=1)
        self.conv5 = Conv(c_, c_, k=3, s=1)
        self.conv6 = Conv(c_, c_, k=3, s=1)
        self.conv7 = Conv(4 * c_, c2, k=1, s=1)

    def forward(self, x):
        # 分支一输出
        output1 = self.conv1(x)
        # 分支二输出
        output2_1 = self.conv2(x)
        output2_2 = self.conv3(output2_1)
        output2_3 = self.conv4(output2_2)
        output2_4 = self.conv5(output2_3)
        output2_5 = self.conv6(output2_4)
        output_cat = torch.cat((output1, output2_1, output2_3, output2_5), dim=1)
        return self.conv7(output_cat)

class ELAN_H(nn.Module):
    def __init__(self, c1, c2,e1=0.5,e2=0.25):
        '''
        :param c1: 输入通道
        :param c2: 这里给的是中间层的输出通道
        :param flg: 判断是否为backbone的最后一层,因为这里的输出通道数有所改变
        '''
        super(ELAN_H, self).__init__()
        c_ = int(c1 * e1)
        c_hidden = int(c1 *e2)
        self.conv1 = Conv(c1, c_, k=1, s=1)
        self.conv2 = Conv(c1, c_, k=1, s=1)
        self.conv3 = Conv(c_, c_hidden, k=3, s=1)
        self.conv4 = Conv(c_hidden, c_hidden, k=3, s=1)
        self.conv5 = Conv(c_hidden, c_hidden, k=3, s=1)
        self.conv6 = Conv(c_hidden, c_hidden, k=3, s=1)
        self.conv7 = Conv(2 * c1, c2, k=1, s=1)

    def forward(self, x):
        '''
        :param x: 输入
        :return:
        '''
        # 分支一输出
        output1 = self.conv1(x)
        # 分支二输出
        output2_1 = self.conv2(x)
        output2_2 = self.conv3(output2_1)
        output2_3 = self.conv4(output2_2)
        output2_4 = self.conv5(output2_3)
        output2_5 = self.conv6(output2_4)
        output_cat = torch.cat((output1, output2_1, output2_2, output2_3, output2_4, output2_5), dim=1)
        return self.conv7(output_cat)

class MPConv(nn.Module):
    def __init__(self, c1, e=0.5):
        '''
        :param ch_in: 输如通道
        :param ch_out: 这里给的是中间层的输出通道
        '''
        c_ = int(c1 * e)
        super(MPConv, self).__init__()
        # 分支一
        self.conv1 = nn.Sequential(
            nn.MaxPool2d(2, 2),
            Conv(c1, c_, 1, 1),
        )
        # 分支二
        self.conv2 = nn.Sequential(
            Conv(c1, c_, 1, 1),
            Conv(c_, c_, 3, 2),
        )
        self.cat=Concat()
    def forward(self, x):
        # 分支一
        output1 = self.conv1(x)
        # 分支二
        output2 = self.conv2(x)
        output=self.cat((output1, output2))
        return output

说明:??????

MPConv模块包括两种结构,分别是MP1和MP2,请注意分别,关于详细差异请参考后续对yolov7.yaml文件的解析文章。

💥💥步骤2:yolo.py文件修改

修改1,在yolo.py文件中找到parse_model函数(443行左右),加入ELAN、ELAN_H。

修改2,在yolo.py文件中找到parse_model函数,然后再找到elif m is nn.BatchNorm2d:语句(493行左右),在其前面加入代码:

        elif m is MPConv:
            if args[0] == 1:
                c2 = ch[f] * 2
            args = [ch[f], *args]

关于这两处修改,具体如下图所示:

💥💥步骤3:创建自定义yaml文件

cfg/traning中复制yolov7.yaml,粘贴并重命名为yolov7_simplify.yaml具体如下图所示:

💥💥步骤4:修改自定义yaml文件

根据上述YOLOv7网络结构图进行修改。修改后的完整yaml文件如下所示:

# parameters
nc: 80  # number of classes
depth_multiple: 1.0  # model depth multiple
width_multiple: 1.0  # layer channel multiple

# anchors
anchors:
  - [12,16, 19,36, 40,28]  # P3/8
  - [36,75, 76,55, 72,146]  # P4/16
  - [142,110, 192,243, 459,401]  # P5/32

# yolov7 backbone
backbone:
  # [from, number, module, args]
  [[-1, 1, Conv, [32, 3, 1]],  # 0
   [-1, 1, Conv, [64, 3, 2]],  # 1-P1/2
   [-1, 1, Conv, [64, 3, 1]],
   [-1, 1, Conv, [128, 3, 2]],  # 3-P2/4
   [-1, 1, ELAN, [256,0.5]],  # 4

   [-1, 1, MPConv, [0.5]],
   [-1, 1, ELAN, [512, 0.5]],  # 6

   [-1, 1, MPConv, [0.5]],
   [-1, 1, ELAN, [1024,0.5]],  # 8

   [-1, 1, MPConv, [0.5]],
   [-1, 1, ELAN, [1024,0.25]],  # 10
  ]

# yolov7 head
head:
  [[-1, 1, SPPCSPC, [512]], # 11 54

   [-1, 1, Conv, [256, 1, 1]],#12
   [-1, 1, nn.Upsample, [None, 2, 'nearest']],
   [8, 1, Conv, [256, 1, 1]], # 14 route backbone P4
   [[-1, -2], 1, Concat, [1]], # 15
   [-1, 1, ELAN_H, [256,0.5,0.25]], #16


   [-1, 1, Conv, [128, 1, 1]], #17
   [-1, 1, nn.Upsample, [None, 2, 'nearest']], #18
   [6, 1, Conv, [128, 1, 1]], # route backbone P3 19
   [[-1, -2], 1, Concat, [1]], # 20
   [-1, 1, ELAN_H, [128,0.5,0.25]], #21

   [-1, 1, MPConv, [1]], # 22
   [[-1, 16], 1, Concat, [1]],# 23
   [-1, 1, ELAN_H, [256,0.5,0.25]], # 24

   [-1, 1, MPConv, [1]], # 25
   [[-1, 11], 1, Concat, [1]], # 26
   [-1, 1, ELAN_H, [512,0.5,0.25]], #27

   [21, 1, RepConv, [256, 3, 1]],
   [24, 1, RepConv, [512, 3, 1]],
   [27, 1, RepConv, [1024, 3, 1]],

   [[28,29,30], 1, Detect, [nc, anchors]],   # Detect(P3, P4, P5)
  ]

💥💥步骤5:验证是否加入成功

yolo.py文件里,将配置改为我们刚才自定义的yolov7_simplify.yaml

修改1,位置位于yolo.py文件237行左右,具体如图所示:

修改2,位置位于yolo.py文件529行左右,具体如下图所示:?

注意,需要修改的代码格式如下所示:

../cfg/training/yolov7_simplify.yaml

配置完毕之后,点击“运行”,结果如下图所示:

由运行结果可知,与我们前面的封装后的YOLOv7网络结构图相一致,证明封装成功了!??

💥💥步骤6:修改默认参数

train.py文件中找到parse_opt函数,然后将第二行?'--cfg'?的default改为?'cfg/training/yolov7_simplify.yaml',然后就可以开始进行训练了。🎈🎈🎈?

💥💥步骤7:实际训练测试

经过实际训练测试,没有发生报错,模型正常训练,具体如下图所示:

安全帽数据集上,经过100轮实际训练测试,得到结果如下:


文章来源:https://blog.csdn.net/weixin_61961691/article/details/135577468
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。