跳到内容

6.3 Gradient Boosting 与 XGBoost:每棵新树拟合当前损失的下降方向

随机森林让许多树分别判断再平均。模型工坊接到的新任务不同:少数高代价样本仍被系统性低估,团队希望每轮都针对当前目标函数还没有解决的部分继续修正。

Gradient Boosting 构造一个加法模型。新树不是泛泛“关注错题”,而是在当前预测处拟合损失对函数值的负梯度;平方损失下,这个方向恰好与 residual 对应。

本课目标

  • 用函数梯度解释 gradient boosting;
  • 理解 squared loss residual 只是一个特例;
  • 看懂 XGBoost 的二阶近似、叶权重和正则项;
  • 正确划分 train、validation 与 test 并使用 early stopping;
  • 联合分析学习率、树容量、采样、校准和工程成本。

1. 加法模型

从常数模型 $F_0(x)$ 开始,第 $t$ 轮加入一棵树:

$$ F_t(x)=F_{t-1}(x)+\eta f_t(x), $$

其中 $\eta$ 是 learning rate/shrinkage。训练目标是经验损失和复杂度约束,而不是“让每棵树单独准确”。

在函数空间的 gradient boosting 中,对每个样本计算 pseudo-residual:

$$ r_{it}=-\left.\frac{\partial\ell(y_i,F(x_i))}{\partial F(x_i)}\right|{F=F{t-1}}. $$

新树拟合 $r_{it}$ 或相应 Newton step,再通过步长加入当前模型。

2. Residual 是平方损失的特例

若:

$$ \ell(y,F)=\frac12(y-F)^2, $$

则:

$$ -\frac{\partial\ell}{\partial F}=y-F, $$

正好是 ordinary residual。

但 binary log loss 通常在 logit/raw-score 空间优化。令 $p=\sigma(F)$,单样本负对数似然的梯度为:

$$ g=\frac{\partial\ell}{\partial F}=p-y, $$

负梯度是 $y-p$,不是“分错为 1、分对为 0”的标签。对 ranking、Poisson、quantile 等目标,pseudo-residual 又不同。因此“新树拟合上一棵树的错误”只是一句粗略直觉。

3. XGBoost 的二阶局部目标

XGBoost 在第 $t$ 轮考虑:

$$ \mathcal L^{(t)}=\sum_i\ell(y_i,\hat y_i^{(t-1)}+f_t(x_i))+\Omega(f_t). $$

对当前预测做二阶 Taylor expansion,去掉与新树无关的常数:

$$ \widetilde{\mathcal L}^{(t)} =\sum_i\left[g_if_t(x_i)+\frac12h_if_t(x_i)^2\right]+\Omega(f_t), $$

其中:

$$ g_i=\partial_{\hat y}\ell(y_i,\hat y_i),\qquad h_i=\partial^2_{\hat y}\ell(y_i,\hat y_i). $$

若一棵树有 $T$ 个叶子、叶权重为 $w_j$,常见正则形式是:

$$ \Omega(f)=\gamma T+\frac12\lambda\sum_{j=1}^Tw_j^2 $$

(实现还可支持 L1 等项)。对落入叶 $j$ 的样本集合 $I_j$,记 $G_j=\sum_{i\in I_j}g_i$、$H_j=\sum_{i\in I_j}h_i$,在 L2 情形下该叶的最优局部权重为:

$$ w_j^*=-\frac{G_j}{H_j+\lambda}. $$

候选分裂的 gain 来自“分裂后两个叶子的最佳目标值”与“未分裂叶子”之差,再扣除新叶复杂度。二阶信息不是抽象的“更准”,而是用于估计当前局部曲率和 Newton-style 更新。

4. 容量参数不是独立旋钮

Learning rate 与轮数

较小 $\eta$ 通常需要更多 boosting rounds。它可能使路径更平滑,但不会自动防止过拟合;轮数仍要由 validation 选择。

树结构

max_depthmax_leaves/grow policy 控制交互复杂度;min_child_weight 约束叶中 Hessian 权重,不等同于固定样本数;gamma/minimum split loss 要求足够分裂收益。

叶权重正则

L2 reg_lambda、L1 reg_alpha 收缩叶值。不同目标下 Hessian 尺度不同,相同参数值不能脱离 objective 比较。

行列采样

subsamplecolsample_bytree 等引入随机性,可降低相关性/成本,但太低会丢信号并增大随机波动。

这些参数相互作用。不存在通用的“先深度、再正则、最后采样”唯一调参顺序;应先固定验证协议和搜索预算,再围绕容量、步长与成本联合比较。

5. Histogram、稀疏与类别支持

精确扫描所有连续阈值成本高。Histogram 方法先把值映射到 bins,再在累计 gradient/Hessian 统计上评估切分。Bin 数影响速度、内存和近似精度。

XGBoost 等实现可为缺失值学习默认分支方向,但这不等于缺失机制已被正确建模。训练与部署的 NaN 含义应一致,并监控缺失率漂移。

原生 categorical、类别分组与 one-hot 策略随库和版本变化。不要把任意整数编码直接当连续数值;应查当前版本文档、固定依赖,并用未见类别做部署测试。

6. Early stopping 必须使用 validation

数据职责应分开:

  • train:拟合每轮树与叶权重;
  • validation:选择轮数、参数与阈值;
  • test:在所有选择冻结后评估一次。

把 test 放进 eval_set 做 early stopping,会让 test 参与模型选择。最终数字不再是未接触数据上的估计。

当前 XGBoost sklearn interface 的训练骨架如下;实际项目应固定并核对依赖版本:

python
from xgboost import XGBClassifier
from sklearn.metrics import log_loss

model = XGBClassifier(
    objective="binary:logistic",
    eval_metric="logloss",
    tree_method="hist",
    n_estimators=2_000,
    learning_rate=0.05,
    max_depth=4,
    min_child_weight=5,
    subsample=0.8,
    colsample_bytree=0.8,
    reg_lambda=1.0,
    early_stopping_rounds=50,
    random_state=42,
)

model.fit(
    X_train,
    y_train,
    eval_set=[(X_valid, y_valid)],
    verbose=False,
)

# sklearn interface 会在预测时使用 early stopping 选出的最佳轮次。
test_probability = model.predict_proba(X_test)[:, 1]
print("test log loss:", log_loss(y_test, test_probability))

不要根据 test loss 继续改 max_depth 或 learning rate;一旦这样做,原 test 已变成 validation,需要新的独立测试数据或 nested evaluation。

7. Native API 的最佳轮次陷阱

使用 xgboost.train 时,early stopping 默认返回的是最后一轮模型,而不是把 booster 截断为最佳轮次。预测需要显式指定类似:

python
best_probability = booster.predict(
    dtest,
    iteration_range=(0, booster.best_iteration + 1),
)

或使用支持 save_best=True 的 early-stopping callback。还要注意:多个 evals/metrics 时,具体哪个数据集与指标控制停止由 API 规则决定,必须核对日志和当前官方文档。

这类行为会随接口版本调整,所以代码审查不能只看“设置了 early_stopping_rounds”,还要验证最终预测实际用了哪几轮。

8. Bagging 与 Boosting 的差异

维度Random Forest / BaggingGradient Boosting
训练依赖树大体可独立、并行第 $t$ 轮依赖前 $t-1$ 轮
组合概率/预测平均加法累积 raw score/预测
多样性来源bootstrap、特征随机等当前梯度、采样与树约束
轮数作用平均逐渐稳定,收益平台持续改变模型容量,需选最佳轮次
常见风险深树体积、相关误差、概率失准对噪声/漂移敏感、调参耦合、串行训练

“Bagging 降方差、Boosting 降偏差”可作入门启发,但不是定律。Bagging 也会改变 bias,Boosting 也可能降低或放大 variance;结果取决于基学习器、损失、正则和数据生成过程。

9. 评估不能停在一个 AUC

Boosted trees 常有很强排序能力,但 sigmoid/softprob 输出不保证校准。Class weights、undersampling、目标错设和分布变化都会改变概率语义。

至少检查:

  • validation/test 的 log loss、Brier、AUC/PR 与业务成本;
  • reliability curve 和不同时间/群体的 calibration;
  • 最佳轮次在 fold 间是否稳定;
  • 特征缺失率、raw score 与预测分布漂移;
  • 推理延迟、模型体积和峰值内存。

若做 post-hoc calibration,校准数据必须独立于 base learner 的拟合,或使用交叉拟合。

10. 解释与外推边界

Gain、weight、cover 等 importance 定义不同,都会受相关特征和训练路径影响。SHAP 等解释工具描述的是给定模型相对某个背景分布的贡献分解,不自动提供因果解释,背景数据选择也会改变结论。

树集成在训练范围外通常延续已有叶值,不能像正确设定的线性/机制模型那样自然外推趋势。面对长期趋势、价格曲线或物理约束,应显式做 out-of-range 测试,必要时加入单调约束、机制特征或选择其他模型。

常见误区

  • Boosting 就是反复拟合错分样本:一般目标下拟合的是负梯度/Newton 方向。
  • 二阶近似天然更准确:它利用局部曲率,结果仍取决于目标与近似条件。
  • 深度 3–6 是固定答案:树生长策略、数据和交互阶数不同。
  • 用了 early stopping 就没有泄漏:控制停止的数据集必须是 validation,不是 test。
  • 更多轮数只会更好:轮数是模型容量的一部分。

练习

  1. 推导 squared loss 与 binary log loss 的 gradient/Hessian。
  2. 在固定 split 下画 train/validation loss,并标出 best iteration。
  3. 比较 sklearn interface 与 native API 是否使用同一最佳轮次预测。
  4. 联合改变 learning rate 与 rounds,比较性能、训练时间和模型大小。
  5. 构造超出训练范围的输入,比较线性模型、随机森林和 boosting 的外推。

小结

Gradient Boosting 顺序构造加法模型,新树沿当前损失的下降方向修正预测。XGBoost 用 gradient、Hessian、结构惩罚与采样把这个过程变成可扩展的树优化系统。真正可靠的训练流程还需要独立 validation、正确的最佳轮次预测、概率评估与部署监控。

下一章离开有标签监督:先问无监督方法究竟优化什么,再讨论聚类、降维和异常检测的验证边界。

Built with VitePress | Software Systems Atlas