文章目录
- 1. 集成学习概述
- 2. Boosting算法详解
- 3. Gradient Boosting算法详解
- 3.1 基本思想
- 3.2 公式推导
- 4. Python实现
1. 集成学习概述
集成学习(Ensemble Learning)是一种通过结合多个模型的预测结果来提高整体预测性能的技术。相比于单个模型,集成学习通过多个基学习器的“集体智慧”来增强模型的泛化能力,通常能够提高模型的稳定性和准确性。
常见的集成学习框架有:
- Bagging:通过并行训练多个模型并对其结果进行平均或投票来减少方差
- Boosting:通过按顺序训练多个模型,每个模型都试图纠正前一个模型的错误,从而减少偏差
- Stacking:通过训练多个不同类型的基学习器,并将它们的输出作为特征输入到一个高层模型中,从而提升预测性能
每种方法都有其独特的优势和适用场景。在本文中,我们将重点介绍 Boosting 算法,它主要聚焦于通过提高模型的准确度来减少偏差。
2. Boosting算法详解
Boosting 是一种迭代加权的集成学习方法,旨在通过多个弱学习器(通常是偏差较大的模型)的组合,构建一个具有较低偏差和较高准确度的强学习器。与 Bagging 不同,Boosting 关注的是减小模型的 偏差,而非仅仅减少方差。
Boosting 算法通过逐步构建和改进模型,使得每个新模型都能够专注于纠正前一个模型的错误。这种方式使得模型的 预测能力 不断得到提高。Boosting 的核心思想是 顺序训练。每个新的模型都在前一个模型的基础上进行训练,重点关注那些被前一个模型错误分类的样本。通过这种方式,Boosting 可以有效地减少偏差,进而提升模型的精度。
3. Gradient Boosting算法详解
3.1 基本思想
Gradient Boosting 是 Boosting 的一种实现方法,它通过梯度下降的方式,逐步减少模型的偏差。在每一轮迭代中,Gradient Boosting 都会根据上一轮模型的预测误差(残差)训练一个新的弱学习器,最终的预测结果是所有模型预测结果的加权和。
举个简单的例子,假设一个样本真实值为10,若第一个学习器拟合结果为7,则残差为 10-7=3, 残差3作为下一个学习器的拟合目标。若第二个学习器拟合结果为2,则这两个弱学习器组合而成的Boosting模型对于样本的预测为7+2 = 9,以此类推可以继续增加弱学习器以提高性能。
Gradient Boosting还可以将其理解为函数空间上的梯度下降。我们比较熟悉的梯度下降是在参数空间上的梯度下降(例如训练神经网络,每轮迭代中计算当前损失关于参数的梯度,对参数进行更新)。而在Gradient Boosting中,每轮迭代生成一个弱学习器,这个弱学习器拟合损失函数关于之前累积模型的梯度,然后将这个弱学习器加入累积模型中,逐渐降低累积模型的损失。即 参数空间的梯度下降利用梯度信息调整参数降低损失,函数空间的梯度下降利用梯度拟合一个新的函数降低损失。
3.2 公式推导
假设有训练样本 { x i , y i } , i = 1... n \{x_i,y_i\}, i=1...n {xi,yi},i=1...n,在第 m − 1 m-1 m−1 轮获得的累积模型为 F m − 1 ( x ) F_{m-1}(x) Fm−1(x),则第 m m m 轮的弱学习器 h ( x ) h(x) h(x) 可以通过下式得到
F m ( x ) = F m − 1 ( x ) + arg min h ∈ H Loss ( y i , F m − 1 ( x i ) + h ( x i ) ) F_m(x) = F_{m-1}(x) + \arg \min_{h \in H} \, \text{Loss}(y_i, F_{m-1}(x_i) + h(x_i)) Fm(x)=Fm−1(x)+argh∈HminLoss(yi,Fm−1(xi)+h(xi))
其中上式等号右边第二项的意思是:在函数空间 H H H 中找到一个弱学习器 h ( x ) h(x) h(x),使得加入这个弱学习器之后的累积模型的 l o s s loss loss 最小。那么应该如何找这个 h ( x ) h(x) h(x) 呢?在第 m − 1 m-1 m−1 轮结束后,我们可以计算得到损失 L o s s ( y , F m − 1 ( x ) ) Loss(y,F_{m-1}(x)) Loss(y,Fm−1(x)),如果我们希望加入第 m m m 轮的弱学习器后模型的 l o s s loss loss 最小,根据最速下降法新加入的模型损失函数沿着负梯度的方向移动,即如果第 m 轮弱学习器拟合函数关于累积模型 F m − 1 ( x ) F_{m-1}(x) Fm−1(x) 的负梯度,则加上该弱学习器之后累积模型的 l o s s loss loss 会最小。
因此可以得知第 m 轮弱学习器训练的目标是损失函数的负梯度,即:
g m = − ∂ Loss ( y , F m − 1 ( x ) ) ∂ F m − 1 ( x ) g_m = - \frac{\partial \, \text{Loss}(y, F_{m-1}(x))}{\partial F_{m-1}(x)} gm=−∂Fm−1(x)∂Loss(y,Fm−1(x))
如果 Gradient Boosting中采用平方损失函数 L o s s = ( y − F m − 1 ( x ) ) 2 Loss=(y-F_{m-1}(x))^2 Loss=(y−Fm−1(x))2,损失函数负梯度计算出来刚好是残差 y − F m − 1 ( x ) y-F_{m-1}(x) y−Fm−1(x),因此也会说Gradient Boosting每一个弱学习器是在拟合之前累积模型的残差。这样的说法不具有一般性,如果使用其他损失函数或者在损失函数中加入正则项,那么负梯度就不再刚好是残差。
由此可得完整的 Gradient Boosting 算法流程:
以上 Gradient Boosting 的算法流程具有一般性,根据其中的损失函数和弱学习器的不同可以演变出多种不同的算法。如果损失函数换成平方损失,则算法变成 L2Boosting;如果将损失函数换成 log-loss,则算法成为 BinomialBoost;如果是指数损失,则算法演变成 AdaBoost;还可以采用 Huber loss 等更加 robust 的损失函数。弱学习器如果使用决策树,则算法成为 GBDT(Gradient Boosting Decision Tree),使用决策树作为弱学习器的 GBDT 使用较为普遍。
4. Python实现
python伪代码实现 GradientBoosting :
class GradientBoosting:def __init__(self, base_learner, n_learner, learning_rate):self.learners = [clone(base_learner) for _ in range(n_learner)]self.lr = learning_ratedef fit(self, X, y):residual = y.copy()for learner in self.learners:learner.fit(X, residual)residual -= self.lr * learner.predict(X)def predict(self, X):preds = [learner.predict(X) for learner in self.learners]return np.array(preds).sum(axis=0) * self.lr
加入学习率 (learning_rate 或 lr) 的目的是为了控制每个基学习器(或弱学习器)对最终模型的贡献度,从而达到更好的训练效果和避免过拟合。
具体来说,学习率的作用可以总结为以下几点(From ChatGPT):
1.防止过拟合
在 Gradient Boosting 中,训练过程是逐步的,每一轮都会基于前一轮的残差训练一个新的基学习器,并将其结果加到已有模型中。假设没有学习率的话,每个基学习器的预测值将完全被加到累积模型中,可能会使模型快速过拟合训练数据。
学习率 lr 的引入通过调整每个基学习器的权重,从而控制模型每次更新的幅度。如果学习率过大,可能会使模型在训练集上快速拟合,导致过拟合;而如果学习率过小,模型训练速度会变得非常慢,可能需要更多的基学习器来达到同样的效果。因此,合理的学习率可以在训练过程中平衡模型的收敛速度和防止过拟合。
2. 控制每个基学习器的贡献度
Gradient Boosting 的训练是一个渐进的过程,每个基学习器都会根据前一轮的残差来进行拟合。没有学习率的情况下,每个新基学习器的贡献将会很大,这可能导致模型在早期就对训练数据过于敏感,无法很好地泛化。
学习率通过缩小每个基学习器的贡献,避免模型在每轮更新时发生过大的变化。通常来说,较小的学习率需要更多的基学习器(即更多的迭代次数)来收敛,但可以有效减少每个基学习器对最终结果的影响,从而降低过拟合的风险。
3. 控制训练过程的收敛速度
学习率对模型的收敛速度有很大的影响。较大的学习率可以使模型快速收敛,但可能导致震荡或过拟合;而较小的学习率使模型收敛较慢,但通常会得到更加平滑和稳健的结果。合理选择学习率,可以在优化过程的初期实现快速的方向调整,而在后期逐渐精细化模型。
4. 改进模型的稳定性
加入学习率可以帮助模型在训练过程中避免跳跃式的大幅更新。每个基学习器的调整幅度得到控制,使得模型更新更为平稳,从而使得训练过程更加稳定,减少了由于每个学习器的过度调整带来的不稳定性。
数学解释:
在训练过程中,每一轮训练的目标是通过最小化损失函数来拟合前一轮累积模型的残差。对于每一轮的弱学习器,其目标是拟合当前模型残差的负梯度。加入学习率 lr 后,训练过程中的每个弱学习器的输出会乘以该学习率,从而调节每个学习器对模型更新的贡献。
具体来说,假设当前模型的输出为 F m − 1 ( x ) F_{m-1}(x) Fm−1(x),而第 m m m 轮的弱学习器的目标是拟合该模型的残差。使用学习率 lr 后,更新步骤变为:
F m ( x ) = F m − 1 ( x ) + l r ∗ h m ( x ) F_m(x) = F_{m-1}(x) + lr*h_m(x) Fm(x)=Fm−1(x)+lr∗hm(x)
这里, h m ( x ) h_m(x) hm(x) 是第 m m m 轮弱学习器的输出。通过学习率 lr,我们可以控制每个弱学习器的输出对最终模型的贡献。
本文参考:
https://borgwang.github.io/ml/2019/04/12/gradient-boosting.html