识别手写数字是深度学习中比较基础的项目,简单来说,手写数字识别相当于是程序设计语言里的 Hello World 任务,用于对 0 ~ 9 的十类数字进行分类,即输入手写数字的图片,使得计算机能够识别出这个图片中的数字。听起来实现该功能可能距离我们比较遥远,但是只要你了解到paddlepaddle深度学习框架,相信你就知道实现这个任务是多么轻松加愉快!
1.环境搭建
在完成这个任务之前,我们需要安装并导入飞浆库。 在PyCharm编译器中,打开终端,在命令行输入如下命令
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple paddlepaddle
下载并安装完毕后,我们可以创建python项目,导入并检验paddlepaddle是否安装成功,具体代码如下所示
import paddle
print(paddle.__version__)
运行效果能够正确输出paddle的版本号即表示检验通过,即安装成功! 如果在环境搭建的过程中遇到TypeError: Descriptors cannot not be created directly的错误,解决方案请参考博客解决方案。
2.数据集定义与加载
在百度飞浆中,MNIST是一个手写体数字的图片数据集,MNIST是深度学习领域标准、易用的成熟数据集,该数据集来由美国国家标准与技术研究所(National Institute of Standards and Technology (NIST))发起整理,一共统计了来自250个不同的人手写数字图片,其中50%是高中生,50%来自人口普查局的工作人员。该数据集的收集目的是希望通过算法,实现对手写数字的识别。 在本任务中,我先后加载了 MNIST 训练集(mode=‘train’)和测试集(mode=‘test’),训练集用于训练模型,测试集用于评估模型效果。该数据集包含60000张训练图片,10000张测试图片,图片的分辨率为28*28,以及对应的分类标签文件。部分图片以及对应的分类标签如下图所示: 具体加载mnist数据集的代码如下所示:
import paddle
from paddle.vision.transforms import Normalize
transform = Normalize(mean=[127.5], std=[127.5], data_format='CHW')
train_dataset = paddle.vision.datasets.MNIST(mode='train', transform=transform)
test_dataset = paddle.vision.datasets.MNIST(mode='test', transform=transform)
print('{} images in train_dataset, {} images in test_dataset'.format(len(train_dataset
Normalize函数的作用是使得没有可比性的数据变得具有可比性,同时又保持相比较的两个数据之间的相对关系。其实,查看源码就会发现,归一化就是将求出某一种数据的均值与方差,将每一个数据减去均值,然后在除去标准差后得到的标准化数据。
paddle.vision.datasets.MNIST(mode=‘train’, transform=transform)是为了加载MINST的60000行训练集数据并对数据进行归一化;paddle.vision.datasets.MNIST(mode=‘test’, transform=transform)是加载MINST的10000行测试集数据并进行归一化。
3.模型组网
飞桨的模型组网有多种方式,既可以直接使用飞桨内置的模型,也可以自定义组网。 『手写数字识别任务』比较简单,普通的神经网络就能达到很高的精度,在本任务中使用了飞桨内置的 LeNet 作为模型。飞桨在 paddle.vision.models 下内置了 CV(Computer Vision) 计算机视图领域的一些经典模型,LeNet 就是其中之一,调用很方便,只需一行代码即可完成 LeNet 的网络构建和初始化。num_classes 字段中定义分类的类别数,因为需要对 0 ~ 9 的十类数字进行分类,所以设置为 10。 另外通过 paddle.summary 可方便地打印网络的基础结构和参数信息。
paddle.summary(net, input_size=None, dtypes=None, input=None)
参数说明:
net (Layer) - 网络实例,必须是 Layer 的子类。
input_size (tuple|InputSpec|list[tuple|InputSpec) - 输入张量的大小。如果网络只有一个输入,那么该值需要设定为tuple或InputSpec。如果模型有多个输入。那么该值需要设定为list[tuple|InputSpec],包含每个输入的shape。默认值:None。
dtypes (str,可选) - 输入张量的数据类型,如果没有给定,默认使用 float32 类型。默认值:None。
input (tensor,可选) - 输入张量数据,如果给出 input ,那么 input_size 和 dtypes 的输入将被忽略。默认值:None。
lenet = paddle.vision.models.LeNet(num_classes=10)
paddle.summary(lenet,(1, 1, 28, 28))
4.模型训练与评估
模型训练需完成如下步骤: 使用 paddle.Model 封装模型。 将网络结构组合成可快速使用 飞桨高层 API 进行训练、评估、推理的实例,方便后续操作。 使用 paddle.Model.prepare 完成训练的配置准备工作。 包括损失函数、优化器和评价指标等。飞桨在 paddle.optimizer 下提供了优化器算法相关 API,在 paddle.nn Loss层 提供了损失函数相关 API,在 paddle.metric 下提供了评价指标相关 API。 使用 paddle.Model.fit 配置循环参数并启动训练。 配置参数包括指定训练的数据源 train_dataset、训练的批大小 batch_size、训练轮数 epochs 等,执行后将自动完成模型的训练循环。 因为是分类任务,这里损失函数使用常见的 CrossEntropyLoss (交叉熵损失函数),优化器使用 Adam,评价指标使用 Accuracy 来计算模型在训练集上的精度。 模型训练完成之后,调用 paddle.Model.evaluate ,使用预先定义的测试数据集,来评估训练好的模型效果,评估完成后将输出模型在测试集上的损失函数值 loss 和精度 acc。
model = paddle.Model(lenet)
model.prepare(paddle.optimizer.Adam(parameters=model.parameters()),
paddle.nn.CrossEntropyLoss(),
paddle.metric.Accuracy())
model.fit(train_dataset, epochs=5, batch_size=64, verbose=1)
model.evaluate(test_dataset, batch_size=64, verbose=1)
5.模型推理
执行模型推理时,可通过 paddle.Model.predict_batch 执行推理操作。 如下示例中,选择测试集中的一张图片 test_dataset[0] 作为输入,执行推理并打印结果,检验推理的结果与可视化图片是否一致。
img, label = test_dataset[0]
img_batch = np.expand_dims(img.astype('float32'), axis=0)
out = model.predict_batch(img_batch)[0]
pred_label = out.argmax()
print('true label: {}, pred label: {}'.format(label[0], pred_label))
from matplotlib import pyplot as plt
plt.imshow(img[0])
plt.show()
6.全部代码展示
import paddle
import numpy as np
from paddle.vision.transforms import Normalize
transform = Normalize(mean=[127.5], std=[127.5], data_format='CHW')
train_dataset = paddle.vision.datasets.MNIST(mode='train', transform=transform)
test_dataset = paddle.vision.datasets.MNIST(mode='test', transform=transform)
lenet = paddle.vision.models.LeNet(num_classes=10)
model = paddle.Model(lenet)
model.prepare(paddle.optimizer.Adam(parameters=model.parameters()),
paddle.nn.CrossEntropyLoss(),
paddle.metric.Accuracy())
model.fit(train_dataset, epochs=5, batch_size=64, verbose=1)
model.evaluate(test_dataset, batch_size=64, verbose=1)
img, label = test_dataset[0]
img_batch = np.expand_dims(img.astype('float32'), axis=0)
out = model.predict_batch(img_batch)[0]
pred_label = out.argmax()
print('true label: {}, pred label: {}'.format(label[0], pred_label))
from matplotlib import pyplot as plt
plt.imshow(img[0])
plt.show()
运行结果展示:
|