欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

tensorflow2.1 构建Vgg16、GoogLeNet-v1、resNet18

程序员文章站 2022-03-21 19:50:00
...

一、Vgg16

from tensorflow.keras.layers import Conv2D, Dense, BatchNormalization, ReLU, MaxPool2D, Flatten, Dropout, InputLayer
from tensorflow.keras.models import Sequential


def make_block(conv_num, filters):
    """

    :param conv_num: 卷积层数量
    :param filters: 卷积核数量
    :return:
    """
    conv_block = Sequential()
    for i in range(conv_num):
        conv_block.add(Conv2D(filters=filters, kernel_size=3, strides=1, padding='same',
                              name='block_' + str(conv_num) + "_" + str(i)),
                       )
        conv_block.add(BatchNormalization())
        conv_block.add(ReLU())
    conv_block.add(MaxPool2D())
    return conv_block


def creat_vgg(block_param, class_num, input_shape):
    """

    :param block_param: vgg16:((2, 64), (2, 128), (3, 256), (3, 512), (3, 512))
    :param class_num: 分类数量
    :param input_shape: 输入大小 (h,w,n)
    :return:
    """
    vgg = Sequential()
    vgg.add(InputLayer(input_shape=input_shape, name="input_layer"))
    for (conv_num, filters) in block_param:
        vgg.add(make_block(conv_num, filters))
    vgg.add(Flatten(name='flatten'))
    vgg.add(Dense(units=2048, activation='relu', name='dense_1'))
    vgg.add(Dropout(0.2))
    vgg.add(Dense(units=1024, activation='relu', name='dense_2'))
    vgg.add(Dropout(0.2))
    vgg.add(Dense(units=class_num, activation='softmax', name='out_layer'))

    return vgg


vgg16_block_parameters = ((2, 64), (2, 128), (3, 256), (3, 512), (3, 512))
vgg16 = creat_vgg(vgg16_block_parameters, 10, (512, 512, 3))
print(vgg16.summary())

二、GoogLeNet-v1

import tensorflow as tf
from tensorflow.keras.layers import Conv2D, BatchNormalization, ReLU, MaxPool2D, Dense, AvgPool2D, Flatten
from tensorflow.keras.models import Sequential


class Inception(tf.keras.layers.Layer):
    def __init__(self, c1, c2, c3, c4):
        super(Inception, self).__init__()
        self.block_1 = Conv2D(c1, kernel_size=1, strides=1, padding='same', activation='relu')
        self.block_2_1 = Conv2D(c2[0], kernel_size=1, strides=1, padding='same', activation='relu')
        self.block_2_2 = Conv2D(c2[1], kernel_size=3, strides=1, padding='same', activation='relu')
        self.block_3_1 = Conv2D(c3[0], kernel_size=1, strides=1, padding='same', activation='relu')
        self.block_3_2 = Conv2D(c3[1], kernel_size=5, strides=1, padding='same', activation='relu')
        self.block_4_1 = MaxPool2D(pool_size=3, strides=1, padding='same')
        self.block_4_2 = Conv2D(c4, kernel_size=1, strides=1, activation='relu', padding='same')

    def call(self, inputs, **kwargs):
        b1_out = self.block_1(inputs)
        b2_out = self.block_2_2(self.block_2_1(inputs))
        b3_out = self.block_3_2(self.block_3_1(inputs))
        b4_out = self.block_4_2(self.block_4_1(inputs))
        out = tf.concat((b1_out, b2_out, b3_out, b4_out), axis=-1)
        return out


# 辅助训练分支
def aux_classifier(x_in, filters):
    x = AvgPool2D(pool_size=5, strides=3, padding='same')(x_in)
    x = Conv2D(filters[0], kernel_size=1, strides=1, padding='valid', activation='relu')(x)
    x = Flatten()(x)
    x = Dense(units=filters[1], activation='relu')(x)
    x = Dense(units=10, activation='softmax')(x)
    return x


# B1模块
model_inputs = tf.keras.Input(shape=(224, 224, 3))
x = Conv2D(filters=64, kernel_size=7, strides=2, activation='relu', padding='same')(model_inputs)
x = MaxPool2D(pool_size=3, strides=2, padding='same')(x)

# B2 模块
x = Conv2D(filters=192, kernel_size=3, strides=1, activation='relu', padding='same')(x)
x = MaxPool2D(pool_size=3, strides=2, padding='same')(x)

# B3 模块
x = Inception(64, (96, 128), (16, 32), 32)(x)
x = Inception(128, (128, 192), (32, 96), 64)(x)
x = MaxPool2D(pool_size=3, strides=2, padding='same')(x)

# B4 模块
x = Inception(192, (96, 208), (16, 48), 64)(x)
# 辅助输出1
aux_output_1 = aux_classifier(x, [128, 1024])
x = Inception(160, (112, 224), (24, 64), 64)(x)
x = Inception(128, (128, 256), (24, 64), 64)(x)
x = Inception(112, (144, 288), (32, 64), 64)(x)
# 辅助输出2
aux_output_2 = aux_classifier(x, [128, 1024])
x = Inception(256, (160, 320), (32, 128), 128)(x)
x = tf.keras.layers.MaxPool2D(pool_size=3, strides=2, padding='same')(x)

# b5 模块
# Inception
x = Inception(256, (160, 320), (32, 128), 128)(x)
# Inception
x = Inception(384, (192, 384), (48, 128), 128)(x)
# GAP
x = tf.keras.layers.GlobalAvgPool2D()(x)
# 输出层
main_outputs = tf.keras.layers.Dense(10, activation='softmax')(x)
# 使用Model来创建模型,指明输入和输出

# 使用Model来创建模型,指明输入和输出
model = tf.keras.Model(inputs=model_inputs, outputs=[main_outputs, aux_output_1, aux_output_2])

三、ResNet-18

# 导入相关的工具包
import tensorflow as tf
from tensorflow.keras import layers, activations


# 定义ResNet的残差块
class Residual(tf.keras.Model):
    # 指明残差块的通道数,是否使用1*1卷积,步长
    def __init__(self, num_channels, use_1x1conv=False, strides=1):
        super(Residual, self).__init__()
        # 卷积层:指明卷积核个数,padding,卷积核大小,步长
        self.conv1 = layers.Conv2D(num_channels,
                                   padding='same',
                                   kernel_size=3,
                                   strides=strides)
        # 卷积层:指明卷积核个数,padding,卷积核大小,步长
        self.conv2 = layers.Conv2D(num_channels, kernel_size=3, padding='same')
        if use_1x1conv:
            self.conv3 = layers.Conv2D(num_channels,
                                       kernel_size=1,
                                       strides=strides)
        else:
            self.conv3 = None
        # 指明BN层
        self.bn1 = layers.BatchNormalization()
        self.bn2 = layers.BatchNormalization()

    # 定义前向传播过程
    def call(self, X):
        # 卷积,BN,**
        Y = activations.relu(self.bn1(self.conv1(X)))
        # 卷积,BN
        Y = self.bn2(self.conv2(Y))
        # 对输入数据进行1*1卷积保证通道数相同
        if self.conv3:
            X = self.conv3(X)
        # 返回与输入相加后**的结果
        return activations.relu(Y + X)


# ResNet网络中模块的构成
class ResnetBlock(tf.keras.layers.Layer):
    # 网络层的定义:输出通道数(卷积核个数),模块中包含的残差块个数,是否为第一个模块
    def __init__(self, num_channels, num_residuals, first_block=False):
        super(ResnetBlock, self).__init__()
        # 模块中的网络层
        self.listLayers = []
        # 遍历模块中所有的层
        for i in range(num_residuals):
            # 若为第一个残差块并且不是第一个模块,则使用1*1卷积,步长为2(目的是减小特征图,并增大通道数)
            if i == 0 and not first_block:
                self.listLayers.append(Residual(num_channels, use_1x1conv=True, strides=2))
            # 否则不使用1*1卷积,步长为1
            else:
                self.listLayers.append(Residual(num_channels))
                # 定义前向传播过程

    def call(self, X):
        # 所有层依次向前传播即可
        for layer in self.listLayers.layers:
            X = layer(X)
        return X


# 构建ResNet网络
class ResNet(tf.keras.Model):
    # 初始化:指定每个模块中的残差快的个数
    def __init__(self, num_blocks):
        super(ResNet, self).__init__()
        # 输入层:7*7卷积,步长为2
        self.conv = layers.Conv2D(64, kernel_size=7, strides=2, padding='same')
        # BN层
        self.bn = layers.BatchNormalization()
        # **层
        self.relu = layers.Activation('relu')
        # 最大池化层
        self.mp = layers.MaxPool2D(pool_size=3, strides=2, padding='same')
        # 第一个block,通道数为64
        self.resnet_block1 = ResnetBlock(64, num_blocks[0], first_block=True)
        # 第二个block,通道数为128
        self.resnet_block2 = ResnetBlock(128, num_blocks[1])
        # 第三个block,通道数为256
        self.resnet_block3 = ResnetBlock(256, num_blocks[2])
        # 第四个block,通道数为512
        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)
        # BN
        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


# 模型实例化:指定每个block中的残差块个数
resnet18 = ResNet([2, 2, 2, 2])
resnet18.build(input_shape=(None, 256, 256, 3))
resnet18.summary()