美文网首页
PaddlePaddle学习笔记———手写数字识别

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

作者: 短腿长颈鹿_0666 | 来源:发表于2018-01-29 22:08 被阅读0次

    本系列将作为个人的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学习笔记———手写数字识别

          本文链接:https://www.haomeiwen.com/subject/ilpfzxtx.html