Настраиваем кондиции модели с Optuna
В этой статье я расскажу об эффективном способе прохождения одного из необходимых этапов создания модели машинного обучения - подборе ее гиперпараметров. При этом остановимся на гибком интерфейсе решения этой задачи (Ask-and-Tell), реализованном в библиотеке Optuna.
Демонстрацию будем проводить на примере тренировочного набора данных, созданного функцией make_regression библиотеки scikit-learn. В качестве алгоритма используется LightGBM, метрикой качества выступает mape на валидационной выборке. Интерфейс Ask-and-Tell предполагает создание объекта study вызовом функции optuna.create_study, который управляет оптимизацией и хранит ее результаты. Затем посредством вызовов методов ask и tell объекта study происходит инициализация каждой попытки (trial) одним из наборов параметров и возврат результата в study. Итоговые параметры модели становятся доступными по окончании оптимизации в атрибуте best_params. Ниже представлен код, реализующий описанную логику:
import optuna import lightgbm as lgb from sklearn.model_selection import train_test_split from sklearn.metrics import mean_absolute_percentage_error from sklearn.datasets import make_regression data, target = make_regression(n_samples=10000, n_features=12, n_informative=12, n_targets=1, random_state=1) X_tr, X_val, y_tr, y_val = train_test_split(data, target, test_size=0.2) study = optuna.create_study() n_trials = 100 for _ in range(n_trials): trial = study.ask() params={'verbosity':-1, 'lambda_l2':trial.suggest_float('lambda_l2', 0.01, 0.2), 'max_depth':trial.suggest_int('max_depth', 5, 55, step=5), 'num_leaves':trial.suggest_int('num_leaves', 5, 45, step=5), 'learning_rate':trial.suggest_float('learning_rate',0.05, 0.25, step=0.05), 'bagging_fraction': trial.suggest_float('bagging_fraction', 0.7, 0.9 , step=0.1) } reg = lgb.LGBMRegressor(**params) reg.fit(X_tr, y_tr) y_pr = reg.predict(X_val) mape = mean_absolute_percentage_error(y_val, y_pr) study.tell(trial, mape)
Теперь сделаем это же, но на примере кросс-валидации и сравним результаты на отложенной выборке:
import optuna import lightgbm as lgb from sklearn.model_selection import train_test_split, KFold from sklearn.metrics import mean_absolute_percentage_error import numpy as np from sklearn.datasets import make_regression data, target = make_regression(n_samples=10000, n_features=12, n_informative=12, n_targets=1, random_state=1) X, X_ts, y, y_ts = train_test_split(data, target, test_size=0.2) n_trials=10 study = optuna.create_study() for _ in range(n_trials): kf = KFold(n_splits=3) trial = study.ask() params={'verbosity':-1, 'lambda_l2':trial.suggest_float('lambda_l2', 0.01, 0.2), 'max_depth':trial.suggest_int('max_depth', 5, 55, step=5), 'num_leaves':trial.suggest_int('num_leaves', 5, 45, step=5), 'learning_rate':trial.suggest_float('learning_rate',0.05, 0.25, step=0.05), 'bagging_fraction': trial.suggest_float('bagging_fraction', 0.7, 0.9 , step=0.1) } reg = lgb.LGBMRegressor(**params) mape_l = [] for tr_idx, val_idx in kf.split(X): X_tr, X_val = X[tr_idx], X[val_idx] #X_tr, X_val = X.iloc[tr_idx], X.iloc[val_idx] y_tr, y_val = y[tr_idx], y[val_idx] # y_tr, y_val = y.iloc[tr_idx], y.iloc[val_idx] reg.fit(X_tr, y_tr) y_pr = reg.predict(X_val) mape_l.append(mean_absolute_percentage_error(y_val, y_pr)) mape = np.mean(mape_l) study.tell(trial, mape) reg = lgb.LGBMRegressor(**study.best_params) reg.fit(X, y) y_pr = reg.predict(X_ts) mape = mean_absolute_percentage_error(y_ts, y_pr) reg2 = lgb.LGBMRegressor() reg2.fit(X, y) y_pr2 = reg2.predict(X_ts) mape2 = mean_absolute_percentage_error(y_ts, y_pr2) print(f'mape - {mape}\nmape2 - {mape2}')
Первое значение соответствует модели с подобранными параметрами, а второе - с параметрами по умолчанию.