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模型来进行实现,省略了很多模型的内部实现。