Python深度学习入门——手写数字分类
大家好,我是丁小杰。
今天来和大家一起学习,如何使用 Python
的 Keras
库来实现手写数字分类。
- 目的:将手写数字的灰度图像(28 像素×28 像素)划分到 10 个类别中(0~9)
- 数据来源:MNIST 数据集,包含 60000 张训练图像和 10000 张测试图像数据。
什么是 Keras
Keras
是基于 TensorFlow
和 Theano
(由加拿大蒙特利尔大学开发的机器学习框架)的深度学习库,是由纯 python
编写而成的高层神经网络 API,也仅支持 Python
开发。它是为了支持快速实践而对 Tensorflow
或者 Theano
的再次封装,让我们可以不用关注过多的底层细节,能够把想法快速转换为结果。它也很灵活,且比较容易学。
安装 Keras
使用豆瓣镜像源安装 Keras
库。
pip install -i https://pypi.douban.com/simple Keras
手写数字分类
导入数据集
加载 Keras
中的 MNIST
数据集。
from keras.datasets import mnist
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()
训练集
train_images
:训练集样本train_labels
:训练集标签
测试集
test_images
:测试集样本test_labels
:测试集标签
查看数据集的形状
train_images.shape
# Out: (60000, 28, 28)
train_labels.shape
# Out: (60000,)
test_images.shape
# Out: (10000, 28, 28)
test_labels.shape
# Out: (10000,)
构建网络
层(layer)是神经网络的核心组件,它是一种数据处理模块,你可以将它看成数据过滤器。进去一些数据,出来的数据变得更加有用。大多数深度学习都是将简单的层链接起来,从而实现渐进式 的数据蒸馏(data distillation)。深度学习模型就像是数据处理的筛子,包含一系列越来越精细的数据过滤器(即层)。
下面先导入所需模块,构造一个序列模型(Sequential),序列模型是多个网络层的线性堆叠。即“一条路走到黑”。
from keras import models
from keras import layers
network = models.Sequential()
通过 add
方法将 layer
加入模型中。
network.add(layers.Dense(512, activation='relu', input_shape=(28 * 28,)))
主要参数
units
:神经元节点数,即输出空间维度activation
:激活函数,若不指定,则不使用激活函数 (即线性激活: a(x) = x)input_shape
:即张量的形状
relu
为线性整流函数,它返回逐元素的 max(x, 0)。
再添加第二层,一个 10 路 softmax
层,通过 Softmax
函数可以将多分类的输出值转换为范围在 [0, 1]和为 1 的概率分布。
network.add(layers.Dense(10, activation='softmax'))
编译(compile)
训练网络之前,我们还需要选择编译步骤的三个参数。
- 损失函数(loss function):网络如何衡量在训练数据上的性能。
- 优化器(optimizer):基于训练数据和损失函数来更新网络的机制。
- 在训练和测试过程中需要监控的指标(metric):本例只关心精度,即正确分类的图像所 占的比例。
network.compile(optimizer='rmsprop',
loss='categorical_crossentropy',
metrics=['accuracy'])
主要参数
RMSprop
:RMSProp 优化器是 AdaGrad 算法的一种改进。将梯度除以最近幅度的移动平均值。categorical_crossentropy
:分类交叉熵,推导公式
对于损失函数和优化器后续文章会详细讲解
数据预处理
在开始训练之前,我们将对数据进行预处理,将其变换为 network
要求的形状 ,并缩放到所有值都在 [0, 1] 区间。
比如,之前训练图像保存在一个 uint8 类型的数组中,其形状为 (60000, 28, 28),取值区间为 [0, 255]。我们需要将其变换为一个 float32 数组,其形状为(60000, 28 * 28),取值范围为 0~1。
train_images = train_images.reshape((60000, 28 * 28))
train_images = train_images.astype('float32') / 255
test_images = test_images.reshape((10000, 28 * 28))
test_images = test_images.astype('float32') / 255
类别转换独热编码
现在我们需要对标签进行分类编码,即将类别标签转换为二进制(只包括0和1)的矩阵类型表示。
看一个简单的例子。我们定义一个类别标签 labels ,并通过 keras.utils.to_categorical
将其转换为独热向量。
from keras.utils import to_categorical
labels = [0,1,2,3,4,5]
convert_to_one_hot = to_categorical(labels)
convert_to_one_hot
可以看到,原来类别标签中的每个值都转换为矩阵里的一个行向量。原标签中的 0 为[1. 0. 0. 0. 0. 0. 0. 0. 0.],第一个作为有效位,其余全部为0。
下面回到本例,对标签进行分类编码。
from keras.utils import to_categorical
train_labels = to_categorical(train_labels)
test_labels = to_categorical(test_labels)
我们可以看一下现在训练集标签(train_labels
)的形状。
# 转换前 Out: (60000,)
train_labels.shape
# Out: (60000, 10)
训练网络
现在我们开始训练网络,通过 fit
方法来训练 network
。
network.fit(train_images, train_labels, epochs=5, batch_size=128)
主要参数
train_images
:训练集样本train_labels
:训练集标签epochs
:训练模型迭代次数batch_size
:每次梯度更新的样本数。在深度学习中,一般采用 SGD 训练,即每次训练在训练集中取 batchsize 个样本训练
上述每次训练输出两个值:一个是网络在训练数据上的损失(loss),即当前输出与预期值的差距,另一个是网络在训练数据上的精度(acc)。
可以看到 loss 的值随着训练次数的增加不断降低,精度最终也达到了98.9%,下面看一下模型在测试集上的性能。
模型测试
test_loss, test_acc = network.evaluate(test_images, test_labels)
test_loss, test_acc
测试集精度为 97.9%,比训练集精度要低。训练精度和测试精度之间的这种差距是过拟合(overfit)造成的,导致模型的泛化性能较差。
内容参考
《Python深度学习》 [美] 弗朗索瓦·肖莱/著 张亮/译
- 点赞
- 收藏
- 关注作者
评论(0)