← Назад к вопросам
Почему градиентный бустинг называется градиентным?
2.0 Middle🔥 181 комментариев
#Машинное обучение
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Почему градиентный бустинг называется градиентным?
Короткий ответ
Потому что каждое новое дерево обучается на градиентах ошибок предыдущих деревьев. Градиент — это производная функции потерь, которая показывает направление минимизации ошибки.
Что такое градиент?
Градиент функции — это вектор частных производных, показывающий направление и скорость наибольшего возрастания функции.
# Для функции потерь L(y, y_pred) = (y - y_pred)^2
# Градиент: dL/dy_pred = -2*(y - y_pred)
# Если y=100, y_pred=90, то:
# dL/dy_pred = -2*(100-90) = -20
# Это значит: увеличивайте y_pred на 20, чтобы уменьшить ошибку
Как работает обучение
Итерация 1: первое дерево
from sklearn.tree import DecisionTreeRegressor
y_pred_1 = tree_1.predict(X)
errors_1 = y - y_pred_1 # ошибки
Итерация 2: считаем градиент и учим новое дерево
# Градиент показывает, на сколько нужно увеличить y_pred
gradient = -dL/dy_pred = -(-2*errors_1) = 2*errors_1
# ИЛИ можно просто использовать остатки (для MSE это одно и то же)
gradient = errors_1
# Теперь обучаем второе дерево НА ГРАДИЕНТАХ
tree_2.fit(X, gradient) # не на (X, y), а на (X, gradient)
y_pred_2_from_tree = tree_2.predict(X)
y_pred_combined = y_pred_1 + learning_rate * y_pred_2_from_tree
Итерация 3: повторяем
errors_2 = y - y_pred_combined
gradient_2 = errors_2 # новые градиенты
tree_3.fit(X, gradient_2)
y_pred_combined += learning_rate * tree_3.predict(X)
Почему именно градиент, а не просто остатки?
Универсальность — вот ключевое слово.
# Для регрессии (MSE):
L = (y - y_pred)^2
gradient = -dL/dy_pred = -2*(y - y_pred) # просто остаток × (-2)
# Для классификации (LogLoss):
L = -[y*log(y_pred) + (1-y)*log(1-y_pred)]
gradient = -dL/dy_pred = y_pred - y # совсем другое
# Для кастомной функции потерь (например, квантильная регрессия):
# gradient = something_else
# Но ЛЮБАЯ дифференцируемая функция потерь имеет градиент
# Вот почему это универсально
Пример кода
import numpy as np
from sklearn.tree import DecisionTreeRegressor
def gradient_boosting_example(X, y, n_trees=5, lr=0.1):
"""Упрощённая реализация градиентного бустинга"""
predictions = np.zeros(len(y))
for iteration in range(n_trees):
# Шаг 1: считаем ошибки
residuals = y - predictions
# Шаг 2: считаем градиент потерь L = (y - y_pred)^2
# dL/dy_pred = -2 * (y - y_pred) = -2 * residuals
# ИЛИ просто используем остатки (результат похож)
gradients = residuals # целевые значения для дерева
# Шаг 3: обучаем дерево предсказывать градиенты
tree = DecisionTreeRegressor(max_depth=3)
tree.fit(X, gradients)
# Шаг 4: обновляем предсказания
tree_predictions = tree.predict(X)
predictions += lr * tree_predictions # с learning rate
# Шаг 5: считаем MSE
mse = np.mean((y - predictions) ** 2)
print(f"Итерация {iteration+1}: MSE = {mse:.4f}")
return predictions
Сравнение: AdaBoost vs Gradient Boosting
AdaBoost (взвешивание ошибок):
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Дерево 1: L1 ошибок
↓
Дерево 2: переобучаем на ОШИБОЧНЫХ объектах (весим их выше)
↓
Дерево 3: переобучаем на неправильных объектах Дерева 2
✗ Работает только для определённых функций потерь
✗ Не универсален
Gradient Boosting:
━━━━━━━━━━━━━━━
Дерево 1: обучаемся на (X, y)
↓
Считаем gradient = -dL/dy_pred ← производная функции потерь
↓
Дерево 2: обучаемся на (X, gradient)
↓
Повторяем
✓ Работает для ЛЮБОЙ дифференцируемой функции потерь
✓ Универсален
✓ Более мощный
Реальные реализации
# XGBoost использует градиент И гессиан (вторую производную)
from xgboost import XGBRegressor
model = XGBRegressor()
model.fit(X_train, y_train)
# Внутри XGBoost использует:
# gradient = -dL/dy_pred
# hessian = d²L/dy_pred²
# Это позволяет оптимизировать ещё эффективнее
# LightGBM делает почти то же
from lightgbm import LGBMRegressor
model = LGBMRegressor()
model.fit(X_train, y_train)
Математическое обоснование
Мы минимизируем: L(y, y_pred) = Σ(y_i - y_pred_i)²
Оптимизация методом градиентного спуска:
y_pred_new = y_pred_old - learning_rate * ∇L
Где ∇L = dL/dy_pred (градиент потерь)
В бустинге:
y_pred_new = y_pred_old + learning_rate * f(X)
Где f(X) — новое дерево, обученное на градиентах
Это эквивалентно шагу градиентного спуска!
Заключение
Градиентный бустинг зовется "градиентным", потому что:
- Использует градиент (производную) функции потерь
- Каждое новое дерево учится приблизительно вычислять градиент
- Это обновление эквивалентно шагу градиентного спуска
- Работает с ЛЮБОЙ дифференцируемой функцией потерь
Это мощнее и универсальнее, чем просто переобучение на ошибках (AdaBoost).