树模型(六):XGBoost

0 XGB vs GBDT

  • 正则项:在使用CART作为基分类器时,XGBoost显式地加入了正则项来控制模型的复杂度,有利于防止过拟合,从而提高模型的泛化能力。
  • 二阶导数:GBDT在模型训练时只使用了代价函数的一阶导数信息,XGBoost对代价函数进行二阶泰勒展开,可以同时使用一阶和二阶导数。
  • 基分类器:传统的GBDT采用CART作为基分类器,XGBoost支持多种类型的基分类器,比如线性分类器。
  • 列采样:传统的GBDT在每轮迭代时使用全部的数据,XGBoost则采用了与随机森林相似的策略,支持对数据进行采样,支持列抽样,不仅能降低过拟合,还能减少计算,这也是xgboost异于传统gbdt的一个特性。
  • 缺失值处理:传统的GBDT没有设计对缺失值进行处理,XGBoost可以自动学习出它的分裂方向。XGBoost对于确实值能预先学习一个默认的分裂方向。
  • Shrinkage(缩减),相当于学习速率(xgboost中的eta)。xgboost在进行完一次迭代后,会将叶子节点的权重乘上该系数,主要是为了削弱每棵树的影响,让后面有更大的学习空间。实际应用中,一般把eta设置得小一点,然后迭代次数设置得大一点。(补充:传统GBDT的实现也有学习速率)

1 加性模型

【图解】

首先,XGBoost与GBDT一样,也是boosting模型。仅对loss及正则做了修改,predict及lr相关不变。对于boosting decision tree, 下面这张图片可以很好的表达出来

输入样本的最终预测值等于各个树的预测值之和

【文字描述】

2 Object Function

主要包括损失函数项和正则项,在2.1和2.2节会分别详细介绍

2.1 损失函数项

2.1.1 定义

2.1.2 MSE Loss

假如我们使用的损失函数是MSE,那么上述表达式会变成这个样子:

这个式子非常漂亮,因为它含有 f t ( x i ) f_{t}(x_{i}) ft(xi)的一次式和二次式,而且一次式项的系数是残差。你可能好奇,为什么有一次式和二次式就漂亮,因为它会对我们后续的优化提供很多方便,继续前进你就明白了

注意 f t ( x i ) f_{t}(x_{i}) ft(xi)是什么?它其实就是 f t f_{t} ft的某个叶子节点的值。之前我们提到过,叶子节点的值是可以作为模型的参数的

2.1.3 二阶导的由来

首先我们需要明确一个概念, 我们的boosting每一轮迭代是在优化什么呢? 换句话说我们在用损失函数 l l l在干什么呢? 其实我们看Boosting的框架, 无论是GBDT还是Adaboost, 其在每一轮迭代中, 根本没有理会损失函数具体是什么, 仅仅用到了损失函数的一阶导数。仅仅用一阶导数的问题就是, 我们根本无法保证我们找到的是全局最优。除非问题本身 f ( x ) f(x) f(x)是强凸的 (convex)而且最好是smooth的。每次迭代相当于就是最优化负梯度。即下式中的 ▽ f ( x i ) \bigtriangledown f(x^{i}) f(xi)
, 因为是负梯度所以前面要加负号, c c c代表学习率。

x c ( i ) = x ( i ) − c ▽ f ( x i ) x^{(i)}_{c} = x^{(i)} - c\bigtriangledown f(x^{i}) xc(i)=x(i)cf(xi)

有没有感觉这个公式形式很熟悉, 是不是就是一般常见的linear regression 的 stochastic 梯度更新公式。既然GBDT用的是Stochastic Gradient Descent, 我们回想一下, 是不是还有别的梯度更新的方式, 这时, 牛顿法 Newton’s method就出现了。可以说, XGBoost是用了牛顿法进行的梯度更新。仅仅用一阶导数的问题就是, 我们根本无法保证我们找到的是全局最优。

2.1.4 牛顿法和二阶泰勒

2.1.5 示例

假设我们正在优化第11棵CART树,也就是说前10棵 CART树已经确定了。这10棵树对样本( X i X_{i} Xi, y i y_{i} yi=1)的预测值是 y i ^ = − 1 \hat{y_{i}}=-1 yi^=1,假设我们现在是做分类,我们的损失函数是

L ( θ ) = ∑ i [ y i l n ( 1 + e − y ^ i ) + ( 1 − y i ) l n ( 1 + e − y ^ i ) ] L(\theta) = \sum_{i}^{}[y_{i}ln(1+e^{-\hat{y}_{i}}) + (1-y{i})ln(1+e^{-\hat{y}_{i}})] L(θ)=i[yiln(1+ey^i)+(1yi)ln(1+ey^i)]

y i y_{i} yi=1时,损失函数变成了

l n ( 1 + e − y ^ i ) ln(1+e^{-\hat{y}_{i}}) ln(1+ey^i)

我们可以求出这个损失函数对于 y i ^ \hat{y_{i}} yi^的梯度,如下所示:

− 1 ∗ 1 1 + e − y ^ i ∗ e − y ^ i = − e − y ^ i 1 + e − y ^ i -1 * \frac{1}{1+e^{-\hat{y}_{i}}} * e^{-\hat{y}_{i}} = \frac{-e^{-\hat{y}_{i}}}{1+e^{-\hat{y}_{i}}} 11+ey^i1ey^i=1+ey^iey^i

y i ^ \hat{y_{i}} yi^=-1代入上面的式子,计算得到-0.27。这个-0.27就是 g i g_{i} gi。该值是负的,也就是说,如果我们想要减小这10棵树在该样本点上的预测损失,我们应该沿着梯度的反方向去走,也就是要增大 y i ^ \hat{y_{i}} yi^的值,使其趋向于正,因为我们的 y i y_{i} yi=1就是正的

【6】QA:在优化第t棵树时,有多少个gi和hi要计算? 嗯,没错就是各有N个,N是训练样本的数量。如果有10万样本,在优化第t棵树时,就需要计算出个10万个gi和hi。感觉好像很麻烦是不是?但是你再想一想,这10万个gi之间是不是没有啥关系?是不是可以并行计算呢?聪明的你想必再一次感受到了,为什么xgboost会辣么快!

2.2 正则项

2.2.1 定义

对于f的定义做一下细化,把树拆分成结构部分q叶子权重部分w。下图是一个具体的例子。结构函数q把输入映射到叶子的索引号上面去,而w给定了每个索引号对应的叶子分数是什么

定义这个复杂度包含了一棵树里面节点的个数,以及每个树叶子节点上面输出分数的L2模平方。当然这不是唯一的一种定义方式,不过这一定义方式学习出的树效果一般都比较不错。下图还给出了复杂度计算的一个例子

注:方框部分在最终的模型公式中控制这部分的比重,对应模型参数中的lambda ,gamma

2.2.2 作用

正则项的作用,可以从几个角度去解释

  • 通过偏差方差分解去解释
  • PAC-learning泛化界解释
  • Bayes先验解释,把正则当成先验

从Bayes角度来看,正则相当于对模型参数引入先验分布:

3 目标函数求解

3.1 推导过程

经过上面的拆解,可以把目标函数进行如下改写,其中I被定义为每个叶子上面样本集合 I j = { i ∣ q ( x i ) = j } I_{j} = \left \{ i|q(x_{i})=j \right \} Ij={ iq(xi)=j},其中g是一阶导数,h是二阶导数,n为样本数,T为叶子节点数,w为待求解权重

这一个目标包含了T个相互独立的单变量二次函数。我们可以定义

最终公式可以化简为

通过对 w j w_{j} wj求导等于0,可以得到

w j ∗ = − G j H j + λ w^{*}_{j} = -\frac{G_{j}}{H_{j}+\lambda} wj=Hj+λGj

然后把 w j w_{j} wj最优解代入得到:

3.2 理解obj*

它表示了这棵树的结构有多好,值越小,代表这样结构越好!也就是说,它是衡量第t棵CART树的结构好坏的标准。注意注意注意~,这个值仅仅是用来衡量结构的好坏的,与叶子节点的值可是无关的。为什么?请再仔细看一下obj的推导过程。obj只和Gj和Hj和T有关,而它们又只和树的结构(q(x))有关,与叶子节点的值可是半毛关系没有。如下图所示:

4 寻找最佳分裂点

那么对于决策树的单个节点,该如何进行划分呢?XGBoost与之前的GBDT、RF、ID3等树模型的计算方法都不一样,但是有一个共性就是计算分裂增益,通过比较分裂增益选择特征的切分点。

通过上式就可以计算出分裂的增益,然后确定分裂方式。关键是如何计算出最优分裂点呢?

4.1 贪心法

遍历所有特征的所有可能的分割点,计算Gain值,选取最大的 (Feature,label) 去分裂。

为了达到这个目标,split finding算法会在所有特征 (features) 上,枚举所有可能的划分(splits)。为了更高效,该算法必须首先根据特征值对数据进行排序(原因:可看下方伪代码,是为了快速计算出每一个候选分裂点的Gain),以有序的方式访问数据来枚举Gain公式中的结构得分 (structure score) 的梯度统计 (gradient statistics)

4.2 近似算法

4.2.1 算法理论

对于每个特征,只考察分位点,减少计算复杂度。

该算法会首先根据特征分布的百分位数 (percentiles of feature distribution),提出候选划分点 (candidate splitting points)。接着,该算法将连续型特征映射到由这些候选点划分的分桶(buckets) 中,聚合统计信息,基于该聚合统计找到在 proposal 间的最优解。

  • Global:学习每棵树前,提出候选切分点;
  • Local:每次分裂前,重新提出候选切分点;

归纳:

  • 全局变量建议( global variant proposes )需要更多数据点,速度更快。
  • 局部变量建议(local variant re-proposes)适合更深的树木,更准确。

4.2.2 近似算法举例:三分位数

4.2.3 实际分裂方式

实际上XGBoost不是简单地按照样本个数进行分位,而是以二阶导数值作为权重(Weighted Quantile Sketch)。

一个例子如下:

要切分为3个,总和为1.8,因此第1个在0.6处,第2个在1.2处

【Q1】为什么需要加权
【A1】现在我们回到Xgboost中,在建立第 i i i棵树的时候已经知道数据集在前面 i − 1 i-1 i1棵树的误差,因此采样的时候是需要考虑误差,对于误差大的特征值采样粒度要加大,误差小的特征值采样粒度可以减小,也就是说采样的样本是需要权重的。
【Q2】为什么用 h i h_{i} hi加权
【A2】公式推导重新审视目标函数,通过配方可以得到:

因此可以将该目标还是看作是关于标签为 − g i / h i -g_{i}/h_{i} gi/hi和权重为 h i h_{i} hi的平方误差形式。 h i h_{i} hi为样本的二阶导数。(注:源论文中公式(2)的地方是错误的,它写成了标签为 g i / h i g_{i}/h_{i} gi/hi

【A2】直观感受

【数学定义】

【引申】
对于大数据集来说,要找到满足该原则 (criteria) 的候选集是不容易的。当每个样本实例都具有相同的权重时,有一种已经存在的算法可以解决该问题:分位数略图 (quantile sketch)。因而,大多数已存在的近似算法,或者会重新排序来对数据的一个随机子集进行排序(有一定的失败率),或者是启发式的 (heuristics),没有理论保障。

为了解决该问题,XGBoost引入了一种新的分布式加权分位数略图算法 (distributed weighted quantile sketch algorithm),使用一种可推导证明的有理论保证的方式,来处理加权数据。总的思想是,提出了一个数据结构,它支持merge和prune操作,每个操作证明是可维持在一个固定的准确度级别

【更多细节】可以参考 Xgboost近似分位数算法

4.3 稀疏特征分裂

稀疏值定义:1)缺失 2)类别one-hot编码 3)大量0值
第三种是针对稀疏特征的分裂方式,XGBoost可以自动学习稀疏特征的分裂方向:

Sparsity Aware Split Finding算法会对比将特征值为missing的样本分配到左叶子结点和右叶子结点的两种情形,还可以为缺失值或者指定的值指定默认分裂方向,这中方式可以大大提升算法的效率,原paper中给出了具体的量化:50倍。 这种方式对性能的提升确实是非常可观的。

5 其他细节

5.1 缺失值处理

  • 在训练阶段寻找分裂点的时候,计算的分裂增益不包含缺失值样本。在逻辑实现上,为了保证完备性,会分别将缺失该特征值的样本分配到左叶子结点和右叶子结点的两种情形,计算增益后选择增益大的方向归类含缺失值样本
  • 在预测阶段,如果训练集没有缺失值而测试集出现缺失值,则要为缺失值(或者指定的值未出现的值)指定分支的默认方向,预测时自动将缺失值的划分到这一分支。

5.2 剪枝策略

  • 前剪枝
    • 当最优分裂点对应的增益值为负时停止分裂
    • 但是这也会存在问题,即将来的某个时刻能够获取更高的增益
  • 后剪枝
    • 将决策树增长到它的最大深度,递归的进行剪枝,剪去那些使得增益值为负值的叶子节点

5.3 目标函数 vs 启发式

当讨论决策树时,它通常是启发式的,大多数启发式可以很好地映射到目标函数

  • 信息增益 -> 训练误差
  • 剪枝 -> 按照树节点的数目定义的正则化项
  • 最大深度 -> 限制函数空间
  • 对叶子值进行平滑操作 -> 叶子权重的L2正则化项

5.4 Shrinkage和列子抽样(column subsampling)

除了正则化目标函数外,还会使用两种额外的技术来进一步阻止overfitting。

  • 第一种技术是Friedman介绍的Shrinkage。Shrinkage会在每一步tree boosting时,会将新加入的weights通过一个因子ηη进行缩放。与随机优化中的learning rate相类似,对于用于提升模型的新增树(future trees),shrinkage可以减少每棵单独的树、以及叶子空间(leaves space)的影响。
  • 第二个技术是列特征子抽样(column feature subsampling)。该技术也会在RandomForest中使用,根据用户的反馈,比起传统的行子抽样(row sub-sampling:同样也支持),使用列子抽样可以阻止overfitting。列子抽样的使用可以加速并行算法的计算。

5.5 特征选择

xgboost get_fscore 判断特征重要程度的三种指标

  • ‘weight’ - the number of times a feature is used to split the data across all trees.
  • ‘gain’ - the average gain of the feature when it is used in trees.
  • ‘cover’ - the average coverage of the feature when it is used in trees.

6 系统设计

6.1 Column Block(用于并行学习)

在建树的过程中,最耗时是找最优的切分点,而这个过程中,最耗时的部分是将数据排序。为了减少排序的时间,提出Block结构存储数据。

  • Block中的数据以稀疏格式CSC进行存储
  • Block中的特征进行排序(不对缺失值排序)— 按列切开,升序存放,分布式计算分裂点
  • Block 中特征还需存储指向样本的索引,这样才能根据特征的值来取梯度。
  • 一个Block中存储一个或多个特征的值

6.2 Cache-aware Access

使用Block结构的一个缺点是取梯度的时候,是通过索引来获取的,而这些梯度的获取顺序是按照特征的大小顺序的。这将导致非连续的内存访问,可能使得CPU cache缓存命中率低,从而影响算法效率

缓存优化方法

  • 预取数据到buffer中(非连续->连续),再统计梯度信息
  • 调节块的大小

6.3 Blocks for Out-of-core Computation

因为XGBoost是要设计一个高效使用资源的系统,所以各种机器资源都要用上,除了CPU和内存之外,磁盘空间也可以利用来处理数据。为了实现这个功能,我们可以将数据分成多个块并将每个块储存在磁盘上。

在计算过程中,使用独立的线程将Block预提取到主内存缓冲区,这样子数据计算和磁盘读取可以同步进行,但由于IO非常耗时,所以还有2种技术来改善这种核外计算:

  • Block Compression: 块压缩,并当加载到主内存时由独立线程动态解压缩;
  • Block Sharding: 块分片,即将数据分片到多个磁盘,为每个磁盘分配一个线程,将数据提取到内存缓冲区,然后每次训练线程的时候交替地从每个缓冲区读取数据,有助于在多个磁盘可用时,增加读取的吞吐量。

7 推导示意图

8 手动计算还原XGBoost流程

8.1 数据及模型参数

以一个简单的UCI数据集,一步一步的演算整个xgboost的过程。数据集如下:

这里为了简单起见,树的深度设置为3(max_depth=3),树的颗数设置为2(num_boost_round=2),学习率为0.1(eta=0.1)。另外再设置两个正则的参数, λ = 1 , γ = 0 \lambda = 1, \gamma = 0 λ=1,γ=0,损失函数选择logloss

8.2 一阶/二阶导数

由于后面需要用到logloss的一阶导数以及二阶导数,这里先简单推导一下:

L ( y i , y ^ i ) = ∑ i [ y i l n ( 1 + e − y ^ i ) + ( 1 − y i ) l n ( 1 + e − y ^ i ) ] L(y_{i},\hat{y}_{i}) = \sum_{i}^{}[y_{i}ln(1+e^{-\hat{y}_{i}}) + (1-y{i})ln(1+e^{-\hat{y}_{i}})] L(yi,y^i)=i[

评论 20
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值