2.1 加法模型与带正则的目标函数


文档摘要

2.1 加法模型与带正则的目标函数 XGBoost 的模型是 K 棵树的加法之和,训练目标是"损失项 + 正则项"的整体最小。 本节定义加法模型与目标函数,用一个五样本迷你任务把每一项算出具体数值,并讲清损失与正则这对矛盾为什么必须同时在场。 第 1 章末尾我们确认了 XGBoost 相对 GBDT 的改进方向,现在进入实现这些改进的数学地基。本节聚焦两个知识点:加法模型怎么定义、目标函数为什么必须带正则项。 一、加法模型:预测是 K 棵树的总和 XGBoost 的预测写法直白:对样本 x,输出等于 K 棵树输出相加。第 t 轮训练时,前 t−1 棵树已经冻结成常数,唯一的自由变量是第 t 棵树 ft。

2.1 加法模型与带正则的目标函数

XGBoost 的模型是 K 棵树的加法之和,训练目标是"损失项 + 正则项"的整体最小。 本节定义加法模型与目标函数,用一个五样本迷你任务把每一项算出具体数值,并讲清损失与正则这对矛盾为什么必须同时在场。

第 1 章末尾我们确认了 XGBoost 相对 GBDT 的改进方向,现在进入实现这些改进的数学地基。本节聚焦两个知识点:加法模型怎么定义、目标函数为什么必须带正则项。

一、加法模型:预测是 K 棵树的总和

XGBoost 的预测写法直白:对样本 x,输出等于 K 棵树输出相加。第 t 轮训练时,前 t−1 棵树已经冻结成常数,唯一的自由变量是第 t 棵树 f_t。所以第 t 轮的目标函数只围绕"旧预测 y_hat 加上 f_t(x)"来构造:

import numpy as np # 五样本迷你任务:预测店铺日销售额(千元) X = np.array([[10], [12], [15], [18], [20]]) # 客流(百人) y = np.array([5.1, 5.8, 7.2, 8.9, 9.4]) # 真实销售额 # 假设已有模型 F0(比如就是全体均值) F0 = np.full(5, y.mean()) print("初始预测:", F0) # 输出: 初始预测: [7.28 7.28 7.28 7.28 7.28] resid = y - F0 print("当前残差:", np.round(resid, 2)) # 输出: 当前残差: [-2.18 -1.48 -0.08 1.62 2.12]

残差随客流单调递增——客流信息还没被用上,第 1 棵树就该去拟合这一列数。加法模型的含义在此显形:模型总输出永远可以拆成"已冻结部分 + 待训练部分",训练只动后者。

二、写出目标函数:两股力量的对峙

第 t 轮的目标函数由两部分构成。损失项逐样本累加,衡量"预测得准不准";正则项作用于第 t 棵树本身,衡量"这棵树复杂不复杂"。XGBoost 把树的复杂度显式定义为两部分之和:叶子数量乘 γ,加上叶子权重平方和乘 λ 的一半。

用文字公式表述(避开排版符号):obj = 所有样本的损失之和 + γ 乘 叶子数 + λ 的一半 乘 叶权平方和。前一项鼓励树多分叉、多修正残差;后两项惩罚多叶子和大权重。γ 是"每多一个叶子交的税",λ 是"叶子权重变大交的税"。GBDT 的目标里没有这两项税,树想长多复杂就多复杂——第 1 章说 Boosting 天生易过拟合,病根就在这里,XGBoost 把药直接写进了目标函数。

# 把"复杂度税"算成看得见的数字 def complexity(weights, gamma, lam): T = len(weights) # 叶子数 return gamma * T + 0.5 * lam * np.sum(np.square(weights)) w1 = [2.0] # 1 个叶子的树:不分裂,输出常数 w2 = [2.5, -1.7, 1.9] # 3 个叶子的树 for gamma, lam in [(0.0, 0.0), (1.0, 1.0), (2.0, 3.0)]: print(f"gamma={gamma} lambda={lam} | 简单树复杂度={complexity(w1, gamma, lam):.2f}" f" | 复杂树复杂度={complexity(w2, gamma, lam):.2f}")

运行输出:

gamma=0 lambda=0 | 简单树复杂度=0.00 | 复杂树复杂度=0.00 gamma=1 lambda=1 | 简单树复杂度=1.00 | 复杂树复杂度=9.69 gamma=2 lambda=3 | 简单树复杂度=2.00 | 复杂树复杂度=26.71

γ 与 λ 全为 0 时正则项消失,退化回 GBDT 式的自由生长;两税齐涨后,三叶子树的复杂度从 0 飙到 26.7——这棵树要想被保留,必须在损失项上赚回超过 26.7 的改善,否则分裂不划算。

损失项与正则项的拉锯示意

目标函数内部:损失下降与复杂度上税的拉锯

目标函数内部:损失下降与复杂度上税的拉锯

绿色损失曲线下降越来越慢(残差里的可学信息被逐步榨干),红色正则曲线一路上扬,两者之和存在一个最低点。最优的树复杂度不是"越深越好",而是这条总和曲线的谷底——调 gamma、lambda、max_depth,本质上都是在挪动这个谷底的位置。

三、为什么正则必须长在目标函数里

一个自然的问题:训练完再剪枝不行吗?事后剪枝只看训练损失,无法知道"这个分裂在带正则的口径下还值不值"。XGBoost 把税写进目标函数,等于让每一次分裂在发生之前就自负盈亏——增益不足 γ 的分裂当场放弃,树的生长与剪枝合并成同一个判断。这带来的实际差异在第 4 节的增益公式里会精确呈现。

💡 关键直觉:把 γ 理解成"开一个新叶子的固定成本",λ 理解成"叶子权重的浮动利率"。成本越高,只有信息量足够大的分裂才付得起钱;利率越高,模型偏好许多小权重的叶子而不是少数极端叶子,预测因此更平滑、更抗噪。

本节要点回顾

  • 加法模型:总预测为 K 棵树之和,第 t 轮只训练第 t 棵,旧预测全部冻结
  • 目标函数 = 损失项 + γ·叶子数 + λ/2·叶权平方和,两股力量方向相反
  • 复杂度税算例显示:三叶子树在 γ=2、λ=3 下复杂度达 26.7,必须赚回等量损失才值得
  • 最优复杂度是"损失下降 + 正则上升"总和曲线的谷底,不是最深
  • 正则内嵌让分裂发生前就自负盈亏,生长与剪枝合为一体

目标函数虽已写出,但损失里面套着"旧预测加新树"的复合结构,没法直接对树求导。下一节请出泰勒二阶展开,把损失信息压缩成每样本两个导数。

常见问答

正则项为什么作用在树上而不是加法模型的整体上

因为加法模型里前 t−1 棵树已冻结,第 t 轮唯一能约束的复杂度只有第 t 棵树本身。整座森林的复杂度控制被分解为两个层面:单棵树的正则由 γ 与 λ 负责,森林的长度由树的数量与早停负责(第 4 章实战会看到后者)。分层控制正是加法模型好调优的原因。

γ 和 λ 应该先调哪一个

经验上先 λ 后 γ。λ 的影响平滑连续,调起来方向感强;γ 是硬闸门,调过头树直接不长,症状剧烈。两者都以对数尺度试探(0.1、0.3、1、3、10),第 3 章的三步走流程把它们放在最后一步精修。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U