ナード戦隊データマン

データサイエンスを用いて悪と戦うぞ

kerasを用いてkaggleのMNISTに再挑戦

以前、Rのh2oライブラリを用いてkaggleのMNISTにチャレンジしました( https://qiita.com/sugiyamath/items/abc7f1480aa6358469d2 )。しかし、機械学習アルゴリズムについて詳しくわかってなかったため、ライブラリをただ使う程度のものでした。今回は、cnnをkerasで構築し、同じ問題に挑戦します。

jupyter notebookで実行

まず、データの準備をします。

In[1]:

# Larger CNN for the MNIST Dataset
import numpy as np
import pandas as pd
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Dropout
from keras.layers import Flatten
from keras.layers.convolutional import Conv2D
from keras.layers.convolutional import MaxPooling2D
from keras.utils import np_utils
from keras import backend as K
from sklearn.utils import shuffle
K.set_image_dim_ordering('th')

# fix random seed for reproducibility
seed = 7
np.random.seed(seed)
# load data

df = pd.read_csv("train.csv")
df = shuffle(df)

y = df["label"]
X = df.drop(labels=["label"], axis=1).as_matrix()

# reshape to be [samples][pixels][width][height]
X = X.reshape(X.shape[0], 1, 28, 28).astype('float32')

# normalize inputs from 0-255 to 0-1
X = X / 255

# one hot encode outputs
y = np_utils.to_categorical(y)
num_classes = y.shape[1]

次に、cnnクラスを作成します。

In[2]:

from sklearn.metrics import accuracy_score
class CNN_mnist:
    def __init__(self, epochs=10, batch_size=200):
        self.epochs = epochs
        self.batch_size = batch_size
    
    def build_network(self):
        model = Sequential()
        model.add(Conv2D(32, (5, 5), input_shape=(1, 28, 28), activation='relu'))
        model.add(MaxPooling2D(pool_size=(2, 2)))
        model.add(Conv2D(16, (3, 3), activation='relu'))
        model.add(MaxPooling2D(pool_size=(2, 2)))
        model.add(Dropout(0.2))
        model.add(Flatten())
        model.add(Dense(128, activation='relu'))
        model.add(Dense(50, activation='relu'))
        model.add(Dense(num_classes, activation='softmax'))
        model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
        self.model = model
        return self.model
    
    def fit(self, X, y):
        self.build_network()
        self.model.fit(X, y, epochs=self.epochs, batch_size=self.batch_size)
        return self
    
    def predict(self, X):
        return self.model.predict_classes(X, verbose=0)

    def score(self, X, y):
        preds = self.predict(X)
        return accuracy_score(y, preds)
    
    def get_params(self, deep=True):
        return {}
    
    def set_params(self, **parameters):
        for parameter, value in parameters.items():
            setattr(self,parameter, value)
        return self

このクラスは、畳み込み->マックスプーリング->畳み込み->マックスプーリング->ドロップアウト->Denseというように試しにcnnを作成したものです。そして、このネットワークが一定の能力を持っていることを確かめるため、訓練データとテストデータに分けて検証します。

In[3]:

from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)
model = CNN_mnist()
model.fit(X_train, y_train)
model.score(X_test, np.argmax(y_test, axis=1))

Out[3]:

0.98847619047619051

結構、精度が高そうなので、epochを増やし、全データを用いて訓練し、提出用データに対して予測します。その前に、提出用テストデータに対して前処理を施します。

In[4]:

X_compe = pd.read_csv("test.csv").as_matrix()

# reshape to be [samples][pixels][width][height]
X_compe = X_compe.reshape(X_compe.shape[0], 1, 28, 28).astype('float32')

# normalize inputs from 0-255 to 0-1
X_compe = X_compe / 255

In[5]:

model = CNN_mnist(epochs=25)
model.fit(X, y)
out = pd.DataFrame()
out["label"] = model.predict(X_compe)
imageid = []
for i in range(len(X_compe)):
    imageid.append(i+1)
out["ImageId"] = imageid
out.to_csv("result.csv", index=False)

結果

Screenshot from 2017-10-19 18-55-15.png

上位23%の順位です。

参考

  1. https://machinelearningmastery.com/handwritten-digit-recognition-using-convolutional-neural-networks-python-keras/