ConvNext学习

参考:
[1] LIU Z, MAO H, WU C Y, et al. A ConvNet for the 2020s[C/OL]//2022 IEEE/CVF Conference on Computer Vision and Pattern Recognition (CVPR), New Orleans, LA, USA. 2022. http://dx.doi.org/10.1109/cvpr52688.2022.01167. DOI:10.1109/cvpr52688.2022.01167.
[2] 薛导ConvNext博客
[3] DropPath理解
[4] 官方源码Facebook

TOC

  • 1 模型学习
    • 1.0 训练策略
    • 1.1 Macro design
    • 1.2 ResNeXt-ify
    • 1.3 Inverted bottleneck
    • 1.4 Large kernel size
    • 1.5 Micro design
    • 1.6 框架图
  • 2 ConvNext代码实现
    • 2.1 DropPath
    • 2.2 GELU
    • 2.3 LayerNorm
    • 2.4 Block的实现
    • 2.5 ConvNext网络搭建
      • 2.5.1 特征提取部分
      • 2.5.2 分类头部分
      • 2.5.3 初始化

1 模型学习

在这里插入图片描述

1.0 训练策略

作者以训练Vit的策略用来训练ResNet50,发现比原来要好,以此为基准。

1.1 Macro design

改变stage的计算比例

  • 原ResNet50的stage的重复次数为[3,4,6,3],而Swin-T的重复次数比例为1:1:3:1, Swin-L的重复次数比例为1:1:9:1,可见第三层stage的重复次数更多。
  • ConvNext将由原来的[3,4,6,4] 魔改为 [3,3,9,3]

改变stem(既开始的部分)

  • 原ResNet的stem为卷积7x7,stride为2,padding为3,再经过stride为2的Maxpooling层,将原图像的高宽缩小4倍(224->56)。但在Swim-T中,卷积之间是没有重叠的,既stride=kernel_size
  • ConvNext仿照Swin-Transformer,用4x4Conv替代原来的7x7Conv,并将步长设置为4,不使用padding,这样直接将下采样四倍了

1.2 ResNeXt-ify

替换GroupConv为DW Conv

  • 将组卷积替换为depthwise卷积(DW卷积),也就是将groups设置为channel,DW卷积最早出现于MobileNet中,也是GroupConv的一种特殊形式(groups = input channels)
  • 然后使用1x1卷积去改变channel数(官方代码中说是使用pointwise 1x1 conv,并且就是一个nn.Linear

改变conv的深度

  • 原ResNet论文中,卷积的深度为(64,128,256,512), ConvNext将其改为(96,192,384,768)

1.3 Inverted bottleneck

在这里插入图片描述

  • 原来ResNet结构的Block都是呈现宽-窄-宽结构,在ConvNext中,变成窄-宽-窄结构,如图的(a)->(b)

1.4 Large kernel size

将DW Conv移到第一层

  • 为了确保efficiency,large-kernel conv通常有较少的channels,而1x1 conv反而会去做繁杂的事情(比如升维、降维)。故ConvNext将DW Conv移动到第一层,并保持维度不变,而第二、三层的1x1 Conv负责升维降维。

增大kernel size

  • ConvNext将DW Conv的3x3 Conv变成7x7 Conv

1.5 Micro design

在这里插入图片描述

  • 将ReLU换成GeLU,GELU可以看作是RELU的smooth版本
  • 减小激活函数的使用,由Swim可知,只在最后一个1x1conv之前(降维之前)使用激活函数
  • 在第二个1x1 Conv之前使用BN层,减小BN层的使用
  • 将BN层换成LN层,BN模块有很多复杂的有害的影响
  • 用2x2 Conv with stride 2替换原来的 1x1 Conv with stride 2进行残差下采样,也就是不使用残差下采样了,而是用 identity残差连接+2x2Conv下采样 替代

1.6 框架图

在这里插入图片描述
在这里插入图片描述

2 ConvNext代码实现

2.1 DropPath

由 DropPath理解可知,droppath是随机失活样本中的一部分,而dropout是随机失活样本的一些权重。需要注意的是,Droppath只在training phase中使用,并且放在block的残差连接之前
下图分别为DropPath和Dropout的输出。
在这里插入图片描述
在这里插入图片描述

具体实现

def droppath(x,drop_prob:float=0.,training:bool=False):if drop_prob == 0. or not training:return xkeep_prob = 1. - drop_probshape = (x.shape[0],) + (1,)*(x.dim -1)# 举个例子: # 如果x为[10,3,224,224],那么shape为[10,1,1,1],只保留第0维,扩展后3维random_tensor = keep_prob + torch.rand(shape, dtype=x.dtype, device=x.device)# random_tensor介于[0,2)之间random_tensor = random_tensor.floor_() # random_tensor为0或1,表示失活或保留x = x.div(keep_prob)*randoom_tensor# 保持期望值不变,参考网址:https://www.cnblogs.com/dan-baishucaizi/p/14703263.html

官方源码调用库函数

from timm.models.layers import DropPath
...self.drop_path = DropPath(drop_path) if drop_path > 0. else nn.Identity()

2.2 GELU

参考:https://alaaalatif.github.io/2019-04-11-gelu/
总的来说,GELU要比RELU的训练效果要好,并且GELU具有导数连续,比RELU更加平滑等优点,并且在0以下的值有一定概率不会变为0,避免了梯度消失。由下图可知,GELU安插在1x1conv升维之前。

代码:

self.gelu = nn.GELU()

2.3 LayerNorm

LayerNorm就是对每一个channel独立地进行求均值和方差的操作,然后再去对每一个channel独立地进行标准化。现在分channel维在第二位和第四位的情况,而pytorch官方可直接调用LayerNorm的情况是channel维在第四位的情况。

代码实现

class LayerNorm(nn.Module):def __init__(self,normalized_shape,eps=1e-6,data_format='channels_last')self.eps = epsself.weight = nn.Parameter(torch.ones(normalized_shape)) # learnable gammaself.bias = nn.Parameter(torch.zeros(normalized_shape)) # learnable betaself.data_format = data_formatif self.data_format not in ['channels_first','channels_last']:raise NotImplementedErrorself.normalized_shape = (normalized_shape,)def forward(self,x):if self.data_format == 'channels_first':return F.layer_norm(x,self.normalized_shape,self.weight,self.bias,self.eps)elif self.data_format == 'channels_last':u = x.mean(1,keepdim=True)s = (x-u).pow(2).mean(1,keepdim=True) # variancex = (x-u)/torch.sqrt(s+self.eps)x = self.weight[:,None,None]*x+self.bias[:,None,None]return x

2.4 Block的实现

Block的源码中有一个layer_scale的操作是原论文中没有提及的,源于改论文Going deeper with image transformers. ICCV, 2021, 简单来说就是每一个通道的值进行缩放,缩放的因子gamma是一个可学习参数。

官方源码中开头的注释:
ConvNeXt Block. There are two equivalent implementations:
(1) DwConv -> LayerNorm (channels_first) -> 1x1 Conv -> GELU -> 1x1 Conv; all in (N, C, H, W)
(2) DwConv -> Permute to (N, H, W, C); LayerNorm (channels_last) -> Linear -> GELU -> Linear; Permute back
We use (2) as we find it slightly faster in PyTorch
Args:
dim (int): Number of input channels.
drop_path (float): Stochastic depth rate. Default: 0.0
layer_scale_init_value (float): Init value for Layer Scale. Default: 1e-6.

代码实现:

class Block(nn.Module):def __init__(self,dim,drop_path:float=0.,layer_scale_init_value:float=1e-6):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,dim*4)self.gelu = nn.GELU()self.pwconv2 = nn.Linear(dim*4,dim)self.gamma = nn.Parameter(layer_scale_init_value* torch.ones((dim)), require_grad=True) if layer_scale_init_value > 0 else Noneself.Droppath = 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) # put channel dim into last dimx = self.norm(x)x = self.pwconv1(x)x = self.gelu(x)x = self.pwconv2(x)if self.gamma is not None:x *= self.gammax = x.permute(0,3,1,2)x = input_ + self.drop_path(x)return x

2.5 ConvNext网络搭建

2.5.1 特征提取部分

在这里插入图片描述

  • stem为 [conv(k=4,s=4) + Layer Norm]
  • downsample为 [Layer Norm + conv(dim1,dim2,k=2,s=2)]
  • stage部分为 [ 多个block ]

2.5.2 分类头部分

在这里插入图片描述

  • 全局平均: 相当于平均每一维,既[B,C,H,W] - > [B,C]
  • Layer Norm + Linear不介绍了

2.5.3 初始化

需要初始化的层包括Linear和Conv,分别初始化其weight和bias

  • 分类头Linear: weight和bias都乘以1(保持不变),且这是一个in-place操作,意味着它会直接修改self.head.bias的值,而不是创建一个新的tensor。
  • 其他Linear和conv:关于weight使用 truncated normal distribution(截断正态分布),关于bias使用常数constant为0

网络代码:

class ConvNext(nn.Module):def __init__(self, in_chans=3, num_classes=1000, depths=[3,3,9,3], dims=[96,192,384,768],drop_path_rate=0.,layer_scale_init_value=1e-6,head_init_scale=1.)super().__init__()# ------------------ 下采样部分 --------------------------------self.downsample_layers = nn.ModuleList() # 保存 stem和3个downsample_layerstem = nn.Sequential(nn.Conv2d(3,dims[0],kernel_size=4,stride=4),LayerNorm(dims[0],eps=1e-6,data_format='channels_first'))for i in range(3):downsample_layer = nn.Sequential(LayerNorm(dim[i],eps=1e-6,data_format='channels_first'),nn.Conv2d(dim[i],dim[i+1],kernel_size=2,stride=2))self.downsample_layers.append(downsample_layer)# ------------------- stage 部分 --------------------------------self.stages = nn.ModuleList()dp_rate = [x.item() for x in torch.linspace(0, drop_path_rate, sum(depths)]cur = 0 # 表示当前在第几层(深度)for i in range(4):stage = nn.Sequential(*[Block(dims[i], drop_path=dp_rate[cur+j],layer_scale_init_value=layer_scale_init_value) for j in range(depths[i]))self.stages.append(stage)cur += depths[i]# ------------------ 分类头和初始化部分 ----------------------------self.norm = LayerNorm(dim[-1],eps=1e-6)self.head = nn.Linear(dim[-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_weight(self,m):if isinstance(m,(nn.Linear, nn.Conv2d)):trunc_normal(m.weight, std=.02),nn.init.constant_(m.bias,0)def forward_features(self,x):# features extraction part(stem, stage and downsample)for i in range(4):x = self.downsample_layers[i](x)x = self.stages[i](x)return self.norm(x.mean([-2,-1])) # GAP(global average pooling) [c,b,h,w] -> [c,b]def forward(self,x):x = self.forward_features(x)x = self.head(x)return x

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/494079.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

计算机设计大赛 深度学习大数据物流平台 python

文章目录 0 前言1 课题背景2 物流大数据平台的架构与设计3 智能车货匹配推荐算法的实现**1\. 问题陈述****2\. 算法模型**3\. 模型构建总览 **4 司机标签体系的搭建及算法****1\. 冷启动**2\. LSTM多标签模型算法 5 货运价格预测6 总结7 部分核心代码8 最后 0 前言 &#x1f5…

python Matplotlib Tkinter--pack 框架案例

环境 python:python-3.12.0-amd64 包: matplotlib 3.8.2 pillow 10.1.0 版本一 import matplotlib.pyplot as plt from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2Tk import tkinter as tk import tkinter.messagebox as messagebox…

Java设计模式 | 七大原则之依赖倒转原则

依赖倒转原则(Dependence Inversion Principle) 基本介绍 高层模块不应该依赖低层模块,二者都应该依赖其抽象(接口/抽象类)抽象不应该依赖细节,细节应该依赖抽象依赖倒转(倒置)的…

2023 re:Invent 用 Amazon Q 打造你的知识库

前言 随着 ChatGPT 的问世,我们迎来了许多创新和变革的机会。一年一度的亚马逊云科技大会 re:Invent 也带来了许多前言的技术,其中 Amazon CEO Adam Selipsky 在 2023 re:Invent 大会中介绍 Amazon Q 让我印象深刻,这预示着生成式 AI 的又一…

使用 Verilog 做一个可编程数字延迟定时器 LS7211-7212

今天的项目是在 Verilog HDL 中实现可编程数字延迟定时器。完整呈现了延迟定时器的 Verilog 代码。 所实现的数字延迟定时器是 CMOS IC LS7212,用于生成可编程延迟。延迟定时器的规格可以在这里轻松找到。基本上,延迟定时器有 4 种操作模式:…

Leetcoder Day23| 回溯part03:组合+分割

语言:Java/Go 39. 组合总和 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target ,找出 candidates 中可以使数字和为目标数 target 的所有不同组合 ,并以列表形式返回。你可以按任意顺序返回这些组合。 candidates 中的同一个…

前端路由与后端路由的区别

聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅:探索Web开发的奇妙世界 欢迎来到前端入门之旅!感兴趣的可以订阅本专栏哦!这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…

Web APIs 3 事件

Web APIs 3 事件 一、事件流事件捕获事件冒泡阻止冒泡解绑事件鼠标经过事件的区别两种注册事件的区别 二、事件委托阻止默认行为 三、其他事件① 页面加载事件② 元素滚动事件滚动到指定的坐标 ③ 页面尺寸事件 元素尺寸与位置① 元素在页面中的位置② 元素尺寸 一、事件流 事…

Sora专辑|AI视频制作新时代的曙光:OpenAI Sora 模型启示录

本文深入剖析 OpenAI 最新发布的人工智能视频生成模型 Sora 的工作原理,并探讨它对电影制作行业的深远影响。Sora 利用海量数据和强大的计算能力,学习视频的"语法规则"即物理定律,从而生成逼真的视频画面。Sora 将从根本上改变电影制作的方式,降低制作成本、赋能…

【步骤】KEIL MDK LIB库文件的制作

问题引出:为什么要做成lib库? 1、有些人不想将自己写的源代码公开,但是同时库文件又需要让别人能够正常调用,那封装成lib的格式就是一个好方法。 2、编译某些工程文件时非常耗时,像UCGUI和ST官方的库时,由…

二 线性代数-向量

1、向量的表示方法: 其中的 i、j、k是坐标轴方向的单位向量。 2、向量的模: 用坐标计算的方法: 3、向量的运算: 3.1 向量的加法减法: 3.2 向量的数乘: 拉格朗日乘数法的 基础 公式。 3.3 向量的数量积&a…

2步破解官方sublime4

sublime简要破解流程 1.下载sublime官方最新版2. 破解流程 1.下载sublime官方最新版 打开 官方网站下载 portable version 版,省的安装。。解压到任意位置,备份 sublime_text.exe 文件 2. 破解流程 打开网址把文件 sublime_text.exe 拖入网页搜索替换…