梯度提升为什么逐轮拟合修正量
上一节已经能训练一棵树。现在的问题是:如果每棵树容量有限,能不能让后面的树修正前面模型还没解决的部分?
本页依赖树的训练与预测。学习目标是解释每轮训练标签从哪里来,并手算两轮预测。使用之前的 X=[[1],[2],[3],[4]]、y=[1,1,3,3],没有换题。
1. 把一个模型写成多次修正
最终模型是:
这与随机森林的核心训练关系不同:随机森林通过样本和特征随机化训练多棵树并聚合;梯度提升中新一棵树的目标依赖当前整个模型。GBDT 的“顺序”指训练依赖,不表示预测一定只能串行执行。
2. 平方损失下,为什么修正目标是残差
使用单样本损失:
注意变量是当前预测值
沿降低损失的方向移动,就使用负梯度
如果可以为每个训练样本自由增加
3. 完整手算两轮
平方损失的最佳初始常数是标签均值,所以
| 步骤 | x=1 | x=2 | x=3 | x=4 |
|---|---|---|---|---|
| 真值 y | 1 | 1 | 3 | 3 |
| 初始 F₀ | 2 | 2 | 2 | 2 |
| 第一轮残差 y−F₀ | -1 | -1 | 1 | 1 |
| 第一棵树 f₁ | -1 | -1 | 1 | 1 |
| F₁=F₀+0.5f₁ | 1.5 | 1.5 | 2.5 | 2.5 |
| 第二轮残差 y−F₁ | -0.5 | -0.5 | 0.5 | 0.5 |
| 第二棵树 f₂ | -0.5 | -0.5 | 0.5 | 0.5 |
| F₂=F₁+0.5f₂ | 1.25 | 1.25 | 2.75 | 2.75 |
两棵树都在 2.5 切分,但它们的叶子值不同。第二轮一定用
训练 MSE 从 1 变成 0.25,再变成 0.0625。这里报告的是不带
运行 python3 examples/python/tree_boosting.py 可以逐行核对表格。把学习率改为 1 时,这个特别简单的数据一轮即可拟合;这不代表实际问题应该总用 1。
4. 一般损失还叫残差吗
对于一般可微损失,修正目标是:
例如二分类时,令
一般梯度提升还可以在分区确定后,为每个叶子按原损失寻找合适的步长:
本章手写版本限定平方损失,此时残差均值就是叶子最优修正;LightGBM 的常见平滑目标则使用梯度与二阶信息建立近似优化,后面专门推导。有关加法模型和目标函数的完整定义可查 scikit-learn 梯度提升说明。
5. 容量、学习率和轮数共同作用
深树能在一轮学习更复杂的修正,也更容易拟合偶然误差。学习率缩小每棵树的影响,通常需要更多轮才能达到相近训练误差。轮数增加让模型更灵活,但训练误差下降不保证验证误差下降。
三者不能分开理解:只把学习率调小又固定极少轮数,模型可能还没学够;只看训练误差不断加树,可能在追逐噪声。早停是在验证数据上选择轮数,不是保证泛化的数学证明。
小结、自测与下一步
- 第二轮的训练目标为什么不是原始 y?
- 二分类能否直接执行
probability += tree_prediction? - 本例学习率 0.5、深度 1,第三轮 MSE 应为多少?
参考答案
- 新树负责修正当前集成模型,平方损失下目标为
y-F_current。 - 不能。应在原始分数空间更新,再用 sigmoid 转成概率。
- 残差由 ±0.25 减为 ±0.125,因此 MSE 为 0.015625。这依赖本例每轮都能精确拟合残差的特殊结构。
下一步:从零实现平方损失 GBDT。