0%

XGBoost的工程师手册

XGBoost的工程师手册 = XGBoost论文理论解析 + XGBoost实战 + XGBoost面试题

编者:袁宵

XGBoost: A Scalable Tree Boosting System

树提升(Tree boosting)算法是一种非常有效且被广泛使用的机器学习方法。 在本文中,我们描述了一个名为 XGBoost (Extreme Gradient Boosting 极限提升树)的有扩展性的端到端的树提升系统,数据科学家们广泛使用该系统来实现许多机器学习挑战的最新成果。我们提出了一种新颖的稀疏数据感知算法(sparsity-aware algorithm)用于稀疏数据,一种带权值的分位数略图(weighted quantile sketch) 来近似实现树的学习。更重要的是,我们提供有关缓存访问模式(cache access patterns),数据压缩和分片(data compression and sharding)的见解,以构建有延展性的提升树系统。通过结合这些见解,XGBoost可用比现系统少得多的资源来处理数十亿规模的数据。

XGBoost极限梯度提升树的三要素

XGBoost模型

给定一个拥有 $n$ 个样例,每个样例有 $m$ 个特征的数据集 $D = \{( \textbf{x}_i, y_i) \} (|D| = n, \textbf{x}_i \in \mathbb R^m, y_i \in \mathbb R)$,一个树集成模型使用 $K$ 个相加的函数去预测输出(如图 1 所示)。

符号 说明
$F$ 函数的假设空间,这里指回归树空间,比如CART树
$q(\textbf{x})$ 表示树结构,作用是把样例 $\textbf{x}$ 映射至对应的树的叶子节点 index
$T$ 树的叶子节点个数
$f_k$ 第 $k$ 颗树,每颗树对应独立的树结构 $q$ 和叶子节点权重 $w$
$w_i$ 第 $i$ 个叶子节点的权重 score

预测过程:对于给定的样例,使用决策树的规则(由 $q(x)$ 树结构决定)把样例映射至每棵树的叶子节点,然后相应叶节点得分score相加(由 $w$ 决定分数score)为最终预测结果。

XGBoost策略

为了学习一系列XGBoost模型中的树,最小化以下带正则化的目标函数:

符号 说明
$l(\hat y_i, y_i)$ 一个可微分的凸损失函数,用来度量预测值 $\hat y_i$ 与 目标值 $y_i$ 之间的差异
$\Omega(f_k)$ 正则项,用来惩罚模型(回归树函数)的复杂性

目标函数 2 表达的是:

XGBoost优化算法

由于XGBoost中的树集成模型的目标函数(式子2)不能使用传统的在欧几里得空间中的优化算法,而是用以一种相加的方式进行训练的。让 $\hat y_i^{(i)}$ 表示在第 $t$ 次迭代中第 $i$ 个示例的预测值,我们需要加上 $f_t$ 来最小化下面的目标函数:

上式意味着我们使用贪心算法(根据)来添加最能提升模型效果的(上述的带正则化的目标函数)函数 $f_t$ 。在一般情况下,二阶近似可用于快速优化目标。


我们可以移除常数项来获得简化形式的第 $t$ 步目标函数。

定义: $I_j = \{ i | q(\textbf{x}) = j \}$ 为叶子 $j$ 的实例集。我们可以重写式子3:

对于一个固定结构的树结构 $q(\textbf{x})$,我们可以计算出树的叶子节点 $j$ 的最优权重 $w^{\star}_j$:

并且可以计算出对应的目标函数最优值:

式子6可以作为一个评分函数来衡量一个树结构 $q$ 的质量,这个分数类似于评价决策树的杂质分数,只是它是针对更大范围的目标函数推导出来的。图2说明了如何计算这个分数。

通常不可能枚举所有可能的树结构 $q$。取而代之的是一个贪婪算法,它从一片叶子开始,迭代地向树中添加分支。假设 $I_L$ 和 $I_R$ 是左边的实例集以及分裂后的右结点。令 $I = I_L \cup IR$ 分拆后的损失减少量(也成为增益)为:

在实践中通常使用式子7来评估候选的数结构(选取增益最大的树)。


(补充推导过程开始)

式子2->式子3:

在式子2中提到,XGBoost 是一个加法模型,假设我们第 $t$ 次迭代要训练的树模型是 $f_t$,则有:

将上式代入2中,注意上式中,只有一个变量,那就是第 $t$ 次迭代要训练的树模型 $f_t$:

这里我们将正则化项进行了拆分,由于前 $t-1$ 棵树的结构已经确定,因此,前 $t-1$ 棵树的复杂度之和可以用一个常量表示:

已知泰勒公式

令 $\Delta x = x - x_0$,则 $x = x_0 + \Delta x$,那么泰勒公式的二阶展开形式如下:

定义损失函数关于 $\hat y ^{(t-1)}$ 的一阶偏导数和二阶偏导数:

那么,我们的损失函数就可以转化为下式:

将上述二阶展开式,带入到的目标函数 Obj 中,可以得到目标函数 Obj 的近似值:

去掉全部常数项,得到目标函数:

即式子3:

为了便于理解和记忆,归纳上述推导思路如下:

(补充推导过程结束)


收缩和列采样(Shrinkage and Column Subsampling)

除了第二节中提到的正规化目标。另外两种技术被用来进一步防止过度拟合。 第一项技术是收缩(Shrinkage)。 在树木生长的每个步骤之后,收缩率将新增加的权重按因子 $\eta$ 缩放。 与随机优化中的学习率相似,收缩可以减少每棵树的影响,并为将来的树留出空间来改进模型。 第二种技术是列(特征)子采样(Column Subsampling)。 该技术用于RandomForest中,在用于梯度增强的商业软件TreeNet 4中实现,但在现有的开源软件包中未实现。 根据用户反馈,使用列子采样比传统的行子采样(也受支持)可以防止过度拟合。 列子样本的使用也加快了稍后描述的并行算法的计算。

树分裂算法

此处仅仅介绍树分裂算法的原理,深入证明请看陈天齐的论文 XGBoost: A Scalable Tree Boosting System

精确贪婪算法(Basic Exact Greedy Algorithm)

树学习的关键问题之一是找到由式(7)所示的最佳分割。为了做到这一点,一个分割查找算法列举了所有特性的所有可能的分割。我们称之为精确贪婪算法(Basic Exact Greedy Algorithm),如算法图1所示。枚举连续特性的所有可能的分割是计算上的要求。为了提高效率,算法必须先根据特征值对数据进行排序,然后访问排序后的数据,累积式(7)中结构得分的梯度统计量。

近似算法(Approximate Algorithm)

精确的贪心算法是非常强大的,因为它贪婪地遍历所有可能的分裂点。然而,当数据不能完全装入内存时,就不可能有效地这样做。同样的问题也会出现在分布式设置中。为了在这两种情况下支持有效的梯度树提升(gradient tree boosting),需要一种近似算法。

我们总结了一个近似的框架,该首先根据特征分布的百分位数提出候选分割点。 然后,该算法将连续特征映射到按这些候选点划分的存储桶中,汇总统计信息,并根据汇总的统计信息找到建议(proposal)中的最佳解决方案。

该算法有两种变体,具体取决于何时给出建议(proposal)。 全局变量建议( global variant proposes )在树构建的初始阶段提出所有候选分割,并在所有级别使用相同的分割发现建议。 局部变量建议(local variant re-proposes)每次拆分后都会重新提出局部变量。 全局方法比本地方法需要更少的建议步骤。 但是,对于全局提案,通常需要更多的候选点,因为在每次拆分后都不会重新定义候选。 本地提案对拆分后的候选者进行了筛选,可能更适合于较深的树木。 图3给出了希格斯玻色子数据集上不同算法的比较。我们发现,本地提议确实需要较少的候选者。 如果有足够的候选项,全球提案可能与本地提案一样准确。

归纳:

  1. 全局变量建议( global variant proposes )需要更多数据点,速度更快。
  2. 局部变量建议(local variant re-proposes)适合更深的树木,更准确。
  3. 如果有足够的候选项,全球提案可能与本地提案一样准确。

加权分位数略图(Weighted Quantile Sketch)

怎样理解weighted quantile sketch? 知乎

分布式加权直方图算法是XGBoost提出的一种可并行的算法,树节点在进行分裂时,需要计算特征的信息增益,该算法用于高效地生成候选分裂点,对于大型的数据集,如果每个实例具有相等权重时,quantile sketch算法可以解决,但对于加权数据集来说,则不适用,为了解决该问题,XGBoost提出了分布式加权分位数略图(Weighted Quantile Sketch)算法。

稀疏感知算法(sparsity-aware algorithm)

稀疏感知分裂发现,在现实生活中,特征往往都是稀疏的,有几种可能的原因导致特征稀疏:

1)presence of missing values in the data;
2)frequent zero entries in the statistics;
3)artifacts of feature engineering such as one-hot encoding

XGBoost以统一的方式处理缺失的情况,分裂中只选择没有缺失的数据去进行节点分支,然后缺失情况默认指定一个方向。

XGBoost的系统设计

TODO:完善内容

Column Block for Parallel Learning

即按列分块并行化学习,XGBoost会对每个特征的值进行排序,使用CSC结构存储到块(block)中,训练过程对特征分枝点计算采用并行处理,寻找合适的分裂点。所以我们常说的XGBoost的并行计算指的是不是树的学习上,而是在特征上的并行处理。

所以,这里XGBoost在设计系统的时候,预留额外的空间(Block)赖储存排序好的数据,这里的排序,是按照每列的值排序,所以索引在不同特征之间是不一样的。

所以,特征预排序只需要在开始的时候做一次即可,后续可以重复调用,大大减少了每次排序的耗时,所以也可以实现并行化学习,计算每个特征的信息增益。

Cache-aware Access

缓存感知访问,对于有大量数据或者说分布式系统来说,我们不可能将所有的数据都放进内存里面。因此我们都需要将其放在外存上或者分布式存储。但是这有一个问题,这样做每次都要从外存上读取数据到内存,这将会是十分耗时的操作。

因此我们使用预读取(prefetching)将下一块将要读取的数据预先放进内存里面。其实就是多开一个线程,该线程与训练的线程独立并负责数据读取。此外,还要考虑Block的大小问题。如果我们设置最大的block来存储所有样本在k特征上的值和梯度的话,cache未必能一次性处理如此多的梯度做统计。如果我们设置过少block size,这样不能充分利用的多线程的优势,也就是训练线程已经训练完数据,但是prefetching thread还没把数据放入内存或者cache中。

经过测试,作者发现block size设置为2^16个examples最好。

Blocks for Out-of-core Computation

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

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

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

XGBoost相关证明

TODO:完善内容

XGBoost应用

实战

TODO:完善内容

调参

Complete Guide to Parameter Tuning in XGBoost with codes in Python

Xgboost参数调优的完整指南及实战

XGBoost面试题

  1. 简单介绍一下XGB
  2. XGBoost为什么使用泰勒二阶展开?为什么用二阶信息不用一阶?
  3. XGBoost在什么地方做的剪枝,怎么做的?
  4. XGBoost如何分布式?特征分布式和数据分布式? 各有什么存在的问题?
  5. XGBoost里处理缺失值的方法?
  6. XGBoost有那些优化?
  7. XGBoost如何寻找最优特征?是又放回还是无放回的呢?
  8. GBDT和XGBoost的区别是什么?
  9. lightgbm和xgboost有什么区别?他们的loss一样么? 算法层面有什么区别?
  10. 比较一下LR和GBDT?GBDT在什么情况下比逻辑回归算法要差?
  11. RF和GBDT的区别;RF怎么解决的过拟合问题;
  12. 怎么理解决策树、xgboost能处理缺失值?而有的模型(svm)对缺失值比较敏感?
  13. 随机森林是怎样避免ID3算法信息增益的缺点的?
  14. gbdt对标量特征要不要onehot编码?
  15. CART为什么选择基尼系数作为特征选择标准 ?
  16. 如何解决类别不平衡问题?
  17. GBDT 如何用于分类 ?

参考答案

参考文献

  1. 理解XGBoost原理,查看陈天齐的PPT Introduction to Boosted Trees 和论文 XGBoost: A Scalable Tree Boosting System
  2. 使用XGBoost,查看GitHub 可扩展,可移植和分布式梯度提升(GBDT,GBRT或GBM)库 xgboost
  3. 阅读:XGBoost超详细推导,终于有人讲明白了! / 珍藏版 | 20道XGBoost面试题,你会几个?(上篇) / 珍藏版 | 20道XGBoost面试题,你会几个?(下篇)
  4. 带你撸一遍 XGBoost论文
本站所有文章和源码均免费开放,如您喜欢,可以请我喝杯咖啡