PaddlePaddle学习笔记———手写数字识别

本系列将作为个人的paddle学习笔记,关于paddle的安装记录后期会补充在这里。本文要介绍深度学习中的“hello world”,手写数字识别。主要是对官方文档和其他文章进行学习,并做一个小小的记录,如有描述不准确的地方期待大家指正。


背景介绍

手写数字识别作为机器学习(或深度学习)的入门教程,一般使用的都是MINIST数据库。这一数据库作为一个简单的计算机视觉数据集,包含了一系列手写数字和对应的标签,并且每张图片都进行了很好的归一化和居中处理。作为新手,我们不必关注复杂的数据处理过程,只需试着理解分类过程跑通代码即可。

模型训练步骤

paddle训练模型的过程可以分为以下几个部分:
加载包--加载数据--搭建网络结构--训练模型--测试结果
官方文档为了对比效果,搭建了三种不同的网络结构进行训练:softmax、多层感知机和CNN网络结构。

模型概览

softmax回归

最简单的softmax回归模型是先将输入层经过一个全连接层得到的特征,然后直接通过softmax 函数进行多分类。
输入层的数据X传到输出层,在激活操作之前,会乘以相应的权重 W ,并加上偏置变量 b ,具体如下:

$ y_i = \text{softmax}(\sum_j W_{i,j}x_j + b_i) $
softmax回归的网络图如下:
[图片上传失败...(image-6f564-1517234805981)]
softmax模型搭建非常简单,在一些小数据集上可以得到不太差的结果。

softmax函数

softmax函数在机器学习中有着广泛的应用,新入门的同学大概更熟悉sigmoid或relu,但softmax无疑也是一种十分好用的函数。从它的名字就可以看出这个函数的意义:max意味着每次都只取概率最大的情况,但完美主义未必能得到最好的结果,伟大的发现总是来自于偶然!因此我们希望可以在一群最大的值中偶尔得到一个小概率事件,这就不是max函数了,我们称之为sofemax。
那么具体每一个取值的概率是多少呢:

假设我们有一个数组,V,Vi表示V中的第i个元素,那么这个元素的softmax值就是[图片上传失败...(image-27a936-1517234805981)]

多层感知器

softmax回归模型只有输入与输出两层网络,尽管它能得到不错的结果,但在追求更加精准的识别效果时,就需要增加在输入输出层之间添加更多的隐含层。
[图片上传失败...(image-17af98-1517234805981)]
其中,每个隐含层中都包含着激活函数,常见的激活函数有sigmoid、tanh、relu等等。

卷积神经网络

卷积神经网络(CNN),是一种专门用来处理具有类似网格结构的数据的神经网络,例如图像数据(可以看作二位的像素网格)。它与FC不同的地方在于,CNN的上下层神经元并不都能直接连接,而是通过“卷积核”作为中介,通过“核”的共享大大减少了隐含层的参数。简单的CNN是一系列层,并且每个层都通过一个可微函数将一个量转化为另一个量,通常用三个主要类型的层去构建CNN结构,包括卷积层(Convolutional Layer)、池化层(Pooling Layer)和全连接层(FC)。卷积网络在诸多应用领域有很好的应用效果,特别是在大型图像处理的场景表现格外出色。
本次手写数字识别使用的是卷积神经网络是LeNet-5,下图展示了它的结构:输入二维图像,经过两次卷积,再经过全连接,最后使用softmax分类作为输出层。
[图片上传失败...(image-387dd7-1517234805981)]

卷积与池化层的内容下次补充

paddle实现

加载包

import paddle.v2 as paddle

分别定义三个分类器:
softmax

def softmax_regression(img):
    predict = paddle.layer.fc(input=img,
                              size=10,
                              act=paddle.activation.Softmax())
    return predict

多层感知器

def multilayer_perceptron(img):
    # 第一个全连接层,激活函数为ReLU
    hidden1 = paddle.layer.fc(input=img, size=128, act=paddle.activation.Relu())
    # 第二个全连接层,激活函数为ReLU
    hidden2 = paddle.layer.fc(input=hidden1,
                              size=64,
                              act=paddle.activation.Relu())
    # 以softmax为激活函数的全连接输出层,输出层的大小必须为数字的个数10
    predict = paddle.layer.fc(input=hidden2,
                              size=10,
                              act=paddle.activation.Softmax())
    return predict

CNN

def convolutional_neural_network(img):
    # 第一个卷积-池化层
    conv_pool_1 = paddle.networks.simple_img_conv_pool(
        input=img,
        filter_size=5,
        num_filters=20,
        num_channel=1,
        pool_size=2,
        pool_stride=2,
        act=paddle.activation.Relu())
    # 第二个卷积-池化层
    conv_pool_2 = paddle.networks.simple_img_conv_pool(
        input=conv_pool_1,
        filter_size=5,
        num_filters=50,
        num_channel=20,
        pool_size=2,
        pool_stride=2,
        act=paddle.activation.Relu())
    # 以softmax为激活函数的全连接输出层,输出层的大小必须为数字的个数10
    predict = paddle.layer.fc(input=conv_pool_2,
                              size=10,
                              act=paddle.activation.Softmax())
    return predict

通过layer.data调用来获取数据,然后调用分类器得到结果,计算其损失函数(分类问题常使用交叉熵函数)

# 该模型运行在单个CPU上
paddle.init(use_gpu=False, trainer_count=1)

images = paddle.layer.data(
    name='pixel', type=paddle.data_type.dense_vector(784))
label = paddle.layer.data(
    name='label', type=paddle.data_type.integer_value(10))

# predict = softmax_regression(images) # Softmax回归
# predict = multilayer_perceptron(images) #多层感知器
predict = convolutional_neural_network(images) #LeNet5卷积神经网络

cost = paddle.layer.classification_cost(input=predict, label=label)
parameters = paddle.parameters.create(cost)

optimizer = paddle.optimizer.Momentum(
    learning_rate=0.1 / 128.0,
    momentum=0.9,
    regularization=paddle.optimizer.L2Regularization(rate=0.0005 * 128))

trainer = paddle.trainer.SGD(cost=cost,
                             parameters=parameters,
                             update_equation=optimizer)

输出训练结果

from paddle.v2.plot import Ploter

train_title = "Train cost"
test_title = "Test cost"
cost_ploter = Ploter(train_title, test_title)

step = 0

# event_handler to plot a figure
def event_handler_plot(event):
    global step
    if isinstance(event, paddle.event.EndIteration):
        if step % 100 == 0:
            cost_ploter.append(train_title, step, event.cost)
            cost_ploter.plot()
        step += 1
    if isinstance(event, paddle.event.EndPass):
        # save parameters
        with open('params_pass_%d.tar' % event.pass_id, 'w') as f:
            trainer.save_parameter_to_tar(f)

        result = trainer.test(reader=paddle.batch(
            paddle.dataset.mnist.test(), batch_size=128))
        cost_ploter.append(test_title, step, result.cost)
lists = []

def event_handler(event):
    if isinstance(event, paddle.event.EndIteration):
        if event.batch_id % 100 == 0:
            print "Pass %d, Batch %d, Cost %f, %s" % (
                event.pass_id, event.batch_id, event.cost, event.metrics)
    if isinstance(event, paddle.event.EndPass):
        # save parameters
        with open('params_pass_%d.tar' % event.pass_id, 'w') as f:
            trainer.save_parameter_to_tar(f)

        result = trainer.test(reader=paddle.batch(
            paddle.dataset.mnist.test(), batch_size=128))
        print "Test with Pass %d, Cost %f, %s\n" % (
            event.pass_id, result.cost, result.metrics)
        lists.append((event.pass_id, result.cost,
                      result.metrics['classification_error_evaluator']))
trainer.train(
    reader=paddle.batch(
        paddle.reader.shuffle(
            paddle.dataset.mnist.train(), buf_size=8192),
        batch_size=128),
    event_handler=event_handler_plot,
    num_passes=5)

打印日志如下:

# Pass 0, Batch 0, Cost 2.780790, {'classification_error_evaluator': 0.9453125}
# Pass 0, Batch 100, Cost 0.635356, {'classification_error_evaluator': 0.2109375}
# Pass 0, Batch 200, Cost 0.326094, {'classification_error_evaluator': 0.1328125}
# Pass 0, Batch 300, Cost 0.361920, {'classification_error_evaluator': 0.1015625}
# Pass 0, Batch 400, Cost 0.410101, {'classification_error_evaluator': 0.125}
# Test with Pass 0, Cost 0.326659, {'classification_error_evaluator': 0.09470000118017197}

训练之后,检查模型预测准确度,一般 softmax回归模型的分类准确率为约为 92.34%,多层感知器为97.66%,卷积神经网络可以达到 99.20%

参考资料

  1. paddle官方文档
  2. 【深度学习系列】PaddlePaddle之手写数字识别

你可能感兴趣的:(PaddlePaddle学习笔记———手写数字识别)