首页 > 其他分享 >YOLOv5改进系列:主干ConvNeXTV2结构助力涨点

YOLOv5改进系列:主干ConvNeXTV2结构助力涨点

时间:2024-03-26 15:59:09浏览次数:21  
标签:__ dim YOLOv5 涨点 nn self ConvNeXTV2 init def

一、论文理论

论文地址:ConvNeXt V2: Co-designing and Scaling ConvNets with Masked Autoencoders

1.理论思想

ConvNeXt V2  ConvNeXt 的基础上增加了两个创新点(一个 framework 和一个 technique):全卷积掩码自编码器(fully convolutional masked autoencoder, FCMAE)和全局响应归一化(global response normalization, GRN)

2.创新点

  • 提出一种全卷积掩码自编码器(FCMAE)框架;
  • 全卷积掩码自编码器(FCMAE)框架是一种基于卷积神经网络的自监督学习方法,它的思想是在输入图像上随机掩盖一些区域,然后让模型尝试恢复被掩盖的部分。这样可以迫使模型学习到图像的全局和局部特征,从而提高其泛化能力。
  • 提出一种全局响应归一化(GRN)层。
  • 全局响应归一化(GRN)层是一种新的卷积神经网络层,它的作用是在每个通道上对特征图进行归一化处理,从而增强通道间的特征竞争。GRN 层与传统的批量归一化(BN)层相比,有两个优势:一是它不需要额外的参数,因为它仅仅是对特征图进行归一化处理;二是它可以处理任意大小的 batch,而 BN 层则需要根据 batch 大小动态调整参数,计算量较大

二、代码部署

1.代码


from timm.models.layers import trunc_normal_, DropPath

import numpy.random as random

class LayerNorm(nn.Module):
    """ LayerNorm that supports two data formats: channels_last (default) or channels_first. 
    The ordering of the dimensions in the inputs. channels_last corresponds to inputs with 
    shape (batch_size, height, width, channels) while channels_first corresponds to inputs 
    with shape (batch_size, channels, height, width).
    """
    def __init__(self, normalized_shape, eps=1e-6, data_format="channels_last"):
        super().__init__()
        self.weight = nn.Parameter(torch.ones(normalized_shape))
        self.bias = nn.Parameter(torch.zeros(normalized_shape))
        self.eps = eps
        self.data_format = data_format
        if self.data_format not in ["channels_last", "channels_first"]:
            raise NotImplementedError 
        self.normalized_shape = (normalized_shape, )
    
    def forward(self, x):
        if self.data_format == "channels_last":
            return F.layer_norm(x, self.normalized_shape, self.weight, self.bias, self.eps)
        elif self.data_format == "channels_first":
            u = x.mean(1, keepdim=True)
            s = (x - u).pow(2).mean(1, keepdim=True)
            x = (x - u) / torch.sqrt(s + self.eps)
            x = self.weight[:, None, None] * x + self.bias[:, None, None]
            return x

def autopad(k, p=None):  # kernel, padding
    # Pad to 'same'
    if p is None:
        p = k // 2 if isinstance(k, int) else [x // 2 for x in k]  # auto-pad
    return p


class Conv(nn.Module):
    # Standard convolution
    def __init__(self, c1, c2, k=1, s=1, p=None, g=1, act=True):  # ch_in, ch_out, kernel, stride, padding, groups mg
        super().__init__()
        self.conv = nn.Conv2d(c1, c2, k, s, autopad(k, p), groups=g, bias=False)
        self.bn = nn.BatchNorm2d(c2)
        self.act = nn.SiLU() if act is True else (act if isinstance(act, nn.Module) else nn.Identity())

    def forward(self, x):
        return self.act(self.bn(self.conv(x)))

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

class GRN(nn.Module):
    """ GRN (Global Response Normalization) layer
    """
    def __init__(self, dim):
        super().__init__()
        self.gamma = nn.Parameter(torch.zeros(1, 1, 1, dim))
        self.beta = nn.Parameter(torch.zeros(1, 1, 1, dim))

    def forward(self, x):
        Gx = torch.norm(x, p=2, dim=(1,2), keepdim=True)
        Nx = Gx / (Gx.mean(dim=-1, keepdim=True) + 1e-6)
        return self.gamma * (x * Nx) + self.beta + x

class ConvNeXtv2(nn.Module):
    """ ConvNeXtV2 Block.
    
    Args:
        dim (int): Number of input channels mg.
        drop_path (float): Stochastic depth rate. Default: 0.0
    """
    def __init__(self, dim, dim2, drop_path=0.):
        super().__init__()
        self.dwconv = nn.Conv2d(dim, dim2, kernel_size=7, padding=3, groups=dim) # depthwise conv
        self.norm = LayerNorm(dim, eps=1e-6)
        self.pwconv1 = nn.Linear(dim, 4 * dim) # pointwise/1x1 convs, implemented with linear layers
        self.grn = GRN(4 * dim)
        self.act = nn.GELU()
        self.pwconv2 = nn.Linear(4 * dim, dim)
        self.drop_path = DropPath(drop_path) if drop_path > 0. else nn.Identity()

    def forward(self, x):
        input = x
        x = self.dwconv(x)
        x = x.permute(0, 2, 3, 1) # (N, C, H, W) -> (N, H, W, C)
        x = self.norm(x)
        x = self.pwconv1(x)
        x = self.act(x)
        x = self.grn(x)
        x = self.pwconv2(x)
        x = x.permute(0, 3, 1, 2) # (N, H, W, C) -> (N, C, H, W)

        x = input + self.drop_path(x)
        return x

class ConvNeXtV2(nn.Module):
    """ ConvNeXt V2
        
    Args:
        in_chans (int): Number of input image channels. Default: 3
        num_classes (int): Number of classes for classification head. Default: 1000
        depths (tuple(int)): Number of blocks at each stage. Default: [3, 3, 9, 3]
        dims (int): Feature dimension at each stage mg. Default: [96, 192, 384, 768]
        drop_path_rate (float): Stochastic depth rate. Default: 0.
        head_init_scale (float): Init scaling value for classifier weights and biases. Default: 1.
    """
    def __init__(self, in_chans=3, num_classes=1000, 
                 depths=[3, 3, 9, 3], dims=[96, 192, 384, 768], 
                 drop_path_rate=0., head_init_scale=1.
                 ):
        super().__init__()
        self.depths = depths
        self.downsample_layers = nn.ModuleList() # stem and 3 intermediate mg downsampling conv layers
        stem = nn.Sequential(
            nn.Conv2d(in_chans, dims[0], kernel_size=4, stride=4),
            LayerNorm(dims[0], eps=1e-6, data_format="channels_first")
        )
        self.downsample_layers.append(stem)
        for i in range(3):
            downsample_layer = nn.Sequential(
                    LayerNorm(dims[i], eps=1e-6, data_format="channels_first"),
                    nn.Conv2d(dims[i], dims[i+1], kernel_size=2, stride=2),
            )
            self.downsample_layers.append(downsample_layer)

        self.stages = nn.ModuleList() # 4 feature resolution stages, each consisting of multiple residual blocks
        dp_rates=[x.item() for x in torch.linspace(0, drop_path_rate, sum(depths))] 
        cur = 0
        for i in range(4):
            stage = nn.Sequential(
                *[ConvNeXtv2(dim=dims[i], drop_path=dp_rates[cur + j]) for j in range(depths[i])]
            )
            self.stages.append(stage)
            cur += depths[i]

        self.norm = nn.LayerNorm(dims[-1], eps=1e-6) # final norm layer
        self.head = nn.Linear(dims[-1], num_classes)

        self.apply(self._init_weights)
        self.head.weight.data.mul_(head_init_scale)
        self.head.bias.data.mul_(head_init_scale)

    def _init_weights(self, m):
        if isinstance(m, (nn.Conv2d, nn.Linear)):
            trunc_normal_(m.weight, std=.02)
            nn.init.constant_(m.bias, 0)

    def forward_features(self, x):
        for i in range(4):
            x = self.downsample_layers[i](x)
            x = self.stages[i](x)
        return self.norm(x.mean([-2, -1])) # global average pooling iscyy, (N, C, H, W) -> (N, C)

    def forward(self, x):
        x = self.forward_features(x)
        x = self.head(x)
        return x

class ConXBv2(nn.Module): # ConXBv2
    def __init__(self, c1, c2, n=1, shortcut=False, e=0.5):  
        super().__init__()
        self.c = int(c2 * e)  
        self.cv1 = Conv(c1, 2 * self.c, 1, 1)
        self.cv2 = Conv((2 + n) * self.c, c2, 1)  
        self.convnextv2 = nn.ModuleList(ConvNeXtv2(self.c, self.c) for _ in range(n))

    def forward(self, x):
        y = list(self.cv1(x).split((self.c, self.c), 1))
        y.extend(convnextv2(y[-1]) for convnextv2 in self.convnextv2)
        return self.cv2(torch.cat(y, 1))

2.配置教程

(1)在models/cmmon.py中添加上述代码,将与初始代码中重复类删除

(2)在./models/yolo.py文件下里的parse_model函数,将类名加入进去

           for i, (f, n, m, args) in enumerate(d['backbone'] + d['head']):内部

        elif m in [ConXBv2]:
            c1, c2 = ch[f], args[0]
            if c2 != no:  # if not outputss
                c2 = make_divisible(c2 * gw, 8)
            args = [c1, c2, *args[1:]]
            if m in [ConXBv2]:
                args.insert(2, n)  # number of repeats
                n = 1

3.yaml文件

# YOLOv5 

标签:__,dim,YOLOv5,涨点,nn,self,ConvNeXTV2,init,def
From: https://blog.csdn.net/ZzzzzKnight/article/details/137045410

相关文章