使用Theano实现kaggle手写识别
前面学习了机器学习的一些基础知识,这两天尝试着做了几个小实验,手写就是利用theano来实现kaggle上的入门问题——手写识别。
Theano是一个Python库,允许我们来定义、优化和评估涉及多维数组的数学表达式,因此其是实现深度学习框架的一个很重要的模块。Deep Learning Tutorials则介绍了如何使用theano来搭建我们需要的深度学习网络来解决我们的实际问题。这里跳过了theano的基本知识(有需要的同学可以阅读Theano basic tutorial),直接通过改造Deep Learning Tutorials中的Logistic Regression、Multilayer perceptron和Deep Convolutional Network实现了kaggle的入门问题——手写识别,虽然精度不高,希望能给后面的同学提供一点点帮助。
本篇博客首先介绍使用逻辑回归来解决手写识别问题。kaggle手写识别问题中的数据来源于MNIST,只不过,其将70000条数据分成了train和test两个数据集,train集中包含42000条数据,且包含每条数据的label;test集中包含28000条数据,不包含每条数据的label。因此我们是通过train中的42000条数据去训练模型,然后再用得到的模型去标记test集中的28000条数据。本文采用了类似十折交叉验证(10-fold cross validation)的方法:将train集中的数据分成了十份,最后一份作为模型训练过程中的测试集,每次训练时选取前九份中的一份作为验证集,其余八份作为训练集,这样我们就可以得到同一个模型的九组参数设置。在预测阶段,前面得到的九组参数设置同时参与预测,具体做法是,对于同一组测试数据,我们分别用九组参数设置去预测,得到九个预测值,我们将这九个预测值中出现次数最多的那个label作为改组测试数据的最终预测值。
实验代码
首先是训练数据的读取函数,该函数有两个参数,一个参数file表示训练数据集所在文件,另一个参数partion表示我们选择训练集中哪一部分来作为验证集。
|
|
然后是test集的读取函数,结构类似于上一个函数。
|
|
下面是逻辑回归类,这个类来自于Deep Learning Tutorials中的Logistic Regression,未作改动。
|
|
然后是模型训练函数,由Deep Learning Tutorials中的Logistic Regression中的模型训练函数改造而来,其中参数多了一个partion,用来指定train集中的哪一部分作为此次训练的验证集。
其中参数的选择我们会在实验结论部分给出。
|
|
最后是预测函数,该函数有两个参数,参数data_path表示测试集所在文件,参数has_label表示测试集中是否含有label,有label的话预测函数会计算出错误率,没有label的话函数会将测试结果保存在文件answer.csv中。
|
|
最后是主函数,如下所示,当然我们可以根据自己的实际需要去做调整。
|
|
结论
在参数的选择上,我们做了多组测试(该测试是选择train.csv中的前3/5座训练集,最后1/10做测试集,中间3/10做验证集得到的),最终选定了上面的参数,下面给出了一组对照数据。测试的机器是12年的,CPU为i3-2350M,主频为2。30GHZ,内存为6G,无GPU(机器太渣,没办法)。在写这篇博客时,我又试验了一下bacth_size大于1000的几种情况,等后续试验数据得出后,如果有更小的错误率,我会更新数据。
batch_size | learning_rate | epoches | seconds | epoches/sec | valid_err | test_err |
---|---|---|---|---|---|---|
300 | 0.13 | 126 | 2207 | 0.057 | 9.786 | 9.904 |
500 | 0.13 | 270 | 2736 | 0.097 | 10.064 | 9.700 |
800 | 0.13 | 162 | 1186 | 0.137 | 9.767 | 9.425 |
800 | 0.3 | 394 | 2922 | 0.135 | 9.98 | 9.875 |
800 | 0.03 | 202 | 1369 | 0.147 | 10.083 | 10.075 |
1000 | 0.13 | 201 | 1205 | 0.167 | 9.792 | 9.475 |
1400 | 0.13 | 408 | 2281 | 0.1789 | 9.6111 | 9.500 |
1600 | 0.13 | 334 | 1590 | 0.2101 | 9.089 | 8.4375 |
3200 | 0.13 | 714 | 1974 | 0.3622 | 9.083 | 8.5313 |
4200 | 0.13 | 834 | 2529 | 0.3297 | 9.2540 | 9.0714 |
单单针对MNIST数据集和逻辑回归模型,我们从上面这张表可以得出一些结论:batch_size越大,计算速度越快,精度慢慢有所提高;learning rate大的话epoches就会变大,也就是在整个train集上计算的次数多。
通过实验,我们得到9个模型在train.csv上的单独错误率分别为[7.783333333333333, 7.804761904761905, 7.457142857142857, 7.554761904761905, 7.9
97619047619048, 7.642857142857143, 7.571428571428571, 7.742857142857143, 7.16428
5714285715],而综合9个模型去做预测的话在train.csv上的错误率为7.097619,比单独的模型的平均错误率减小了0.538%,可以说十折交叉验证的确提高了模型的性能,但感觉不明显。
然后,我们又综合9个模型去预测test.csv中的数据,提交到kaggle上的正确率为0.91429,下面截图为证。而9个模型分别单独去预测test.csv中的数据,得到的正确率分别为[0.91057, 0.90543, 0.90986, 0.91371, 0.91214](数据还没有全部拿到,kaggle一天只允许提交5次),可以看到十折交叉验证的方法提高了0.4%的准确率,可能是实验方法不恰当,没有想象的高。
另外一个感受就是,theano实在太慢了,逻辑回归求一个模型大概需要跑20分钟,后面的mlp至少需要跑80度分钟,而卷积网络时间就更长了。等整理完了mlp和卷积网络的实验数据,就入门libgpuarray,好像利用GPU来做运算,比CPU快很多。