XGBoost原理解析
摘要:对xgboost论文中的细节进行记录。
算法原理
系统设计
基于column block的并行

树学习最耗时的部分通常是对数据进行排序,为了降低排序带来的计算负荷,xgb使用基于block的结构对数据进行存储。每个block中的数据以compressed format(CSC)格式存储,每列按照数值大小进行排序。这样的数据结构仅需要在训练前计算一次,在后续的迭代过程中,可以重复使用。
对于精确算法,将所有数据保存在一个block中。建树的过程可以实现特征级别的并行,即每个线程处理一个特征。在单个线程内部,对数据的单次扫描可计算所有叶子节点在该特征上的最优分裂点。
对于近似算法,可以将不同的数据(按行)分布在不同的block中,并可以将不同的block分布到不同的机器。使用排好序的数据,qutile finding算法只需要线性扫描数据即可完成。
利用这样的结构,在对单个特征寻找分裂点时,也可以实现并行化,这也是xgb能够进行分布式并行的关键。
缓存感知(cache aware access)
block结构降低了计算的复杂度,但也带来了另外一个问题,那就是对梯度信息的读取是不连续的,如果梯度信息不能全部装进cache,这会导致cpu缓存命中率降低,从而影响性能。
在精确算法中,xgb使用cache-aware prefetch算法缓解这个问题。也就是为每个线程分配一个buffer,将梯度信息读入buffer,并以mini-batch的方式进行梯度累加。
对于近似算法,解决缓存命中失效的方法是选择合适的block size。过小的block size导致单线程的计算负载过小,并行不充分,过大的block size又会导致cache miss,因此需要做一个平衡。论文建议使用的block size为2^16。
核外计算(out of core computation)
为进行核外计算,将数据划分为多个block。计算期间,使用独立线程将磁盘上的block结构数据读进内存,因此计算和IO可以同步进行。然而,这只能解决一部分问题,因为IO占用的时间要远多于计算。因此,xgb使用以下两种方式优化:
数据压缩(block compression):将block按列进行压缩,并使用独立线程解压缩。这样可以对IO和CPU的占用时间进行对冲。
数据分区(block sharding):将数据分散到多个磁盘,每个磁盘使用一个线程读取数据,以此提高磁盘吞吐量。
单机精确算法实现
I. ObjFunction:对应于不同的Loss Function,可以完成一阶和二阶导数的计算。
II. GradientBooster:用于管理Boost方法生成的Model,注意,这里的Booster Model既可以对应于线性Booster Model,也可以对应于Tree Booster Model。
III. Updater:用于建树,根据具体的建树策略不同,也会有多种Updater。比如,在XGBoost里为了性能优化,既提供了单机多线程并行加速,也支持多机分布式加速。也就提供了若干种不同的并行建树的updater实现,按并行策略的不同,包括:
I). inter-feature exact parallelism (特征级精确并行)
II). inter-feature approximate parallelism(特征级近似并行,基于特征分bin计算,减少了枚举所有特征分裂点的开销)
III). intra-feature parallelism (特征内并行)
IV). inter-node parallelism (多机并行)
此外,为了避免overfit,还提供了一个用于对树进行剪枝的updater(TreePruner),以及一个用于在分布式场景下完成结点模型参数信息通信的updater(TreeSyncher),这样设计,关于建树的主要操作都可以通过Updater链的方式串接起来,比较一致干净,算是Decorator设计模式的一种应用。
以ColMaker(单机版的inter-feature parallelism,实现了精确建树的策略)为例,其建树操作大致如下:
updater_colmaker.cc:
ColMaker::Update()
-> Builder builder;
-> builder.Update()
-> InitData()
-> InitNewNode() // 为可用于split的树结点(即叶子结点,初始情况下只有一个
// 叶结点,也就是根结点) 计算统计量,包括gain/weight等
-> for (depth = 0; depth < 树的最大深度; ++depth)
-> FindSplit()
-> for (each feature) // 通过OpenMP获取
// inter-feature parallelism
-> UpdateSolution()
-> EnumerateSplit() // 每个执行线程处理一个特征,
// 选出每个特征的
// 最优split point
-> ParallelFindSplit()
// 多个执行线程同时处理一个特征,选出该特征
//的最优split point;
// 在每个线程里汇总各个线程内分配到的数据样
//本的统计量(grad/hess);
// aggregate所有线程的样本统计(grad/hess),
//计算出每个线程分配到的样本集合的边界特征值作为
//split point的最优分割点;
// 在每个线程分配到的样本集合对应的特征值集合进
//行枚举作为split point,选出最优分割点
-> SyncBestSolution()
// 上面的UpdateSolution()/ParallelFindSplit()
//会为所有待扩展分割的叶结点找到特征维度的最优split
//point,比如对于叶结点A,OpenMP线程1会找到特征F1
//的最优split point,OpenMP线程2会找到特征F2的最
//优split point,所以需要进行全局sync,找到叶结点A
//的最优split point。
-> 为需要进行分割的叶结点创建孩子结点
-> ResetPosition()
//根据上一步的分割动作,更新样本到树结点的映射关系
// Missing Value(i.e. default)和非Missing Value(i.e.
//non-default)分别处理
-> UpdateQueueExpand()
// 将待扩展分割的叶子结点用于替换qexpand_,作为下一轮split的
//起始基础
-> InitNewNode() // 为可用于split的树结点计算统计量



XGB vs GBDT
- 传统GBDT以CART作为基分类器,xgboost还支持线性分类器,这个时候xgboost相当于带L1和L2正则化项的逻辑斯蒂回归(分类问题)或者线性回归(回归问题)。
- 传统GBDT在优化时只用到一阶导数信息,xgboost则对代价函数进行了二阶泰勒展开,同时用到了一阶和二阶导数。顺便提一下,xgboost工具支持自定义代价函数,只要函数可一阶和二阶求导。
- xgboost在代价函数里加入了正则项,用于控制模型的复杂度。正则项里包含了树的叶子节点个数、每个叶子节点上输出的score的L2模的平方和。从Bias-variance tradeoff角度来讲,正则项降低了模型的variance,使学习出来的模型更加简单,防止过拟合,这也是xgboost优于传统GBDT的一个特性。
- Shrinkage(缩减),相当于学习速率(xgboost中的eta)。xgboost在进行完一次迭代后,会将叶子节点的权重乘上该系数,主要是为了削弱每棵树的影响,让后面有更大的学习空间。实际应用中,一般把eta设置得小一点,然后迭代次数设置得大一点。(补充:传统GBDT的实现也有学习速率)
- 列抽样(column subsampling)。xgboost借鉴了随机森林的做法,支持列抽样,不仅能降低过拟合,还能减少计算,这也是xgboost异于传统gbdt的一个特性。
- 对缺失值的处理。对于特征的值有缺失的样本,xgboost可以自动学习出它的分裂方向。
- xgboost工具支持并行。xgboost的并行不是tree粒度的并行,xgboost也是一次迭代完才能进行下一次迭代的(第t次迭代的代价函数里包含了前面t-1次迭代的预测值)。xgboost的并行是在特征粒度上的。我们知道,决策树的学习最耗时的一个步骤就是对特征的值进行排序(因为要确定最佳分割点),xgboost在训练之前,预先对数据进行了排序,然后保存为block结构,后面的迭代中重复地使用这个结构,大大减小计算量。这个block结构也使得并行成为了可能,在进行节点的分裂时,需要计算每个特征的增益,最终选增益最大的那个特征去做分裂,那么各个特征的增益计算就可以开多线程进行。
- 可并行的近似直方图算法。树节点在进行分裂时,我们需要计算每个特征的每个分割点对应的增益,即用贪心法枚举所有可能的分割点。当数据无法一次载入内存或者在分布式情况下,贪心算法效率就会变得很低,所以xgboost还提出了一种可并行的近似直方图算法,用于高效地生成候选的分割点.
参考链接
https://arxiv.org/pdf/1603.02754.pdf
http://www.ra.ethz.ch/CDstore/www2011/proceedings/p387.pdf
https://www.zhihu.com/question/41354392
https://weibo.com/p/1001603801281637563132
XGBoost原理解析的更多相关文章
- [原][Docker]特性与原理解析
Docker特性与原理解析 文章假设你已经熟悉了Docker的基本命令和基本知识 首先看看Docker提供了哪些特性: 交互式Shell:Docker可以分配一个虚拟终端并关联到任何容器的标准输入上, ...
- 【算法】(查找你附近的人) GeoHash核心原理解析及代码实现
本文地址 原文地址 分享提纲: 0. 引子 1. 感性认识GeoHash 2. GeoHash算法的步骤 3. GeoHash Base32编码长度与精度 4. GeoHash算法 5. 使用注意点( ...
- Web APi之过滤器执行过程原理解析【二】(十一)
前言 上一节我们详细讲解了过滤器的创建过程以及粗略的介绍了五种过滤器,用此五种过滤器对实现对执行Action方法各个时期的拦截非常重要.这一节我们简单将讲述在Action方法上.控制器上.全局上以及授 ...
- Web APi之过滤器创建过程原理解析【一】(十)
前言 Web API的简单流程就是从请求到执行到Action并最终作出响应,但是在这个过程有一把[筛子],那就是过滤器Filter,在从请求到Action这整个流程中使用Filter来进行相应的处理从 ...
- GeoHash原理解析
GeoHash 核心原理解析 引子 一提到索引,大家脑子里马上浮现出B树索引,因为大量的数据库(如MySQL.oracle.PostgreSQL等)都在使用B树.B树索引本质上是对索引字段 ...
- alibaba-dexposed 原理解析
alibaba-dexposed 原理解析 使用参考地址: http://blog.csdn.net/qxs965266509/article/details/49821413 原理参考地址: htt ...
- 支付宝Andfix 原理解析
支付宝Andfix 原理解析 使用参考地址: http://blog.csdn.net/qxs965266509/article/details/49802429 原理参考地址: http://blo ...
- xgboost原理及应用
1.背景 关于xgboost的原理网络上的资源很少,大多数还停留在应用层面,本文通过学习陈天奇博士的PPT 地址和xgboost导读和实战 地址,希望对xgboost原理进行深入理解. 2.xgboo ...
- JavaScript 模板引擎实现原理解析
1.入门实例 首先我们来看一个简单模板: <script type="template" id="template"> <h2> < ...
随机推荐
- 简历求职:STAR法则
做了近2年的大学生就业辅导工作,也接触了很多即将走出校园的大学生,做个总结与大家分享,同时也是对自己的一个总结. 最近刚听说STAR法则,这也是一直我们给学生的指导思想,百度了一下: STAR法则,即 ...
- 一个C#开发编写Java框架的心路历程
前言 这一篇絮絮叨叨,逻辑不太清晰的编写Java框架的的一个过程,主要描述我作为一个java初学者,在编写Java框架时的一些心得感悟. 因为我是C#的开发者,所以,在编写Java框架时,或多或少会带 ...
- C# 通过ServiceStack 操作Redis——List类型的使用及示例
Redis list的实现为一个双向链表,即可以支持反向查找和遍历,更方便操作,不过带来了部分额外的内存开销, /// <summary> /// Redis list的实现为一个双向链表 ...
- Qt3D使用assimp加载常规模型文件
Qt3D使用assimp加载三维模型文件,assimp支持很多常规格式的三维模型格式: 其中支持导入的格式有: 3D 3DS 3MF AC AC3D ACC AMJ ASE ASK B3D BLEND ...
- Python-tkinter-window
示例代码讲解 1.加载tkinter模块 2.创建一个窗口 3.设置窗口的主题 4.开始窗口的事件循环 import tkinter 2 win = tkinter.Tk() 3 win.title( ...
- I - Tetrahedron HDU - 6814
题目链接:https://vjudge.net/problem/HDU-6814 题意:在[1,n]中随机取三个数a,b,c作为直角四面体的三条直角棱,求顶点d到ABC面的高的倒数平方的数学期望. 思 ...
- Linux入门视频笔记三(常用工具集)
一.全局变量(Linux中的全局变量指在整个系统中都能用的变量) 1.USER:当前登录系统的用户的用户名 2.HOME:当前用户的主目录 cd $HOME 或 cd ~可以进入用户主目录 3.PAT ...
- Simulink中Scope数据保存至Workspace制图
0 问题 通常情况下,仿真模型中scope波形可编辑程度并不高,尽管高版本MATLAB中已经可以将其直接导出到figure,但效果并不是特别理想.在需要高质量输出波形图场合,就需要将其中数据导出到wo ...
- 如何在 NET 程序万种死法中有效的生成 Dump (上)
一:背景 相信很多人都知道通过 任务管理器 抓取dump,虽然简单粗暴,但无法满足程序的无数种死法,比如: 内存膨胀,程序爆炸 CPU爆高,程序累死 应用无响应,用户气死 意外退出,和人生一样 既然手 ...
- python进阶(16)深入了解GIL锁(最详细)
前言 python的使用者都知道Cpython解释器有一个弊端,真正执行时同一时间只会有一个线程执行,这是由于设计者当初设计的一个缺陷,里面有个叫GIL锁的,但他到底是什么?我们只知道因为他导致pyt ...