Как регуляризуется градиентный бустинг?

«Как регуляризуется градиентный бустинг?» — вопрос из категории Деревья и ансамбли, который задают на 26% собеседований Data Scientist / ML Инженер. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

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

Стратегии регуляризации, которые я использую:

  1. Регуляризация самих деревьев (базовых learners):

    • max_depth / num_leaves: Жёстко ограничиваю глубину или количество листьев.
    • min_child_weight (XGB) / min_data_in_leaf (LGBM): Задаю минимальную сумму весов (или количество объектов) в листе, чтобы не создавать слишком специфичные разделения.
    • gamma (XGB): Минимальное снижение потерь для выполнения split.
  2. L1 и L2 регуляризация на веса листьев:

    • reg_alpha (L1) и reg_lambda (L2) в XGBoost. lambda_l1, lambda_l2 в LightGBM.
    • L1 может занулять веса некоторых листьев, действуя как отбор признаков на уровне дерева.
  3. Стохастические методы:

    • subsample: Обучаю каждое дерево на случайной подвыборке данных (например, 0.8).
    • colsample_bytree, colsample_bylevel, colsample_bynode: Случайно выбираю подмножество признаков для всего дерева, уровня или каждого разделения.
  4. Контроль скорости обучения:

    • Небольшой learning_rate (например, 0.01-0.1) в сочетании с большим числом n_estimators. Это требует больше итераций, но делает процесс обучения более плавным и устойчивым.
  5. Ранняя остановка (Early Stopping):

    • Это мой основной инструмент. Я всегда выделяю валидационную выборку и останавливаю обучение, когда её метрика перестаёт улучшаться.

Пример настройки регуляризованной модели в XGBoost:

import xgboost as xgb
from sklearn.model_selection import train_test_split

X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2)

dtrain = xgb.DMatrix(X_train, label=y_train)
dval = xgb.DMatrix(X_val, label=y_val)

params = {
    'objective': 'binary:logistic',
    'max_depth': 4,               # Неглубокие деревья
    'min_child_weight': 5,        # Минимум объектов в листе
    'subsample': 0.8,             # Стохастичность по объектам
    'colsample_bytree': 0.8,      # Стохастичность по признакам
    'eta': 0.05,                  # Малая скорость обучения
    'reg_alpha': 0.1,             # L1 регуляризация
    'reg_lambda': 1.5,            # L2 регуляризация
    'eval_metric': 'logloss'
}

evals = [(dtrain, 'train'), (dval, 'eval')]
model = xgb.train(params, dtrain, num_boost_round=1000,
                  evals=evals, early_stopping_rounds=50, verbose_eval=50)