经典卷积网络--AlexNet

该网络值得借鉴的地方:激活函数使用 Relu,提升训练速度;Dropout 防止过拟合。

1、AlexNet网络结构

  AlexNet 网络诞生于 2012 年,是第一个在图像识别比赛中获得冠军的深度学习模型,其 ImageNet Top5 错误率为 16.4 %,可以说 AlexNet 的出现使得已经沉寂多年的深度学习领域开启了黄金时代。

  AlexNet 的总体结构和 LeNet5 有相似之处,但是有一些很重要的改进:

  • 由五层卷积、三层全连接组成,输入图像尺寸为 224 * 224 * 3,网络规模远大于 LeNet5;
  • 使用了 Relu 激活函数;
  • 进行了舍弃(Dropout)操作,以防止模型过拟合,提升鲁棒性;
  • 增加了一些训练上的技巧,包括数据增强、学习率衰减、权重衰减(L2 正则化)等。 AlexNet 的网络结构如图所示。

image-20220515144529709

image-20220515144506889

  原文使用LRN(local response normalization) 局部响应标准化,但现在LRN已经很少使用了,这里使用BN(Batch Normalization)替代。

  可以看到,上图所示的网络结构将模型分成了两部分,这是由于当时用于训练 AlexNet 的显卡为 GTX 580(显存为 3GB),单块显卡运算资源不足的原因。

2、使用Tensorflow搭建AlexNet

  在 Tensorflow 框架下利用 Keras 来搭建 AlexNet 模型,这里做了一些调整,将输入图像 尺寸改为 32 * 32 * 3 以适应 cifar10 数据集,并且将原始的 AlexNet 模型中的 11 * 11、7 * 7、 5 * 5 等大尺寸卷积核均替换成了 3 * 3 的小卷积核,如图所示。

image-20220515144814387

  图中紫色块代表卷积部分,可以看到卷积操作共进行了 5 次:

  • 第 1 次卷积:共有 96 个 3 * 3 的卷积核,不进行全零填充,进行 BN 操作,激活函数为 Relu,进行最大池化,池化核尺寸为 3 * 3,步长为 2;image-20220515144930903
  • 第 2 次卷积:与第 1 次卷积类似,除卷积核个数由 96 增加到 256 之外几乎相同;image-20220515145001411
  • 第3 次卷积:共有 384 个 3 * 3 的卷积核,进行全零填充,激活函数为 Relu,不进行 BN 操作以及最大池化;image-20220515145025270
  • 第 4 次卷积:与第 3 次卷积几乎完全相同;image-20220515145052815
  • 第 5 次卷积:共有 96 个 3 * 3 的卷积核,进行全零填充,激活函数为 Relu,不进行 BN 操作,进行最大池化,池化核尺寸为 3 * 3,步长为 2。image-20220515145110164

  图中红色块代表全连接部分,共有三层:

  • 第一层共 2048 个神经元,激活函数为 Relu,进行 0.5 的 dropout

     self.flatten = Flatten()
     self.f1 = Dense(2048, activation='relu')
     self.d1 = Dropout(0.5)
    
  • 第二层与第一层几乎完全相同;

    self.f2 = Dense(2048, activation='relu')
    self.d2 = Dropout(0.5)
    
  • 第三层共 10 个神经元,进行 10 分类。

    self.f3 = Dense(10, activation='softmax')
    

  可以看到,与结构类似的 LeNet5 相比,AlexNet 模型的参数量有了非常明显的提升, 卷积运算的层数也更多了,这有利于更好地提取特征;Relu 激活函数的使用加快了模型的 训练速度;Dropout 的使用提升了模型的鲁棒性,这些优势使得 AlexNet 的性能大大提升。

3、完整代码实现

import tensorflow as tf
import os
import numpy as np
from matplotlib import pyplot as plt
from tensorflow.keras.layers import Conv2D, BatchNormalization, Activation, MaxPool2D, Dropout, Flatten, Dense
from tensorflow.keras import Model

np.set_printoptions(threshold=np.inf)

cifar10 = tf.keras.datasets.cifar10
(x_train, y_train), (x_test, y_test) = cifar10.load_data()
x_train, x_test = x_train / 255.0, x_test / 255.0

# 定义模型
class AlexNet8(Model):
    def __init__(self):
        super(AlexNet8, self).__init__()
        self.c1 = Conv2D(filters=96, kernel_size=(3, 3))
        self.b1 = BatchNormalization()
        self.a1 = Activation('relu')
        self.p1 = MaxPool2D(pool_size=(3, 3), strides=2)

        self.c2 = Conv2D(filters=256, kernel_size=(3, 3))
        self.b2 = BatchNormalization()
        self.a2 = Activation('relu')
        self.p2 = MaxPool2D(pool_size=(3, 3), strides=2)

        self.c3 = Conv2D(filters=384, kernel_size=(3, 3), padding='same',
                         activation='relu')
                         
        self.c4 = Conv2D(filters=384, kernel_size=(3, 3), padding='same',
                         activation='relu')
                         
        self.c5 = Conv2D(filters=256, kernel_size=(3, 3), padding='same',
                         activation='relu')
        self.p3 = MaxPool2D(pool_size=(3, 3), strides=2)

        self.flatten = Flatten()
        self.f1 = Dense(2048, activation='relu')
        self.d1 = Dropout(0.5)
        self.f2 = Dense(2048, activation='relu')
        self.d2 = Dropout(0.5)
        self.f3 = Dense(10, activation='softmax')

    def call(self, x):
        x = self.c1(x)
        x = self.b1(x)
        x = self.a1(x)
        x = self.p1(x)

        x = self.c2(x)
        x = self.b2(x)
        x = self.a2(x)
        x = self.p2(x)

        x = self.c3(x)

        x = self.c4(x)

        x = self.c5(x)
        x = self.p3(x)

        x = self.flatten(x)
        x = self.f1(x)
        x = self.d1(x)
        x = self.f2(x)
        x = self.d2(x)
        y = self.f3(x)
        return y


model = AlexNet8()

#编译模型
model.compile(optimizer='adam',
              loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=False),
              metrics=['sparse_categorical_accuracy'])
#读取模型
checkpoint_save_path = "./checkpoint/AlexNet8.ckpt"
if os.path.exists(checkpoint_save_path + '.index'):
    print('-------------load the model-----------------')
    model.load_weights(checkpoint_save_path)
#保存模型
cp_callback = tf.keras.callbacks.ModelCheckpoint(filepath=checkpoint_save_path,
                                                 save_weights_only=True,
                                                 save_best_only=True)
#训练模型
history = model.fit(x_train, y_train, batch_size=32, epochs=5, validation_data=(x_test, y_test), validation_freq=1,
                    callbacks=[cp_callback])
#查看模型摘要
model.summary()

# 将模型参数存入文本
# print(model.trainable_variables)
file = open('./weights.txt', 'w')
for v in model.trainable_variables:
    file.write(str(v.name) + '\n')
    file.write(str(v.shape) + '\n')
    file.write(str(v.numpy()) + '\n')
file.close()

###############################################    show   ###############################################

# 显示训练集和验证集的acc和loss曲线
acc = history.history['sparse_categorical_accuracy']
val_acc = history.history['val_sparse_categorical_accuracy']
loss = history.history['loss']
val_loss = history.history['val_loss']

plt.subplot(1, 2, 1)
plt.plot(acc, label='Training Accuracy')
plt.plot(val_acc, label='Validation Accuracy')
plt.title('Training and Validation Accuracy')
plt.legend()

plt.subplot(1, 2, 2)
plt.plot(loss, label='Training Loss')
plt.plot(val_loss, label='Validation Loss')
plt.title('Training and Validation Loss')
plt.legend()
plt.show()

acc和loss曲线:

image-20220515145525207

  模型摘要:

image-20220515145604005

猜你喜欢

转载自blog.csdn.net/qq_43753724/article/details/124782381