T1:实现mnist手写数字识别

>- ** 本文为[365天深度学习训练营](https://mp.weixin.qq.com/s/0dvHCaOoFnW8SCp3JpzKxg) 中的学习记录博客**
>- ** 原作者:[K同学啊](https://mtyjkh.blog.csdn.net/)**

写在最前:目标

1.知道如何配置环境

2.跑通模型(不报错)

3.储存模型,供后续使用

4.了解如何衡量模型训练结果是否是优秀

一、环境配置

编译器:PyCharm Community

语言环境:python3.11.7

深度学习环境:TensorFlow 2.9.1

1.1基于pycharm的环境配置

待补

1.2查询目前的环境配置

打开pycharm,打开目标python脚本,调出终端输入conda info可以查询当前激活的Conda环境及其路径。也可用conda list命令来查看是否正确安装

conda info
conda list

二、跑通模型

2.1设置GPU

原代码

import tensorflow as tf
gpus = tf.config.list_physical_devices("GPU")

if gpus:
    gpu0 = gpus[0] #如果有多个GPU,仅使用第0个GPU
    tf.config.experimental.set_memory_growth(gpu0, True) #设置GPU显存用量按需使用
    tf.config.set_visible_devices([gpu0],"GPU")

原有代码运行出现问题。gpt提示:使用了一个过时的 API。应该使用 tf.config.set_memory_growth 而不是 tf.config.experimental.set_memory_growth

import tensorflow as tf
gpus = tf. config.list_physical_devices("GPU")

# 如果有 GPU 可用,配置 TensorFlow 使用它们
if gpus:
    gpu0 = gpus[0]  # 只使用第一个 GPU
    tf.config.set_memory_growth(gpu0, True)  # 设置显存按需增长
    tf.config.set_visible_devices([gpu0], "GPU")

2.2导入数据

(train_images, train_labels), (test_images, test_labels) = datasets.mnist.load_data()
  • 这一行代码从 tensorflow.keras.datasets 模块中导入 MNIST 数据集。
  • datasets.mnist.load_data() 函数返回两个元组:一个是训练数据及其标签 (train_images, train_labels),另一个是测试数据及其标签 (test_images, test_labels)。
  • train_imagestest_images 是手写数字的图像数据,train_labelstest_labels 是对应的标签(即图像代表的数字)。

2.3归一化

train_images, test_images = train_images / 255.0, test_images / 255.0
  • 这一行代码将训练和测试图像的数据进行归一化处理。
  • MNIST 数据集中每个图像像素的取值范围是 0 到 255。将这些像素值除以 255.0 可以将它们归一化到 0 到 1 之间,这有助于加速模型的训练并提高模型的性能。

2.4调整测试集和训练集图像

train_images = train_images.reshape((60000, 28, 28, 1))
test_images = test_images.reshape((10000, 28, 28, 1))
  • 这一行代码将训练和测试图像的数据形状进行调整。
  • 原始的 train_imagestest_images 的形状分别是 (60000, 28, 28)(10000, 28, 28),表示每张图像是 28x28 的二维矩阵。
  • reshape((60000, 28, 28, 1)) 将训练图像重新调整为 (60000, 28, 28, 1) 的形状,其中 1 表示单通道(灰度图像)。测试图像也类似调整为 (10000, 28, 28, 1)
  • 调整后的形状适用于卷积神经网络(CNN),因为 CNN 通常期望输入的图像数据具有高度、宽度和通道三个维度。

2.5构建CNN网络模型

model = models.Sequential([
    layers.Conv2D(32,(3,3),activation='relu',input_shape=(28,28,1)),
    layers.MaxPooling2D((2,2)),
    layers.Conv2D(64,(3,3),activation='relu'),
    layers.MaxPooling2D((2,2)),
    layers.Flatten(),
    layers.Dense(64,activation='relu'),
    layers.Dense(10)
])
  1. 第一层:卷积

    layers.Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1))
    • Conv2D 是一个二维卷积层,它会对输入图像进行卷积操作。
    • 32 是输出的通道数,也就是卷积核的数量。
    • (3, 3) 是卷积核的尺寸(高和宽)。
    • activation='relu' 表示使用 ReLU 激活函数,使模型能够学习非线性特征。
    • input_shape=(28, 28, 1) 定义了输入图像的形状。对于 MNIST 数据集,输入图像是 28x28 像素的单通道灰度图像。
  2. 第二层:最大池化层

    layers.MaxPooling2D((2, 2))
    • MaxPooling2D 是一个最大池化层,它会对输入进行下采样(取局部区域的最大值),从而减少数据的尺寸和计算量。
    • (2, 2) 表示池化窗口的大小。这里使用 2x2 的窗口进行池化。
  3. 第三层:卷积层

    layers.Conv2D(64, (3, 3), activation='relu')
    • 这是第二个卷积层,参数设置类似于第一个卷积层。
    • 64 表示输出通道数增加到了 64 个。
  4. 第四层:最大池化层

    layers.MaxPooling2D((2, 2))
    • 这是第二个最大池化层,参数设置与第一个池化层相同。
  5. 第五层:扁平层

    layers.Flatten()
    • Flatten 层将多维输入(即图像数据)展平成一维,准备输入到全连接层中。
  6. 第六层:全连接层

    layers.Dense(64, activation='relu')
    • Dense 层是全连接层,每个神经元与上一层的所有神经元相连。
    • 64 表示这一层有 64 个神经元。
    • activation='relu' 表示使用 ReLU 激活函数。
  7. 第七层:输出层

    layers.Dense(10)
    • 这是最后的输出层,也是全连接层。
    • 10 表示这一层有 10 个神经元,对应于 MNIST 数据集的 10 个类别(数字 0 到 9)。
    • 这一层通常没有激活函数,后面会结合损失函数计算 logits(未归一化的预测值)。

T1:实现mnist手写数字识别_第1张图片

2.6编译模型

设置模型的优化器、损失函数和评估指标,以便在训练过程中使用。这是机器学习模型的一个重要步骤,确保模型能够正确地学习和评估。

model.compile(
    optimizer='adam',
    loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
    metrics=['accuracy']
)
2.6.1参数详解
  1. optimizer='adam'

    • optimizer 参数指定了优化器,这里选择的是 Adam 优化器。
    • Adam(Adaptive Moment Estimation)优化器是一种广泛使用的优化算法,它结合了动量梯度下降和 RMSProp 的优点,可以加速训练并且在很多情况下效果很好。
    • 优化器负责根据损失函数的输出来更新模型的权重,以最小化损失函数的值。
  2. loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)

    • loss 参数指定了损失函数,这里选择的是稀疏分类交叉熵损失函数。
    • SparseCategoricalCrossentropy 用于多分类问题,特别适用于目标标签是整数(如 0, 1, 2, ... 9)而不是独热编码(one-hot encoding)的情况。
    • from_logits=True 表示模型的输出是 logits(未归一化的预测值)。在这种情况下,损失函数内部会先对 logits 进行 softmax 归一化,然后再计算交叉熵损失。
  3. metrics=['accuracy']

    • metrics 参数指定了评估指标,这里选择的是准确率。
    • 准确率(accuracy)是模型在训练和验证过程中的一个常见评估指标,表示预测正确的样本占总样本的比例。
    • 在每个训练轮次结束后,Keras 会计算并显示模型在训练集和验证集上的准确率,以帮助评估模型的性能。
2.6.2整体功能

通过调用 model.compile(),你为模型配置了训练时所需的关键设置,包括:

  • 优化器:Adam,负责权重更新。
  • 损失函数:稀疏分类交叉熵,用于计算预测结果与实际标签之间的差异。
  • 评估指标:准确率,用于监控训练和验证过程中模型的表现。

这一步是训练模型前的必要步骤,它告诉 Keras 如何在训练过程中调整模型的权重、计算损失以及评估模型性能。

2.7模型训练


history = model.fit(
    train_images,
    train_labels,
    epochs=10,
    validation_data=(test_images,test_labels)
)
2.7.1参数详解
  1. train_images

    • 这是训练集的输入数据(图像),在前面的步骤中已经进行了归一化和形状调整。
  2. train_labels

    • 这是训练集的标签(目标值),对应于 train_images 中每张图像的实际分类标签(数字 0-9)。
  3. epochs=10

    • epochs 参数指定了训练的轮次(epochs)数量。
    • 在这里,模型将训练 10 个轮次。每个轮次,模型会遍历整个训练集一次。
  4. validation_data=(test_images, test_labels)

    • validation_data 参数用于指定验证集(图像和标签)。
    • 验证集的数据不会用于训练模型,只用于在每个轮次结束后评估模型的性能。
    • test_imagestest_labels 分别是验证集的输入数据和标签,前面也已经进行了归一化和形状调整。
2.7.2整体功能

调用 model.fit() 方法时,模型会执行以下操作:

  1. 训练模型

    • 模型会在 train_imagestrain_labels 上进行训练。
    • 每个训练轮次,模型会遍历整个训练数据集一次,并调整模型权重以最小化损失函数。
  2. 评估模型

    • 在每个训练轮次结束后,模型会在 validation_data(即 test_imagestest_labels)上进行评估。
    • 评估过程中,模型会计算在验证集上的损失值和评估指标(如准确率),这些信息用于监控模型在训练过程中的性能。
  3. 记录训练过程

    • history 对象会记录训练过程中每个轮次的损失值和评估指标(如准确率)的变化情况。
    • 你可以通过 history.history 属性访问这些记录,用于绘制训练过程中的损失值和准确率变化曲线,以直观地了解模型的学习效果。
2.7.3例子说明

假设你正在训练一个手写数字分类模型:

  • 训练数据train_images 是 60000 张手写数字图像,train_labels 是对应的标签。
  • 验证数据test_images 是 10000 张手写数字图像,test_labels 是对应的标签。
  • 训练过程:模型将训练 10 个轮次。在每个轮次中,模型会使用训练数据进行训练,并使用验证数据进行评估。
  • 结果记录:训练过程中的损失值和准确率会记录在 history 对象中,可以用于后续分析和可视化。

2.8可视化训练过程

2.8.1(注意:这里可能会报错)

你的程序中存在多个 OpenMP 运行时库的副本,这可能会导致性能下降或产生不正确的结果。OpenMP 是一个并行编程模型,常用于利用多核处理器进行并行计算。多个 OpenMP 运行时库的副本同时存在会引起冲突。

解决方法

设置环境变量 KMP_DUPLICATE_LIB_OKTRUE: 虽然这是一个不安全、不支持、且未记录的方法,但它可以让程序继续执行。需要注意,这可能会导致崩溃或产生不正确的结果。

在代码中添加以下几行:

import os
os.environ["KMP_DUPLICATE_LIB_OK"] = "TRUE"

这种方法应作为临时解决方案,不建议长期使用。

# 绘制训练准确率和验证准确率
plt.plot(history.history['accuracy'], label='Train Accuracy')
plt.plot(history.history['val_accuracy'], label='Validation Accuracy')
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
plt.legend(loc='lower right')
plt.show()

# 绘制训练损失和验证损失
plt.plot(history.history['loss'], label='Train Loss')
plt.plot(history.history['val_loss'], label='Validation Loss')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.legend(loc='upper right')
plt.show()

T1:实现mnist手写数字识别_第2张图片T1:实现mnist手写数字识别_第3张图片

训练损失和验证损失曲线
  • Train Loss:训练集上的损失随着训练轮次的增加而减少,表现良好。
  • Validation Loss:验证集上的损失在前几轮次中减少,然后略有增加,这可能是过拟合的迹象。
2.8.2训练准确率和验证准确率曲线
  • Train Accuracy:训练集上的准确率随着训练轮次的增加而提高,接近 1.0,说明模型在训练集上表现非常好。
  • Validation Accuracy:验证集上的准确率也较高,但在后期略有波动,这表明模型可能在某些轮次上表现不稳定。
2.8.3过拟合现象

从损失和准确率曲线来看,模型在训练集上的表现非常好,但在验证集上的表现略有波动,这可能是过拟合的表现。过拟合是指模型在训练数据上表现良好,但在未见过的验证数据上表现不佳。

2.8.4改进建议
  1. 数据增强: 数据增强可以增加训练数据的多样性,帮助模型更好地泛化。

    from tensorflow.keras.preprocessing.image import ImageDataGenerator
    
    datagen = ImageDataGenerator(
        rotation_range=10,
        width_shift_range=0.1,
        height_shift_range=0.1,
        zoom_range=0.1
    )
    
    train_generator = datagen.flow(train_images, train_labels, batch_size=64)
    
  2. 正则化: 添加 Dropout 层或 L2 正则化项以减少过拟合。

    model = models.Sequential([
        layers.Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1)),
        layers.MaxPooling2D((2, 2)),
        layers.Conv2D(64, (3, 3), activation='relu'),
        layers.MaxPooling2D((2, 2)),
        layers.Flatten(),
        layers.Dense(64, activation='relu', kernel_regularizer=tf.keras.regularizers.l2(0.01)),
        layers.Dropout(0.5),
        layers.Dense(10)
    ])
    
  3. 早停法: 使用早停法在验证集损失不再下降时停止训练,以防止过拟合。

    from tensorflow.keras.callbacks import EarlyStopping
    
    early_stopping = EarlyStopping(monitor='val_loss', patience=3, restore_best_weights=True)
    
    history = model.fit(
        train_generator,
        epochs=50,
        validation_data=(test_images, test_labels),
        callbacks=[early_stopping]
    )
    
  4. 调整学习率: 使用学习率调度器动态调整学习率。

    from tensorflow.keras.callbacks import ReduceLROnPlateau
    
    reduce_lr = ReduceLROnPlateau(monitor='val_loss', factor=0.2, patience=2, min_lr=0.001)
    
    history = model.fit(
        train_generator,
        epochs=50,
        validation_data=(test_images, test_labels),
        callbacks=[early_stopping, reduce_lr]
    )
    

通过这些方法,可以帮助模型更好地泛化,提高验证集上的表现,减少过拟合现象。

三、储存模型

在模型训练后可将模型储存,并可在另开的文件中随时调用该模型

model.save('D:/100 Deep learning projects(model)/mnist_handwritten_digit_recognition_model.h5')

调用语句

# 加载已保存的模型
model = load_model('D:/100 Deep learning projects(model)/mnist_handwritten_digit_recognition_model.h5')

你可能感兴趣的:(neo4j)