【Tensorflow 2.0 正式版教程】VGG16

这篇文章我们来搭建一个早期的经典网络VGG16,数据集采用稍复杂的Cifar-10。该数据集Tensorflow同样提供了官方的加载方式

(train_images, train_labels, test_images, test_labels) = load_CIFAR('/home/user/Documents/dataset/Cifar-10')
train_labels = tf.keras.utils.to_categorical(train_labels, 10)
test_labels = tf.keras.utils.to_categorical(test_labels, 10)

其中tf.keras.utils.to_categorical是将数据转换为one hot格式。

第一次执行时会自动下载,但是该数据集一共有200M左右,而且官方提供的下载如果在国内的话速度会很慢,所以这里建议从官网下载。压缩包解压后并非一张张图片,而是采用二进制方式存储,我提供一份加载数据的代码

def load_CIFAR_batch(filename):
    """ load single batch of cifar """
    with open(filename, 'rb')as f:
        datadict = p.load(f, encoding='iso-8859-1')
        X = datadict['data']
        Y = datadict['labels']
        X = X.reshape(10000, 3, 32, 32)
        Y = np.array(Y)
        return X, Y


def load_CIFAR(Foldername):
    train_data = np.zeros([50000, 32, 32, 3], dtype=np.float32)
    train_label = np.zeros([50000, 10], dtype=np.float32)
    test_data = np.zeros([10000, 32, 32, 3], dtype=np.float32)
    test_label = np.zeros([10000, 10], dtype=np.float32)

    for sample in range(5):
        X, Y = load_CIFAR_batch(Foldername + "/data_batch_" + str(sample + 1))

        for i in range(3):
            train_data[10000 * sample:10000 * (sample + 1), :, :, i] = X[:, i, :, :]
        for i in range(10000):
            train_label[i + 10000 * sample][Y[i]] = 1

    X, Y = load_CIFAR_batch(Foldername + "/test_batch")
    for i in range(3):
        test_data[:, :, :, i] = X[:, i, :, :]
    for i in range(10000):
        test_label[i][Y[i]] = 1

    return train_data, train_label, test_data, test_label

网上关于VGG论文的解读非常多,因此这里对网络结构和参数不多赘述,可以像下面这样简单的搭建好,由于我们所用的数据是Cifar-10,所以最终网络的输出维度设为10。并且超参数的设置遵循原文,即
weight_decay = 5e-4dropout_rate = 0.5

def VGG16():
    model = models.Sequential()
    model.add(Conv2D(64, (3, 3), activation='relu', padding='same', input_shape=(32, 32, 3), kernel_regularizer=regularizers.l2(weight_decay)))
    model.add(Conv2D(64, (3, 3), activation='relu', padding='same', kernel_regularizer=regularizers.l2(weight_decay)))
    model.add(MaxPooling2D((2, 2)))

    model.add(Conv2D(128, (3, 3), activation='relu', padding='same', kernel_regularizer=regularizers.l2(weight_decay)))
    model.add(Conv2D(128, (3, 3), activation='relu', padding='same', kernel_regularizer=regularizers.l2(weight_decay)))
    model.add(MaxPooling2D((2, 2)))

    model.add(Conv2D(256, (3, 3), activation='relu', padding='same', kernel_regularizer=regularizers.l2(weight_decay)))
    model.add(Conv2D(256, (3, 3), activation='relu', padding='same', kernel_regularizer=regularizers.l2(weight_decay)))
    model.add(Conv2D(256, (3, 3), activation='relu', padding='same', kernel_regularizer=regularizers.l2(weight_decay)))
    model.add(MaxPooling2D((2, 2)))

    model.add(Conv2D(512, (3, 3), activation='relu', padding='same', kernel_regularizer=regularizers.l2(weight_decay)))
    model.add(Conv2D(512, (3, 3), activation='relu', padding='same', kernel_regularizer=regularizers.l2(weight_decay)))
    model.add(Conv2D(512, (3, 3), activation='relu', padding='same', kernel_regularizer=regularizers.l2(weight_decay)))
    model.add(MaxPooling2D((2, 2)))

    model.add(Conv2D(512, (3, 3), activation='relu', padding='same', kernel_regularizer=regularizers.l2(weight_decay)))
    model.add(Conv2D(512, (3, 3), activation='relu', padding='same', kernel_regularizer=regularizers.l2(weight_decay)))
    model.add(Conv2D(512, (3, 3), activation='relu', padding='same', kernel_regularizer=regularizers.l2(weight_decay)))

    model.add(Flatten())  # 2*2*512
    model.add(Dense(4096, activation='relu'))
    model.add(Dropout(0.5))
    model.add(Dense(4096, activation='relu'))
    model.add(Dropout(0.5))
    model.add(Dense(10, activation='softmax'))

    return model

下面介绍变学习率的设置方式。要用到的是model.fit中的callbacks参数,从参数名可以理解,我们需要写一个回调函数来实现学习率随训练轮数增加而减小。VGG原文中采用带动量的SGD,初始学习率为0.01,每次下降为原来的十分之一,这里我们让网络训练50个epoch,即epoch_num = 50,其中前20个采用0.01,中间20个采用0.001,最后10个采用0.0001

def scheduler(epoch):
    if epoch < epoch_num * 0.4:
        return learning_rate
    if epoch < epoch_num * 0.8:
        return learning_rate * 0.1
    return learning_rate * 0.01

sgd = optimizers.SGD(lr=learning_rate, momentum=0.9, nesterov=True)
change_lr = LearningRateScheduler(scheduler)

最后,在训练网络时将change_lr参数传入即可

model.compile(loss='categorical_crossentropy', optimizer=sgd, metrics=['accuracy'])
model.fit(train_images, train_labels,
          batch_size=batch_size,
          epochs=epoch_num,
          callbacks=[change_lr],
          validation_data=(test_images, test_labels))

最终测试集准确率大约在83%,当然这并不是一个很好的结果,一方面是因为Batch normalization这一重要技术出现在VGG之后,另一方面我们也没有使用数据增强。这两点将在下一篇教程ResNet中讲解。

完整的代码可以在我的github上找到
https://github.com/Apm5/tensorflow_2.0_tutorial/blob/master/CNN/VGG16.py

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是基于TensorFlow 2.0和VGG16模型添加SENet进行人脸表情识别的示例代码: ```python import tensorflow as tf from tensorflow.keras.layers import Input, Conv2D, MaxPooling2D, Flatten, Dense, Dropout, GlobalAveragePooling2D, Reshape, Multiply, Add from tensorflow.keras.models import Model from tensorflow.keras.applications.vgg16 import VGG16 # 定义SE模块 def se_module(input_feature, ratio=8): channel = input_feature.shape[-1] gap = GlobalAveragePooling2D()(input_feature) fc1 = Dense(channel // ratio, activation='relu')(gap) fc2 = Dense(channel, activation='sigmoid')(fc1) fc2 = Reshape((1, 1, channel))(fc2) return Multiply()([input_feature, fc2]) # 加载VGG16模型 base_model = VGG16(weights='imagenet', include_top=False, input_shape=(48, 48, 3)) for layer in base_model.layers: layer.trainable = False # 添加SE模块 x = base_model.output x = se_module(x) x = Flatten()(x) x = Dense(128, activation='relu')(x) x = Dropout(0.5)(x) predictions = Dense(7, activation='softmax')(x) model = Model(inputs=base_model.input, outputs=predictions) # 编译模型 model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy']) # 训练模型 model.fit(train_generator, epochs=10, validation_data=val_generator) ``` 其中,`se_module`函数定义了SE模块,`ratio`参数用于控制FC层输出通道数与输入通道数的比例,默认为8。 在加载VGG16模型后,通过调用`base_model.output`获取模型输出,然后将输出作为SE模块的输入,并将SE模块输出后的结果通过Flatten层压平,接着添加一个全连接层、一个Dropout层和一个Softmax层,最终构建出完整的SENet-VGG16模型,并使用`model.compile`编译模型,使用`model.fit`训练模型。 需要注意的是,本示例代码中的`train_generator`和`val_generator`需要根据具体情况进行替换,以适配训练数据的输入形式和标签形式。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值