みなさん、こんにちは。今日は、Tensorflowを使用してConvNeXt畳み込みニューラルネットワークモデルを構築する方法を紹介します。
紙のアドレス:https ://arxiv.org/pdf/2201.03545.pdf
完全なコードは私のGiteeにあります:https ://gitee.com/dgvv4/neural-network-model/tree/master/
過去21年間、Transformerは頻繁に視野を超えてきました。最初は、画像分類でGoogle ViTによって突破され、その後、オブジェクト検出と画像セグメンテーションでMicrosoftSwinTransformerによって獲得されました。ますます多くの学者がビジュアルトランスフォーマーの研究に従事するにつれて、3つの主要なタスクリストはすべてトランスフォーマーまたは2つのアーキテクチャを組み合わせたモデルによって支配されています。現時点では、ConvNeXtは畳み込みニューラルネットワークの略です。
1.ConvNeXtブロックモジュール
1.1基本構造
(1)ConvNeXtは、 MobileNetV1の深さ方向の畳み込み(深さ方向の畳み込み)と同じ、グループ化された畳み込みの概念を使用します。入力特徴マップのチャネルと同じ数の畳み込みカーネルがあります。各畳み込みカーネルは対応するチャネルを処理し、各畳み込みカーネルは特徴マップを生成します。生成されたすべての特徴マップをチャネル次元にスタックすると、出力特徴マップと同じ数のチャネルを持つ入力特徴マップがあります。
(2)残差構造を逆にして、最初に1 * 1畳み込みで次元を増やし、次に1*1畳み込みで次元を減らします。MobileNetV2の逆残差構造を借用しています。精度は、小さいモデルでは1から2に、大きいモデルでは1から1に増加しました。80.5%
80.6%
81.9%
82.6%
私の以前の記事を参照できます:https ://blog.csdn.net/dgvv4/article/details/123476899
(3)バッチ正規化の代わりにレイヤー正規化を使用して、正規化レイヤーを減らします。著者はTransformerの構造を借用し、深さ方向の畳み込み後にのみ正規化レイヤーを保持し、置換後に精度がわずかに向上します。
1.2コード表示
次のコードでは、gamaは1*1次元削減畳み込みの出力特徴マップのデータをスケーリングします。gamaは学習可能な変数であり、バックプロパゲーションはネットワークトレーニング中のgamaの値を最適化します。
gamaは、出力特徴マップのチャネル数と同じ数の要素を持つ1次元ベクトルです。ベクトルの各要素は対応する特徴マップを処理し、特徴マップのすべてのピクセル値は、特徴マップデータをスケーリングする目的を達成するために、ベクトルの要素で乗算されます。
トレーニング可能なパラメーターadd_weight()の定義は、Layerクラスのメソッドです。使用する前に、Layerクラスlayers.Layer()をインスタンス化します。
#(2)ConvNeXt Block
def block(inputs, dropout_rate=0.2, layer_scale_init_value=1e-6):
'''
layer_scale_init_value 缩放比例gama的初始化值
'''
# 获取输入特征图的通道数
dim = inputs.shape[-1]
# 残差边
residual = inputs
# 7*7深度卷积
x = layers.DepthwiseConv2D(kernel_size=(7,7), strides=1, padding='same')(inputs)
# 标准化
x = layers.LayerNormalization()(x)
# 1*1标准卷积上升通道数4倍
x = layers.Conv2D(filters=dim*4, kernel_size=(1,1), strides=1, padding='same')(x)
# GELU激活函数
x = layers.Activation('gelu')(x)
# 1*1标准卷积下降通道数
x = layers.Conv2D(filters=dim, kernel_size=(1,1), strides=1, padding='same')(x)
# 创建可学习的向量gama,该函数用于向某一层添加权重变量,类实例化layers.Layer()
gama = layers.Layer().add_weight(shape=[dim], # 向量个数和输出特征图通道数量一致
initializer=tf.initializers.Constant(layer_scale_init_value), # 权重初始化
dtype=tf.float32, # 指定数据类型
trainable=True) # 可训练参数,可通过反向传播调整权重
# layer scale 对特征图的每一个通道数据进行缩放,缩放比例gama
x = x * gama # [56,56,96]*[96]==>[56,56,96]
# Dropout层随机杀死神经元
x = layers.Dropout(rate=dropout_rate)(x)
# 残差连接输入和输出
x = layers.add([x, residual])
return x
2.バックボーンネットワーク
2.1ネットワーク構造図
2.2設計スキーム
ネットワークアーキテクチャ。上記のように、ResNet50ネットワークでは、res2からres5までのスタッキングブロックの数は(3、4、6、3)であり、比率は約1:1:2:1ですが、たとえばSwinTransformerではSwin-Tの比率は1:1:3:1、Swin-Lの比率は1:1:9:1です。明らかに、積み重ねられたブロックの割合は、SwinTransformerの方が高くなっています。そのため、作成者はResNet50のスタッキング時間を(3、4、6、3)から(3、3、9、3)に調整しました。これは、Swin-Tと同様のFLOPを持ちます。
ダウンサンプリング層の設計。ResNetネットワークのダウンサンプリングは、メインブランチの3x3畳み込み層のストライドを2に設定し、残りの側の1x1畳み込み層のストライドを2に設定することによって行われます。ただし、Swin Transformerでは、個別のパッチマージによって実現されます。著者は、Swin-Tを利用して、ConvNextネットワークに単一のダウンサンプリングレイヤーを使用します。これは、Lairer正規化と、kernel_size=2およびstrides=2の畳み込みレイヤーで構成されます。
2.3完全なコード表示
ConvNeXt
既存のすべての構造と方法が使用され、構造や方法の革新はありません。また、コードも非常に合理化されており、100行を超えるコードを作成できます。
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import Model, layers
#(1)输入图像经过的第一个卷积块
def pre_Conv(inputs, out_channel):
# 4*4卷积+标准化
x = layers.Conv2D(filters=out_channel, # 输出特征图的通道数
kernel_size=(4,4),
strides=4, # 下采样
padding='same')(inputs)
x = layers.LayerNormalization()(x)
return x
#(2)ConvNeXt Block
def block(inputs, dropout_rate=0.2, layer_scale_init_value=1e-6):
'''
layer_scale_init_value 缩放比例gama的初始化值
'''
# 获取输入特征图的通道数
dim = inputs.shape[-1]
# 残差边
residual = inputs
# 7*7深度卷积
x = layers.DepthwiseConv2D(kernel_size=(7,7), strides=1, padding='same')(inputs)
# 标准化
x = layers.LayerNormalization()(x)
# 1*1标准卷积上升通道数4倍
x = layers.Conv2D(filters=dim*4, kernel_size=(1,1), strides=1, padding='same')(x)
# GELU激活函数
x = layers.Activation('gelu')(x)
# 1*1标准卷积下降通道数
x = layers.Conv2D(filters=dim, kernel_size=(1,1), strides=1, padding='same')(x)
# 创建可学习的向量gama,该函数用于向某一层添加权重变量,类实例化layers.Layer()
gama = layers.Layer().add_weight(shape=[dim], # 向量个数和输出特征图通道数量一致
initializer=tf.initializers.Constant(layer_scale_init_value), # 权重初始化
dtype=tf.float32, # 指定数据类型
trainable=True) # 可训练参数,可通过反向传播调整权重
# layer scale 对特征图的每一个通道数据进行缩放,缩放比例gama
x = x * gama # [56,56,96]*[96]==>[56,56,96]
# Dropout层随机杀死神经元
x = layers.Dropout(rate=dropout_rate)(x)
# 残差连接输入和输出
x = layers.add([x, residual])
return x
#(3)下采样层
def downsampling(inputs, out_channel):
# 标准化+2*2卷积下采样
x = layers.LayerNormalization()(inputs)
x = layers.Conv2D(filters=out_channel, # 输出通道数个数
kernel_size=(2,2),
strides=2, # 下采样
padding='same')(x)
return x
#(4)卷积块,一个下采样层+多个block卷积层
def stage(x, num, out_channel, downsampe=True):
'''
num:重复执行多少次block ; out_channel代表下采样层输出通道数
downsampe:判断是否执行下采样层
'''
if downsampe is True:
x = downsampling(x, out_channel)
# 重复执行num次block,每次输出的通道数都相同
for _ in range(num):
x = block(x)
return x
#(5)主干网络
def convnext(input_shape, classes): # 输入图像shape和分类类别数
# 构造输入层
inputs = keras.Input(shape=input_shape)
# [224,224,3]==>[56,56,96]
x = pre_Conv(inputs, out_channel=96)
# [56,56,96]==>[56,56,96]
x = stage(x, num=3, out_channel=96, downsampe=False)
# [56,56,96]==>[28,28,192]
x = stage(x, num=3, out_channel=192, downsampe=True)
# [28,28,192]==>[14,14,384]
x = stage(x, num=9, out_channel=384, downsampe=True)
# [14,14,384]==>[7,7,768]
x = stage(x, num=3, out_channel=768, downsampe=True)
# [7,7,768]==>[None,768]
x = layers.GlobalAveragePooling2D()(x)
x = layers.LayerNormalization()(x)
# [None,768]==>[None,classes]
logits = layers.Dense(classes)(x) # 不经过softmax
# 构建网络
model = Model(inputs, logits)
return model
#(6)接收网络模型
if __name__ == '__main__':
# 构造网络,传入输入图像的shape,和最终输出的分类类别数
model = convnext(input_shape=[224,224,3], classes=1000)
model.summary() # 查看网络结构
ネットワークパラメータは次のとおりです
==================================================================================================
Total params: 28,582,504
Trainable params: 28,582,504
Non-trainable params: 0
__________________________________________________________________________________________________
3.ネットワークモデル図
ひまわりの小さな緑豆 ブロガーのモデル図に感謝し ます