#はじめに
機械学習とベイズ最適化の勉強のために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入門