optunaとkerasとtitanic

#はじめに
機械学習とベイズ最適化の勉強のためにｋ、kaggleのチュートリアル的なコンペ「Titanic: Machine Learning from Disaster」をニューラルネットワークでスコアを出してみました。
ハイパラ最適化には、Preferred Networksの[optunaライブラリ(公式サイト)](https://preferred.jp/ja/projects/optuna/ 'optunaライブラリ')を使っています。
#結果
Public Score : 0.7655

#ノート
kaggleノートのリンクを貼っときます。
[kaggleノート](https://www.kaggle.com/pgogavi/notebookf56f390b43 "ノート")
#コード
##前処理
まずは欠損地処理と関係なさそうな特徴量の削除の前処理です。勘で行いました。

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

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

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

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

```python
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で最適化します。

```python
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)`としてやれば良いです。

```python
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秒かかりました。

```python
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, )
```

最適化の結果を見ます。


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

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

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

0.17937219142913818

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


```python
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に出力して完了です。

 ```python
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入門](https://qiita.com/studio_haneya/items/2dc3ba9d7cafa36ddffa'Optuna入門')