俺人〜OREGIN〜俺、バカだから人工知能に代わりに頑張ってもらうまでのお話

俺って、おバカさんなので、とっても優秀な人工知能を作って代わりに頑張ってもらうことにしました。世界の端っこでおバカな俺が夢の達成に向けてチマチマ頑張る、そんな小さなお話です。現在はG検定、E資格に合格し、KaggleやProbSpaceのコンペに参画しながら、Pythonや機械学習、統計学、Dockerなどの勉強中です。学習したことをブログにアウトプットすることで、自分の身に着けていきたいと思います。まだまだ道半ばですが、お時間がありましたら見て行ってください。

エピソード3-12: 選択した特徴量を使ってNNモデルの学習率をグリッドサーチする。Acc62%→66%(KaggleでKickstarter Projectsに挑戦する。)

「Kaggle」のデータセットKickstarter Projects」に取り組んで、前回、LassoCVを使った特徴量選択を実施したので、その特徴量を使ってNNモデルを作り学習率をグリッドサーチします。

前回の記事は、以下にありますので、ご参照ください。

oregin-ai.hatenablog.com

 

では、さっそく取り組んでまいります。

 

1.まずは、選択された特徴量だけに絞り込んで、学習用の訓練データと、性能検証用のテストデータに分割します。

# ラベルデータとして’state’を採用する。

train_label = df_train['state']



# Leakageになりそうなカラム、相関が強いカラムをドロップする

train_data = df_train.drop(['state','name','currency','deadline','goal','launched','pledged','backers','usd pledged','usd_pledged_real','period'], axis=1)
# Lassoで削除するべき特徴量に選ばれたカラムをドロップする train_data = train_data.drop(train_data.columns[removed_idx], axis=1) #目的変数'state'を正解としてyに格納 y = train_label.values
#カラムをドロップした説明変数を、Xに格納 X = train_data.values # 全データのうち、30%をテストデータにする test_size = 0.3 # ホールドアウト法を実行(テストデータはランダム選択) X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=test_size,shuffle=True, random_state=1234) #X_train : 学習用の訓練データの説明変数
#X_test : 検証用のテストデータの説明変数
#y_train : 学習用の訓練データの目的変数
#y_test : 検証用のテストデータの目的変数
print(X_train.shape, X_test.shape, y_train.shape, y_test.shape)

(144879, 172) (62091, 172) (144879,) (62091,)

 

144,879個の訓練データと、62,091個のテストデータに分かれて、説明変数は172個になりました。

 

2.1,2層目tanh 3,4層目ReLU、5層目Sigmoid の2値分類ニューラルネットワークモデルを採用, それぞれの層でバッチ正規化の処理を入れる。

モデルを一から作るのは大変なので、Kerasでくみ上げることにしました。

import keras

from keras.models import Sequential

from keras.layers import Dense, Dropout, Activation

from keras.layers.normalization import BatchNormalization

from keras.optimizers import Adam



model = Sequential()

#Lassoで削除された説明変数を削除する場合

model.add(Dense(256, activation='tanh', input_dim=172))

model.add(BatchNormalization())

model.add(Dense(256, activation='tanh'))

model.add(BatchNormalization())

model.add(Dense(128, activation='relu'))

model.add(BatchNormalization())

model.add(Dense(64, activation='relu'))

model.add(BatchNormalization())

model.add(Dense(1, activation='sigmoid')

3.最適化手法にAdamを採用し学習率を交差検証法で探索する。

最適化手法にはAdamを採用し学習率を変化させて、テストデータAccuracyが最大になる値を探索することにしました。
探索にあたっては、交差検証法(クロスバリデーション)を利用しました。

#学習率毎のAccuracy格納用データフレームを初期化

df_lr_Acc = pd.DataFrame(index=[], columns=['lr','step','loss', 'val_loss','acc', 'val_acc'])

for lr in np.arange(0.001,0.01,0.001):

    #クロスバリデーションの検証毎のAccuracy格納用データフレームを初期化

    df_val_Acc = pd.DataFrame(index=[], columns=['step','loss', 'val_loss','acc', 'val_acc'])

    #クロスバリデーションでの検証ステップを初期化

    step = 1

    #クロスバリデーションで検証(訓練データを三分割して、2つを学習用、1つを検証用に使うを三回実施)

    for train_index, test_index in KFold(n_splits=3,shuffle=True, random_state=1234).split(X_train, y_train):

        X_val_train, X_val_test = X[train_index], X[test_index]

        y_val_train, y_val_test = y[train_index], y[test_index]

        print(X_val_train.shape, X_val_test.shape,y_val_train.shape, y_val_test.shape)

        

        # ------ 最適化手法 ------

        adam = Adam(lr=lr)

        # -----------------------------



        model.compile(loss='binary_crossentropy',

                      optimizer=adam,

                      metrics=['accuracy'])

    

        # 計算の実行

        fit = model.fit(X_val_train, y_val_train,epochs=5,batch_size=256,validation_data=(X_val_test, y_val_test))



        # 各epochにおける損失と精度をdfに入れる

        df = pd.DataFrame(fit.history)

        

        val_df = pd.DataFrame(index=[],columns=['step','loss', 'val_loss','acc', 'val_acc'])

        val_df = val_df.append(df,ignore_index = True,sort=False)

        val_df[['step']] = step

        

        df_val_Acc = df_val_Acc.append(val_df, ignore_index = True,sort=False) 

        step = step + 1



    lr_df = pd.DataFrame(index=[],columns=['lr','step','loss', 'val_loss','acc', 'val_acc'])

    lr_df = lr_df.append(df_val_Acc.mean(),ignore_index = True,sort=False)

    lr_df['lr'] = lr

    

    df_lr_Acc = df_lr_Acc.append(lr_df, ignore_index = True,sort=False)

計算にはすごく時間がかかりましたが、何とか以下の結果が得られました。

display(df_lr_Acc)

 
  lr step loss val_loss acc val_acc
0 0.001 2.0 0.616865 0.629140 0.656589 0.644717
1 0.002 2.0 0.614168 0.626992 0.659109 0.646534
2 0.003 2.0 0.612774 0.626886 0.660399 0.647079
3 0.004 2.0 0.611683 0.622813 0.661034 0.648478
4 0.005 2.0 0.610517 0.622491 0.662487 0.646077
5 0.006 2.0 0.610405 0.627468 0.662440 0.646147
6 0.007 2.0 0.611132 0.625084 0.661896 0.647473
7 0.008 2.0 0.612308 0.627778 0.660742 0.646867
8 0.009 2.0 0.616417 0.631615 0.656790 0.639158
df_lr_Acc[['acc', 'val_acc']].plot()

plt.show()
 

f:id:kanriyou_h004:20190608165947p:plain


三番目のVal_Accが最大になっているので、0.004を学習率として採用する。

4.訓練データをすべて投入し、epoch数を増やしてみて学習後、テストデータでの精度を確認する。

エポック数は100にしてみます。

# ------ 最適化手法 ------

adam = Adam(lr=0.004)

# -----------------------------



model.compile(loss='binary_crossentropy',

              optimizer=adam,

              metrics=['accuracy'])



# 計算の実行

fit = model.fit(X_train, y_train,epochs=100,batch_size=256,validation_data=(X_test, y_test))



# 各epochにおける損失と精度をdfに入れる

df = pd.DataFrame(fit.history)

    

# グラフ化

df[['loss', 'val_loss']].plot()

plt.ylabel('loss')

plt.xlabel('epoch')

plt.show()



df[['acc', 'val_acc']].plot()

plt.ylabel('acc')

plt.xlabel('epoch')

plt.show()

 

f:id:kanriyou_h004:20190608171122p:plain

f:id:kanriyou_h004:20190608171137p:plain

結構、過学習気味(?)ですが、なんとか精度が66%まで改善しました。

前回のLeakageの気づきで大きく手戻りしましたが、ロジスティック回帰で分類した62%から、66%まで改善することができました。

次回は、別のモデルを採用してさらなる改善を目指します。

 

 2019年3月9日(土)にG検定を受験し、見事合格できました!

受験の体験記や勉強法などを別のブログにまとめました。

これから受験される方がいらっしゃいましたらご参考まで。

g-kentei.hatenablog.com