YOLOv5 combat: how to add the RepVgg module



1. Prepare RepVgg

1. Refer to YOLOv7

In the yolov7 git repository, the detailed RepConv and the related CSPRepBettleneck module are provided in common.py

RepConv and RepBottleNeck codes are as follows (example):

class C3RepVGG(nn.Module):
    # CSP RepBottleneck with 3 convolutions, modified by wqt
    def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5, act=True):  # ch_in, ch_out, number, shortcut, groups, expansion
        super(C3RepVGG, self).__init__()
        c_ = int(c2 * e)  # hidden channels
        self.cv1 = Conv(c1, c_, 1, 1, act=act)
        self.cv2 = Conv(c1, c_, 1, 1, act=act)
        self.cv3 = Conv(2 * c_, c2, 1, act=act)  # act=FReLU(c2)
        # self.m = nn.Sequential(*[RepBottleneck(c_, c_, shortcut, g, e=1.0) for _ in range(n)])   #original RepBottleneck format
        self.m = nn.Sequential(*[RepBottleneck(c_, c_, shortcut, g, e=0.5) for _ in range(n)])   # change e=0.5, otherwise, bugs happens.

    def forward(self, x):
        return self.cv3(torch.cat((self.m(self.cv1(x)), self.cv2(x)), dim=1))


class RepBottleneck(Bottleneck):
    # Standard bottleneck
    def __init__(self, c1, c2, shortcut=True, g=1, e=0.5):  # ch_in, ch_out, shortcut, groups, expansion
        super().__init__(c1, c2, shortcut=True, g=1, e=0.5)
        c_ = int(c2 * e)  # hidden channels
        self.cv2 = RepConv(c_, c2, 3, 1, g=g)


class RepBottleneckCSPA(BottleneckCSPA):   #相当于Rep后的C3module
    # CSP Bottleneck https://github.com/WongKinYiu/CrossStagePartialNetworks
    def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5):  # ch_in, ch_out, number, shortcut, groups, expansion
        super().__init__(c1, c2, n, shortcut, g, e)
        c_ = int(c2 * e)  # hidden channels
        self.m = nn.Sequential(*[RepBottleneck(c_, c_, shortcut, g, e=1.0) for _ in range(n)])

The RepConv code segment is relatively long and is omitted here.

2. Use RepVgg

1. Building blocks

Add the module to the *.yaml file that defines the module in the config directory

backbone:
  # [from, number, module, args]
  [ 
    # [ -1, 1, Focus, [ 64, 3 ] ],  # 0-P1/2
    [ -1, 1, Conv, [ 128, 4, 4, 0 ] ],  # 1-P2/4
    [ -1, 3, C3RepVGG, [ 128 ] ],    #modify C3 with RepConv    次出添加来一层C3RepVGG
    [ -1, 1, Conv, [ 256, 3, 2 ] ],  # 3-P3/8
    [ -1, 9, C3, [ 256 ] ],
    [ -1, 1, Conv, [ 512, 3, 2 ] ],  # 5-P4/16
    [ -1, 9, C3, [ 512 ] ],
    [ -1, 1, Conv, [ 768, 3, 2 ] ],  # 7-P5/32
    [ -1, 3, C3, [ 768 ] ],
    [ -1, 1, Conv, [ 1024, 3, 2 ] ],  # 9-P6/64
    [ -1, 1, SPP, [ 1024, [ 3, 5, 7 ] ] ],
    [ -1, 3, C3, [ 1024, False ] ],  # 11
  ]

2. Analytical model

After defining the model, the parameters need to be parsed, so the newly added RepVgg module also needs parameter parsing, find parse_model in yolo.py:

	        if m in [DeConv, Conv, GhostConv, Bottleneck, GhostBottleneck, SPP, DWConv, MixConv2d, Focus, ConvFocus, CrossConv, BottleneckCSP,
                 C3, C3RepVGG, RepBottleneckCSPA, C3TR]:
            c1, c2 = ch[f], args[0]
            if c2 != no:  # if not output
                c2 = make_divisible(c2 * gw, 8)

            args = [c1, c2, *args[1:]]
            if m in [BottleneckCSP, C3, C3RepVGG, RepBottleneckCSPA, C3TR]:
                args.insert(2, n)  # number of repeats
                n = 1
            if m in [DeConv, Conv, GhostConv, Bottleneck, GhostBottleneck, DWConv, MixConv2d, Focus, ConvFocus, CrossConv, BottleneckCSP, 
                        RepBottleneckCSPA, C3, C3RepVGG, C3TR]:
                if 'act' in d.keys():
                    args_dict = {
    
    "act" : d['act']}

In the inference phase, fuse may be used

    def fuse(self):  # fuse model Conv2d() + BatchNorm2d() layers
        print('Fusing layers... ')
        for m in self.model.modules():
            if isinstance(m, RepConv):
                #print(f" fuse_repvgg_block")
                m.fuse_repvgg_block()
            elif isinstance(m, RepConv_OREPA):
                #print(f" switch_to_deploy")
                m.switch_to_deploy()
            elif type(m) is Conv and hasattr(m, 'bn'):
                m.conv = fuse_conv_and_bn(m.conv, m.bn)  # update conv
                delattr(m, 'bn')  # remove batchnorm
                m.forward = m.fuseforward  # update forward
        self.info()
        return self

After adding the above code segment, you can run the train function.

3. Reasoning

Entering the test stage, we compared the parameters and Flops size of the two, and found that RepVgg can effectively reduce the number of parameters and improve performance.

Method Stage Params Flops [email protected] [email protected]:0.95
YOLO5FacePose Train 13.13 17.1 96.8 90.8
YOLO5FacePose +RepVgg Train 13.126 16.8 96.2 90.3
YOLO5FacePose +RepVgg Test 13.13 17.1 96.7 90.9

Summarize

According to the above operation, the train operation is normal; but the role of Rep is to reflect the role in the reasoning stage, and it is necessary to give a conclusion after further testing the inference.

reference

There are some other reference methods to achieve, which may be useful but need to be tested and verified
YOLOv5-Lite: Repvgg reparameterization experiment and thinking on YOLO industrial landing
YOLOv5-Lite
YOLOv7-common

おすすめ

転載: blog.csdn.net/wqthaha/article/details/127597131