Kaggle 0 手写数字识别器的探索

最近打算开始玩Kaggle,作为入门选了一个入门级的任务Digit-Recognizer。正好在翻《机器学习实战》的时候看到可以用KNN做图像识别,于是就打算用KNN来做一个手写数字的识别器(9.13:现在要换成CNN来做了)。这也算是我第一次应用机器学习来解决比较实际的问题。此篇作为一个类似于项目日志的东西,在这个项目完成之前,应该会一直更新。

9.11

没看书自己实现了一下KNN,算法本身也没什么复杂的,但是实现起来还是费了一番不小的功夫,动手能力还需增强啊…

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
@author: drapor
"""

import pandas as pd
import numpy as np
print('Importing the data...')
train_set = pd.read_csv('train.csv')
pixel = train_set.iloc[:,1:785]
label = train_set.iloc[:,0]
test_set = pd.read_csv('test.csv')
r = []
for t in range(len(test_set)):
        print('%d/28000' % (t+1))
    a = np.array(test_set.loc[t])
    d = []
    for i in range(len(train_set)):
        b = np.array(pixel.loc[i])
        d.append(np.dot((a-b).T,(a-b)))
    k = list(zip(d,range(len(d))))
    k.sort()
    m = []
    for i in k[:10]:
        m.append(label.loc[i[1]])
    r.append(sum(m)/10)

跑了几个试了试,K选了10,有一些误差,不过效果看起来还可以。但是全量数据一起跑的时候就发现,完成任务需要的时间非常久,大概至少需要三十个小时。这当然是不能接受的,得想办法改进才行。目前初步的打算是用多进程,应该可以明显地缩短完成任务所需的时间。


9.12

昨天请教了公司的组长之后得知,还可以用Deep Learning中的Pooling来降低计算的复杂度,但还是想先上多线程看看。经过一个晚上和半个上午的研究探索,终于成功地让任务以多进程的方式跑起来了。

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Description:
kaggle 0 

@author: drapor
"""

import pandas as pd
import numpy as np
import multiprocessing
import os
#import matplotlib.pyplot as plt

def processing(test_set):
    s = []
    print("Running... pid:" + str(os.getpid()))
    for idx, df in test_set.iterrows():
        print('%d/28000, pid %s' % (idx, os.getpid()))
        a = np.array(df)
        d = []
        for i in range(42000):
            b = np.array(pixel.iloc[i])
            d.append(np.dot((a-b).T,(a-b)))
        k = list(zip(d,range(len(d))))
        k.sort()
        m = []
        for i in k[:10]:
            m.append(label.loc[i[1]])
        s.append([idx,sum(m)/10])
    return s

if __name__ == '__main__':
    print('Importing the data...')
    train_set = pd.read_csv('train.csv')
    pixel = train_set.iloc[:,1:785]
    label = train_set.iloc[:,0]
    #plt.imshow(test.reshape(28,28), cmap=plt.cm.gray)
    test_set = pd.read_csv('test.csv')
    pool = multiprocessing.Pool(processes = 16)
    r = []
    for i in range(16):
        train = test_set.loc[1750*i:1750*(i+1)-1]
        r.append(pool.apply_async(processing,(train,)))
    pool.close()
    pool.join()
    result  = []
    for i in r:
        for j in i.get():
            result.append(j)
    result.sort()
    with open('result.csv',"w") as f:
        for i in result:
            f.writelines(str(i[0]+1)+','+str(round(i[1]))[:-2]+'\n')

为了能够快速地完成任务,我又去AWS上租了一个c4.4xlarge,配置是16 vCPU, 2.9 GHz, Intel Xeon E5-2666v3, 30 GiB 内存,在上面把任务分成16个进程进行计算。即便如此,整个任务还是花费了大概三四个小时的时间,但总算最后还是成功地跑出来了。

将结果按照要求稍微整理一下就可以提交了,初次提交的分数是0.87314,预料之中。虽然准确率看起来还可以,但这个成绩在这项竞赛中的排名是1534/1625,非常的惨淡,不过这也说明改进的空间还很大。之后考虑用Pooling试试。


9.13

今天发现其实Pooling并不是一种可以提高精度的办法,只是一种可以降低计算复杂度的方法,如果原算法的精度本身就不高的话,Pooliing之后同样也不高,组长建议我改用CNN。我想了一下,就算调整K的值重新跑一次可能不会使准确率有明显的提升,Google了一下发现大家用KNN做手写识别,精度可能也就追求到0.8。嗯……这两天探索一下Tensorflow+CNN(之前只是知道,并没有深入了解过),尝试用这种方式解决这个问题。

Contents


本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可。

知识共享许可协议