使用 全连接神经网络 训练MNIST数据分类模型

(一) 实验目的

使用简单的全连接层神经网络对MNIST手写数字图片进行分类。通过本次实验,可以掌握如下知识点:

  1. 学习 TensorFlow2 神经网络模型构建方式;
  2. 学习 tf.keras.layers.Flatten()tf.keras.layers.Dense()tf.keras.layers.Dropout() 三种神经网络层;
  3. 学习 relusoftmax 两种激活函数;(另写)
  4. 学习 adam 优化算法。 (另写)

(二) 实验过程

1. 导入 TensorFlow 模块
import tensorflow as tf

print(tf.__version__)

2.3.0

2. 读取 MNIST 数据集

(1) Tensorflow2 版本已经集成了包括MNIST在内的几种常见数据集,可以通过 tf.keras.datasets 模块进行下载和读取

(train_x, train_y), (test_x, test_y) = tf.keras.datasets.mnist.load_data()

(2) 查看数据的维度信息。训练集数据是由60000张手写数字图片组成,每张图片为 28x28 矩阵。

print("训练集的图片数据维度:", train_x.shape)
print("训练集的标签数据维度:", train_y.shape)

print("测试集的图片数据维度:", test_x.shape)
print("测试集的标签数据维度:", test_y.shape)

训练集的图片数据维度: (60000, 28, 28)
训练集的标签数据维度: (60000,)
 
测试集的图片数据维度: (10000, 28, 28)
测试集的标签数据维度: (10000,)

(3) 查看前5张图片

for i in range(5):
    plt.subplot(1,5,i+1)
    plt.xticks([])
    plt.yticks([])
    plt.imshow(train_x[i], cmap=plt.cm.binary)
    plt.xlabel(train_y[i])
plt.show()

在这里插入图片描述

(4) 对图片数据进行归一化处理,取值范围从原 [0-255] 转换为 [0-1]。

归一化的目的是为了减少各维度数据因取值范围差异而带来干扰。例如,有两个维度的特征数据A和B。其中,A的取值范围是(0,10),而B的取值范围是(0,10000)。这时就会发现,在B面前,A的取值范围变化是可以忽略的,从而导致A的信息在噪声中被淹没。

train_x, test_x = train_x / 255.0, test_x / 255.0
3. 构建神经网络模型

(1) 实例化一个网络模型。 tf.keras.Sequential() 方法可以让我们将神经网络层进行线性组合形成神经网络结构。

model = tf.keras.Sequential()

(2) 添加 tf.keras.layers.Flatten() 作为第1层神经网络。

Flatten层用来将输入“压平”,即把多维的输入一维化。还需要注意的一点是:作为第一层,需要设置input_shape 参数(参数值为元组形式),用以说明喂入模型的训练集数据的形状。

model.add(tf.keras.layers.Flatten(input_shape = (28,28)))

(3) 添加 tf.keras.layers.Dense 作为第2层神经网络。

Dense层,即全连接神经网络层,第一个参数为units,这里设为128。理解为这一层的输出神经元为128个。
 
知乎上有一篇介绍全连接层原理的文章

model.add(tf.keras.layers.Dense(128, activation = "relu"))

(4) 添加tf.keras.layers.Dropout() 作为第3层神经网络。

Dropout层的工作机制就是每步训练时,按照一定的概率随机使神经网络的神经元失效,这样可以极大降低连接的复杂度。同时,由于每次训练都是由不同的神经元协同工作的,这样也可以很好地避免数据带来的过拟合,提高了神经网络的泛化性。
 
在使用Dropout时,需要配置的参数如下:

  • rate:配置神经元失效的概率
  • noise_shape:配置Dropout的神经元
  • seed:生成随机数
model.add(tf.keras.layers.Dropout(0.2))

(5) 添加 tf.keras.layers.Dense 作为第4层神经网络。相比于第2层的全连接神经网络,这里输出的神经元为10,正好对应label标签的数目(即数字0-9)。此外,激活函数也是选择softmax

model.add(tf.keras.layers.Dense(10, activation = "softmax"))

(6) 构建好神经网络后,需要调用 model.compile() 方法对模型进行编译。

optimizer 参数用来配置模型的优化器,可以通过名称tf.keras.optimizers API调用定义好的优化器。

loss 参数用来配置模型的损失函数,可以通过名称tf.losses API调用已经定义好的loss函数。

metrics 参数用来配置模型评价的方法,如 accuracy、mse 等。

model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])

(7) 查看神经网络模型

通过 summary() 方法,查看构建的神经网络模型信息。如下图所示,我们的模型一共包含4层,依次为Flatten、 Dense、 Dropout和Dense。 整个神经网络模型共有101770个参数。

model.summary()

在这里插入图片描述

4. 训练神经网络模型

在神经网络模型编译后,可以使用准备好的训练数据对模型进行训练。Sequential().fit() 方法提供了神经网络模型的训练功能。其中主要的配置参数如下(epoch和batch_size的概念):

  • x:配置训练的输入数据,可以是array或者tensor类型。
  • y:配置训练的标注数据,可以是array或者tensor类型。
  • batch_size:配置批大小,默认值是32。
  • epochs:配置训练的epochs的数量。
  • verbose:配置训练过程信息输出的级别,共有三个级别,分别是0、1、2。0表示不输出任何训练过程信息;1表示以进度条的方式输出训练过程信息;2表示每个epoch输出一条训练过程信息。
  • validation_split:配置验证数据集占训练数据集的比例,取值范围为0-1.
  • validation_data:配置验证数据集。如果已经配置validation_split参数,则可以不配置该参数。如果同时配置validation_split和validation_data,那么validation_split参数的配置将会失效。
  • shuffle:配置是否随机打乱训练数据集。当配置steps_per_epoch参数为None时,本参数失效。
  • initial_epoch:配置进行fine-tune时,新的训练周期是从指定的epoch开始继续训练的。
  • steps_per_epoch:配置每个epoch训练的步数。
model.fit(train_x, train_y, epochs=5)
5. 模型评估

利用测试数据集和evaluate() 方法对已经训练好的模型进行评估。

model.evaluate(test_x, test_y, verbose=2)

输出结果如下所示:

313/313 - 0s - loss: 0.0724 - accuracy: 0.9769
[0.07237865030765533, 0.9768999814987183]
 
损失函数值为0.0724; 正确率为0.9769

6. 保存训练得到的模型

通过save()或者save_weights()方法保存并导出训练得到的模型,在使用这两个方法是需要分别配置一下参数。

  • save() 方法的参数配置
  1. filepath:配置模型文件保存的路径。
  2. overwrite:配置是否覆盖重名的HDF5文件。
  3. include_optimizer:配置是否保存优化器的参数。
  • save_weights()方法的参数配置
  1. filepath:配置模型文件保存的路径。
  2. overwrite:配置是否覆盖重名的模型文件。
  3. save_format:配置保存文件的格式
model.save("mnist_dense")

可以看到在当前文件目录下,出现了一个名为 mnist_dense 的文件夹,里面的东西就是这次训练好的神经网络模型。

在这里插入图片描述

7. 神经模型的加载

通过 tf.keras.models.load_model() 方法加载一个已经训练好的模型。需要配置的参数如下:

  1. filepath:加载模型文件的路径
  2. custom_objects:配置神经网络模型自定义的对象。如果自定义了神经网络层级,则需要进行配置,否则在加载时会出现无法找到自定义对象的错误。
  3. compile:配置加载模型之后是否需要进行重新编译。
mnist_load = tf.keras.models.load_model("./mnist_dense")

查看重新加载的模型信息:

mnist_load.summary()

在这里插入图片描述

8. 神经网络的预测

(1) 作为例子,对测试数据集中的第一个数据进行预测。首先,提取该数据并转换为模型相对应的格式,即将二维数据压缩成一维数据。

pre = test_x[1].reshape(1,-1)

(2) 利用模型的predict()方法对数据进行预测。

res = mnist_load.predict(pre)
print(res)

预测结果如下,对应label标签(即数字0-9)的概率值,其中概率最大的就是预测的最有可能的结果。

tf.Tensor(
[[2.0393419e-07 1.3130091e-05 9.9991751e-01 6.6462977e-05 2.1617651e-15
8.9421718e-07 6.9612319e-08 2.9972663e-13 1.5803761e-06 1.0543532e-13]], shape=(1, 10), dtype=float32)

(3) 获得预测结果标签为2,这与真实数据是一致的。

print("预测的数字为:", np.argmax(res))
print("预测正确的概率为:", res.max())

print("实际数字为:", test_y[1])

预测的数字为: 2
预测正确的概率为: 0.9999175
 
实际数字为: 2

  • 3
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值