XGBoost: 你不能不知的机器学习算法

XGBoost做为一个很是经常使用的算法,我以为颇有必要了解一下它的前因后果,因而抽空找了一些资料,主要包括陈天奇大佬的论文以及演讲PPT,以及网络上的一些博客文章,今天在这里对这些知识点进行整理概括,论文中的一些专业术语尽量保留不翻译,但会在下面写出本身的理解与解释。算法

资料下载:公众号(SAMshare)回复"xgb"获取缓存

🚗 Index

  • XGBoost介绍
  • XGBoost亮点
  • 梯度加强树算法介绍
    • Regularized Learning Objective
    • Gradient Tree Boosting
    • Shrinkage and Column Subsampling
  • 分裂查找算法介绍
    • Basic Exact Greedy Algorithm
    • Approximate Algorithm
    • Weighted Quantile Sketch
    • Sparsity-aware Split Finding
  • XGBoost的系统设计
    • Column Block for Parallel Learning
    • Cache-aware Access
    • Blocks for Out-of-core Computation

🙊 XGBoost介绍

在Paper中,做者定义XGBoost:网络

a scalable machine learning system for tree boosting.多线程

XGBoost为“Extreme Gradient Boosting”的缩写,里面包含了关键字'Boosting',意味着它是一个boosting集成算法,因此它的主要思路是将成百上千个树模型组合起来成为一个准确率很高的模型,此模型经过不断迭代生成新的树。app

XGBoost咱们经常使用于监督学习,即创建一个数据模型,输入相关特征从而预测出目标,而这一过程,须要咱们找到训练数据最好的参数,因此咱们须要定义一个目标函数,一般由训练损失(traning loss)和正则项(regularization term)组成。机器学习

训练损失评估了预测模型的效果,例如经常使用的训练损失指标是均方偏差或是逻辑回归的logistic loss。正则项则是控制着模型的复杂度,避免模型不被过分拟合。这两个互相博弈(tradeoff)的指标保证了模型的预测效果以及简洁程度。分布式

💫 XGBoost亮点

  • We design and build a highly scalable end-to-end tree boosting system.
  • We propose a theoretically justified weighted quantile sketch for efficient proposal calculation.
  • We introduce a novel sparsity-aware algorithm for par- allel tree learning.
  • We propose an effective cache-aware block structure for out-of-core tree learning.

翻译来讲,就是它设计并构建了适用于大规模的 end-to-end 的Boosting系统(end-to-end指的是端到端,就是只关心输入和输出,中间过程都不care),并且实现特征选择的并行处理,正则使用L2的稀疏感知算法,并且也提出了有效的缓存结构,加大训练效率函数

另外,其余博文也有一些总结:学习

  • 相对GBDT来讲,XGB在增长二阶梯度有更高的精度;
  • XGB的节点划分策略带有进行预排序,利用样本在损失函数上面的二阶梯度做为权值;
  • XGB对稀疏的特征划分方式;
  • 在处理特征的粒度上进行多线程的优化;
  • 使用近似算法替代每一个样本逐个判断最佳分裂点的Exact Greedy Algorithm算法。

🌲 梯度加强树算法介绍

XGBoost仍是采用属于gradient tree boosting algorithms,推导过程和已有的算法理论相似,但这里有了一些创新,好比正则化学习目标、样本子采样、特征子采样、近似算法等等。测试

3.1 Regularized Learning Objective

给定一个n X m维的数据集D,经过训练D,获得K棵树,而这K棵树累加的值做为咱们的预测值。
file

其中,file
是CART的空间,q表示每一个树的结构,其能够将每一个样本映射到对应的叶节点中,T是树中叶子节点的个数。

有了上面的预测值,咱们能够代入loss function,获得咱们的损失函数:

file

能够看出损失函数由两部分组成,Training Loss和Regularization。

3.2 Gradient Tree Boosting

这一节是对损失函数的推导求解,这里不是采起传统的优化方法进行优化,而是采用了Additive Training训练,咱们将Training Loss部分,展开成K棵树叠加的形式,开始于一个常数,每次增长一个新的函数学习当前的树,贪婪地利用偏差函数改善当前模型,而这里创新的点在于对偏差函数进行二阶泰勒近似展开。

具体公式推导就不展开了,建议查阅:

XGBoost原理介绍:http://www.javashuo.com/article/p-yxrafazt-b.html

3.3 Shrinkage and Column Subsampling

这一节讲到了两种防止过拟合的tricks,Shrinkage和Column Subsampling。

  • Shrinkage:权值收缩,主要针对叶子节点,在每一次的Tree Boosting后,收缩叶子节点的权重,下降了每棵独立树的影响,为未来的优化留出一些空间。
  • Column Subsampling:这种技术出如今RF中,这种作法不只能够防止过拟合,还能提高一部分训练效率。

分裂查找算法介绍

4.1 Basic Exact Greedy Algorithm

这个是常见的基础贪心算法,即对全部的特征进行遍历处理,这就要求对计算资源要求比较高,由于须要对每一个特征计算其信息增益,选择增益最大的做为分裂点,固然是须要比较多的时间和算力。

file

4.2 Approximate Algorithm

顾名思义,近似算法就是可能效果或者原理和Exact Greedy Algorithm差很少的算法,它的原理是根据特征分布的百分位数进行采样,选择待分裂点,而后,该算法将连续特征映射到由这些候选点分割的桶中,汇总统计信息并根据汇总的信息找到最佳解决方案,这里选择分裂点的方式有global和local:

  • global:在树构建的初始状态阶段选出全部候选分裂点,后面每层都使用相同的策略选择分裂点。
  • local:每次分裂后从新选出候选分裂点,适合深度较大的树,由于不须要提早准备过多的候选分裂点。

file

4.3 Weighted Quantile Sketch

分布式加权直方图算法是XGBoost提出的一种可并行的算法,树节点在进行分裂时,须要计算特征的信息增益,该算法用于高效地生成候选分裂点,对于大型的数据集,若是每一个实例具备相等权重时,quantile sketch算法能够解决,但对于加权数据集来讲,则不适用,为了解决该问题,XGBoost提出了分布式加权quantile sketch算法。

4.4 Sparsity-aware Split Finding

稀疏感知分裂发现,在现实生活中,特征每每都是稀疏的,有几种可能的缘由致使特征稀疏:

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以统一的方式处理缺失的状况,分裂中只选择没有缺失的数据去进行节点分支,而后缺失状况默认指定一个方向,其效率paper里说了是提高了50倍。

file

file

📚 XGBoost的系统设计

5.1 Column Block for Parallel Learning

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

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

file

因此,特征预排序只须要在开始的时候作一次便可,后续能够重复调用,大大减小了每次排序的耗时,因此也能够实现并行化学习,计算每一个特征的信息增益。

5.2 Cache-aware Access

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

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

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

file

5.3 Blocks for Out-of-core Computation

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

在计算过程当中,使用独立的线程将Block预提取到主内存缓冲区,这样子数据计算和磁盘读取能够同步进行,但因为IO很是耗时,因此还有2种技术来改善这种核外计算:

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

📖 References

相关文章
相关标签/搜索