現在、7月9日より開催されているkaggler-jaというslackグループのin-classコンペに参加しています。
今日はその途中経過を報告したいと思います。
また、このモデルを構築するまでに試行錯誤したことなど、最後にまとめてありますので良ければご参考になさってください。
コンペの内容
詳細は下記URLを参照していただければ分かると思いますが、簡単に言うとFashion MNISTのデータで学習モデルを作成し、その精度を競うコンペです。
Kaggler-ja In-class Competition 1
ソースコード
始めに、自分の提出したモデル構築のソースを載せておきます。
# ライブラリのimport import pandas as pd import numpy as np import matplotlib.pyplot as plt import matplotlib.image as mpimg import seaborn as sns import itertools from sklearn.model_selection import train_test_split from sklearn.metrics import confusion_matrix from keras import initializers from keras.utils.np_utils import to_categorical # convert to one-hot-encoding from keras.models import Sequential from keras.layers import Dense, Dropout, Flatten, Conv2D, MaxPool2D, Activation, MaxPooling2D from keras.optimizers import RMSprop, Adadelta from keras.preprocessing.image import ImageDataGenerator from keras.callbacks import ReduceLROnPlateau, EarlyStopping # データの読み込み train = pd.read_csv('train.csv') # 正解ラベルと入力データに分割 Y_train = train['label'] X_train = train.drop(labels=['label'], axis=1) # 正規化 X_train = X_train / 255.0 # スケールの変換 X_train = X_train.values.reshape(-1, 28, 28, 1) # 正解ラベルをone-hot-vectorに変換 Y_train = to_categorical(Y_train, num_classes=10) # 入力データを、訓練データとテストデータに分割 X_train, X_test, y_train, y_test = train_test_split(X_train, Y_train, test_size = 0.1, random_state=2) # コールバック関数の設定 # このコールバックは評価値を監視し,'patience'で指定されたエポック数の間改善が見られなかった場合,学習率を減らします. learning_rate_reduction = ReduceLROnPlateau(monitor='val_acc', patience=3, verbose=1, factor=0.5, min_lr=0.00001) # 過学習の抑制 # patientce = 20とし、val_lossの最小値が20回更新されなければ計算ストップ early_stopping = EarlyStopping(monitor='val_loss', patience=20 , verbose=1) # 画像の水増し処理 datagen = ImageDataGenerator( featurewise_center=False, # set input mean to 0 over the dataset samplewise_center=False, # set each sample mean to 0 featurewise_std_normalization=False, # divide inputs by std of the dataset samplewise_std_normalization=False, # divide each input by its std zca_whitening=False, # apply ZCA whitening rotation_range=5, # randomly rotate images in the range (degrees, 0 to 180) horizontal_flip=False, # randomly flip images vertical_flip=False) # randomly flip images # 水増し画像を訓練用画像の形式に合わせる datagen.fit(X_train) # CNNのモデル定義 model = Sequential() model.add(Conv2D(filters = 32, kernel_size = (3,3),padding = 'Same', activation ='relu', input_shape = (28,28,1))) model.add(Conv2D(filters = 32, kernel_size = (3,3),padding = 'Same', activation ='relu')) model.add(MaxPool2D(pool_size=(2,2))) model.add(Dropout(0.25)) model.add(Conv2D(filters = 64, kernel_size = (3,3),padding = 'Same', activation ='relu')) model.add(Conv2D(filters = 64, kernel_size = (3,3),padding = 'Same', activation ='relu')) model.add(MaxPool2D(pool_size=(2,2), strides=(2,2))) model.add(Dropout(0.5)) model.add(Flatten()) model.add(Dense(256, activation = "relu")) model.add(Dropout(0.5)) model.add(Dense(10, activation = "softmax")) # オプティマイザ optimizer = Adadelta(lr=1.0, rho=0.95, epsilon=None, decay=0.0) # コンパイル model.compile(optimizer = optimizer , loss = "categorical_crossentropy", metrics=["accuracy"]) # エポック数とバッチサイズ設定 epochs = 100 batch_size = 100 # 学習 history = model.fit_generator(datagen.flow(X_train,y_train, batch_size=batch_size), epochs = epochs, validation_data = (X_test,y_test), verbose = 1, steps_per_epoch=X_train.shape[0] // batch_size , callbacks=[learning_rate_reduction, early_stopping]) # 評価 score = model.evaluate(X_test, y_test, verbose=0) print('Test loss:', score[0]) print('Test accuracy:', score[1]) # =>Test loss: 0.16710302633792162 # =>Test accuracy: 0.94
94%の精度なので、まずまずかなぁと思いました。
精度と損失関数の遷移グラフも表示してみます。
#Accuracy plt.plot(history.history['acc']) plt.plot(history.history['val_acc']) plt.title('model accuracy') plt.ylabel('accuracy') plt.xlabel('epoch') plt.legend(['train', 'test'], loc='upper left') plt.show() #loss plt.plot(history.history['loss']) plt.plot(history.history['val_loss']) plt.title('model loss') plt.ylabel('loss') plt.xlabel('epoch') plt.legend(['train', 'test'], loc='upper left') plt.show()
予測
このモデルを使用して予測し、その結果を提出しました。
# 予測 test = pd.read_csv('test.csv') # テストデータも正規化を行う test = test / 255.0 # テストデータのReshape test = test.values.reshape(-1, 28, 28, 1) # predict results results = model.predict(test) # select the indix with the maximum probability results = np.argmax(results,axis = 1) results = pd.Series(results,name="label") submission = pd.concat([pd.Series(range(1,10001),name = "id"),results],axis = 1) submission.to_csv("loss_16710_acc_94000.csv",index=False)
精度結果
結果がこちら
94.9%の精度で、現在5位です。
DLのみで学習させた割には、良いスコアが出たかな?と言う印象です。
この結果に到るまでに試行錯誤したこと
参考にしたnotebook
まず、下記notebookを参考に、データをFashion MNISTに置き換えて学習させました。
Introduction to CNN Keras - 0.997 (top 6%) | Kaggle
この時点で、精度は90%弱でした。
以降、精度に影響を与えそうな部分のコードを修正しながら、トライアンドエラーを繰り返しました。
オプティマイザの検証
参考にしたnotebookだと、RMSprop をオプティマイザとして採用していましたが、今回のデータセットでは、違うオプティマイザの方が良い精度が出る可能性もあると考え、一通りのオプティマイザで実験しました。
kerasで使用できるオプティマイザ(最適化アルゴリズム)は、公式ドキュメントに載っています。
今回作成したモデルは、この中で一番良い精度が出たAdadeltaを使用しました。
レイヤーの検証
次に、レイヤーの検証を行いました。
ここはレイヤー修正→検証→修正→検証・・・の繰り返しでした。
filterの数を変更してみたり、Dropoutを減らしたり増やしたり、BatchNormalizationレイヤーを追加してみたり・・・
結果的に冒頭で記述したレイヤーに落ち着きました。
この辺りで精度が93%程度まで向上しました。
画像の水増し処理
最後に、データの前処理部分で精度が向上しないか、検証しました。
参考にしたnotebookでは、MNISTデータを使用していました。
MNISTデータは、手書き数字の画像データですが、間違えやすいような数字(実際には人間でも読み間違えてしまうようで画像)も含まれており、データの前位処理部分で、画像の回転、画像の水平移動、上下移動、ズームなど、様々な方法で水増し処理が実装されています。
しかし、今回のデータを見てみると、そこまで変なデータ(人間でも間違えてしまうような、きわどいデータ)は含まれていないと判断し、水平移動や上下移動の前処理は省きました。
その結果、94%程度まで精度が向上しました。
まとめ
以上が、自分が試行錯誤した主たる部分です。
コンペ期間はまだ数日残っているため、もう少し精度を向上できるように、頑張ってみたいと思います。