基于TensorFlow实现MNIST手写体数字识别

1. 背景描述

1.1 数据源介绍

数据源说明:60000训练集 + 10000测试集
图中的每个数字都是[28,28]的二阶数组表示,每个位点上的值是颜色的深度[0-255] ~ [白色-黑色]。根据规范化处理,我们后面会将灰度值缩放到[0,1]。
在这里插入图片描述
使用程序获取数据

from keras.datasets import mnist
# 注意keras的默认路径是~/.keras/datasets,下面的数据会自动从S3上下载到~/.keras/datasets/mnist/mnist.npz路径下进行加载
(x_train, y_train), (x_test, y_test) = mnist.load_data(path='mnist/mnist.npz')
import matplotlib.pyplot as plt

fig = plt.figure()
for i in range(0,15,1):
    plt.subplot(3,6,i+1) # 绘制前15个手写体数字,以3行6列子图形式展示
    plt.tight_layout() # 自动适配
    plt.imshow(x_train[i], cmap='Greys') # 使用灰色显示像素灰度值
    plt.title("Label: {}".format(y_train[i])) # 设置标签为子图标题

在这里插入图片描述
数据源地址:http://yann.lecun.com/exdb/mnist/index.html,这里有详细介绍。

1.2 实验目标

很简单,看上面的图每张图上有一个label,一起来玩猜label啊。

2. 算法原理

2.1 感知机

找个最简单的例子来理解下感知机。两个输入,一个规则,实现逻辑与、逻辑或。可以看到适合做二分类
在这里插入图片描述

2.2 前向传播

不说过于复杂的原理了,能把人给绕晕,直接看下面的这个简单的3层网络吧。计算第二层的输出值。这里不过多赘述,这个到处都能找到。
在这里插入图片描述
上面的计算可以归结为下面的公式。
在这里插入图片描述
在这里插入图片描述

2.3 后向传播

BP算法的基本思想是通过损失函数对模型参数进行求导。这里我就不罗列公式了,网上很多。

2.4 激励函数

现在用的比较多的是Sigmoid和ReLU
在这里插入图片描述

3. 基于TensorFlow的算法实现

接下来我们来到核心就是使用TensorFlow进行实现了。

3.1 模型定义

我们定义如下的模型,输入–> 隐含层1:512个节点 --> 隐含层2:512个节点 --> 输出10个数的概率,选择概率最大的那个。
在这里插入图片描述

3.2 可视化输入

一样的配方,还是先看下输入分布,比较有安全感,哈哈~~

from keras.datasets import mnist
import numpy as np
import matplotlib.pyplot as plt

# 导入数据
(x_train, y_train), (x_test, y_test) = mnist.load_data('mnist/mnist.npz')
# 将图像本身从[28,28]转换为[784,]
X_train = x_train.reshape(60000, 784)
X_test = x_test.reshape(10000, 784)
# 将数据类型转换为float32
X_train = X_train.astype('float32')
X_test = X_test.astype('float32')
# 数据归一化
X_train /= 255
X_test /= 255
# 统计测试数据中每个数字的分布
label, count = np.unique(y_train, return_counts=True)
print(label, count)
## 输出: [0 1 2 3 4 5 6 7 8 9] [5923 6742 5958 6131 5842 5421 5918 6265 5851 5949]

看上面的输出结果展示不是很友好,我们使用下面的图来展示
在这里插入图片描述

3.3 数据编码

这里我们有9个数字,需要一种规则来进行数字编码。编码后占用空间比较小。常见的三种编码方式,如下图,我们这里的9个数字是完全独立的,正好可以用one_hot的这种编码;在有相关性的场景下,可能这种就不合适了。前面的两种其实是有一种距离的概念,001-010和001-110的距离可能是不一样的,编码对于模型的训练结果是很大的影响的。

Binary Gray code One-hot
000 000 00000001
001 001 00000010
010 011 00000100
011 010 00001000
100 110 00010000
101 111 00100000
110 101 01000000
111 100 10000000

实现起来比较简单,因为Keras已经提供了这种方法

from keras.utils import np_utils
n_classes = 10
Y_train = np_utils.to_categorical(y_train, n_classes)
Y_test = np_utils.to_categorical(y_test, n_classes)
print(Y_train[0],Y_train[0])

3.4 使用Keras实现模型

from keras.models import Sequential
from keras.layers.core import Dense, Activation

# 创建模型
model = Sequential()
model.add(Dense(512, input_shape=(784,)))
model.add(Activation('relu'))                            

model.add(Dense(512))
model.add(Activation('relu'))

model.add(Dense(10))
model.add(Activation('softmax'))

# 编译模型
model.compile(loss='categorical_crossentropy', metrics=['accuracy'], optimizer='adam')

# 模型训练
history = model.fit(X_train,
                    Y_train,
                    batch_size=128,
                    epochs=5,
                    verbose=2,
                    validation_data=(X_test, Y_test))

训练完成后对模型进行可视化,可以看见test数据集合的准确率一开始就比较高,因为用的是第一次已经训练好的模型进行的测试。
在这里插入图片描述

4. TODO

1、对于真是的项目而言,数据肯定不可能这样的干净,还有很多数据预处理的工作需要做。
2、这里直接采用的高层的keras模型来进行实现,省略了很多模型的内部实现。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章