Байесовская оптимизация для легкой модели GBM

Я могу успешно улучшить производительность моей модели XGBoost с помощью байесовской оптимизации, но лучшее, что я могу достичь с помощью байесовской оптимизации при использовании Light GBM (мой предпочтительный выбор), хуже, чем то, что я смог достичь, используя его гиперпараметры по умолчанию. и следуя стандартному подходу к ранней остановке.

При настройке с помощью байесовской оптимизации я обязательно включил гиперпараметры алгоритма по умолчанию в область поиска для справки.

В приведенном ниже коде показана RMSE из модели Light GBM с гиперпараметрами по умолчанию с использованием фрейма данных seaborn diamonds в качестве примера моей работы:

#pip install bayesian-optimization

import seaborn as sns
from sklearn.model_selection import train_test_split
import lightgbm as lgb
from bayes_opt import BayesianOptimization

df = sns.load_dataset('diamonds')

df["color"] = df["color"].astype('category')
df["color_cat"] = df["color"].cat.codes
df = df.drop(["color"],axis = 1)

df["cut"] = df["cut"].astype('category')
df["cut_cat"] = df["cut"].cat.codes
df = df.drop(["cut"],axis = 1)

df["clarity"] = df["clarity"].astype('category')
df["clarity_cat"] = df["clarity"].cat.codes
df = df.drop(["clarity"],axis = 1)

y = df['price']
X = df.drop(['price'], axis=1)

seed = 7
test_size = 0.3
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=test_size,random_state=seed)

train_lgb = lgb.Dataset(X_train, y_train)
eval_lgb = lgb.Dataset(X_test, y_test, reference = train_lgb)

params = { 'objective': 'regression',
  'metric': 'RMSE',
  'learning_rate': 0.02}
lgb_reg = lgb.train(params, train_lgb, num_boost_round = 10000, early_stopping_rounds=50, verbose_eval = 100, valid_sets=eval_lgb)

Результаты

OUT:
Training until validation scores don't improve for 50 rounds.
Early stopping, best iteration is:
[1330 (n_estimators)] valid_0's rmse: 538.728

Вот моя попытка реализовать байесовскую оптимизацию и полученные значения RMSE:

def modelFitter(colsampleByTree, subsample,maxDepth, num_leaves):   
    model = lgb.LGBMRegressor(learning_rate=0.02, n_estimators=10000, max_depth=maxDepth.astype("int32"), subsample=subsample, colsample_bytree=colsampleByTree,num_leaves=num_leaves.astype("int32"))

    evalSet  = [(X_test, y_test)]
    model.fit(X_train, y_train, eval_metric="rmse", eval_set=evalSet, early_stopping_rounds=50, verbose=False)

    bestScore = model.best_score_[list(model.best_score_.keys())[0]]['rmse']

    return -bestScore

# Bounded region of parameter space
pbounds = {'colsampleByTree': (0.8,1.0), 'subsample': (0.8,1.0), 'maxDepth': (2,5), 'num_leaves': (24, 45)}

optimizer = BayesianOptimization(
    f=modelFitter,
    pbounds=pbounds,
    random_state=1)

optimizer.maximize(init_points=5,n_iter=5)  #n_iter=bayesian, init_points=random

Результаты

iter    |  target   | colsam... | maxDepth  | num_le... | subsample |
-------------------------------------------------------------------------
|  1        | -548.7    |  0.8834   |  4.161    |  24.0     |  0.8605   |
|  2        | -642.4    |  0.8294   |  2.277    |  27.91    |  0.8691   |
|  3        | -583.5    |  0.8794   |  3.616    |  32.8     |  0.937    |
|  4        | -548.7    |  0.8409   |  4.634    |  24.58    |  0.9341   |
|  5        | -583.5    |  0.8835   |  3.676    |  26.95    |  0.8396   |
|  6        | -548.7    |  0.8625   |  4.395    |  24.29    |  0.8968   |
|  7        | -548.7    |  0.8435   |  4.603    |  24.42    |  0.9298   |
|  8        | -551.5    |  0.9271   |  4.266    |  24.11    |  0.8035   |
|  9        | -548.7    |  0.8      |  4.11     |  24.08    |  1.0      |
|  10       | -548.7    |  0.8      |  4.44     |  24.45    |  0.9924   |

RMSE (-1 x «цель»), сгенерированный во время байесовской оптимизации, должен быть лучше, чем сгенерированный значениями по умолчанию LightGBM, но я не могу добиться лучшего RMSE (ищу лучше / выше -538,728, достигнутого с помощью вышеупомянутого «нормального» процесс ранней остановки).

MaxDepth и num_leaves должны быть целыми числами; похоже, что существует открытый тикет для обеспечения этого (т.е. ввод «ptypes»): https://github.com/fmfn/BayesianOptimization/pull/131/files

Есть ли причина, по которой байесовская оптимизация, похоже, не находит лучшего решения с LightGBM, но с XGBoost?


person xxyy    schedule 08.05.2019    source источник
comment
какой у вас вопрос, связанный с кодированием? похоже, что это принадлежит обмену статистикой   -  person Yuca    schedule 08.05.2019
comment
Привет, @Yuca! Есть ли что-то в моем вышеупомянутом коде, из-за которого байесовская оптимизация не работает?   -  person xxyy    schedule 08.05.2019
comment
пожалуйста, ответь на мой вопрос. тогда я могу ответить на ваш :)   -  person Yuca    schedule 08.05.2019
comment
@Yuca - Я надеялся, что допустил ошибку в коде, которую можно исправить.   -  person xxyy    schedule 08.05.2019
comment
Привет @Yuca - Я поставил этот вопрос на stats-exchange, но получил от модераторов: отложить как не по теме. Этот вопрос кажется не по теме, потому что он ЛИБО не касается статистики, машинного обучения, анализа данных, интеллектуального анализа данных или визуализации данных, ИЛИ он фокусируется на программировании, отладке или выполнении рутинных операций в рамках платформы статистических вычислений. Кажется, я застрял между ними. Если вы знаете ответ, не могли бы вы поделиться?   -  person xxyy    schedule 09.05.2019
comment
да, я искренне подумал, что у тебя там будет больше шансов. У меня нет ответа для вас, потому что это требует высокой специализации и много свободного времени, чтобы ответить, а это редкость здесь. Так что вам, возможно, придется подождать много времени или опубликовать в codereview   -  person Yuca    schedule 09.05.2019
comment
Вы пытались подогнать LGBMRegressor с параметрами по умолчанию и посмотреть полученные метрики? Причина в том, что значения по умолчанию для собственного API (lgb.train) и scikit-learn API (LGBMRegressor) могут отличаться (они не должны быть такими, но я не уверен, что авторы предоставляют какие-либо гарантии). Кроме того, значение по умолчанию, которое вы используете в собственном API, - max_depth=-1, тогда как ваши границы оптимизации отличаются от этого. Ограничение глубины может привести к другой древовидной структуре   -  person Mischa Lisovyi    schedule 12.05.2019
comment
Привет @ Mykhailo Lisovyi - спасибо за это - изменение max_depth в фунтах работает   -  person xxyy    schedule 13.05.2019


Ответы (2)


Этот вопрос относится к stats.SE; Я бы посоветовал вам спросить на Мета, почему это не актуально. Это может быть слишком широко, так как может быть несколько возможных причин разницы.

1) Дважды убедитесь, что пространство гиперпараметров, которое вы оптимизируете, согласовано в обеих моделях. (параметры фунтов, кажется, сейчас определены только в модели LGBM)

2) Если диапазон области поиска слишком мал, могут быть локальные максимумы при значении по умолчанию, которое обычно является эвристическим, эмпирическим «довольно хорошим» набором значений по умолчанию для начала.

3) Обе модели являются моделями повышения градиента, но у них разные способы определения наилучшего значения разделения. Это означает, что ваше пространство решений может, возможно, разработать различные оптимальные значения с точки зрения алгоритмов, которые могут делать только наилучшее предположение на основе своей данной архитектуры, и если функция оптимизации изменяется, вы можете случайно разработать наилучший вариант. решение при значениях гиперпараметров LGBM по умолчанию.

4) Если вы смотрите на крайне неоптимальное пространство поиска, похожее на небольшое подпространство, вы получите посредственные результаты на максимуме, которые значительно отстают от настроек по умолчанию. (Это похоже на поиск вершины горы в океане, тогда как по умолчанию это может быть какой-то местный холм.)

person Dave Liu    schedule 22.05.2019

Что касается регрессии, мне удалось добиться улучшенных результатов, используя cv-функцию в пакете lightgbm.

Функция черного ящика в моем BayesianOptimization() возвращает минимум l1-среднего.

def black_box_lgbm():
    params = {...} #Your params here
    cv_results = lgb.cv(params, train_data, nfold=5, metrics='mae', verbose_eval = 200, stratified=False)
    return min(cv_results['l1-mean'])

после вызова maximize() на BayesianOptimization() и получения результата с наименьшей ошибкой l1 я повторно обучил модель и сравнил ее со значениями по умолчанию. Это постоянно приводит к более низкой MSE по сравнению со значениями по умолчанию.

person docPersson    schedule 19.01.2021