LoginSignup
0
2

More than 3 years have passed since last update.

optunaとkerasとtitanic

Last updated at Posted at 2020-10-12

はじめに

機械学習とベイズ最適化の勉強のためにk、kaggleのチュートリアル的なコンペ「Titanic: Machine Learning from Disaster」をニューラルネットワークでスコアを出してみました。
ハイパラ最適化には、Preferred Networksのoptunaライブラリ(公式サイト)を使っています。

結果

Public Score : 0.7655

ノート

kaggleノートのリンクを貼っときます。
kaggleノート

コード

前処理

まずは欠損地処理と関係なさそうな特徴量の削除の前処理です。勘で行いました。

train = train.fillna({'Age':train['Age'].mean()})
X_df = train.drop(columns=['PassengerId','Survived', 'Name', 'Ticket', 'Cabin', 'Embarked'])
y_df = train['Survived']

次は、ダミー変数の取得です。

X_df = X_df.replace('male', 0)
X_df = X_df.replace('female', 1)

データを訓練用と評価用に分けます。

from sklearn.model_selection import train_test_split
X_train, X_val, y_train, y_val = train_test_split(X_df.values, y_df.values, test_size=0.25, shuffle=True, random_state=0)

X_trainの中身を見てみます。カラム名は、Pclass,Sex,Age,SibSp,Parch,Fareです。

[[ 3.          0.         28.          0.          0.          7.8958    ]
 [ 3.          1.         17.          4.          2.          7.925     ]
 [ 3.          0.         30.          1.          0.         16.1       ]
 ...
 [ 3.          0.         29.69911765  0.          0.          7.7333    ]
 [ 3.          1.         36.          1.          0.         17.4       ]
 [ 2.          0.         60.          1.          1.         39.        ]]

ニューラルネットワーク

ニューラルネットワークモデルを組んでいきます。全結合層のみです。隠れ層の数やユニット数の数もoptunaで最適化します。

def create_model(activation, num_hidden_layer, num_hidden_unit):
    inputs = Input(shape=(X_train.shape[1],))
    model = inputs
    for i in range(1,num_hidden_layer):
        model = Dense(num_hidden_unit, activation=activation,)(model)


    model = Dense(1, activation='sigmoid')(model)
    model = Model(inputs, model)

    return model

optunaで最適化するパラメータの範囲を決めます。関数の返り値を最小化もしくは最大化してくれます。デフォルトでは最小化になっています。最大化したい場合は後ほど出てくる、create_study('direction = maximize)としてやれば良いです。

def objective(trial):
    K.clear_session()

    activation = trial.suggest_categorical('activation',['relu','tanh','linear'])
    optimizer = trial.suggest_categorical('optimizer',['adam','rmsprop','adagrad', 'sgd'])


    num_hidden_layer = trial.suggest_int('num_hidden_layer',1,5,1)
    num_hidden_unit = trial.suggest_int('num_hidden_unit',10,100,10)



    learning_rate = trial.suggest_loguniform('learning_rate', 0.00001,0.1)
    if optimizer == 'adam':
      optimizer = Adam(learning_rate=learning_rate)
    elif optimizer == 'adagrad':
      optimizer = Adagrad(learning_rate=learning_rate)
    elif optimizer =='rmsprop':
      optimizer = RMSprop(learning_rate=learning_rate)
    elif optimizer =='sgd':
      optimizer = SGD(learning_rate=learning_rate)


    model = create_model(activation, num_hidden_layer, num_hidden_unit)
    model_list.append(model)
    model.compile(optimizer=optimizer, loss='binary_crossentropy', metrics=['acc', 'mape'],)

    es = EarlyStopping(monitor='val_acc', patience=50)
    history = model.fit(X_train, y_train, validation_data=(X_val, y_val), verbose=0, epochs=200, batch_size=20, callbacks=[es])


    history_list.append(history)

    val_acc = np.array(history.history['val_acc'])

    return 1-val_acc[-1]

学習と最適化を行います。最適化のあとで、再度学習しやすい用に各モデルをリストに格納しました。約6分12秒かかりました。

model_list=[]
history_list=[]
study_name = 'titanic_study'
study = optuna.create_study(study_name=study_name,storage='sqlite:///../titanic_study.db', load_if_exists=True)
study.optimize(objective, n_trials=50, )

最適化の結果を見ます。

print(study.best_params)
print('')
print(study.best_value)

最適化の結果です。
雑で申し訳ないです。
上が各ハイパラ、下が正答率です。

{'activation': 'relu', 'learning_rate': 0.004568302718922509, 'num_hidden_layer': 5, 'num_hidden_unit': 50, 'optimizer': 'rmsprop'}

0.17937219142913818

テストデータを用いて予測します。その前に、ベストパラメータで十分な量の学習を行います。テストデータの前処理は、ほぼ学習用データの同じですが、PassengerIdは、スコア提出用に別データフレームに取っておきます。

model_list[study.best_trial._number-1].compile(optimizer=study.best_trial.params['optimizer'], loss='binary_crossentropy', metrics=['acc', 'mape'],)  
es = EarlyStopping(monitor='val_acc', patience=100)
history = model_list[study.best_trial._number-1].fit(X_train, y_train, validation_data=(X_val, y_val), verbose=1, epochs=400, batch_size=20, callbacks=[es])
predicted = model_list[study.best_trial._number-1].predict(X_test.values)
predicted_survived = np.round(predicted).astype(int)

予測結果

乗船者と生存予測結果を紐づけて、csvに出力して完了です。

df = pd.concat([test_df_index,pd.DataFrame(predicted_survived, columns=['Survived'])], axis=1)
df.to_csv('gender_submission.csv', index=False)
df
PassengerId Survived
0 892 0
1 893 0
2 894 0
3 895 0
4 896 0
... ... ...
413 1305 0
414 1306 1
415 1307 0
416 1308 0
417 1309 0

418 rows × 2 columns

Public Score : 0.7655

感想

微妙な結果でした。でも非常に楽でした。この先ずっと、optunaに頼ってしまいそうで、チューニングの技術力が上がらないことが心配です。すべて、自動最適化してしまっていいんでしょうか。

参考サイト

非常に分かりやすくて参考になりました。
Optuna入門

0
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2