手写数字识别案例(第一版)
任务:输入:28*28的灰度图片
输出:0-9的数字标签
样本量:6万训练样本,1万测试样本
数据处理:读取数据和预处理操作
模型设计:网络结构
训练配置:优化器和计算资源配置
训练过程:循环调用训练过程,前向计算+损失函数(优化目标)+后向传播
保存模型:将训练好的模型保存
数据处理:
train_reader=paddle.batch(paddle.dataset.mnist.train(), batch_size=8)
paddle.dataset.mnist.train()取出mnist训练的数据集 使用paddle.batch把它变成一个可以batch输入的形式 batch_size指定参数
for batch_id ,data in enumerate(train_reader()):
#获取图像数据,并转化为float32类型的数组
img_data=np.array[x[0] for x in data]).astype('float32')
#获取图像标签数据
label_data=np.array(x[1] for x in data]).astype('float32')
#打印数据形状
print("图像数据形状和对应数据为:",img_data.shape, img_data[0])
print("图像标签形状和对应数据为:",label_data.shape, label_date[0])
break
图像数据形状和对应数据为:(8,784)
图像标签形状和对应数据为:(8,)5.0
一个批次有8个图片和8个标签,这次读取的数字标签是5
img=np.array(img_data[0]+1)*127.5(图片打印时候要做反归一化)
模型设计,训练,测试
模型设计:首次采用已知模型进行预测
若采用房价预测网络模型(线性回归模型,一层神经网络)
我们输入的是28*28的灰色图片,一层神经网络对于像素的位置进行单层排列,无法捕捉图像的内容(1*784)
# 定义mnist数据识别网络结构,同房价预测网络
class MNIST(fluid.dygraph.Layer):
def __init__(self,name_scope):
super(MNIST, self).__init__(name_scope)
name_scope=self.full_name()
# 定义一层全连接层,输出维度是1,激活函数为none
self.fc = Linear(input_dim=784, output_dim=1,act=None)
# 定义网络结构的前向计算过程
def forward(self, inputs):
outputs = self.fc(inputs)
return outputs
模型训练:
训练配置
训练配置需要先生成模型实例(设为“训练”状态),再设置优化算法和学习率(使用随机梯度下降SGD,学习率设置为0.001),实现方法如下所示。
通过with语句创建一个dygraph运行的context
动态图下的一些操作需要在guard下进行
with fluid.dygraph.guard():
model =MINST("mnist")
# 启动训练模式
model train()
# 加载训练集 batch_size 设为 16
train_loader=paddle.batch(paddle.dataset.mnist.train(),batch_size=16)
# 定义优化器,使用随机梯度下降SGD优化器,学习率设置为0.001
optinizer= fluid.optinizer.SGDOptimizer(learning_rate=0.001, parameters=model.parameters())
EPOCH_NUM=10
训练过程
训练过程采用二层循环嵌套方式,训练完成后需要保存模型参数,以便后续使用。
- 内层循环:负责整个数据集的一次遍历,遍历数据集采用分批次(batch)方式。
- 外层循环:定义遍历数据集的次数,本次训练中外层循环10次,通过参数EPOCH_NUM设置
for epoch_id in range(EPOCH_NUM):
for batch_id, data in enumerate(train_loader()):
#准备数据,格式需要转化为符合框架要求的
img_data=np.array[x[0] for x in data]).astype('float32')
label_data=np.array(x[1] for x in data]).astype('float32').reshape(-1,1) *为了loss的计算,label的最后一维需要为-1
#将数据转化为飞桨动态图片格式
image= fluid.dygraph.to_variable(image_data)
label=fluid.dygraph.to_variable(image_data)
#前向计算的过程 predicts = model(images)
# 计算损失 loss = F.square_error_cost(predicts, labels)
avg_loss = paddle.mean(loss)
#每训练了1000批次的数据,打印下当前Loss的情况
if batch_id % 1000 == 0:
print("epoch_id: {}, batch_id: {}, loss is: {}".format(epoch, batch_id, avg_loss.numpy()))
#后向传播,更新参数的过程
avg_loss.backward()
opt.step()
opt.clear_grad()
#保存模型
fluid.save_dygraph(model.state_dict(),'mnist')
结论:从训练过程中损失所发生的变化可以发现,虽然损失整体上在降低,但到训练的最后一轮,损失函数值依然较高。可以猜测手写
数字识别完全复用房价预测的代码,训练效果并不好。接下来我们通过模型测试,获取模型训练的真实效果。
模型测试
# 读取一张本地的样例图片,转变成模型输入的格式
def load_image(img_path):
# 从img_path中读取图像,并转为灰度图
im = Image.open(img_path).convert('L')
print(np.array(im)) im = im.resize((28, 28), Image.ANTIALIAS)
im = np.array(im).reshape(1, -1).astype(np.float32)
# 图像归一化,保持和数据集的数据范围一致
im = im / 127.5 - 1 return im
# 定义预测过程
model = MNIST()
params_file_path = 'mnist.pdparams'
img_path = './work/example_0.png'
# 加载模型参数
param_dict = paddle.load(params_file_path)
model.load_dict(param_dict)
# 灌入数据
model.eval()
tensor_img = load_image(img_path)
result = model(paddle.to_tensor(tensor_img))
# 预测输出取整,即为预测的数字,打印结果
print("本次预测的数字是", result.numpy().astype('int32'))
预测为-1,不准