驚くほど簡単な技術系健忘録

驚くほど簡単な技術系健忘録

アプリやWebサービス、RPAを作る上での健忘録を書いていきます。

Optunaでパラメータチューニングしてみた【第一弾】

rin-effort.com

このサイトを参考にOptunaでパラメータチューニングを初めてやってみた。
参考サイトは別のCSVのデータで行っていますが、こちらの記事ではsklearnに入っているデータを利用してみた。

参考サイトですごいなと思ったのは他のサイトであるあるな感じでoptunaで普通に単純にパラメータを出すだけではなく、rmse値を最小化するようにパラメータをチューニングする以下の関数

def objective(trial):
    params = {'metric': {'rmse'},
              'max_depth' : trial.suggest_int('max_depth', 1, 10),
              'subsumple' : trial.suggest_uniform('subsumple', 0.0, 1.0),
              'subsample_freq' : trial.suggest_int('subsample_freq', 0, 1),
              'leaning_rate' : trial.suggest_loguniform('leaning_rate', 1e-5, 1),
              'feature_fraction' : trial.suggest_uniform('feature_fraction', 0.0, 1.0),
              'lambda_l1' : trial.suggest_uniform('lambda_l1' , 0.0, 1.0),
              'lambda_l2' : trial.suggest_uniform('lambda_l2' , 0.0, 1.0)}
 
    gbm = lgb.train(params,
                    lgb_train,
                    valid_sets=(lgb_train, lgb_eval),
                    num_boost_round=10000,
                    early_stopping_rounds=100,
                    verbose_eval=50)
    predicted = gbm.predict(X_test)
    RMSE = np.sqrt(mean_squared_error(y_test, predicted))
    
    pruning_callback = optuna.integration.LightGBMPruningCallback(trial, 'rmse')
    return RMSE

を作っていたのが非常に面白かったので利用してみました。

以下がコードの全貌です。

#データセット用のライブラリ
from sklearn import datasets, model_selection

#データ分析用のライブラリ
import pandas as pd
import numpy as np

#データ可視化ライブラリ
import matplotlib.pyplot as plt
import seaborn as sns

#LightGBMライブラリ
import lightgbm as lgb

#訓練データとモデル評価用データに分けるライブラリ
from sklearn.model_selection import train_test_split

#ハイパーパラメータチューニング自動化ライブラリ
import optuna

#関数処理で必要なライブラリ
from sklearn.metrics import mean_squared_error
from sklearn.metrics import r2_score

#その他
from sklearn import metrics

#データ準備
features, labels = datasets.load_boston(return_X_y = True)
#データ分割
X_train,X_test,y_train,y_test = train_test_split(features, labels, test_size=0.2)

#LightGBM用のデータセットに加工
lgb_train = lgb.Dataset(X_train, y_train)
lgb_eval = lgb.Dataset(X_test, y_test)

#optunaへ入れる情報をまとめた関数
def objective(trial):
    params = {'metric': {'rmse'},
              'max_depth' : trial.suggest_int('max_depth', 1, 10),
              'subsumple' : trial.suggest_uniform('subsumple', 0.0, 1.0),
              'subsample_freq' : trial.suggest_int('subsample_freq', 0, 1),
              'leaning_rate' : trial.suggest_loguniform('leaning_rate', 1e-5, 1),
              'feature_fraction' : trial.suggest_uniform('feature_fraction', 0.0, 1.0),
              'lambda_l1' : trial.suggest_uniform('lambda_l1' , 0.0, 1.0),
              'lambda_l2' : trial.suggest_uniform('lambda_l2' , 0.0, 1.0)}
 
    gbm = lgb.train(params,
                    lgb_train,
                    valid_sets=(lgb_train, lgb_eval),
                    num_boost_round=1000,
                    early_stopping_rounds=100,
                    verbose_eval=300)
    predicted = gbm.predict(X_test)
    RMSE = np.sqrt(mean_squared_error(y_test, predicted))
    
    pruning_callback = optuna.integration.LightGBMPruningCallback(trial, 'rmse')
    return RMSE

#optunaの起動
study = optuna.create_study()
study.optimize(objective, timeout = 60)

print('Best trial:')
trial = study.best_trial
print('Value:{}'.format(trial.value))
print('Paramas:')
for key, value in trial.params.items():
    print(',"{}":{}'.format(key, value))

#予測値と正解値を描写する関数
def True_Pred_map(pred_df):
    RMSE = np.sqrt(mean_squared_error(pred_df['true'], pred_df['pred']))
    R2 = r2_score(pred_df['true'], pred_df['pred']) 
    plt.figure(figsize=(8,8))
    ax = plt.subplot(111)
    ax.scatter('true', 'pred', data=pred_df)
    ax.set_xlabel('True Value', fontsize=15)
    ax.set_ylabel('Pred Value', fontsize=15)
    ax.set_xlim(pred_df.min().min()-0.1 , pred_df.max().max()+0.1)
    ax.set_ylim(pred_df.min().min()-0.1 , pred_df.max().max()+0.1)
    x = np.linspace(pred_df.min().min()-0.1, pred_df.max().max()+0.1, 2)
    y = x
    ax.plot(x,y,'r-')
    plt.text(0.1, 0.9, 'RMSE = {}'.format(str(round(RMSE, 5))), transform=ax.transAxes, fontsize=15)
    plt.text(0.1, 0.8, 'R^2 = {}'.format(str(round(R2, 5))), transform=ax.transAxes, fontsize=15)

#Optunaで最適化されたパラメータ
params = {
    "metric": {'rmse'}
    ,"max_depth":4
    ,"subsumple":0.5654007940457206
    ,"subsample_freq":0
    ,"leaning_rate":0.00017894703178220227
    ,"feature_fraction":0.5230674363641012
    ,"lambda_l1":0.7312452385011556
    ,"lambda_l2":0.021966875171314314
}

#LightGBMのモデル構築
model = lgb.train(
    params
    ,lgb_train
    ,valid_sets=(lgb_train, lgb_eval)
    ,num_boost_round=10000
    ,early_stopping_rounds=100
    ,verbose_eval=300
)

#モデル評価用データで予測値出力
y_pred = model.predict(X_test)

#可視化関数にぶち込めるように予測値と正答値をデータフレームに加工
pred_df = pd.concat([pd.Series(y_test), pd.Series(y_pred)], axis=1)
pred_df.columns = ['true', 'pred']

#可視化関数を実行
True_Pred_map(pred_df)

# 特徴量の重要度をプロット
lgb.plot_importance(model)


何もしていないのに結構精度が良くてさすがLightGBMとOptunaですね。
f:id:nade_nadegata:20210607001724p:plain