机器学习入坑指南(九):TensorFlow 实战——手写数字识别(MNIST 数据集)

字数 1415阅读 2176

上篇文章简要介绍了「深度学习」,接下来,我们将从最经典的例子入手进行实战。

一、背景知识简介

1 TensorFlow

Tensor:张量(即多维数组),Flow:(数据)流

TensorFlow,是一个使用数据流图(data flow graohs)技术来进行科学计算的开源软件库,它由Google Brain 团队开发,被广泛应用于各种感知和语言理解任务的机器学习。

点击访问:TensorFlow 官网,可以查阅官方文档、获取一手资讯和下载最新版本。

或者访问:GitHub - tensorflow 来达到同样的效果

英文阅读有困难的同学参考:TensorFlow 中文文档

在本次实战中我们还将使用 Keras,它是一个基于 Theano(另一个开源库)和 TensorFlow 构建的高级神经网络 API,能够在 Theano、TensorFlow 或 Microsoft Cognitive Toolkit 上运行。

点击访问:Keras 中文文档

2 MNIST 数据集

在上篇文章中我们已经提到过 MNIST 了,它是一个收录了许多 28 x 28 像素手写数字图片(以灰度值矩阵存储)及其对应的数字的数据集,可以把它理解成下图这个样子:

MNIST 数据集

图片来源:3Blue1Brown 的视频,强烈推荐观看系列视频:B 站播放地址

二、Python 实现

这里我们依旧使用 Jupyter Notebook 作为开发环境,没有使用过的同学参考我的文章「机器学习入坑指南(一):Python 环境搭建」

当然,使用 Pycharm 等 IDE 也没有问题。

1 安装并导入 TensorFlow、Keras

在 Anaconda 终端中输入命令

conda install tf-nightly

或输入(Python Shell 中也可以使用此命令)

pip install tf-nightly

Keras 已经被集成进了 TensorFlow 中。我们可以通过 tensorflow.keras来访问它。

接下来,导入这两个库

import tensorflow.keras as keras
import tensorflow as tf

可以通过简单的代码测试导入是否成功

print(tf.__version__)
image

2 导入并测试 MNIST 数据集

Keras 默认从 googleapis 下载 MNIST,如果无法访问,可在 GitHub 上下载,点击这里,下载到本地后更改 mnist.py 中的引用路径。

TensorFlow 中存在多个 mnist.py ,这里我们需要修改的是 Keras 下的,我的路径为

C:\ProgramData\Anaconda3\Lib\site-packages\tensorflow\python\keras\datasets

打开之后,把

origin_folder = 'https://storage.googleapis.com/tensorflow/tf-keras-datasets/'

中的路径修改为你存放数据集的位置即可。进入正题

mnist = tf.keras.datasets.mnist #导入mnist
(x_train,y_train),(x_test,y_test) = mnist.load_data() #分割
print(x_train[0]) # 查看第一个测试数据的输入

然后你就看到了如下的输出:


image

让我们把这个矩阵用图像表示出来

import matplotlib.pyplot as plt
%matplotlib inline # 加上这句才能显示图像
plt.imshow(x_train[0],cmap=plt.cm.binary) # 显示黑白图像
plt.show()
image

可以通过以下代码对数据进行归一化处理

x_train = tf.keras.utils.normalize(x_train, axis=1)
x_test = tf.keras.utils.normalize(x_test, axis=1)

再次查看图像

plt.imshow(x_train[0],cmap=plt.cm.binary)
plt.show()
image

图像的像素值被限定在了 [0,1] 。可以通过

print(x_train[0])

查看矩阵数据。

3 构建与训练模型

终于进入核心环节了。在这里,我们使用 Keras 的 Sequential 模型(顺序模型)。Sequential 模型是最常用的模型,也就是一个按照顺序向前传递的神经网络。

model = tf.keras.models.Sequential()

接下来为模型添加图层。神经网络的输入层是一个一维向量,所以我们需要把输入的图像矩阵展平,从 28 x 28 变为 1 x 784 。Keras 为我们提供了如下方法:

model.add(tf.keras.layers.Flatten())

之后,为神经网络添加隐藏层。这里我们使用最简单的 Dense 层(即全连接层,每一个神经元与前后两层的所有神经元相连)

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

这个层有 128 个单元,激活函数选择 reLU,最初人们喜欢用 Sigmoid 函数,但后来发现 reLU 效果更好,所以可以当做一个默认的选择。

接下来再加入一个相同的层

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

再加入输出层

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

输出层有 10 个结点,代表 10 种不同的数字。这里使用 softmax 函数作为激活函数,因为我们想要找到预测结果的概率分布。(使用 reLU 得到的数字并没有这个意义)

我们构建出的模型大概是这个样子的(示意图来自 3Blue1Brown,隐藏层只有 16 个单元,实际上我们有 128 个)


image

添加好所有的层后,“编译”这个模型。

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

optimizer 即优化器,我们一般默认使用 adam
loss 指损失函数,这里我们将其指定为 sparse_categorical_crossentropy,即计算分类结果的交叉熵损失。
metrics 列表,参数为评估模型性能的指标,典型用法即 metrics=['accuracy']

最后,拟合这个模型

model.fit(x_train, y_train, epochs=3)
image

在训练的过程中,我们会发现损失值(loss)在降低,而准确度(accuracy)在提高,最后达到了一个令人满意的程度。

4 测试模型

让我们利用测试集试试这个模型是不是真的学会了识别数字

val_loss, val_acc = model.evaluate(x_test, y_test)
print(val_loss)
print(val_acc)
image

损失和准确度看起来还凑合,尝试识别训练集

predictions = model.predict(x_test)
print(predictions)

image

看不出来这是个啥?别急,用 argmax 解析一下(就是找出最大数对应的索引,即为识别出的数字)

import numpy as np

print(np.argmax(predictions[0]))

image

啊哈,来看看 x_test[0] 这个图像是什么样的

plt.imshow(x_test[0],cmap=plt.cm.binary)
plt.show()
image

OK,妥妥的,相信你也认为这就是个 7,我们的模型已经可以识别数字啦!当然,这只是一个简单的开始,后面的路还有很长,要多思考多动手,坚持学习,才能早日成为大牛!

最后附上可以跑起来的完整代码,来自Deep Learning basics with Python, TensorFlow and Keras p.1

import tensorflow as tf  # 深度学习库,Tensor 就是多维数组

mnist = tf.keras.datasets.mnist  # mnist 是 28x28 的手写数字图片和对应标签的数据集
(x_train, y_train),(x_test, y_test) = mnist.load_data()  # 分割数据集

x_train = tf.keras.utils.normalize(x_train, axis=1)  # 把数据值缩放到 0 到 1
x_test = tf.keras.utils.normalize(x_test, axis=1)  

model = tf.keras.models.Sequential()  # 基础的前馈神经网络模型
model.add(tf.keras.layers.Flatten())  # 把图片展平成 1x784
model.add(tf.keras.layers.Dense(128, activation=tf.nn.relu))  # 简单的全连接图层,,128 个单元,激活函数为 relu
model.add(tf.keras.layers.Dense(128, activation=tf.nn.relu)) 
model.add(tf.keras.layers.Dense(10, activation=tf.nn.softmax))  # 输出层 ,10 个单元, 使用 Softmax 获得概率分布

model.compile(optimizer='adam',  # 默认的较好的优化器
              loss='sparse_categorical_crossentropy',  # 评估“错误”的损失函数,模型应该尽量降低损失
              metrics=['accuracy'])  # 评价指标

model.fit(x_train, y_train, epochs=3)  # 训练模型

val_loss, val_acc = model.evaluate(x_test, y_test)  # 评估模型对样本数据的输出结果
print(val_loss)  # 模型的损失值
print(val_acc)  # 模型的准确度

您的认真阅读就是对我最大的鼓励!如果觉得我的文章对您有帮助,想要和我一起不断学习新的知识、不断进步,欢迎点击头像旁边的「关注」按钮,让我好跟基友们吹个牛逼!

欢迎关注 evan 的博客

推荐阅读更多精彩内容