教你使用keras在kaggle数字识别大赛中拿到前百名

3,257 阅读6分钟

一、写在前面

    最近一直在研究深度学习,每一种深度学习算法都让我感觉打开了新世界的大门。

    没想到第一次在kaggle上随便参加了个简单比赛就取得了前5%的成绩,虽然只是一个简单的比赛,但是这个结果也让初学者的我非常开心。

   

   目前我的模型的识别率是99.771%,爬到52名之后就往上爬不动了。如果有大佬有能提高识别率,甚至识别率达到100%的方法,或者对这篇文章有任何意见建议,欢迎和我交流。

我的微博是@阿扣是谁哇  欢迎来找我玩OVO

二、模型选择

   在此我们选择最简单的神经网络模型MLP


   为什么选择MLP呢?有如下几个原因:


   1、因为up主现在很穷,用的电脑还是13年的macbook,还是只有集显的那种,卷积神经网络up主也测试过,但是训练起来电脑有点吃力,所以就放弃了╮(╯▽╰)╭。

   2、kaggle中提供的训练数据和传统的mnist数据维度完全一样,都是长宽为28像素的黑白图像,单张图只有784维,即使不进行池化卷积等操作,需要训练的参数也只有不到20万个。

   3、如果简单的神经网络能解决问题,就不要用复杂的模型了(当然复杂的模型也要能理解并且能coding),毕竟现在显卡那么贵.......算了扯远了.....



三、代码详解


该项目完整代码:在这里

(https://github.com/hikariming/Digit_Recognizer_99.771-/blob/master/digit_kaggle.py)


1、引入各种包

这一步就不细说啦,大概就是引入各种包,最主要的还是引入keras还有numpy

# -*- coding: utf-8 -*-
import tensorflow as tf
import keras
from keras.models import Sequential
from keras.layers import Dense, Dropout, Activation
from keras.optimizers import SGD
import numpy as np
import csv

2、引入训练数据


定义一个打开训练集的函数,训练数据从kaggle上下载下来即可,下载下来的数据的shape为(42000,784),即有42000个训练数据。

def LoadTraincsvfile():
    tmp=np.loadtxt('/Users/itwork/Desktop/train_set/big-mnist/train.csv',dtype=np.str,delimiter=',')
    x_data=tmp[1:,1:].astype(np.float)
    y_data=tmp[1:,0].astype(np.float)
    return x_data,y_data
#打开从kaggle上下载下来的训练数据
x_data,y_data=LoadTraincsvfile()

3、扩充训练数据


为了达到更高的识别率,我们需要更多的训练数据,个人感觉常规的通过图像变形的方法对手写数字没啥卵用(毕竟手写的数字经过变形、翻转之后就不像数字了,而且训练数据像素比较低),所以我放弃了这种扩充数据集的方法。

在这里,我直接把标准的mnist数据集也引入进训练集中,mnist里面有60000万个28x28的手写数字图像。



path = './mnist.npz'
f = np.load(path)
x_train1, y_train1 = f['x_train'], f['y_train']
x_test1, y_test1 = f['x_test'], f['y_test']
f.close()
x_train1 = x_train1.reshape(60000, 784).astype('float32')



把kaggle上的手写训练数据和mnist手写数据结合一下,就有102000条训练数据了,这样训练数据就扩充了2倍多。

x_train=np.concatenate((x_data[0:42000,:],x_train1),axis=0)
y_train=np.concatenate((y_data[0:42000],y_train1),axis=0)


4、构建测试集(可忽略)、数据标准化


在这里的测试集其实没啥子用,为了提高准确度我把所有kaggle给的训练数据全都当做训练集了,这里的测试集和训练集是重合的。


数据标准化非常简单,直接把单个像素点除个255就好

#构件测试集
x_test=x_data[41000:,:]
y_test=y_data[41000:]
print (x_train.shape)
print (y_train.shape)

#数据标准化
x_train /= 255
x_test /= 255

5、建立网络开始训练+调参


正片开始了,建立好粗略的MLP模型的之后,慢慢的调参。


我主要调整了损失函数(改变损失函数之后,识别率突然飙升,我也没搞懂为啥会这样- -),学习率,每层的神经元的个数

在没有调参和修改损失函数前,这个模型的识别率大概在97%左右,经过调参识别率就上升到了99.7%了,损失函数的值已经降到了10的-5还是-7次方了,可以说非常夸张。

在这里我没有用dropout,up主不是很喜欢用dropout,因为总觉得它会造成网络内随机性和风险增加,降低识别率

此处代码不详细说,参考keras官方文档即可。

model = Sequential()

model.add(Dense(200, activation='relu', input_dim=784))
model.add(Dense(120, activation='relu'))
model.add(Dense(10, activation='softmax'))
#使用adam加速方法,beta的值是adam创始人论文的推荐值,因此就不调了
adam = keras.optimizers.Adam(lr=0.0005, beta_1=0.9, beta_2=0.999, epsilon=1e-08)
model.compile(loss='binary_crossentropy',
              optimizer=adam,
              metrics=['accuracy'])

model.fit(x_train, y_train,
          epochs=50,
          batch_size=256)
score = model.evaluate(x_test, y_test, batch_size=4096)
print(model.metrics_names)
print(score)


6、对未知数据进行预测,将结果上传到kaggle

每一个kaggle上的比赛,对上传的结果文件格式都有一定的要求,格式要求在相应竞赛的附件里面有,自己下载下来参考即可。



根据Digit_Recognizer比赛的要求,我们对测试集进行预测,并将预测结果输出成csv文件:


#预测部分
is_predict=1
if(is_predict):
    #将测试数据标准化
    tmp = np.loadtxt('/Users/itwork/Desktop/train_set/big-mnist/test.csv', dtype=np.str, delimiter=',')
    x_predict = tmp[1:, :].astype(np.float)
    x_predict /= 255
    #进行预测
    classes = model.predict_classes(x_predict)
   
    #输出结果
    resultlist = []
    imgid = 1
    for i in classes:
        res_data = {'ImageId': imgid, 'Label': i}
        resultlist.append(res_data)
        imgid = imgid + 1

    headers = ['ImageId', 'Label']
    with open('result.csv', 'w', newline='') as f:
        # 标头在这里传入,作为第一行数据
        writer = csv.DictWriter(f, headers)
        writer.writeheader()
        for row in resultlist:
            writer.writerow(row)

四、后记

1、比赛方面

   数字识别虽然是最简单的机器学习分类问题之一,但是能玩到这么高的识别率,对于萌新如我的人来说还是挺开心的。

   损失函数的构建公式对预测结果影响还是挺大的,希望自己能多多理解损失函数的内涵吧。

   kaggle上有不少人已经达到了100%的识别率了,真心佩服,真心想知道他们是怎么实现的。

2、最后的唠叨

   计算机视觉这方面的内容由于我电脑机能的原因就暂时没法学了QAQ,建议各位想学深度学习的孩子还是砸锅卖铁弄台好电脑。

    kaggle上的大部分计算机视觉的题目,光是将训练集就直接可以把我的笔记本电脑内存塞满,电脑崩溃╮(╯▽╰),即使解决了内存问题。如果显卡不好的话,即使你用迁移学习,训练一趟也还是要花几个小时,简直没法玩。


接下来我会研究LSTM这些RNN的相关技术,参加一下kaggle上面的文本识别比赛,有兴趣的朋友欢迎组个队呀~如果你不嫌弃我电脑卡技术菜的话2333