【机器学习】任务九:卷积神经网络(基于 Cifar-10 数据集的彩色图像识别分类、基于 CNN 的手写数字识别的实验)

1.卷积神经网络

        卷积神经网络(Convolutional Neural Network, CNN)是一种专门用于处理数据网格结构(如图像、视频等)的深度学习模型,在计算机视觉任务中被广泛应用,如图像分类、目标检测、图像分割等。以下是卷积神经网络的详细介绍:

1.1 卷积神经网络 (CNN) 结构及原理

核心组件:

  • 卷积层: 使用卷积核对输入数据(如图像)进行滑动,生成特征图(feature map)。
  • 池化层: 通过下采样减少特征图的尺寸,降低计算复杂度和内存消耗。常见方法包括最大池化 (max pooling)平均池化 (average pooling)
  • 全连接层: 将卷积和池化提取到的特征映射为输出类别,实现分类或回归任务。
  • Dropout层: 防止过拟合,通过随机丢弃部分神经元。

激活函数: 常用ReLU函数引入非线性,帮助模型学习复杂模式。

特点:

  • 局部连接: 每一层只与相邻节点连接,减少参数数量。
  • 权重共享: 同一卷积核在不同位置重复使用,进一步降低计算复杂度。
CNN 结构:
  • 典型的卷积神经网络由卷积层、池化层和全连接层 3 部分组成。在图像分类中表现良好的深度卷积神经网络,往往由多个“卷积层+池化层”的组合堆叠而成,通常多达十几层甚至上百层
  • 卷积层用于提取图像中的局部特征;池化层用于对提取出的局部特征
    进行降维处理,防止过拟合;全连接层用于接收池化层的输出,为后续分类任务
    做准备。

1.2 经典卷积神经网络结构

LeNet-5: 主要用于手写数字识别,包括多个卷积层和池化层组合。

  • 网络结构:输入层 → 卷积层 → 池化层 → 卷积层 → 池化层 → 全连接层 → 输出层

VGGNet: 探索卷积网络深度与性能的关系,VGG16和VGG19为其常见变体。

  • 特点:多组3×3卷积核,每组卷积后接2×2最大池化层。

ResNet: 引入残差模块,允许数据直接跳过某些层,提高网络性能。

2.基于 Cifar-10 数据集的彩色图像识别分类

2.1 导入所需的模块和包并进行数据预处理

2.1.1 实现目的:

导入TensorFlow等所需模块,用于加载 CIFAR-10 数据集,并完成数据类型转换和标准化处理,确保模型可以正常使用这些数据进行训练和测试。

2.1. 代码片段与结果

'''步骤一,导入本项目所需要的模块和包,从 Keras 中导入 Cifar-10 数据集,将训练集的特征值和标签值分别存储在
x_train 和 y_train 中,将测试集的特征值和标签值分别存储在 x_test 和 y_test 中。将特征值 x_train 和 x_test 
的数据类型转换为 tf.float32,并进行标准化处理,使其取值范围为 0~1;将标签值 y_train 和 y_test的数据类型转换为 tf.int32。'''# 导入所需要的模块与包
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
import os# 导入Cifar-10数据集,将训练集和测试集存储在相应变量中
cifar10 = tf.keras.datasets.cifar10
(x_train, y_train), (x_test, y_test) = cifar10.load_data()# 转换特征值的数据类型并进行标准化处理
x_train, x_test = tf.cast(x_train, dtype=tf.float32) / 255.0, tf.cast(x_test, dtype=tf.float32) / 255.0# 转换标签值的数据类型
y_train, y_test = tf.cast(y_train, dtype=tf.int32), tf.cast(y_test, dtype=tf.int32)# 显示数据集的特征值和标签值的 shape 属性值
print("x_train.shape =", x_train.shape)
print("y_train.shape =", y_train.shape)
print("x_test.shape =", x_test.shape)
print("y_test.shape =", y_test.shape)

2.1.3 代码解释:

1.导入 TensorFlow、NumPy、Matplotlib 和 OS 模块:

  • TensorFlow:用于深度学习模型构建和数据处理。
  • NumPy:用于数值计算和数据操作。
  • Matplotlib:用于数据的可视化。
  • OS:用于文件和目录操作。

2.加载 CIFAR-10 数据集:

  • tf.keras.datasets.cifar10 提供了 CIFAR-10 数据集。该数据集包含 10 类图片,适用于图像分类任务。
  • load_data() 将数据集拆分为训练集和测试集,并存储在 (x_train, y_train)(x_test, y_test) 中。

3.数据类型转换与标准化:

  • 使用 tf.cast() 将特征值转换为 tf.float32 数据类型。
  • 将像素值标准化到 [0, 1] 范围内,方便模型训练。
  • 将标签值转换为 tf.int32,用于模型的分类任务。

4.显示数据形状:

  • 通过 print() 输出训练集和测试集的特征值及标签值的形状,以验证数据加载是否正确。

2.1.4 结果与结果分析

x_train.shape = (50000, 32, 32, 3)

x_train.shape = (50000, 32, 32, 3)

y_train.shape = (50000, 1)

y_test.shape = (10000, 1)

1. 训练集数据 (x_train, y_train)

x_train.shape = (50000, 32, 32, 3)

  • 50000:训练集包含 50,000 张图像。
  • 32 × 32:每张图像的大小是 32 × 32 像素。
  • 3:代表图像的 3 个颜色通道(RGB),即每个像素点包含红、绿、蓝三种颜色值。

y_train.shape = (50000, 1)

  • 每张图像有 1 个标签,表示其所属类别。CIFAR-10 有 10 个类别,用标签 0~9 表示。

2. 测试集数据 (x_test, y_test)

x_test.shape = (10000, 32, 32, 3)

  • 10000:测试集包含 10,000 张图像。
  • 32 × 32:每张图像的尺寸为 32 × 32 像素。
  • 3:表示每张图像有 3 个颜色通道(RGB)。

y_test.shape = (10000, 1)

  • 每张测试图像也有 1 个标签,对应其类别。

2.2 构建 CNN 模型

2.2.1 实现目的:

构建一个用于 CIFAR-10 图像分类的卷积神经网络(CNN)模型。通过多个卷积层、池化层和全连接层的组合来提取图像特征,并最终完成分类任务。

2.2.2 代码片段:

'''步骤二,构建 CNN 模型,图像识别分类网络模型采用卷积神经网络,包括两
个卷积层、两个池化层、4 个 Dropout 层、一个拉伸层、两个全连接层和一个输
出层'''
# 构建 CNN 模型
model = tf.keras.models.Sequential([# 使用 Input 层明确指定输入形状tf.keras.Input(shape=x_train.shape[1:]),  # 创建卷积层tf.keras.layers.Conv2D(32, kernel_size=(3, 3), padding='same', activation=tf.nn.relu),# 创建最大池化层tf.keras.layers.MaxPool2D(pool_size=(2, 2), strides=(1, 1), padding='same'),  # 创建 Dropout 层tf.keras.layers.Dropout(0.2),  # 创建第二个卷积层tf.keras.layers.Conv2D(64, kernel_size=(3, 3), padding='same', activation=tf.nn.relu),# 创建最大池化层tf.keras.layers.MaxPool2D(pool_size=(2, 2), strides=(1, 1), padding='same'),  # 创建 Dropout 层tf.keras.layers.Dropout(0.2),  # 创建拉伸层(Flatten)tf.keras.layers.Flatten(),  # 创建全连接层tf.keras.layers.Dense(512, activation='relu'),  # 创建 Dropout 层tf.keras.layers.Dropout(0.2),  # 创建另一个全连接层tf.keras.layers.Dense(256, activation='relu'),  # 创建 Dropout 层tf.keras.layers.Dropout(0.5),  # 创建全连接层作为输出层tf.keras.layers.Dense(10, activation='softmax')  
])# 打印模型结构
model.summary()

2.2.3 代码解释:

1.Sequential 模型:

  • 使用 tf.keras.models.Sequential() 按顺序定义模型结构。

2.输入层:

  • tf.keras.Input() 定义输入层,输入数据的形状与训练数据集的形状一致。

3.卷积层:

  • 第一层卷积:Conv2D(32, (3, 3)) 使用 32 个大小为 3x3 的卷积核,提取低层次特征。
  • 第二层卷积:Conv2D(64, (3, 3)) 使用 64 个卷积核,提取更复杂的特征。

4.池化层:

  • 使用 MaxPool2D(pool_size=(2, 2), strides=(1, 1)) 进行最大池化,减少特征图的尺寸,保留主要信息。

5.Dropout 层:

  • 在多处使用 Dropout() 随机丢弃神经元,防止过拟合。丢弃概率分别为 0.2 和 0.5。

6.拉伸层(Flatten):

  • 使用 Flatten() 将二维特征图展开为一维向量,方便传入全连接层。

7.全连接层:

  • 第一层全连接层:512 个神经元,激活函数为 ReLU。
  • 第二层全连接层:256 个神经元,激活函数为 ReLU。

8.输出层:

  • 使用 Dense(10, activation='softmax') 作为输出层,适用于 CIFAR-10 的 10 分类任务。

9.打印模型结构:

  • 使用 model.summary() 打印模型的结构、参数数量和层次关系。

2.2.4 结果与结果分析

(1)模型层结构:

1.Conv2D (卷积层)

  • 输出形状(None, 32, 32, 32)
    说明:32 个 3×3 的卷积核,输出 32 个特征图。
  • 参数数量:896
    计算:$(3 \times 3 \times 3 + 1) \times 32 = 896$(包含偏置项)。

2.MaxPooling2D (最大池化层)

  • 输出形状(None, 32, 32, 32)
    说明:池化窗口为 2×2,没有改变输出形状。

3.Dropout (丢弃层)

  • 丢弃部分神经元,防止过拟合。

4.第二个 Conv2D (卷积层)

  • 输出形状(None, 32, 32, 64)
    说明:64 个 3×3 的卷积核。
  • 参数数量:18,496
    计算:$(3 \times 3 \times 32 + 1) \times 64 = 18,496$。

5.Flatten (拉伸层)

  • 输出形状(None, 65536)
    说明:将 32×32×64 的特征图展平为一维向量。

6.Dense (全连接层)

  • 输出形状(None, 512)
    参数数量:33,554,944
    计算:$65536 \times 512 + 512 = 33,554,944$。

7.Dense (全连接层)

  • 输出形状(None, 256)
    参数数量:131,328
    计算:$512 \times 256 + 256 = 131,328$。

8.输出层 (Dense)

  • 输出形状(None, 10)
    说明:10 个神经元,表示 10 个分类类别。
  • 参数数量:2,570
    计算:$256 \times 10 + 10 = 2,570$。
(2)模型总参数:
  • 总参数数量:33,708,234
  • 可训练参数数量:33,708,234
  • 非可训练参数:0

2.3 编译、训练和评估 CNN 模型

2.3.1 实现目的:

  1. 编译模型:配置优化器、损失函数和评估指标,为训练过程做好准备。
  2. 训练模型:用训练集训练模型,并在训练过程中监控验证集性能。
  3. 评估模型:在测试集上评估模型性能,确保模型的泛化能力。

2.3.3 代码片段:

'''步骤三,编译、训练和评估 CNN 模型'''
# 编译网络模型
model.compile(optimizer='adam', loss=tf.keras.losses.SparseCategoricalCrossentropy(), metrics=['sparse_categorical_accuracy'])os.environ["CUDA_VISIBLE_DEVICES"] = "-1"
# 训练网络模型
history = model.fit(x_train, y_train, batch_size=128, epochs=10, validation_split=0.2)# 评估网络模型
model.evaluate(x_test, y_test, batch_size=64, verbose=2)

2.3.3 代码解释:

1.模型编译 (model.compile):

  • optimizer='adam':Adam 优化器,兼具自适应学习率和动量优化的特点。
  • loss=tf.keras.losses.SparseCategoricalCrossentropy():用于多分类任务的损失函数。
  • metrics=['sparse_categorical_accuracy']:评估指标为稀疏分类准确率,用于处理标签是整数编码的情况。

2.训练模型 (model.fit):

  • batch_size=128:每次梯度更新时处理 128 个样本。
  • epochs=10:训练模型 10 个完整的周期(轮次)。
  • validation_split=0.2:将 20% 的训练数据用于验证模型性能。

3.评估模型 (model.evaluate):

  • 在测试集上评估模型性能,batch_size=64 指定每次处理的样本数。
  • verbose=2 控制输出日志的详细程度。

2.3.4 结果与结果分析

(1)训练过程:

1.趋势分析:

1.Epoch 1/10

  • 训练损失(loss):1.3763
  • 训练准确率(sparse_categorical_accuracy):51.22%
  • 验证损失(val_loss):1.1739
  • 验证准确率(val_sparse_categorical_accuracy):59.02%

2.Epoch 10/10

  • 训练损失:0.3544
  • 训练准确率:87.84%
  • 验证损失:1.0411
  • 验证准确率:69.57%

趋势分析:

训练损失和训练准确率逐渐优化,模型在训练数据上的表现不断提高,最终训练准确率达到 87.84%

验证集的准确率逐渐提高到 69.57%,但验证损失(val_loss)在第 7-10 轮趋于不稳定(略有增加),表明模型可能出现了一些过拟合

(2)测试集评估结果:

loss: 1.0738 sparse_categorical_accuracy: 69.16%

解释:

  • 测试损失:1.0738
  • 测试准确率:69.16%
  • 在测试集上的准确率为 69.16%,与验证集准确率(69.57%)非常接近,表明模型的泛化能力良好
  • 测试损失验证损失接近,进一步验证模型的性能稳定。

2.4 可视化训练的结果

2.4.1 实现目的:

使用 Matplotlib 将训练损失、验证损失以及训练准确率、验证准确率随轮次的变化情况绘制成折线图,帮助分析模型的训练过程和性能。

2.4.2 代码片段:

'''步骤四,可视化训练的结果'''
print(history.history)# 确保 epochs 数组的定义与 loss 和 acc 的数据一致
epochs = range(1, len(history.history['loss']) + 1)# 创建画布并设置画面大小
plt.figure(figsize=(10, 3))# 在子图1中绘制损失函数的折线图
plt.subplot(121)
plt.plot(epochs, history.history['loss'], color='b', label='train')  # 蓝色线表示训练集损失
plt.plot(epochs, history.history['val_loss'], color='r', label='validate')  # 红色线表示验证集损失
plt.xlabel('Epochs')  # 添加横轴标签
plt.ylabel('Loss')  # 添加纵轴标签
plt.legend()  # 显示图例# 在子图2中绘制准确率的折线图
plt.subplot(122)
plt.plot(epochs, history.history['sparse_categorical_accuracy'], color='b', label='train')  # 蓝色线表示训练集准确率
plt.plot(epochs, history.history['val_sparse_categorical_accuracy'], color='r', label='validate')  # 红色线表示验证集准确率
plt.xlabel('Epochs')  # 添加横轴标签
plt.ylabel('Accuracy')  # 添加纵轴标签
plt.legend()  # 显示图例# 显示图像
plt.show()

2.4.3 代码解释:

1.打印训练历史:

  • history.history 中包含每一轮训练和验证的损失准确率

2.绘制损失函数曲线:

  • 子图 1 展示训练和验证的损失随轮次的变化:
    • 蓝线:训练集损失
    • 红线:验证集损失

3.绘制准确率曲线:

  • 子图 2 展示训练和验证的准确率随轮次的变化:
    • 蓝线:训练集准确率
    • 红线:验证集准确率

4.显示图像:

  • 使用 plt.show() 将两张图同时显示出来。

2.4.4 结果与结果分析

(1)损失曲线(左图):
  • 蓝色线(train):训练集的损失值逐渐下降,说明模型在逐步学习特征。
  • 红色线(validate):验证集的损失在前几轮下降后逐渐趋于平稳并略有上升。

分析:

  • 训练损失持续降低,而验证损失在后期上升,表明模型可能出现过拟合
  • 改进建议
    • 增加 Dropout 层的使用或增大丢弃率。
    • 使用更多正则化(如 L2 正则化)。
    • 尝试减少模型的复杂度或收集更多数据。
(2)准确率曲线(右图):
  • 蓝色线(train):训练集的准确率逐渐提升,最终接近 90%。
  • 红色线(validate):验证集的准确率在 70% 附近趋于平稳。

分析:

  • 训练准确率不断上升,而验证准确率停滞在约 70% 左右。这进一步表明模型可能在训练集上表现良好,但在验证集上出现过拟合

2.5 应用卷积神经网络模型

2.5.1 实现目的:
  • 随机选取 10 张测试集中的图片,使用训练好的 CNN 模型对其进行预测,并将标签值和预测值显示在图像上方。
  • 验证模型的效果,观察模型在测试集上的分类准确性
2.5.2 代码片段:

'''步骤五,应用卷积神经网络模型'''
plt.figure()  # 创建画布for i in range(10):  # 循环显示10张图片n = np.random.randint(1, 10000)  # 生成随机整数 nplt.subplot(2, 5, i + 1)  # 创建子图 (2行5列)plt.axis("off")  # 不显示坐标轴plt.rcParams['font.sans-serif'] = ['SimHei']  # 设置字体为 SimHei,支持中文显示# 显示测试集中随机图片,使用灰度颜色映射plt.imshow(x_test[n], cmap='gray')# 将图片 reshape 为模型输入的形状 (1, 32, 32, 3)demo = tf.reshape(x_test[n], (1, 32, 32, 3))# 使用模型预测该图片的类别y_pred = np.argmax(model.predict(demo))# 设置子图标题,显示标签值与预测值title = "标签值: " + str((y_test.numpy())[n, 0]) + "\n预测值: " + str(y_pred)plt.title(title)# 展示图像
plt.show()
2.5.3 代码解释:

1.画布与子图:

  • plt.figure():创建一个用于显示图像的画布。
  • plt.subplot(2, 5, i + 1):将画布分成 2 行 5 列的子图,每次在新的子图中显示一张图片。

2.随机选取测试图片:

  • 使用 np.random.randint(1, 10000) 生成 1 到 9999 之间的随机数,作为图片索引。

3.显示图片:

  • 使用 plt.imshow() 在子图中显示随机图片,使用 灰度颜色映射 (cmap='gray')。

4.模型预测:

  • 将选中的图片 reshape 为模型的输入形状 (1, 32, 32, 3)
  • 使用 model.predict() 对图片进行预测,并使用 np.argmax() 获取预测的类别。

5.设置标题:

  • 子图标题中显示标签值预测值,标签值来自 y_test,预测值来自模型的预测结果。

6.展示图像:

  • 使用 plt.show() 展示 10 张图片及其标签与预测结果。

2.5.4 结果与分析

(1)展示内容:

每个子图显示了一张来自 CIFAR-10 测试集的随机图片,且每张图片的标题标注了:

  • 标签值(真实类别):来自 y_test,表示图片的真实类别标签。
  • 预测值(模型预测结果):模型根据输入图像预测的类别。
(2)分析结果:

1.正确预测的示例

  • 标签值:6预测值:6:模型正确地识别出图片中的类别。
  • 标签值:7预测值:7:另一个成功分类的示例。

2.错误预测的示例

  • 标签值:4预测值:3:模型将真实类别 4 误判为 3。
  • 标签值:3预测值:2:该图片也被模型错误分类。
(3)模型表现观察:
  • 部分图片的预测结果是正确的,说明模型对某些类别的识别效果较好。
  • 某些类别的预测出现错误,这可能是因为:
    • 类别之间的相似性导致分类困难(如狗和猫)。
    • 数据不足或模型过拟合,使得模型在某些类别上泛化能力不足。

3.基于 CNN 的手写数字识别的实验

3.1 随机选取并保存测试图片

3.1.1 实现目的:

通过随机从 MNIST 测试集中选取一些图片,并将它们以 PNG 格式保存到指定目录。这有助于我们检查数据集的样本内容,并在后续使用这些图片进行预测和验证。

3.1.2 代码片段:

import numpy as np
import matplotlib.pyplot as plt
from tensorflow.keras.datasets import mnist# 加载 MNIST 数据集
(x_train, y_train), (x_test, y_test) = mnist.load_data()# 创建保存路径
import os
save_path = 'test_images'
os.makedirs(save_path, exist_ok=True)# 保存一些图片为 PNG
def save_images(images, labels, indices):for i in indices:img = images[i]label = labels[i]file_name = f"{save_path}/{label}_{i}.png"plt.imsave(file_name, img, cmap='gray')print(f"保存图片: {file_name}")# 从测试集里保存 3 张图片 (你可以指定其他索引)
save_images(x_test, y_test, [0, 3, 9])  # 保存索引 0, 3, 9 处的图片

3.1.3 代码解释:

1.导入库

  • numpy:用于处理数组和数值操作。
  • matplotlib.pyplot:用于保存和显示图片。
  • tensorflow.keras.datasets:用于加载 MNIST 数据集。

2.加载数据集

  • 使用 mnist.load_data() 加载 MNIST 手写数字数据集,该数据集包含 60,000 张训练图片和 10,000 张测试图片。
    • x_trainx_test:保存图片的 numpy 数组,每张图片大小为 28x28 像素。
    • y_trainy_test:保存图片对应的标签(0-9)。

3.创建保存路径

  • 使用 os.makedirs() 创建 test_images 文件夹,如果文件夹不存在则会自动创建。

4.定义 save_images() 函数

  • 遍历传入的索引列表 indices,根据索引获取图片和对应标签。
  • 使用 plt.imsave() 将图片保存为 PNG 格式,并以 {标签}_{索引}.png 命名。

5.调用 save_images() 函数

  • 选取测试集中的第 0、3、9 张图片,并将其保存到 test_images 文件夹中。

3.1.4 结果与分析:

保存图片: test_images/7_0.png

保存图片: test_images/0_3.png

保存图片: test_images/9_9.png

1.图片内容检查

  • 打开 test_images 文件夹,检查是否存在 3 张 PNG 图片。
  • 图片的名称格式为 {标签}_{索引}.png,其中 标签 是图片的真实类别。

2.潜在问题与解决方案

  • 路径问题:确保有权限在当前工作目录下创建文件夹和保存文件。
  • 图片内容错误:如果保存的图片标签与预期不符,请检查代码中的索引是否正确。

3.实际应用

  • 这些保存的图片可以用于模型的预测测试,验证训练模型的准确性。
  • 在接下来的步骤中,我们将使用这些保存的图片,并通过训练好的模型进行预测。

3.2 数据的读取与预处理

3.2.1 实现目的:

本步骤的目的是加载 MNIST 数据集,并对其进行预处理。具体目标包括:

  1. 检查本地是否存在数据集,如果没有则自动从网上下载。
  2. 为每张图片增加通道维度,以适配 CNN 模型的输入需求。
  3. 将图片的像素值缩放至 [0, 1] 区间,提高模型的训练性能。
  4. 打印数据集的形状,并验证每张图片是否为单通道(灰度图)。

3.2.2 代码片段:

import os
import tensorflow as tf
from tensorflow.keras.datasets.mnist import load_dataclass DataSource:def __init__(self):# 数据集路径配置(使用当前目录)data_path = os.path.join(os.getcwd(), 'data', 'mnist.npz')# 检查本地是否存在数据集if os.path.exists(data_path):(x_train, y_train), (x_test, y_test) = load_data(path=data_path)else:print("mnist.npz 文件不存在,从网上下载数据集...")(x_train, y_train), (x_test, y_test) = load_data()# 增加一个通道维度x_train = x_train[..., tf.newaxis]x_test = x_test[..., tf.newaxis]# 像素值缩放到 [0, 1] 之间x_train, x_test = x_train / 255.0, x_test / 255.0self.train_images, self.train_labels = x_train, y_trainself.test_images, self.test_labels = x_test, y_test# 创建 DataSource 实例,加载数据
data = DataSource()# 打印训练集和测试集的形状
print(f"训练集图片形状: {data.train_images.shape}")
print(f"训练集标签形状: {data.train_labels.shape}")
print(f"测试集图片形状: {data.test_images.shape}")
print(f"测试集标签形状: {data.test_labels.shape}")# 验证是否为单通道
print(f"训练集单张图片通道数: {data.train_images.shape[-1]}")
print(f"测试集单张图片通道数: {data.test_images.shape[-1]}")

3.2.3 代码解释:

1.导入库

  • os:用于文件和目录的路径操作。
  • tensorflow:用于加载 MNIST 数据集并进行张量操作。

2.定义 DataSource

  • 检查数据集是否存在于 data 目录中。如果存在则加载本地数据集,否则自动从网上下载。
  • 增加通道维度:将每张图片从 (28, 28) 形状扩展为 (28, 28, 1),以适应 CNN 模型的输入格式。
  • 像素值缩放:将图片的像素值从 [0, 255] 缩放到 [0, 1] 区间,提高模型训练的效率和收敛速度。

3.创建 DataSource 实例

  • 实例化 DataSource 类并加载数据,将数据集保存在 train_imagestrain_labelstest_imagestest_labels 中。

4.打印数据集的形状

  • 输出训练集和测试集的图片形状与标签形状。
  • 检查每张图片的通道数是否为 1,确保数据为灰度图。

3.2.4 结果与分析:

训练集图片形状: (60000, 28, 28, 1)
训练集标签形状: (60000,)
测试集图片形状: (10000, 28, 28, 1)
测试集标签形状: (10000,)
训练集单张图片通道数: 1
测试集单张图片通道数: 1

1.预期结果分析

  • 形状正确:训练集有 60,000 张图片,测试集有 10,000 张图片,每张图片大小为 (28, 28, 1)
  • 通道数:每张图片应为单通道(灰度图)。

2.潜在问题与解决方案

  • 数据集不存在:如果程序提示 "mnist.npz 文件不存在",确保程序有网络访问权限以从网上下载数据集。
  • 维度错误:如果图片形状不符合 (28, 28, 1),检查是否正确添加了新维度。

3.实际应用

  • 预处理后的数据可直接用于训练 CNN 模型,提高模型的训练效率。
  • 数据集结构清晰,确保了模型输入格式的一致性。

3.3 搭建卷积神经网络(CNN模型)

3.3.1 实现目的:

本步骤旨在构建一个卷积神经网络(CNN),用于对 MNIST 手写数字数据集进行分类。卷积神经网络是一种适用于图像数据的深度学习模型,通过卷积层提取特征,并通过全连接层进行分类。本模型设计为一个简单的多层 CNN,适用于 MNIST 数据集。

3.3.2 代码片段:

from tensorflow.keras import layers, modelsclass CNN:def __init__(self):# 构建 Sequential 模型,按层堆叠模型结构model = models.Sequential([# 第1层卷积层 + 最大池化层layers.Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1)),layers.MaxPooling2D((2, 2)),# 第2层卷积层 + 最大池化层layers.Conv2D(64, (3, 3), activation='relu'),layers.MaxPooling2D((2, 2)),# 第3层卷积层layers.Conv2D(64, (3, 3), activation='relu'),# 展平层 + 全连接层layers.Flatten(),layers.Dense(64, activation='relu'),# 输出层(10类,用 softmax 激活函数)layers.Dense(10, activation='softmax')])# 打印模型结构model.summary()self.model = model  # 将模型存储为类的属性

3.3.3 代码解释:

1.导入所需模块

  • layersmodels:来自 TensorFlow 的 Keras API,分别用于创建网络层和模型。

2.模型构建

  • Sequential:顺序模型,按层堆叠每一层。
  • 卷积层:提取图像的局部特征,通过 ReLU 激活函数引入非线性。
    • 第1层:32 个 3x3 卷积核,输入形状为 (28, 28, 1)
    • 第2层:64 个 3x3 卷积核。
    • 第3层:64 个 3x3 卷积核。

3.池化层

  • 最大池化层:每次将 2x2 区域的最大值作为特征,减少特征维度。

4.展平层

  • 将卷积层输出的多维张量展平为一维向量,便于输入到全连接层。

5.全连接层

  • Dense:全连接层,包含 64 个神经元,并使用 ReLU 激活函数。

6.输出层

  • Dense:输出层包含 10 个神经元,对应 10 个类别,使用 softmax 激活函数进行多分类。

7.模型摘要

  • model.summary():打印模型结构,包括每层的输出形状和参数数量。

3.3.4 结果(此结果在下一段代码打印)与分析:

1.Conv2D (卷积层)

  • 功能:提取图像特征,如边缘、纹理等。
  • 输出形状(None, 26, 26, 32),表示卷积后的输出尺寸为 26×26,每个像素点有 32 个通道。
  • 参数数量 (Param #):320。这由卷积核的数量和大小决定。

2.MaxPooling2D (最大池化层)

  • 功能:缩减图像尺寸,保留重要特征,减少参数。
  • 输出形状(None, 13, 13, 32),池化层将图像尺寸缩小了一半。

3.Flatten (展平层)

  • 功能:将多维的特征图展平为一维,供全连接层使用。
  • 输出形状(None, 576),将图像的特征展平为 576 维向量。

4.Dense (全连接层)

  • 功能:用于分类或回归任务,将展平的特征映射到输出类别上。
  • 输出形状:第一层为 (None, 64),第二层为 (None, 10),表示 10 个输出类别。

5.总参数数量:

  • Total params (总参数数量): 93,322
  • Trainable params (可训练参数): 93,322
  • Non-trainable params (不可训练参数): 0

3.4 训练模型、保存结果与可视化

3.4.1 实现目的:

本部分的目的是对构建的卷积神经网络(CNN)进行训练,并在训练过程中记录日志、保存模型检查点,以便可视化和模型的复用。训练结束后,打印测试结果以评估模型性能。

3.4.2 代码片段:

import numpy as np
from datetime import datetime
from tensorflow.keras.callbacks import TensorBoard, ModelCheckpoint
# 忽略警告
import warnings
warnings.filterwarnings('ignore', category=UserWarning)class Train:def __init__(self):self.network = CNN()  # 创建CNN实例self.data = DataSource()  # 加载数据集def train(self):# 设置 TensorBoard 日志路径logdir = "./logs/scalars/" + datetime.now().strftime("%Y%m%d-%H%M%S")tensorboard_cb = TensorBoard(log_dir=logdir)# # 设置模型检查点路径# check_path = './ckpt/cp-{epoch:04d}.ckpt'# save_model_cb = ModelCheckpoint(check_path, save_weights_only=True, verbose=1)# 设置模型检查点路径(每5个epoch保存一次)check_path = './ckpt/cp-{epoch:04d}.weights.h5'save_model_cb = tf.keras.callbacks.ModelCheckpoint(filepath=check_path,  # 修改文件后缀为 .weights.h5save_weights_only=True,verbose=1)# 编译模型self.network.model.compile(optimizer='adam',loss='sparse_categorical_crossentropy',metrics=['accuracy'])# 训练模型并保存日志training_history = self.network.model.fit(self.data.train_images,self.data.train_labels,epochs=10,validation_data=(self.data.test_images, self.data.test_labels),callbacks=[tensorboard_cb, save_model_cb])# 保存模型为 .keras 格式os.makedirs('./keras', exist_ok=True)self.network.model.save('./keras/model.keras')print("模型已保存为 './keras/model.keras'")# 打印最终测试结果test_loss, test_acc = self.network.model.evaluate(self.data.test_images, self.data.test_labels)print(f"准确率:{test_acc * 100:.2f}%,共测试了 {len(self.data.test_labels)} 张图片")print("平均误差:", np.average(training_history.history['loss']))if __name__ == "__main__":mnist_train = Train()mnist_train.train()

3.4.3 代码解释:

1.引入必要的库:

  • TensorBoardModelCheckpoint 用于训练过程的监控和模型权重保存。
  • warnings 模块用于忽略不必要的警告信息,保持输出清晰。

2.初始化训练实例:

  • Train 类的 __init__() 方法创建了 CNN 模型实例,并加载了数据源。

3.训练配置:

  • TensorBoard 可视化: 配置 TensorBoard 的日志路径,每次运行生成新的日志目录,使用当前时间戳命名。
  • 模型检查点: 使用 ModelCheckpoint 在每个 epoch 结束后保存模型权重。文件名以 cp-{epoch:04d}.weights.h5 形式保存,确保每个 epoch 都有独立的权重文件。

4.模型编译:

  • 使用 Adam 优化器和 sparse_categorical_crossentropy 损失函数。
  • 指定 accuracy 为评估指标,用于监控训练和验证过程的分类准确率。

5.模型训练:

  • 训练数据和标签通过 fit() 方法传入,训练 10 个 epoch。
  • 每个 epoch 结束时,验证集上的损失和准确率会被计算并打印。
  • 使用回调函数记录训练过程的 TensorBoard 日志,并在每 5 个 epoch 保存一次模型权重。

6.模型保存:

  • 训练完成后,将模型保存为 .keras 格式,方便后续加载和预测。

7.模型评估:

  • 使用 evaluate() 方法在测试集上评估模型性能,并打印准确率和平均损失。

3.4.4 结果与分析:

Epoch 1/10
1871/1875 ━━━━━━━━━━━━━━━━━━━━ 0s 5ms/step - accuracy: 0.8945 - loss: 0.3399
Epoch 1: saving model to ./ckpt/cp-0001.weights.h5
1875/1875 ━━━━━━━━━━━━━━━━━━━━ 14s 6ms/step - accuracy: 0.8947 - loss: 0.3394 - val_accuracy: 0.9853 - val_loss: 0.0450
Epoch 2/10
1867/1875 ━━━━━━━━━━━━━━━━━━━━ 0s 5ms/step - accuracy: 0.9863 - loss: 0.0462
Epoch 2: saving model to ./ckpt/cp-0002.weights.h5
1875/1875 ━━━━━━━━━━━━━━━━━━━━ 11s 6ms/step - accuracy: 0.9863 - loss: 0.0462 - val_accuracy: 0.9860 - val_loss: 0.0424
Epoch 3/10
1871/1875 ━━━━━━━━━━━━━━━━━━━━ 0s 5ms/step - accuracy: 0.9899 - loss: 0.0324
Epoch 3: saving model to ./ckpt/cp-0003.weights.h5
1875/1875 ━━━━━━━━━━━━━━━━━━━━ 11s 6ms/step - accuracy: 0.9899 - loss: 0.0324 - val_accuracy: 0.9875 - val_loss: 0.0379
Epoch 4/10
1871/1875 ━━━━━━━━━━━━━━━━━━━━ 0s 5ms/step - accuracy: 0.9918 - loss: 0.0257
Epoch 4: saving model to ./ckpt/cp-0004.weights.h5
1875/1875 ━━━━━━━━━━━━━━━━━━━━ 11s 6ms/step - accuracy: 0.9918 - loss: 0.0257 - val_accuracy: 0.9916 - val_loss: 0.0264
Epoch 5/10
1870/1875 ━━━━━━━━━━━━━━━━━━━━ 0s 5ms/step - accuracy: 0.9948 - loss: 0.0178
Epoch 5: saving model to ./ckpt/cp-0005.weights.h5
1875/1875 ━━━━━━━━━━━━━━━━━━━━ 11s 6ms/step - accuracy: 0.9948 - loss: 0.0178 - val_accuracy: 0.9906 - val_loss: 0.0293
Epoch 6/10
1875/1875 ━━━━━━━━━━━━━━━━━━━━ 0s 5ms/step - accuracy: 0.9952 - loss: 0.0138
Epoch 6: saving model to ./ckpt/cp-0006.weights.h5
1875/1875 ━━━━━━━━━━━━━━━━━━━━ 11s 6ms/step - accuracy: 0.9952 - loss: 0.0138 - val_accuracy: 0.9919 - val_loss: 0.0270
Epoch 7/10
1868/1875 ━━━━━━━━━━━━━━━━━━━━ 0s 5ms/step - accuracy: 0.9962 - loss: 0.0119
Epoch 7: saving model to ./ckpt/cp-0007.weights.h5
1875/1875 ━━━━━━━━━━━━━━━━━━━━ 11s 6ms/step - accuracy: 0.9962 - loss: 0.0119 - val_accuracy: 0.9925 - val_loss: 0.0293
Epoch 8/10
1874/1875 ━━━━━━━━━━━━━━━━━━━━ 0s 5ms/step - accuracy: 0.9977 - loss: 0.0079
Epoch 8: saving model to ./ckpt/cp-0008.weights.h5
1875/1875 ━━━━━━━━━━━━━━━━━━━━ 11s 6ms/step - accuracy: 0.9977 - loss: 0.0079 - val_accuracy: 0.9894 - val_loss: 0.0419
Epoch 9/10
1870/1875 ━━━━━━━━━━━━━━━━━━━━ 0s 5ms/step - accuracy: 0.9972 - loss: 0.0080
Epoch 9: saving model to ./ckpt/cp-0009.weights.h5
1875/1875 ━━━━━━━━━━━━━━━━━━━━ 11s 6ms/step - accuracy: 0.9972 - loss: 0.0080 - val_accuracy: 0.9921 - val_loss: 0.0317
Epoch 10/10
1870/1875 ━━━━━━━━━━━━━━━━━━━━ 0s 5ms/step - accuracy: 0.9977 - loss: 0.0072
Epoch 10: saving model to ./ckpt/cp-0010.weights.h5
1875/1875 ━━━━━━━━━━━━━━━━━━━━ 11s 6ms/step - accuracy: 0.9977 - loss: 0.0072 - val_accuracy: 0.9921 - val_loss: 0.0382
模型已保存为 './keras/model.keras'
313/313 ━━━━━━━━━━━━━━━━━━━━ 1s 2ms/step - accuracy: 0.9886 - loss: 0.0526
准确率:99.21%,共测试了 10000 张图片
平均误差: 0.03288608025759458

1.结果分析:

  • 训练表现:随着 epoch 数的增加,模型的训练准确率逐渐提高,损失函数逐渐降低。
  • 测试集表现:在测试集上的准确率达到了 99.21%,表明模型在 MNIST 数据集上有非常好的表现。
  • 平均误差:训练的平均误差较低,表明模型已成功拟合训练数据。

2.优化建议:

  • 正则化:可以引入 Dropout 或 L2 正则化来防止过拟合。
  • 数据增强:通过随机裁剪或旋转图片,提高模型的泛化能力。

3.5 小标题:加载模型并进行预测

3.5.1 实现目的:

本步骤的目标是使用训练好的卷积神经网络(CNN)模型,对手写数字图片进行预测,验证模型的分类能力。通过加载保存的模型,读取测试图片,并显示模型的预测结果,判断模型是否能够准确识别输入图片中的数字。

3.5.2 代码片段:

# 步骤4:加载模型并进行预测
from PIL import Imageclass Predict:def __init__(self):# 加载已训练的模型self.model = tf.keras.models.load_model('./keras/model.keras')def predict(self, image_path):# 读取并预处理图片img = Image.open(image_path).convert('L')img = img.resize((28, 28))  # 确保图片大小为 28x28img_array = np.array(img).reshape(1, 28, 28, 1) / 255.0  # 归一化# 进行预测prediction = self.model.predict(img_array)predicted_label = np.argmax(prediction[0])print(f"{image_path} -> 预测数字为:{predicted_label}")# 测试预测
if __name__ == "__main__":app = Predict()app.predict('./test_images/7_0.png')app.predict('./test_images/0_3.png')app.predict('./test_images/9_9.png')

3.5.3 代码解释:

1.加载模型:

  • 使用 tf.keras.models.load_model() 加载保存为 model.keras 格式的训练模型。该模型已经通过训练,并保存在目录 ./keras 下。

2.读取和预处理图片:

  • 使用 PIL 库中的 Image.open() 读取指定路径的图片,并将其转换为灰度模式(L)。
  • 使用 img.resize((28, 28)) 将图片大小调整为 28x28,以符合模型的输入要求。
  • 使用 np.array() 将图片转换为 NumPy 数组,并 reshape 为 (1, 28, 28, 1),以便输入到模型中进行预测。最后对像素值归一化到 [0, 1] 范围内。

3.模型预测:

  • 使用 self.model.predict() 对图片数据进行预测,得到一个概率数组。
  • 使用 np.argmax() 获取预测结果中概率最高的类别标签,即模型认为的数字。

4.测试代码:

  • 代码通过调用 app.predict(),对三张测试图片进行预测,并打印结果到控制台。

3.5.4 结果与分析:

1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 95ms/step
./test_images/7_0.png -> 预测数字为:7
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 20ms/step
./test_images/0_3.png -> 预测数字为:0
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 19ms/step
./test_images/9_9.png -> 预测数字为:9

1.预测分析:

这些结果表明模型对这几张测试图片的识别非常准确。

  • 对于输入图片 7_0.png,模型成功预测为数字 7。
  • 对于输入图片 0_3.png,模型成功预测为数字 0。
  • 对于输入图片 9_9.png,模型成功预测为数字 9。

2.模型表现:

  • 模型在这些测试图片上的预测结果全部正确,说明模型在训练过程中已经学习到了有效的特征。
  • 预测速度较快,每次预测耗时在 20ms-95ms 之间,表明模型推理效率较高。

3.优化建议:

  • 异常处理: 在加载图片时增加异常捕获,以避免文件缺失或路径错误导致程序崩溃:
    try:img = Image.open(image_path).convert('L')
    except FileNotFoundError:print(f"文件未找到: {image_path}")
    

  • 批量预测: 如果需要对多张图片进行预测,可以编写循环批量加载和预测,提升效率。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/883371.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[手机Linux PostmarketOS]七, Linux使用selenium爬虫

一,selenium安装 # 用pip 安装 selenium pip3 install selenium --break-system-packages 二,安装浏览器Chrome Alpine Linux 环境中没有google Chrome, 使用 Chromium 浏览器作为 Chrome 的替代品,Chromium 是 Chrome 的开源版本…

在GeoTools中的Shapefile属性表读取效率之Shp与Dbf对比

目录 前言 一、POI测试数据简介 1、选用的POI数据 2、关于数据的属性数据 二、属性数据读取的两种方式实现 1、基于DbaseFileReader的读取 2、基于SimpleFeatureSource的读取 三、实际运行对比 1、内存和CPU占用情况 2、运行耗时情况 四、总结 前言 众所周知&#x…

Unity3D 开发技巧

视频教程: Unity3D 开发技巧分享,你可能不知道的小知识 Unity中文课堂教程地址: Unity3D开发-你可能不知道的知识 | Unity 中文课堂 Start 函数可以用协程 默认协同函数 Start 可将 void 改为IEnumerator 作为协程启动 using System.Colle…

多层感知机的从零实现与softmax的从零实现(真·0000零基础)

今天再读zh.d2l书(4.2. 多层感知机的从零开始实现 — 动手学深度学习 2.0.0 documentation), 看了关于多层感知机的从零实现与softmax的从零实现 目录 mlp从零实现, 点击“paddle”的代码 点击“torch”的代码 训练 参数解…

DataSophon集成ApacheImpala的过程

注意: 本次安装操作系统环境为Anolis8.9(Centos7和Centos8应该也一样) DataSophon版本为DDP-1.2.1 整合的安装包我放网盘了: 通过网盘分享的文件:impala-4.4.1.tar.gz等2个文件 链接: https://pan.baidu.com/s/18KfkO_BEFa5gVcc16I-Yew?pwdza4k 提取码: za4k 1…

C#与C++交互开发系列(十二):托管和非托管内存管理策略

前言 在进行C#与C互操作开发时,内存管理是一个非常重要的环节。由于C#采用托管内存管理(由垃圾回收机制GC控制),而C则使用手动内存管理(需要开发者负责分配和释放内存),因此跨语言调用时&#…

光耦的应用

什么是光耦 光耦是一种实现信号隔离的元器件,通常用于各部分电路之间,使其不互相受到影响。 工作原理 光耦是由一个发光二极管和一个光敏三极管封装而成的。其使用原理为: 当发光二极管有信号输入时,则会被点亮,此时…

PHP-FPM 性能配置优化

4 核 8 G 服务器大约可以开启 500 个 PHP-FPM,极限吞吐量在 580 qps (Query Per Second 每秒查询数)左右。 Nginx php-fpm 是怎么工作的? php-fpm 全称是 PHP FastCGI Process Manager 的简称,从名字可得知&#xff…

基于SSM的“众优”大学生家教平台的设计与实现

前言 对于当今社会的人们来说,互联网技术是必不可少的,随着经济和技术的不断发展,计算机已经深入到各个领域。“众优”大学生家教平台将人们的时间需求与计算机技术结合起来,架起一座桥梁,使用在线查看“众优”大学生…

设计模式讲解

设计原则 单一职责原则 > 一个对象应该只包含单一的职责,并且该职责被完整地封装在一个类中 > //一个人类 public class People {/*** 人类会编程*/public void coding(){System.out.println("int mian() {");System.out.println(" print…

直播系统源码技术搭建部署流程及配置步骤

系统环境要求 PHP版本:5.6、7.3 Mysql版本:5.6,5.7需要关闭严格模式 Nginx:任何版本 Redis:需要给所有PHP版本安装Redis扩展,不需要设置Redis密码 最好使用面板安装:宝塔面板 - 简单好用的…

Android——事件冲突处理

当我们给列表的item设置了点击事件后&#xff0c;又给item中的按钮设置了点击事件&#xff0c;此时item的点击事件会失效。 解决 给item的布局xml中设置以下属性 android:descendantFocusability"blocksDescendants"<LinearLayout xmlns:android"http://sc…

HT7181 16.8V,14A高效升压转换器

1、特征 输入电压范围:2.7V-16V 输出电压范围:最高16.8V 固定开关频率:360kHz 可编程峰值电流:14A 高转换效率: 94% (VIN 7.2V, VOUT9.3V, IOUT1.5A) 90% (VIN 7.2V, VOUT9.3V, IOUT 7A) 93% (VIN 7.2V, VOUT12V, IOUT 1.5A) 90% (VIN 7.2V, VOUT12V, IOUT 5.5A) 90% (VIN …

220V降12V1A恒流点灯WT5112

220V降12V1A恒流点灯WT5112 芯片特点 高精度恒流输出&#xff1a;WT5112 是一款适用于非隔离降压型恒流 LED 驱动芯片。在 220V 降 12V、1A 恒流点灯应用中&#xff0c;它能够提供高精度的恒流输出。其恒流精度通常可以达到 3% - 5% 左右&#xff0c;这对于 LED 灯的稳定发光非…

安卓基础001

前言 也是好久没有更新博客了,最近实习也是需要学习一些知识哈哈哈哈哈哈为了更好的发展嘛,咱们从客户端开始,过程可能有点像写前端,不喜勿喷,希望在学习的过程中也可以给大家带来一些简单得帮助吧....... tips:这里跳过安卓studio安装,大家可自行寻找教程 写的不详细,只是为了…

从“摸黑”到“透视”:AORO A23热成像防爆手机如何改变工业检测?

在工业检测领域&#xff0c;传统的检测手段常因效率低下、精度不足和潜在的安全风险而受到诟病。随着科技的不断进步&#xff0c;一种新兴的检测技术——红外热成像技术&#xff0c;正逐渐在该领域崭露头角。近期&#xff0c;小编对一款集成红外热成像技术的AORO A23防爆手机进…

君正 T31 型号芯片架构模块介绍

文章目录 1. 核心模块2. 存储模块3. 安全模块4. 图像和视频处理5. 输入输出接口6. 其他支持模块 T31 型号 MCU 结构图&#xff1a; T31 集成了高性能 CPU、多功能图像处理单元、丰富的输入输出接口以及多种安全保护机制&#xff0c;适合用于视频监控、智能家居、工业控制等高性…

改进YOLOv8系列:引入低照度图像增强网络Retinexformer | 优化低光照目标检测那题

改进YOLOv8系列:引入低照度图像增强网络Retinexformer | 优化低光照目标检测那题 🚀论文研究概括🚀加入到网络中的理论研究🚀需要修改的代码1 🍀🍀Retinexformer 代码2🍀🍀tasks里引用🚀创建yaml文件🚀测试是否创建成功前言:这篇论文提出了一种用于低光图像…

设计模式06-结构型模式1(适配器/桥接/组合模式/Java)

#1024程序员节&#xff5c;征文# 4.1 适配器模式 结构型模式&#xff08;Structural Pattern&#xff09;的主要目的就是将不同的类和对象组合在一起&#xff0c;形成更大或者更复杂的结构体。结构性模式的分类&#xff1a; ​ 类结构型模式关心类的组合&#xff0c;由多个类…

项目部署 —— 前端、后端

一、 前端 ● 二号标题 在命令框里输入 npm run build 打包成功&#xff1a; 项目就会出现一个 dist 文件夹 将Linux的nginx文件夹中&#xff0c;重命名为 news 二、 后端 ● 通过maven打包后端程序 最终会在项目中生成一个 target 文件夹&#xff0c;将 news-1.0-SNAPSHOT.…