Tensorflow2.0之自定义ResNet

1、ResNet 网络结构

残差网络由残差块(ResnetBlock)组成,每一个残差块又是由多个 Residual 构成的。下面以 ResNet18 为例,分析残差网络结构的构建。

1.1 Residual

Residual 的结构为:
在这里插入图片描述
将其展开,则为:
在这里插入图片描述
上图中卷积层参数的设置:

  • 卷积层1:kernel_size=3x3,padding=‘same’
  • 卷积层2:kernel_size=3x3,padding=‘same’,strides=1
  • 卷积层3:kernel_size=1x1,padding=‘valid’
  • 注1:卷积层的通道数都是相同的,由用户指定。
  • 注2:卷积层1和卷积层3的步长相等,由用户指定。

XY 的过程:

  • 先通过卷积层1,此时的通道数可能发生改变,由于步长不确定,故此时的长宽也会发生改变。
  • 然后经过卷积层2,由于卷积层2的步长确定为1,通道数和卷积层1的相同,所以这一层的输入和输出的 shape 是相同的。

但是,在进行 X + Y 的时候,我们需要让 XYshape 相同,所以此时需要卷积层3的参与。
如果 YshapeX 的不同,则将 X 输入到卷积层3来使其 shape 等于 Yshape ;否则,卷积层3不被需要。

1.2 ResnetBlock

因为在残差网络中,第一个残差块的输入和输出的 shape 是相同的,而在其他残差块中,输出的长和宽是输入的一半,而且输出的通道数是输入的两倍。所以残差网络中的第一个残差块中的所有 Residual 都不需要卷积层3,而其他残差块中的第一个 Residual 都需要卷积层3使 XYshape 相同。所以 ResnetBlock 的构建规则为:
在这里插入图片描述
【注】其实 ResnetBlock 有两种,一种两层结构,一种三层结构:
在这里插入图片描述

1.3 ResNet

残差网络的参数变化如图所示:
在这里插入图片描述

  • conv1:卷积层、BN层、ReLU层;
  • conv2_x:池化层、残差块;
  • conv3_x:残差块;
  • conv4_x:残差块;
  • conv5_x:残差块;
  • 全局平均池化层后接上全连接层输出。

2、代码构建残差网络

2.1 Residual

class Residual(tf.keras.Model):
    def __init__(self, num_channels, use_1x1conv=False, strides=1):
        super().__init__()
        self.conv1 = tf.keras.layers.Conv2D(num_channels, kernel_size=3,
                                            strides=strides, padding='same')
        self.conv2 = tf.keras.layers.Conv2D(num_channels, kernel_size=3,
                                            padding='same')
        if use_1x1conv:
            self.conv3 = tf.keras.layers.Conv2D(num_channels,
                                       kernel_size=1,
                                       strides=strides)
        else:
            self.conv3 = None
        self.bn1 = tf.keras.layers.BatchNormalization()
        self.bn2 = tf.keras.layers.BatchNormalization()
        
    def call(self, x):
        y = tf.nn.relu(self.bn1(self.conv1(x)))
        y = self.bn2(self.conv2(y))
        if self.conv3:
            x = self.conv3(x)
        return tf.nn.relu(y + x)

2.2 ResnetBlock

class ResnetBlock(tf.keras.Model):
    def __init__(self, num_channels, num_residuals, first_block=False):
        super().__init__()
        self.listLayers=[]
        for i in range(num_residuals):
            if i == 0 and not first_block:
                self.listLayers.append(Residual(num_channels,
                                                use_1x1conv=True,
                                                strides=2))
            else:
                self.listLayers.append(Residual(num_channels))
                
    def call(self, x):
        for layer in self.listLayers.layers:
            x = layer(x)
        return x

2.3 ResNet

class ResNet(tf.keras.Model):
    def __init__(self, num_blocks):
        super().__init__()
        self.conv=layers.Conv2D(64, kernel_size=7, strides=2, padding='same')
        self.bn=layers.BatchNormalization()
        self.relu=layers.Activation('relu')
        
        self.mp=layers.MaxPool2D(pool_size=3, strides=2, padding='same')
        self.resnet_block1=ResnetBlock(64,num_blocks[0], first_block=True)
        
        self.resnet_block2=ResnetBlock(128,num_blocks[1])
        
        self.resnet_block3=ResnetBlock(256,num_blocks[2])
        
        self.resnet_block4=ResnetBlock(512,num_blocks[3])
        
        self.gap=layers.GlobalAvgPool2D()
        self.fc=layers.Dense(units=10,activation=tf.keras.activations.softmax)

    def call(self, x):
        x=self.conv(x)
        x=self.bn(x)
        x=self.relu(x)
        x=self.mp(x)
        x=self.resnet_block1(x)
        x=self.resnet_block2(x)
        x=self.resnet_block3(x)
        x=self.resnet_block4(x)
        x=self.gap(x)
        x=self.fc(x)
        return x

2.4 网络检验

mynet=ResNet([2,2,2,2])
X = tf.random.uniform(shape=(1,  224, 224 , 1))
for layer in mynet.layers:
    X = layer(X)
    print(layer.name, 'output shape:\t', X.shape)
conv2d_51 output shape:	 (1, 112, 112, 64)
batch_normalization_42 output shape:	 (1, 112, 112, 64)
activation_2 output shape:	 (1, 112, 112, 64)
max_pooling2d_2 output shape:	 (1, 56, 56, 64)
resnet_block_9 output shape:	 (1, 56, 56, 64)
resnet_block_10 output shape:	 (1, 28, 28, 128)
resnet_block_11 output shape:	 (1, 14, 14, 256)
resnet_block_12 output shape:	 (1, 7, 7, 512)
global_average_pooling2d_2 output shape:	 (1, 512)
dense_2 output shape:	 (1, 10)
  • 6
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
TensorFlow 2.0是一个开源的机器学习框架,可用于构建和训练深度学习模型。ResNet-50是一个具有50个卷积层的深度卷积神经网络架构,在图像识别和分类任务中表现优秀。 要使用TensorFlow 2.0来进行ResNet-50的分类,我们需要进行以下步骤: 1. 数据准备:准备一个包含待分类图像的数据集。确保图像具有正确的标签,并将其分为训练集和验证集。 2. 模型构建:使用TensorFlow 2.0的高级API(例如tf.keras)来构建ResNet-50模型。tf.keras提供了一系列方便的神经网络层和模型,可以简化模型的构建过程。 3. 模型训练:使用训练集数据对ResNet-50模型进行训练。通过定义优化器(如Adam优化器)和损失函数(如交叉熵损失函数)来调整模型权重,以使模型能够更好地进行分类。 4. 模型评估:使用验证集数据对训练好的模型进行评估。计算模型在验证集上的准确率、精确率、召回率或其他指标,以衡量模型的性能。 5. 模型调优:根据评估结果对模型进行调优。可以调整模型的超参数(如学习率、批大小等)或使用正则化技术(如dropout)来改善模型的泛化能力。 6. 模型应用:使用训练好的ResNet-50模型对新的未知图像进行分类。将待分类图像输入到模型中,观察模型输出的预测结果,并根据预测结果进行分类。 通过以上步骤,我们可以使用TensorFlow 2.0来构建和训练一个ResNet-50模型,从而实现图像分类任务。这个过程需要一些计算资源和时间,但可以获得一个准确性较高的图像分类模型。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

cofisher

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

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

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

打赏作者

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

抵扣说明:

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

余额充值