вступление

Сегодня я собираюсь показать вам, как сжать XGBoost так сильно, чтобы выскочили обе буквы «о». Мы добьемся этого, настроив его гиперпараметры до такой степени, что он больше не сможет bst после предоставления нам всей возможной производительности.

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

Давайте погрузимся!

То, что мы хотели все время…

Глупая модель XGBoost с недостаточным оснащением практически неизвестна. Даже со значениями параметров по умолчанию он довольно хорошо справляется со многими табличными задачами. Тем не менее, его самая большая проблема заключается в чрезмерной подгонке.

Чтобы решить эту проблему, большинство гиперпараметров XGBoost помещаются туда, чтобы приручить лежащего в основе зверя, чтобы он не просто проглотил тренировочный набор и не отрыгнул кости во время тестирования.

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

Следующие параметры имеют решающее значение для контроля переобучения:

  • eta
  • num_boost_round
  • max_depth
  • subsample
  • colsample_bytree
  • gamma
  • min_child_weight
  • lambda
  • alpha

В дополнение к этому мы изучим методы настройки еще нескольких параметров.

Sklearn XGBoost против родного XGBoost

Я действительно борюсь с этими двумя, так как Sklearn — моя любимая библиотека, а XGBoost — мое любимое имя библиотеки (оно идеально подходит для bexgboost — домен занят).

Однако, когда мы рассматриваем объективные факты, собственный API обучения XGBoost предлагает небольшое преимущество перед API Sklearn с точки зрения гибкости и доступа к расширенным и нюансированным функциям.

Я согласен с тем, что Scikit-learn API легко интегрируется с экосистемой Sklearn, включая конвейеры, кросс-валидаторы и другие функции. Но для целей этой статьи мы сосредоточимся на собственном XGBoost API.

Однако для тех, кто твердо настроен на Sklearn API, я также предоставлю псевдонимы гиперпараметров специально для этого интерфейса.

Код для настройки

За два года работы с XGBoost я обнаружил, что код для настройки его гиперпараметров не так сложен, как понимание теории, лежащей в основе каждого параметра, и выбор для них подходящих диапазонов настройки.

Итак, прежде чем я объясню, как работает каждый гиперпараметр и его важность, я оставлю эту ссылку GitHub Gist, чтобы скопировать/вставить ее в вашу собственную работу. Код настроит любую модель XGBoost с перекрестной проверкой и вернет лучшие параметры. Нет необходимости делиться кодом здесь, так как он станет очень нечитаемым на мобильных устройствах.

Для тех, кто хочет понять код и то, как Optuna работает в настройке, я рекомендую эту мою статью (весьма объективный выбор :)



И прежде чем я, наконец, начну объяснять параметры, я также оставлю две таблицы, к которым вы можете обратиться за некоторыми деталями, на запоминание которых не стоит тратить время.

Первый содержит псевдонимы Sklearn параметров и рекомендуемые диапазоны их настройки:

Вы можете использовать таблицу, если хотите использовать тюнер, отличный от Optuna.

А это для взаимодействия между отдельными парами параметров:

Эти отношения не высечены на камне, и на них могут влиять другие параметры. Но они могут дать примерную картину того, что с чем сталкивается в XGBoost.

История 10 параметров

0. objective – нет псевдонима Sklearn

Во-первых, вы должны определить свой путь в лесу, установив objective (XGBoost — это древовидная ансамблевая модель):

objective напрямую влияет на тип деревьев решений и используемую функцию потерь.

1. num_boost_round - n_estimators

После этого вы должны определить количество деревьев решений (часто называемых базовыми учащимися в XGBoost) для посадки во время обучения с использованием num_boost_round. Значение по умолчанию — 100, но этого недостаточно для современных больших наборов данных.

Увеличение параметра приведет к посадке большего количества деревьев, но значительно увеличит вероятность переобучения по мере усложнения модели.

Одна хитрость, которую я узнал от Kaggle, заключается в том, чтобы установить большое число, например 100 000, для num_boost_round и использовать раунды ранней остановки.

В каждом раунде повышения XGBoost сажает еще одно дерево решений, чтобы улучшить общий балл предыдущих. Вот почему это называется усилением. Этот процесс продолжается до num_boost_round раундов, независимо от того, является ли каждый новый раунд улучшением предыдущего или нет.

Но, используя раннюю остановку, мы можем остановить обучение и, следовательно, посадку ненужных деревьев, когда счет не улучшается в течение последних 5, 10, 50 или любого произвольного количества раундов.

С помощью этого трюка мы можем найти идеальное количество деревьев решений, даже не настраивая num_boost_round, и сэкономим время и вычислительные ресурсы. Вот как это будет выглядеть в коде:

# Define the rest of the params
params = {...}

# Build the train/validation sets
dtrain_final = xgb.DMatrix(X_train, label=y_train)
dvalid_final = xgb.DMatrix(X_valid, label=y_valid)

bst_final = xgb.train(
    params,
    dtrain_final,
    num_boost_round=100000 # Set a high number
    evals=[(dvalid_final, "validation")],
    early_stopping_rounds=50, # Enable early stopping
    verbose_eval=False,
)

Приведенный выше код заставил бы XGBoost использовать 100 тыс. деревьев решений, но из-за ранней остановки он остановится, когда оценка проверки не улучшится в течение последних 50 раундов. Обычно количество требуемых деревьев будет меньше 5000–10000.

Контроль num_boost_round также является одним из важнейших факторов, влияющих на продолжительность процесса обучения, поскольку большее количество деревьев требует больше ресурсов.

2. eta - learning_rate

В каждом раунде все существующие деревья возвращают предсказание на заданном входе. Например, в пятом раунде бустинга пять деревьев могут вернуть следующие прогнозы для выборки N:

  1. Дерево 1: 0,57
  2. Дерево 2: 0,9
  3. Дерево 3: 4,25
  4. Дерево 4: 6,4
  5. Дерево 5: 2.1

Чтобы вернуть окончательный прогноз, эти выходные данные необходимо суммировать, но перед этим XGBoost сжимает или масштабирует их, используя параметр под названием eta или скорость обучения. После масштабирования окончательный результат будет таким:

output = eta * (0.57 + 0.9 + 4.25 + 6.4 + 2.1)

Большая скорость обучения придает больший вес вкладу каждого дерева в ансамбль, но это может привести к переобучению/нестабильности, но к более быстрому обучению. И наоборот, более низкая скорость обучения ослабляет вклад каждого дерева, делая процесс обучения медленнее, но более надежным.

Этот эффект регуляризации параметра скорости обучения особенно полезен для сложных и зашумленных наборов данных.

Скорость обучения имеет обратную зависимость с другими параметрами, такими как num_boost_round, max_depth, subsample и colsample_bytree. Более низкая скорость обучения требует более высоких значений этих параметров и наоборот. Но вам не нужно беспокоиться о взаимодействии между этими параметрами, так как программа настройки гиперпараметров найдет наилучшее сочетание.

3, 4. subsample и colsample_bytree

Подвыборка — это форма бэггинга, которая вносит больше случайности в обучение и, следовательно, помогает бороться с переоснащением.

subsample=0.7 означает, что каждое дерево решений в ансамбле будет обучаться на 70% доступных данных, выбранных случайным образом. Значение 1,0 указывает, что будут использоваться все строки (без подвыборки).

Подобно subsample, есть также colsample_bytree. Как следует из названия, colsample_bytree управляет долей функций, которые будет использовать каждое дерево решений. colsample_bytree=0.8 заставляет каждое дерево использовать случайные 80% доступных функций (столбцов) в каждом дереве.

Настройка этих двух параметров позволяет контролировать компромисс между смещением и дисперсией. Использование меньших значений снижает корреляцию между деревьями и увеличивает разнообразие в ансамбле, что может помочь улучшить обобщение и уменьшить переоснащение.

Однако это также может привести к большему количеству шума и увеличению смещения модели. И наоборот, использование больших значений увеличивает корреляцию между деревьями, уменьшая разнообразие и потенциально приводя к переоснащению.

5. max_depth

Максимальная глубина определяет максимальное количество уровней, которых может достичь дерево решений во время обучения.

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

Чтобы контролировать эту сложность, max_depth можно ограничить, что приведет к более мелким, более простым деревьям и захвату более общих закономерностей.

max_depth — отличный баланс между сложностью и обобщением.

6, 7. alpha, lambda

alpha (L1) и lambda (L2) — еще два параметра регуляризации, помогающие при переоснащении.

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

На эффект alpha и lambda могут влиять другие параметры, такие как max_depth, subsample и colsample_bytree. Более высокие значения alpha или lambda могут потребовать корректировки других параметров, чтобы компенсировать усиление регуляризации. Например, более высокое значение alpha может выиграть от большего значения subsample для поддержания разнообразия моделей и предотвращения недообучения.

8. gamma

Если вы читаете документы XGBoost, там говорится, что gamma это:

минимальное снижение потерь, необходимое для создания дальнейшего раздела на листовом узле дерева.

Я думаю, что это предложение не имеет смысла ни для кого, кроме человека, который его написал. Давайте сломаем это.

Ниже представлено дерево решений с двумя уровнями:

Чтобы оправдать добавление дополнительных слоев в дерево путем разделения листовых узлов, XGBoost должен рассчитать, что эта операция должна значительно снизить функцию потерь.

Но «насколько существенно?» — спросите вы. Здесь мы устанавливаем gamma — он действует как порог для принятия решения о том, следует ли далее разбивать конечный узел.

Если функция сокращения потерь (часто называемая выигрыш) меньше выбранной gamma после потенциального разделения, то разделение не выполняется. Это означает, что конечный узел останется прежним, и с этого момента дерево не будет расти.

Таким образом, цель настройки gamma состоит в том, чтобы найти наилучшие разбиения, которые приводят к наибольшему снижению функции потерь, что означает улучшение производительности модели.

9. min_child_weight

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

Затем, когда XGBoost выбирает потенциальные функции и критерии разделения, которые приводят к наибольшему снижению потерь, более глубокие узлы будут содержать все меньше и меньше экземпляров.

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

Вот почему XGBoost позволяет пользователям установить порог минимального количества экземпляров в каждом узле для продолжения разделения. Чтобы определить это, все экземпляры в узле взвешиваются и находятся суммы весов. Затем, если этот окончательный вес меньше min_child_weight, разделение останавливается, и узел становится листовым узлом.

Несмотря на то, что это объяснение сильно упрощает весь процесс, оно должно дать вам общее представление.

Заключение

Несмотря на то, что мы рассмотрели много теории, нам еще многое предстоит узнать. Я предлагаю дать ChatGPT следующие две подсказки:

1) Explain the {parameter_name} XGBoost parameter in detail and how to choose values for it wisely.

2) Describe how {parameter_name} fits into the step-by-step tree-building process of XGBoost.

Я хочу оставить последнее примечание о том, что вы должны использовать как перекрестную проверку, так и исходный окончательный набор тестов для тестирования производительности модели после настройки.

Вы можете разделить свои данные 80/20 и настроить XGBoost на 80% с 5–7-кратным коэффициентом вариации, и как только будут найдены лучшие параметры, в последний раз измерить производительность на нетронутых 20%. Это гарантирует, что полученные результаты будут максимально надежными.

Не забудьте использовать GitHub gist code для настройки. Спасибо за чтение!

Понравилась эта статья и, скажем прямо, ее причудливый стиль написания? Представьте себе, что у вас есть доступ к десяткам таких же, написанных блестящим, обаятельным, остроумным автором (кстати, это я :).

Всего за 4,99 $ членства вы получите доступ не только к моим историям, но и к сокровищнице знаний от лучших и самых ярких умов на Medium. А если вы воспользуетесь моей реферальной ссылкой, то получите мою сверхновую благодарность и виртуальную пятерку за поддержку моей работы.