XGBoost: A Scalable Tree Boosting System
共 9375字,需浏览 19分钟
·
2021-11-22 15:40
论文地址:https://arxiv.org/pdf/1603.02754.pdf
代码地址:https://github.com/dmlc/xgboost
1. INTRODUCTION
XGBoost 的全称是 eXtreme Gradient Boosting,它是经过优化的分布式梯度提升库,旨在高效、灵活且可移植。XGBoost 是大规模并行 boosting tree 的工具。在工业界大规模数据方面,XGBoost 的分布式版本有广泛的可移植性,支持在 Kubernetes、Hadoop、SGE、MPI、 Dask 等各个分布式环境上运行,使得它可以很好地解决工业界大规模数据的问题。
XGBoost 成功背后最重要的因素是它在所有场景中的可扩展性。在单台机器上的运行速度比现有流行解决方案快十倍以上,并且可以在分布式或内存有限的设置中扩展到数十亿个样本。XGBoost 的可扩展性归功于几个重要的系统和算法优化。这些创新包括:一种用于处理稀疏数据的新型树学习算法;理论上合理的加权分位数略图程序(a theoretically justified weighted quantile sketch procedure)能够处理近似树学习中的样本权重。并行和分布式计算使学习速度更快,从而实现更快的模型探索。更重要的是,XGBoost 利用核外计算(out-of-core computation ),使数据科学家能够处理数亿个样本。最后,更令人兴奋的是将这些技术结合起来制作一个端到端系统,以最少的集群资源扩展到更大的数据。本文的主要贡献如下:
- 作者设计并构建了一个高度可扩展的端到端树集成模型(tree boosting system)。
- 作者提出了一种理论上合理的加权分位数略图,用于有效的提案计算。
- 作者为并行树学习引入了一种新颖的稀疏感知算法。
- 作者提出了一种有效的缓存- 用于核外树学习(out-of-core tree learning)的感知块结构。
2. TREE BOOSTING IN A NUTSHELL
2.1 Regularized Learning Objective
图 1:树集成模型,给定示例的最终预测是每棵树的预测总和
对于给定 个样本 个特征的数据集 ,一个 Tree ensemble model 使用 个累加函数去预测输出
其中 是回归树的空间(CART)。其中 代表每棵树的结构,即将一个例子映射到相应的叶子索引上。 是叶子节点是数量。每一个 对应独立的树状结构 和叶子节点权重 。不同于决策树,每个回归树在每个叶子上都包含一个连续的分数,使用 代表第 个叶子节点的分数。对于给定的样本,将使用树中的决策规则()将其分类为叶子,并通过对相应叶子()的分数求和来计算最终预测。学习模型中使用的函数集,作者最小化以下正则化目标:
这里 是一个可微的凸损失函数,它衡量预测 和目标 之间的差异。第二项 惩罚模型的复杂性(例如回归树函数)。额外的正则化项有助于平滑最终学习的权重以避免过度拟合。直观地,正则化目标将倾向于选择使用简单和预测函数的模型。在正则化贪婪森林 (RGF) 模型中使用了类似的正则化技术。作者提出的目标和相应的学习算法比 RGF 更简单,更容易并行化。当正则化参数设置为零时,目标回落到传统的 Gradient tree boosting 。
2.2 Gradient Tree Boosting
公式 (2)中的树集成模型包含函数作为参数,无法在欧几里德空间中使用传统的优化方法进行优化。相反,模型以加法方式进行训练。形式上,让 是第 个样本在第 次迭代时的预测,需要添加 以最小化以下目标:
这意味着根据等式 (2)贪婪地添加最能改进模型的 。二阶近似可用于在一般设置中快速优化目标 。
其中 , 是损失函数的一阶和二阶梯度统计,则可以在第 次迭代去除常数项以获得以下简化目标:
图2:结构分数计算。只需要将每片叶子的梯度和二阶梯度统计量相加,然后应用评分公式就可以得到质量分数
定义 为叶子节点 的样本集。则能通过扩展 将等式 (3) 改写为:
对于固定结构 ,可以通过以下计算方式计算叶子节点 的最佳权重 :
并计算相应的最优值:
公式 (6) 可以作为一个评价函数来衡量一个树结构的质量 。这个分数就像评估决策树的 impurity score 一样,只是它是针对更广泛的目标函数得出的。图 2 说明了这个分数的计算方式。
通常情况下,我们不可能列举出所有可能的树结构 。 取而代之的是一种贪婪的算法,它从单一的叶子开始,迭代地在树上添加分支。假设 和 是分裂后的左右节点的实例集。假设 ,则分裂后的损失减少量为:
这个公式在实践中通常被用来评估 。
2.3 Shrinkage and Column Subsampling
除了第 2.1节中提到的正则化目标外,还有两项技术被用来进一步防止过度拟合。第一种方法是 Friedman 引入的缩减技术。缩减是在每一步 Tree boosting 之后,将新增加的权重按系数 η 进行缩减。类似于弹性优化中的学习率,收缩减少了每个单独的树的影响,并为未来的树留下空间以改进模型。第二种技术是列(特征)抽样。该技术用于随机深林,它在一个用于梯度提升的商业软件 TreeNet 中实现,但没有在现有的开源软件包中实现。根据用户的反馈,使用列子采样甚至比传统的行采样(也支持)更能防止过度拟合。
3. SPLIT FINDING ALGORITHMS
3.1 Basic Exact Greedy Algorithm
树状学习中的一个关键问题是找到如公式(7)所示的最佳拆分,即为树如何生长。为了做到这一点,一个寻找分裂的算法列举了所有特征上的所有可能的拆分。 大多数现有的单机树形提升实现,如 scikit-learn、R 的 gbm 以及 XGBoost 的单机版都支持精确的贪婪算法。精确的贪心算法要列举出连续特征的所有可能的拆分,在计算上是很困难的。为了有效地做到这一点,该算法必须首先根据特征值对数据进行排序,并按排序顺序访问数据,以积累公式(7)中结构得分的梯度统计。
图 3. 为一次拆分步骤,其基本思路同 CART 一样,对特征值排序后遍历拆分点,将其中最优二叉拆分作为当前结点的拆分,得到左右子树。
3.2 Approximate Algorithm
精确贪心算法非常强大,因为它枚举所有可能的拆分点。但是,当数据不能完全装入内存时,就不可能有效地这样做。同样的问题也出现在分布式环境中。为了在这两种设置中支持有效的 gradient tree boosting 就需要一种近似算法。
作者总结了一个近似的框架,它类似于过去文献中提出的想法,在算法 2 中。 概括地说,该算法首先根据特征分布的百分位数提出候选分割点(具体标准将在第 3.3 节给出)。然后,该算法将连续特征映射到由这些候选点分割的桶中,汇总统计数据,并根据汇总的统计数据在提案中找到最佳解决方案。
图 4 :Higgs 10M dataset 上测试 AUC 收敛性的比较。其中 eps 参数表示分桶数量的倒数,作者发现局部方案需要较少的桶,因为它可以细化拆分的候选点。
该算法有两种变体,取决于对特征分位数的选取。全局变体在树构建的初始阶段在全体样本上的特征值中选取特征分位数,并在所有级别上使用相同的策略来寻找分位数。本地变体则是在待拆分节点包含的样本特征值上选取,每个节点拆分前都要进行。全局方法比局部方法需要更少的提议步骤,在根节点拆分之前进行一次即可。然而,通常全局提议需要更多的候选点,因为候选点在每次拆分后都不会被完善。局部提议在拆分后完善候选点,可能更适合于较深的树。图 4 给出了不同算法在 Higgs boson dataset 上的比较。实验发现,局部方案需要较少的候选点。 如果有足够多的候选点,全局方案可以和局部方案一样准确。
大多数现有的分布式树状学习的近似算法也遵循这个框架。值得注意的是,直接构建梯度统计的近似直方图也是可行。也可以使用其他变种的分桶策略来代替分位数。 分位数策略的优点是可分配和可重新计算,将在下一小节中详细介绍。从图 4 中,作者还发现,在合理的近似水平下,分位数策略可以获得与精确贪心算法相同的精度。
这三类配置在 XGBoost 包均有实现。
3.3 Weighted Quantile Sketch
近似算法的一个重要步骤是提出候选拆分点。通常使用特征分位数来使候选拆分点在数据上均匀分布。记多重集合 表示第 个特征值和每个训练实例的二阶梯度统计。作者定义排序函数 为:
表示特征值 小于 的实例的比例。其目的就是为了找到拆分点 ,以至于
其中 为近似因子,直观地说,这意味着每个分桶大约有 个候选点。这里每个数据点都由 加权。
要理解为什么 代表权重大小,作者将等式 3 写为:
可以理解为该目标函数以 为权重,以 为标签的平方损失函数,所以近似算法取分位数时,会以二阶偏导 为权重进行划分。
图 5. 按照 进行加权取分位数
3.4 Sparsity-aware Split Finding
图 6. 具有默认方向的树结构。当分割所需的特征缺失时,一个示例将被归类到默认方向。
在许多实际问题中,输入 稀疏是很常见的。造成稀疏的原因有多种:1)数据中存在缺失值;2) 统计中经常出现零条目;3)特征工程的产物,例如 one-hot 编码。让算法了解数据中的稀疏模式很重要。为此,作者建议在每个树节点中添加一个默认方向,如图 6 所示。当稀疏矩阵 x 中缺少一个值时,实例被分类为默认方向。
每个分支有两种默认方向选择。从数据中学习最佳默认方向。算法 3 关键的改进是只访问非缺失条目 。所提出的算法将不存在视为缺失值,并学习处理缺失值的最佳方向。当不存在对应于用户指定的值时,也可以应用相同的算法,方法是将枚举限制为一致的解决方案。
图 7.稀疏感知算法对 Allstate-10K 数据集的影响。数据集稀疏主要是由于 one-hot 编码。稀疏感知算法比未考虑稀疏性的原始版本快 50 倍以上
大多数现有的树形学习算法要么只对密集数据进行了优化,要么需要特定的程序来处理有限的情况,如分类编码。XGBoost 以一种统一的方式处理所有的稀疏模式。更重要的是,作者的方法利用了稀疏性,使计算复杂度与输入中的非缺失项数量成线性关系。图 7 显示了在 Allstate-10K 数据集(数据集的描述见第 6 节)上稀疏意识和原始的实现的比较。作者发现稀疏意识算法比原始的版本快 50 倍。这证实了稀疏感知算法的重要性。
4. SYSTEM DESIGN
4.1 Column Block for Parallel Learning
XGBoost 将每一列特征提前进行排序,以块(Block)的形式储存在缓存中,并以索引将特征值和梯度统计量 对应起来,每次节点拆分时会重复调用排好序的块。而且不同特征会分布在独立的块中,因此可以进行分布式或多线程的计算。
图 8.用于并行学习的块状结构。块中的每一列都是按相应的特征值排序的。对块中的一列进行线性扫描就足以列举出所有的拆分点
4.2 Cache-aware Access
特征值排序后通过索引来取梯度 会导致访问的内存空间不一致,进而降低缓存的命中率,影响算法效率。为解决这个问题,XGBoost 为每个线程分配一个单独的连续缓存区,用来存放梯度信息。
4.3 Blocks for Out-of-core Computation
数据量过大时,不能同时全部载入内存。XGBoost 将数据分为多个 blocks 并储存在硬盘中,使用一个独立的线程专门从磁盘中读取数据到内存中,实现计算和读取数据的同时进行。为了进一步提高磁盘读取数据性能,XGBoost 还使用了两种方法:一是通过压缩 block,用解压缩的开销换取磁盘读取的开销;二是将block分散储存在多个磁盘中,有助于提高磁盘吞吐量。
知识补充1. XGBoost 的优缺点
优点
精度更高:GBDT 只用到一阶泰勒展开,而 XGBoost 对损失函数进行了二阶泰勒展开。XGBoost 引入二阶导一方面是为了增加精度,另一方面也是为了能够自定义损失函数,二阶泰勒展开可以近似大量损失函数;
灵活性更强:GBDT 以 CART 作为基分类器,XGBoost 不仅支持 CART 还支持线性分类器,使用线性分类器的 XGBoost 相当于带 L1 和 L2 正则化项的逻辑斯蒂回归(分类问题)或者线性回归(回归问题)。此外,XGBoost 工具支持自定义损失函数,只需函数支持一阶和二阶求导;
正则化:XGBoost 在目标函数中加入了正则项,用于控制模型的复杂度。正则项里包含了树的叶子节点个数、叶子节点权重的 L2 范式。正则项降低了模型的方差,使学习出来的模型更加简单,有助于防止过拟合,这也是 XGBoost 优于传统 GBDT 的一个特性。
Shrinkage(缩减):相当于学习速率。XGBoost 在进行完一次迭代后,会将叶子节点的权重乘上该系数,主要是为了削弱每棵树的影响,让后面有更大的学习空间。传统 GBDT 的实现也有学习速率;
列抽样:XGBoost 借鉴了随机森林的做法,支持列抽样,不仅能降低过拟合,还能减少计算。这也是 XGBoost 异于传统 GBDT 的一个特性;
缺失值处理:对于特征的值有缺失的样本,XGBoost 采用的稀疏感知算法可以自动学习出它的分裂方向;
XGBoost 工具支持并行:boosting 不是一种串行的结构吗? 怎么并行的?注意 XGBoost 的并行不是 tree 粒度的并行,XGBoost 也是一次迭代完才能进行下一次迭代的(第 t 次迭代的代价函数里包含了前面 t-1 次迭代的预测值)。XGBoost 的并行是在特征粒度上的。我们知道,决策树的学习最耗时的一个步骤就是对特征的值进行排序(因为要确定最佳分割点),XGBoost 在训练之前,预先对数据进行了排序,然后保存为 block 结构,后面的迭代中重复地使用这个结构,大大减小计算量。这个 block 结构也使得并行成为了可能,在进行节点的分裂时,需要计算每个特征的增益,最终选增益最大的那个特征去做分裂,那么各个特征的增益计算就可以开多线程进行。
可并行的近似算法:树节点在进行分裂时,我们需要计算每个特征的每个分割点对应的增益,即用贪心法枚举所有可能的分割点。当数据无法一次载入内存或者在分布式情况下,贪心算法效率就会变得很低,所以 XGBoost 还提出了一种可并行的近似算法,用于高效地生成候选的分割点。
缺点
虽然利用预排序和近似算法可以降低寻找最佳分裂点的计算量,但在节点分裂过程中仍需要遍历数据集;
预排序过程的空间复杂度过高,不仅需要存储特征值,还需要存储特征对应样本的梯度统计值的索引,相当于消耗了两倍的内存。
2.分类回归树 Classification And Regression Tree,CART
参考自:《统计学习方法》【李航】第 5 章 5.5 节
CART 是在给定输入随机变量 X 条件下输出随机变量 Y 的条件概率分布的学习方法。CART 假设决策树是二叉树, 内部结点特征的取值为“是”和“否”, 左分支是取值为“是”的 分支, 右分支是取值为“否”的分支。这样的决策树等价于递归地二分每个特征, 将输入空 间即特征空间划分为有限个单元, 并在这些单元上确定预测的概率分布, 也就是在输入给 定的条件下输出的条件概率分布。
CART算法由以下两步组成:
- 决策树生成:基于训练数据集生成决策树, 生成的决策树要尽量大;
- 决策树剪枝:用验证数据集对已生成的树进行剪枝并选择最优子树, 这时用损 失函数最小作为剪枝的标准。
2.1 CART 生成算法
决策树的生成就是递归地构建二叉决策树的过程。对回归树用平方误差最小化准则,
对分类树用基尼指数(Gini index) 最小化准则, 进行特征选择, 生成二叉树。
2.1.1 回归数的生成
假设 与 分别为输入和输出变量,且 是连续变量,给定训练数据集
考虑如何生成回归树。
一个回归树对应于输入空间(即特征空间)的一个划分以及划分的单元的输出值。假设已将输入空间划分为 个单元 ,并且在每个单元 上有一个固定的输出值 ,于是回归树模型可表示为:
当输入空间的划分确定时,可以用平方误差 来表示回归树对于训练数据的预测误差,用平方误差最小准则求解每个单元上的最优输出值。易知,单元 上的 的最优值 是 上的所有的输入实例 对应的输出 的均值,即
问题在于如何对输入空间进行划分。这里采用启发式的方法,选择第 个变量 和它的取值 作为切分变量(Splitting Variable)和切分点(Splitting Point),并定义两个区域:
然后寻找最优切分变量 和最优切分点 。具体地,求解
对固定输入变量 可以找到最优切分点 。
遍历所有输入变量,找到最优的切分变量 ,构成一个对 。依此将输入空间划分为两个区域。接着,对每个区域重复上述划分过程,直到满足停止条件为止。这样就生成一棵回归树。这样的回归树通常称为最小二乘回归树(least squares regression tree),现将算法叙述如下:
算法(最小二乘回归树生成算法)
1.选择最优切分变量 与切分点 ,求解
遍历变量 ,对固定的切分变量 扫描切分点 ,选择上式达到最小值的对 。
2.用选定的对 划分区域并决定相应的输出值:
3.继续对两个子区域调用 1、2,直到满足停止条件。
4.将输入空间划分为 个区域 ,生成决策树:
输入:训练数据集 ;
输出:回归树 。
具体细节:在训练数据集所在的输入空间中,递归地将每个区域划分为两个子区域并决定每个子区域上的输出值,构建二叉决策树:
2.1.2 分类树的生成
分类树用基尼指数选择最优特征,同时决定该特征的最优二值切分点。
基尼指数定义:分类问题中,假设有 个类,样本点属于第 类的概率为 ,则概率分布的基尼指数定义为
对于二分类问题,若样本点属于第 1 个类的概率是 ,则概率分布的基尼指数为
对于给定的样本集合 ,其基尼指数为
这里, 是 中属于第 类的样本子集, 是类的个数。
如果样本集合 根据特征 是否取某一可能值 被分割成 和 两部分,即
基尼指数 表示集合 的不确定性,基尼指数 表示经 分割后集合 的不确定性。基尼指数越大,样本集合的不确定性也就越大,这一点与熵相似。
算法(CART 生成算法)
1.设结点的训练数据集为 ,计算现有特征对该数据集的基尼指数。此时,对每
一个特征 ,对其可能取的每个值 ,根据样本点对 = 的测试为“是”或“否”将 分割成 和 两部分,利用 计算 = 时的基尼指数。
2.在所有可能的特征 以及它们所有可能的切分点 中,选择基尼指数最小的特征
及其对应的切分点作为最优特征与最优切分点。依最优特征与最优切分点,从现结点生成
两个子结点,将训练数据集依特征分配到两个子结点中去。
3.对两个子结点递归地调用 1,2 直至满足停止条件。
4.生成 CART 决策树。
5.算法停止计算的条件是结点中的样本个数小于预定阈值,或样本集的基尼指数小于预 定阈值(样本基本属于同一类),或者没有更多特征
输入:训练集 ;停止计算的条件;
输出:CART 决策树
具体细节:根据训练数据集,从根结点开始,递归地对每个结点进行以下操作,构建二叉决策
树:
2.2 CART 减枝
CART 剪枝算法从“完全生长”的决策树的底端剪去一些子树,使决策树变小(模型变简单),从而能够对未知数据有更准确的预测。CART 剪枝算法由两步组成:首先从生成算法产生的决策树 底端开始不断剪枝,直到 的根结点,形成一个子树序列 ;然后通过交叉验证法在独立的验证数据集上对子树序列进行测试,从中选择最优子树。
1.剪枝,形成一个子树序列
在剪枝过程中,计算子树的损失函数: 。其中, 为任意子树, 为训练数据的预测误差(如基尼指数), 为子树的叶结点个数, 为参数, 为参数是 时的子树 的整体损失。参数 权衡训练数据的拟合程度与模型的复杂度。
对于固定的 ,一定存在使损失函数 最小的子树,将其表示为 。 在损失函数 最小的意义下是最优的。任意验证这样的最优子树是唯一的。当 大的时候,最优子树 偏小;当 小的时候,最优子树 偏大。极端情况下,当 时,整体树是最优的。当 时,根节点组成的单结点树是最优的。
Breiman 等人证明:可以用递归的方法对树进行剪枝。将 从小增大,,产生一系列区间 ;剪枝得到的子树序列对应着区间 的最优子树序列 ,序列中子树是嵌套的。
具体为,从整体树 开始剪枝。对 的任意内部结点 ,以 为单结点树的损失函数是:
以 为根结点的子树 的损失函数为:
当 及 充分小时,有不等式:
当 增大时,在某一 有:
当 再增大时,。只要 , 与 有相同的损失函数值,而 的结点少,因此 比 更可取,对 进行剪枝。
为此,对 中每一内部结点 ,计算
它表示剪枝后函数减少的程度。在 中减去 最小的 ,将得到的子树作为 ,同时将最小的 设为 。 为区间 的最优子树。
如此剪枝下去,直至得到根结点。在这一过程中,不断地增加 的值,产生新的区间。
2.在剪枝得到的子树序列 中通过交叉验证选取最优子树
具体地,利用独立的验证数据集,测试子树序列 中各棵子树的平方误差或基尼指数。平方误差或基尼指数最小的决策树被认为是最优的决策树。在子树序列中,每棵子树 都对应于一个参数 。所以,当最优子树 确定时,对应的 也确定了,即得到最优决策树 。
- CART 剪枝算法
- 1.设 ;
- 2.设 ;
- 3.自下而上对内部结点 计算 以及 。其中 表示以 为根节点的子树, 是对训练数据的预测误差, 是 的叶节点个数;
- 4.自上而下地访问内部结点 ,如果有 ,进行剪枝,并对叶节点 以多数表决法决定其类,得到树 ;
- 5.设 ;
- 6.如果 不是由根结点单独构成的树,则回到步骤 4;
- 7.采用交叉验证法在子树序列 中选取最优子树 ;
- 输入:CART 算法生成的决策树 ;
- 输出:最优决策树 ;
- 具体过程:
- XGBoost: A Scalable Tree Boosting System: https://arxiv.org/pdf/1603.0275
- 机器学习 | XGBoost详解:https://zhuanlan.zhihu.com/p/142413825
- 《统计学习方法》【李航】第 5 章 5.5 节