浅谈ConvNeXt(Pytorch)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

在 Transformer 的时代,总有人逆流而上,继续研究卷积神经网络。
于是就出现了超越 Swin - Transformer 性能的 ConvNeXt。假期看了许久,了解一下它。
内容如下:

内容 链接
论文 链接
官方源码 链接
自己复现(简化、注解) 链接

自己的复现版本,添加有MLP-Mixer,Conv-Mixer 网络和训练配置(可参考我的其他博客 MLP-Mixer 博文 Conv-Mixer 博文

ConvNeXt 网络没有特别创新的地方,只不过把卷积网络按照Swin - Transformer 的结构和训练方法做了调整。发现性能却超越了Transformer。
是一篇值得学习的调参论文。
在这里插入图片描述

一、ConvNeXt

在这里插入图片描述
文章选用ResNet50作为基本模型,参照Swin-Transformer模型来进行优化。本片论文的精华就在这张图里了,按照从上到下的方式介绍。

1.Macro Design

stage ratio

在ResNet50中(如下图),每个stage 的比率为(3:4:6:3)
在这里插入图片描述
而在Swin-Transformer 中,这部分的比率大致为 (1:1:3:1),Swin-L 中的比率为 (1:1:9:1)
替换后准确率 78.8->79.4

Patchify stem

stem: 输入到主干网络前,用卷积和池化进行的下采样(长宽变小,通道数增加)。
在标准的ResNet是使用kernel_size = 7x7, strides = 2 的卷积和一个最大池化来进行4倍的下采样。
Swin Transformer 中使用的是kernel_size = 4x4 strides = 4 的卷积来进行4倍下采样。
调整后准确率79.4->79.5

2.ResNeXt

ResNeXt中使用分组卷积(Group Convlution),使FloPs 和accuracy 达到了一个较好的平衡。ConvNeXt 更极端的 不适用普通卷积和分组卷积,直接使用了深度可分离卷积(Depthwise Convolution)。同时将通道数由最初的64 -> 96 变宽了。

3.Inverted Bottleneck

在这里插入图片描述
图a 中 的瓶颈结构(Bottleneck),两头粗 中间细(粗细指卷积核的个数)。移动反转瓶颈结构(Inverted Bottleneck),反转变成两头细 中间粗,如图中b,再将3x3的卷积那层提到最前方就是ConvNeXt。 所使用的结构了。
网络由
1x1 Conv -> DwConv -> 1x1 Conv
改变为 DwConv -> 1x1 Conv -> 1x1 Conv
但在作者实现网络的过程中,将1x1 的卷积用全连接来替代。这样在Pytorch 计算时 会更快。
也就是
DwConv -> Linear -> GELU -> Linear;

4.Large Kernel Sizes

常见的网络中,一般使用的都是3x3 的卷积核,作者捐给卷积核往大了调整,kernel_size = 5,7,9,11。当调整为11 时,模型的性能也就到达极限了。

5. Micro Design

  • RELU激活函数------>GELU激活函数(Transformer中使用的)
  • 减少激活函数和Normalization Layers
    一般的卷积网络中,每个卷积后就要添加一个激活函数和一个Normalization Layers,而在 Transfomer 中,每个模块后添加一个激活函数。所以作者也仿照这样,调整了结构,只在Depthwise Convolution 后保留了一个Normal。
  • 将BN(Batch Normal)-> LN(Layer Normal)
  • 下采样层
    作者不在使用池化做下采样,而是使用 一个Layer Normal + kernel_size = 2x2,stride = 2 的卷积来进行下采样。

二、实现

1.Pytorch 实现

网络结构图
在这里插入图片描述
ConvNeXt Block 代码如下:

from statistics import mode
import torch
import torch.nn as nn
import torch.nn.functional as F
from timm.models.layers import trunc_normal_,DropPath
from timm.models.registry import register_model
from torchsummary import summary
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

class Block(nn.Module):
    #-----------------------------------------------------------------------#
    # ConvNeXt Block 块 两种实现方式
    #   (1) 深度可分离卷积 + 1x1 的卷积
    #       DwConv -> LayerNorm (channels_first) -> 1x1 Conv -> GELU -> 1x1 Conv; all in (N, C, H, W)
    #   (2)深度可分离卷积 + Linear 全连接来代替 1x1 卷积 ,发现在pytorch 更快
    #        DwConv -> Permute to (N, H, W, C); LayerNorm (channels_last) -> Linear -> GELU -> Linear; Permute back
    # 参数:
    #   dim:维度  drop_path:0~1  layer_scale_init_value:
    #-------------------------------------------------------------------------#
    def __init__(self, dim, drop_path=0., layer_scale_init_value=1e-6):
        super().__init__()
        self.dwconv = nn.Conv2d(dim, dim, kernel_size=7, padding=3, groups=dim) # 深度课分离卷积
        self.norm = LayerNorm(dim, eps=1e-6)
        self.pwconv1 = nn.Linear(dim, 4 * dim) # 用全连接代替1x1的卷积
        self.act = nn.GELU()
        self.pwconv2 = nn.Linear(4 * dim, dim)
        # 一个可学习的参数
        self.gamma = nn.Parameter(layer_scale_init_value * torch.ones((dim)), 
                                    requires_grad=True) if layer_scale_init_value > 0 else None
        self.drop_path = DropPath(drop_path) if drop_path > 0. else nn.Identity()

    
  • 9
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

__不想写代码__

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值