梯度提升Gradient Boosting
总览#
Gradient Boosting 梯度提升,是一种强大的 ML 技术,用于回归和分类问题。
弱学习算法通常更易发现、更易训练。Boosting 系列算法的基本思想是将弱基础模型组合为一个强大的集成。
Gradient Boosting 的基本思想是:不断重复生成弱学习器,每次生成弱学习器的目标是拟合先前累加模型的损失函数的负梯度, 使组合上该弱学习器后的累积模型 损失往负梯度的方向减少。
Gradient Boosting 概述#
约定以下符号:
- 输入
输出 - 模型
- 弱模型
- 损失函数
由于 Gradient Boosting 会依次训练出
个模型,所以用下标 区分它们。
在 Gradient Boosting 中,我们对 损失函数相对于模型输出的导数 感兴趣:
为了训练出下一个弱模型
很容易令人联想到均方误差
。可以说,获得弱模型就是使用 MSE 损失函数拟合负梯度 。
借助弱模型
如此,一直重复获得
第一个弱模型#
第一个弱模型通常只是一个常数
对于 MSE 损失,这个
就是 的均值。
Gradient Boosting 的步骤#
有了以上的认识,应当能理解 Gradient Boosting 算法流程:
- 初始化一个常数模型
- 拟合模型的负梯度,获得一个弱模型
- 用弱模型更新模型
- 回到 step.2
实现#
以下一个示例,从输入 x
预测 sigma
和 mu
。
可见使用到了 DecisionTreeRegressor
。这个学习器易训练,很适合堆叠。
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.tree import DecisionTreeRegressor
from sklearn.linear_model import LinearRegression
from sklearn.datasets import fetch_california_housing
from sklearn.model_selection import train_test_split
import torch
from torch.distributions.normal import Normal
from torch.autograd import Variable
from typing import List, Optional
class GaussianGradientBoosting:
def __init__(self,
learning_rate: float = 0.025,
max_depth: int = 1,
n_estimators: int =100):
self.learning_rate: float = learning_rate
self.max_depth: int = max_depth
self.n_estimators: int = n_estimators
self.init_mu: Optional[float] = None
self.mu_trees: List[DecisionTreeRegressor] = []
self.init_sigma: Optional[float] = None
self.sigma_trees: List[DecisionTreeRegressor] = []
self.is_trained: bool = False
def predict(self, X: np.array) -> np.array:
assert self.is_trained
mus = self._predict_mus(X).reshape(-1,1)
log_sigmas = np.exp(self._predict_log_sigmas(X).reshape(-1,1))
return np.concatenate([mus, log_sigmas], 1)
def _predict_raw(self, X: np.array) -> np.array:
assert self.is_trained
mus = self._predict_mus(X).reshape(-1,1)
log_sigmas = self._predict_log_sigmas(X).reshape(-1,1)
return np.concatenate([mus, log_sigmas], 1)
def fit(self, X: np.array, y: np.array) -> None:
self._fit_initial(y)
self.is_trained = True
for _ in range(self.n_estimators):
y_pred = self._predict_raw(X)
gradients = self._get_gradients(y, y_pred)
mu_tree = DecisionTreeRegressor(max_depth=self.max_depth)
mu_tree.fit(X, gradients[:,0])
self.mu_trees.append(mu_tree)
sigma_tree = DecisionTreeRegressor(max_depth=self.max_depth)
sigma_tree.fit(X, gradients[:,1])
self.sigma_trees.append(sigma_tree)
def _fit_initial(self, y: np.array) -> None:
assert not self.is_trained
self.init_mu = np.mean(y)
self.init_sigma = np.log(np.std(y))
def _get_gradients(self, y: np.array, y_pred: np.array) -> np.array:
y_torch = torch.tensor(y).float()
y_pred_torch = Variable(torch.tensor(y_pred).float(), requires_grad=True)
normal_dist = Normal(y_pred_torch[:,0], torch.exp(y_pred_torch[:,1])).log_prob(y_torch).sum()
normal_dist.backward()
return y_pred_torch.grad.numpy()
def _predict_mus(self, X: np.array) -> np.array:
output = np.zeros(len(X))
output += self.init_mu
for tree in self.mu_trees:
output += self.learning_rate * tree.predict(X)
return output
def _predict_log_sigmas(self, X: np.array) -> np.array:
output = np.zeros(len(X))
output += self.init_sigma
for tree in self.sigma_trees:
output += self.learning_rate * tree.predict(X)
return output
参考来源#
- 周永_52ML,“第06章:深入浅出ML之Boosting家族”,http://www.52caml.com/head_first_ml/ml-chapter6-boosting-family/
- sarem-seitz,“With PyTorch, I can Gradient Boost anything”,https://sarem-seitz.com/posts/with-pytorch-i-can-gradient-boost-anything/
- 王桂波“Gradient Boosting 原理、推导及代码实现”,https://zhuanlan.zhihu.com/p/64863699
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律