深度学习基础 - 基于Theano-MLP的字符识别实验(MNIST)

深度学习基础 - 基于Theano-MLP的手写字符识别实验


本文的完整代码托管在我的Github PY131/Practice-of-Machine-Learning,欢迎访问。

基础知识

深度学习回顾

深度学习的概念起源于人工神经网络,本文所采用的包含多隐层的多层感知机(MLP)就是其中的典型模型。长期以来,由模型复杂度所带来的计算效率低下问题一直是抑制深度学习进一步发展的瓶颈。近年来,随着大数据、云计算的兴起以及进步的算法设计,以“深度学习”为代表的大容量复杂模型开始突破其效率瓶颈,走向实用。深度学习正被愈发广泛地应用于计算机视觉、语音识别、自然语言处理等领域,其所具备的强大学习能力已初现威力。

Theano简介

Theano是一个基于python的科学计算框架,它在集成了numpy/scipy的基础上,实现了对GPU的透明支持,theano常被用作深度学习的基础框架。下面回顾theano的几个基础概念(核心概念):

- tensor variable(张量)
- theano function(theano函数)
- shared variable(共享变量)
- gradient(梯度)

基于MLP的字符识别模型

这里我们采用简单的单隐层MLP来实现,具体过程可参考:MNIST_Multilayer Perceptron。

这里列出一些建模过程中所要注意的内容:

  • 参数(连接权+偏置)的初始化区间需根据激活函数而定;
  • 此处面向分类问题,输出层可采用softmax来获得最终预测结果;
  • 采用MSGD(块随机梯度下降)来加速寻优,注意mini-batch的size选取;
  • 采用L1/L2正则化提升模型泛化能力,注意正则化参数的调节;

实验内容

查看完整代码和数据集

数据集分析

这里我采用规约好的MNIST数据集,相关内容可参考:Getting Started - Datasets - MNIST Dataset,数据集(mnist.pkl.gz)相关统计内容如下:

- 维度属性:
    数据集包含3个子数据集,对应train_set、valid_set、test_set,样本规模分别为50000、10000、10000;
    每条样本包含:
        输入向量[1*784],对应输入图片灰度矩阵[28*28];
        输出值,对应图片类别标签(数字0-9);
- 完整度:
    样本完整;
- 平衡度:
    未知;
- 更多信息:
    手写字符所覆盖的灰度已被人工调整到了图片的中部。

根据上面的分析,在数据处理时需要对数据进行维度转换。

下面是一些样例图片:

深度学习基础 - 基于Theano-MLP的字符识别实验(MNIST)_第1张图片

网络模型实现

首先给出基于python-theano编程实现MLP的步骤如下:

  1. 编写模型训练、验证、测试函数体;
  2. 基于theano.function及python函数实现相关函数(sigmoid、tanh、MSGD、train_model、valid_model、test_model、),;
  3. 基于theano.shared初始化参数(连接权+偏置);
  4. 设置其他参数(隐层节点数、学习率、块大小、迭代次数、正则化系数、早停参数等);
  5. 完善模型训练、验证、测试函数体;

其中训练函数体的流程概述如下:

1. 加载数据,生成训练集、验证集、测试集;
2. 根据数据维度,生成对应的MLP网络结构;
3. 训练模型,更新参数,实时记录训练误差、分时记录验证误差和测试误差(泛化误差);
4. 达到训练停止条件(迭代次数、耐心指数),输出模型与相关记录信息;

简化的模型训练程序块样例如下:完整程序

# 函数参数包括相关参数设置
def test_mlp(learning_rate=0.01,          # 学习率 (等号右边为默认值) 
             L1_reg=0.00, L2_reg=0.0001,  # 正则化系数
             n_epochs=1000,               # 迭代次数
             batch_size=20,               # mini-batch大小
             n_hidden=500,                # 隐层节点数
             dataset='mnist.pkl.gz'       # 数据集
            ):  

    # 加载数据、获取训练集、验证集、测试集
    datasets = load_data(dataset)   
    train_set_x, train_set_y = datasets[0]
    valid_set_x, valid_set_y = datasets[1]
    test_set_x,   test_set_y = datasets[2]

    ...

    # 初始化MLP网络结构和参数
    classifier = MLP(
        rng=rng,
        input=x,
        n_in=28 * 28,
        n_hidden=n_hidden,
        n_out=10
    )

    # 生成“似然+正则化”损失函数体
    cost = (
        classifier.negative_log_likelihood(y) 
        + L1_reg * classifier.L1 
        + + L2_reg * classifier.L2_sqr
    )

    # “模型测试”函数体
    test_model = theano.function(...)

    # “模型验证”函数体
    validate_model = theano.function(...)

    # “梯度计算”函数体
    gparams = [T.grad(cost, param) for param in classifier.params]

    # “参数更新”机制
    updates = [
        (param, param - learning_rate * gparam)
        for param, gparam in zip(classifier.params, gparams)
    ]

    # 训练函数体
    train_model = theano.function(...)

    ###############
    # 模型训练主体 #
    ###############

    # 早停机制设计
    ...

    # 迭代主体
    while (epoch < n_epochs) and (not done_looping):
        epoch = epoch + 1

        # 一个块的迭代训练
        for minibatch_index in range(n_train_batches):

            # 一条样本迭代训练(前向计算、基于梯度的参数更新)
            train_outputs = train_model(minibatch_index)  

            # 训练损失计算
            minibatch_avg_cost = train_outputs[0]    

            # 验证块
            # 达到验证所要求迭代次数 - 进行验证
               validation_losses = [validate_model(i) for i in range(n_valid_batches)]  # 计算0-1损失
               this_validation_loss = numpy.mean(validation_losses)  # 平均验证误差计算

               # 记录最优信息
            ...

            # 是否达到测试所要求条件 - 进行测试
               test_losses = [test_model(i) for i in range(n_test_batches)] # 计算0-1损失
               test_score = numpy.mean(test_losses)  # 测试误差计算
               ...

            # 早停判断               
            ...      
    ...

    # 过程信息反回
    return err_train, err_valid, err_test   

实验结果分析

通过合适的参数设置,记录训练过程中的训练误差(每iteration记录一次),验证误差(每epoch记录一次),测试误差(当验证精度提高时计算一次),得出三种误差的收敛曲线如下图示:

深度学习基础 - 基于Theano-MLP的字符识别实验(MNIST)_第2张图片

最终的分类结果如下:

Optimization complete. Best validation score of 1.880000 % (验证误差结果)
obtained at iteration 2077500, with test performance 1.840000 % (测试误差结果)

而整个程序运行时间为:

The code for file MLP.py ran for 68.32m (分钟)

我们可以对结果作如下分析:

  • 这里的MLP模型在当前参数和软硬件条件下下,采用了一个多小时(略长)的参数训练,得到了小于2%的误差精度,一方面说明了神经网络模型的庞大计算量,另一方面说明了该模型的出色效果。
  • 误差曲线在较早时就已经趋向于稳定,说明当前结构和参数下模型精度已经难再提升。
  • 神经网络模型的参数设置,有时会对训练过程和最终效果产生重要影响,比如这里的学习率、L1/L2正则化系数、隐层规模、mini-batch规模等。

总结

这里采用python-theano实现了一个简单的多层感知机网络,并基于MNIST手写字符数据集实现了分类实验

在这个过程中,我们回顾了神经网络的基础知识,练习了theano计算框架的使用,采用了相关辅助方法来优化训练,为后面开展“深度学习”研究积累了经验。

通过实验我们看到,一方面,神经网络模型训练往往伴随着巨大的计算量,相关参数设置也需要谨慎考虑并结合实验结果科学调整;另一方面,通过大量训练所得到的神经网络模型能够表现出优异的性能

参考资料

相关重要参考列出如下:

核心参考:

  • 基础知识:Introduction to Multi-Layer Perceptrons (Feedforward Neural Networks)
  • 教程参考:Multilayer Perceptron
  • 教程参考:General: MNIST - CNN example

其他参考:

  • 深度学习门户网站:Deep Learning
  • 教程参考:Classifying MNIST digits using Logistic Regression
  • 教程参考:在Python中利用Theano训练神经网络
  • 源码参考:lisa-lab/DeepLearningTutorials - GitHub
  • 基础知识:机器学习中的正则化原理讨论 - 知乎

你可能感兴趣的:(机器学习,深度学习)