Настраиваем кондиции модели с 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}')Первое значение соответствует модели с подобранными параметрами, а второе - с параметрами по умолчанию.