这篇论文一作为陈天齐,XGBoost是从竞赛pk中脱颖而出的算法,目前开源在github ,和传统gbdt方式不同,XGBoost对loss function 进行了二阶的泰勒展开,并增加了正则项,用于权衡目标函数的下降和模型的复杂度[12]。罗列下优势:
可扩展性强
为稀疏数据设计的决策树训练方法
理论上得到验证的加权分位数略图法
并行和分布式计算
设计高效核外计算,进行cache-aware数据块处理
分布式训练树模型boosting方法已有[1,2,3]。
整体目标 L ( ϕ ) = ∑ i l ( y i , ^ y i ) + ∑ k Ω ( f k ) L ( ϕ ) = ∑ i l ( y i , y ^ i ) + ∑ k Ω ( f k )
其中L ( ⋅ ) L ( ⋅ ) 为目标函数,l ( ⋅ ) l ( ⋅ ) 是损失函数,通常是凸函数,用于 刻画预测值^ y i y ^ i 和真实值y i y i 的差异,第二项Ω ( ⋅ ) Ω ( ⋅ ) 为模型的正则化项, 用于降低模型的复杂度,减轻过拟合问题,类似的正则化方法可以在引文[4]看到。模型目标是最小化目标函数。L ( ⋅ ) L ( ⋅ ) 为函数空间上的表达,我们可以将其转换为下面这张gradient boosting 的方式,记^ y ( t ) i y ^ i ( t ) 为第i i 个样本第t t 轮迭代:L ( t ) = n ∑ i = 1 l ( y i , ^ y i ( t − 1 ) + f t ( x i ) ) + Ω ( f t ) L ( t ) = ∑ i = 1 n l ( y i , y ^ i ( t − 1 ) + f t ( x i ) ) + Ω ( f t ) 对该函数在^ y ( t ) i y ^ i ( t ) 位置进行二阶泰勒展开,可以加速优化过程,我们得到目标函数的近似:L ( t ) ≃ n ∑ i = 1 [ l ( y i , ^ y ( t − 1 ) ) + g i f t ( x i ) + 1 2 h i f 2 t ( x i ) ] + Ω ( f t ) L ( t ) ≃ ∑ i = 1 n [ l ( y i , y ^ ( t − 1 ) ) + g i f t ( x i ) + 1 2 h i f t 2 ( x i ) ] + Ω ( f t ) 泰勒展开的推导部分,可以参考思考1,其中第一项是常数项,删除可得:~ L ( t ) = n ∑ i = 1 [ g i f t ( x i ) + 1 2 h i f 2 t ( x i ) ] + Ω ( f t ) − − ( 1 ) L ~ ( t ) = ∑ i = 1 n [ g i f t ( x i ) + 1 2 h i f t 2 ( x i ) ] + Ω ( f t ) − − ( 1 ) 下面对正则化项进行参数化定义。延续前文GBDT的概念,引入分裂节点j j 定义的区域记作I j = { i | q ( x i ) = j } I j = { i | q ( x i ) = j } 那么Ω Ω 展开原目标函数改写为:~ L ( t ) = n ∑ i = 1 [ g i f t ( x i ) + 1 2 h i f 2 t ( x i ) ] + γ T + 1 2 λ T ∑ j = 1 w 2 j = T ∑ j = 1 ⎡ ⎣ ⎛ ⎝ ∑ i ∈ I j g i ⎞ ⎠ w j + 1 2 ⎛ ⎝ ∑ i ∈ I j h i + λ ⎞ ⎠ w 2 j ⎤ ⎦ + γ T − − ( 2 ) L ~ ( t ) = ∑ i = 1 n [ g i f t ( x i ) + 1 2 h i f t 2 ( x i ) ] + γ T + 1 2 λ ∑ j = 1 T w j 2 = ∑ j = 1 T [ ( ∑ i ∈ I j g i ) w j + 1 2 ( ∑ i ∈ I j h i + λ ) w j 2 ] + γ T − − ( 2 ) 对于固定的树结构q ( x ) q ( x ) ,对w j w j 求导得解析解w ∗ j w j ∗ : w ∗ j = ∑ i ∈ I j g i ∑ i ∈ I j h i + λ w j ∗ = ∑ i ∈ I j g i ∑ i ∈ I j h i + λ 代入到( 1 ) ( 1 ) 式中,可得~ L ( t ) ( q ) = − 1 2 ( ∑ i ∈ I j g i ) 2 ∑ i ∈ I j h i + λ + γ T − − ( 3 ) L ~ ( t ) ( q ) = − 1 2 ( ∑ i ∈ I j g i ) 2 ∑ i ∈ I j h i + λ + γ T − − ( 3 ) 公式( 3 ) ( 3 ) 可以作为分裂节点的打分,形式上很像CART树纯度打分的计算,区别在于它是从目标函数中推导而得。图中显示目标函数值的计算: 实践中,很难去穷举每一颗树进行打分,再选出最好的。通常采用贪心的方式,逐层选择最佳的分裂节点。假设I L I L 和I R I R 为分裂节点的左右节点,记I = I L ∪ I R I = I L ∪ I R 。 则选择此节点分裂的收益为:L s p l i t = 1 2 ⎡ ⎢
⎢
⎢
⎢
⎢
⎢
⎢ ⎣ ( ∑ i ∈ I L g i ) 2 ∑ i ∈ I L h i + λ + ( ∑ i ∈ I J g i ) 2 ∑ i ∈ I J h i + λ − ( ∑ i ∈ I g i ) 2 ∑ i ∈ I h i + λ ⎤ ⎥
⎥
⎥
⎥
⎥
⎥
⎥ ⎦ − γ − − ( 4 ) L s p l i t = 1 2 [ ( ∑ i ∈ I L g i ) 2 ∑ i ∈ I L h i + λ + ( ∑ i ∈ I J g i ) 2 ∑ i ∈ I J h i + λ − ( ∑ i ∈ I g i ) 2 ∑ i ∈ I h i + λ ] − γ − − ( 4 ) [补充] 1.作为GB类方法,也可以采用shrinkage策略 2.随机森林[5]的特征降采样(subsampling)克服过拟合代码 ,xgboost用了类似的技术。和传统的降采样不同,xgboost按列进行降采样,在并行化有加速作用。(待研究)
查找分裂节点(split finding) 贪心算法 贪心算法是最基本的方法,前面介绍的时候有提过。具体做法:遍历所有特征中可能的分裂点位置,根据公式( 4 ) ( 4 ) 找到最合适的位置。S p l i t _ F i n d i n g ( ) S p l i t _ F i n d i n g ( ) 算法流程如下S p l i t _ F i n d i n g ( ) : I n p u t : I , i n s t a n c e s e t o f c u r r e n t n o d e I n p u t : d , f e a t u r e d i m e n s i o n g a i n ← 0 G ← ∑ i ∈ I g i , H ← ∑ i ∈ I h i f o r k = 1 t o m d o G L ← 0 , H L ← 0 f o r j i n s o r t e d ( I , b y x j k ) d o G L ← G L + g j , H L ← H L + h j G R ← G − G L , H R ← H − H L s c o r e ← max ( s c o r e , G 2 L H L + λ + G 2 R H R + λ − G 2 H + λ ) e n d e n d O u t p u t : s p l i t _ v a l u e w i t h m a x s c o r e S p l i t _ F i n d i n g ( ) : I n p u t : I , i n s t a n c e s e t o f c u r r e n t n o d e I n p u t : d , f e a t u r e d i m e n s i o n g a i n ← 0 G ← ∑ i ∈ I g i , H ← ∑ i ∈ I h i f o r k = 1 t o m d o G L ← 0 , H L ← 0 f o r j i n s o r t e d ( I , b y x j k ) d o G L ← G L + g j , H L ← H L + h j G R ← G − G L , H R ← H − H L s c o r e ← max ( s c o r e , G L 2 H L + λ + G R 2 H R + λ − G 2 H + λ ) e n d e n d O u t p u t : s p l i t _ v a l u e w i t h m a x s c o r e 近似算法 如果数据不能一次读入内存,使用贪心算法效率较低。近似算法在过去也有应用[6, 7, 8]。具体描述为,对于某个特征x k x k ,找到该特征若干值域分界点{ s k 1 , s k 2 , . . . , s k l } { s k 1 , s k 2 , . . . , s k l } 。根据特征的值对样本进行分桶,对于每个桶内的样本统计值G G 、H H 进行累加(两个统计量含义同贪心算法),记为分界点v v 的统计量,v v 满足{ x k j = s k v } { x k j = s k v } 。最后在分界点集合上调用S p l i t _ F i n d i n g ( ) S p l i t _ F i n d i n g ( ) 进行贪心查找,得到的结果为最佳分裂点的近似。具体如下: f o r k = 1 t o m d o P r o p o s e S k = { s k 1 , s k 2 , . . . , s k l } b y p e r c e n t i l e o n f e a t u r e k P r o p o s e c a n b e d o n e p e r t r e e ( g l o b a l ) , o r p e r s p l i t ( l o c a l ) e n d f o r k = 1 t o m d o G k v ←= ∑ j ∈ { j | s k , v ≥ x j k > s k , v − 1 } g j H k v ←= ∑ j ∈ { j | s k , v ≥ x j k > s k , v − 1 } h j e n d c a l l S p l i t _ F i n d i n g ( ) f o r k = 1 t o m d o P r o p o s e S k = { s k 1 , s k 2 , . . . , s k l } b y p e r c e n t i l e o n f e a t u r e k P r o p o s e c a n b e d o n e p e r t r e e ( g l o b a l ) , o r p e r s p l i t ( l o c a l ) e n d f o r k = 1 t o m d o G k v ←= ∑ j ∈ { j | s k , v ≥ x j k > s k , v − 1 } g j H k v ←= ∑ j ∈ { j | s k , v ≥ x j k > s k , v − 1 } h j e n d c a l l S p l i t _ F i n d i n g ( ) 下面介绍找特征值域分界点{ s k 1 , s k 2 , . . . , s k l } { s k 1 , s k 2 , . . . , s k l } 的方法,加权分位数略图 。为了尽可能地逼近最佳分裂点,我们需要保证采样后数据分布同原始数据尽可能一致。记D k = { ( x 1 k , h 1 ) , ( x 2 k , h 2 ) ⋯ ( x n k , h n ) } D k = { ( x 1 k , h 1 ) , ( x 2 k , h 2 ) ⋯ ( x n k , h n ) } 表示 每个训练样本的第k k 维特征值和对应二阶导数。接下来定义排序函数为r k ( ⋅ ) : R → [ 0 , + ∞ ) r k ( ⋅ ) : R → [ 0 , + ∞ ) r k ( z ) = 1 ∑ ( x , h ) ∈ D k h ∑ ( x , h ) ∈ D k , x < z h r k ( z ) = 1 ∑ ( x , h ) ∈ D k h ∑ ( x , h ) ∈ D k , x < z h 函数表示特征的值小于z z 的样本分布占比,其中二阶导数h h 可以视为权重,后面论述。在这个排序函数下,我们找到一组点{ s k 1 , s k 2 , . . . , s k l } { s k 1 , s k 2 , . . . , s k l } ,满足:∣ ∣ r k ( s k , j ) − r k ( s k , j + 1 ) ∣ ∣ < ε | r k ( s k , j ) − r k ( s k , j + 1 ) | < ε 其中,s k 1 = min i x i k , s k l = max i x i k s k 1 = min i x i k , s k l = max i x i k 。ε ε 为采样率,直观上理解,我们最后会得到1 / ε 1 / ε 个分界点。 讨论下为何h i h i 表示权重。从目标函数( 1 ) ( 1 ) 出发,配方得到n ∑ i = 1 [ 1 2 ( f t ( x i ) − g i / h i ) 2 ] + Ω ( f t ) + c o n s t a n t ∑ i = 1 n [ 1 2 ( f t ( x i ) − g i / h i ) 2 ] + Ω ( f t ) + c o n s t a n t 具体证明过程见原作附录。这是一个关于标签为g i / h i g i / h i 和权重为h i h i 的平方误差形式。当每个权重相同的时候,退化为普通的分位数略图[9, 10] 接下来介绍另一个论文的亮点,寻找分裂点的过程中,如何克服数据稀疏。稀疏数据可能来自于missing value 、大量的0值、或者特征工程例如采用one-hot表示带来的。为了解决这个问题,设定一个默认指向,当发生特征缺失的时候,将样本分类到默认分支,如下图: 默认方向由训练集中non-missing value学习而得,把不存在的值也当成missing value进行学习和处理,如下:S p a r s i t y _ S p l i t _ F i n d i n g ( ) : I n p u t : I , i n s t a n c e s e t o f c u r r e n t n o d e I n p u t : d , f e a t u r e d i m e n s i o n g a i n ← 0 G ← ∑ i ∈ I g i , H ← ∑ i ∈ I h i f o r k = 1 t o m d o G L ← 0 , H L ← 0 f o r j i n s o r t e d ( I k , a s c e n t o r d e r b y x j k ) d o G L ← G L + g j , H L ← H L + h j G R ← G − G L , H R ← H − H L s c o r e ← max ( s c o r e , G 2 L H L + λ + G 2 R H R + λ − G 2 H + λ ) e n d G R ← 0 , H R ← 0 f o r j i n s o r t e d ( I k , a s c e n t o r d e r b y x j k ) d o G R ← G R + g j , H R ← H R + h j G L ← G − G R , H L ← H − H R s c o r e ← max ( s c o r e , G 2 L H L + λ + G 2 R H R + λ − G 2 H + λ ) e n d e n d O u t p u t : s p l i t _ v a l u e a n d d e f a u l t d i r e c t i o n s w i t h m a x s c o r e S p a r s i t y _ S p l i t _ F i n d i n g ( ) : I n p u t : I , i n s t a n c e s e t o f c u r r e n t n o d e I n p u t : d , f e a t u r e d i m e n s i o n g a i n ← 0 G ← ∑ i ∈ I g i , H ← ∑ i ∈ I h i f o r k = 1 t o m d o G L ← 0 , H L ← 0 f o r j i n s o r t e d ( I k , a s c e n t o r d e r b y x j k ) d o G L ← G L + g j , H L ← H L + h j G R ← G − G L , H R ← H − H L s c o r e ← max ( s c o r e , G L 2 H L + λ + G R 2 H R + λ − G 2 H + λ ) e n d G R ← 0 , H R ← 0 f o r j i n s o r t e d ( I k , a s c e n t o r d e r b y x j k ) d o G R ← G R + g j , H R ← H R + h j G L ← G − G R , H L ← H − H R s c o r e ← max ( s c o r e , G L 2 H L + λ + G R 2 H R + λ − G 2 H + λ ) e n d e n d O u t p u t : s p l i t _ v a l u e a n d d e f a u l t d i r e c t i o n s w i t h m a x s c o r e
论文后续内容为系统部分 (包括并行化、cache-aware加速、数据块预处理,需要结合代码研读)、实验 (在不同的数据集上进行了实验,包括分类、LTR、CTR预估)详见论文[11] 代码阅读: 代码易用,注释较完备,支持多种语言,目前仍在持续集成和更新,其中稀疏矩阵存储为CSR格式(见附录思考[2])。 很多核心的机器学习函数复用了作者的另一个机器学习库DMLC(Distributed Machine Learning Common Codebase),和参考[12]中介绍代码版本对比,运用较多通用的工厂类方法(见附录思考[3]),草草介绍下主体代码组成,下一篇会进行详细拆解:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Data.h 定义基础数据结构,
如数据信息MetaInfo,稀疏矩阵RowBatch,数据集合RowSet,训练时矩阵表达DMatrix。
Tree_model.h 定义了树相关参数TreeParam,树的模板类TreeModel(对应树节点Node),
回归树RegTree,关于树的操作(增删改查,读写load,save,dump2text等)。
Tree_updater.h 完成对树的更新,包含对象工厂类用于注册不同的更新操作:
"updater_colmaker.cc" , 通过数据列(论文介绍方式)树的更新(单机多线程版本)
"updater_skmaker.cc" , 分位数略图法进行数据采样
"updater_refresh.cc" , 更新操作
"updater_prune.cc" , 更新过程中进行剪枝
"updater_histmaker.cc" , 通过直方图相关统计量完成树的更新
"updater_sync.cc" , 从分布训练机器节点中进行树的同步
Objective.h 定义了目标函数,具体优化目标实现,回归,分类,排序函数由对象工厂生成:
"multiclass_obj.cc" , 多分类损失函数("SoftmaxMultiClass" ,"SoftprobMultiClass" )
"rank_obj.cc" , 排序损失函数,有多种可选(PairwiseRankObj,LambdaRankNDCG,LambdaRankObjMAP)
"regression_obj.cc" ,回归损失函数("GammaRegression" )
看demo可知,xgboost允许用户自定义损失函数。
metric.h 模型效果评估类,包含elementwise_metric、multiclass_metric、rank_metric三类。
"elementwise_metric.cc" : 定义评估函数有(RMSE, MAE, logLoss, Error, PosssionNegLoglik,
GammaDeviance, GammaNlogLik)
"multiclass_metric.cc" : 定义两种评估指标(SoftmaxMultiClass, SoftprobMultiClass)
"rank_metric.cc" : 定义评估指标(AMS, Auc, Precision, NDCG, MAP)
附录 引文 [1] Panda, Biswanath, et al. “PLANET: massively parallel learning of tree ensembles with MapReduce.” Proceedings of the Vldb Endowment 2.2(2009):1426-1437. [2] Tyree, Stephen, et al. “Parallel boosted regression trees for web search ranking.” International Conference on World Wide Web ACM, 2011:387-396. [3] Ye, Jerry, et al. “Stochastic gradient boosted distributed decision trees.” ACM Conference on Information and Knowledge Management, CIKM 2009, Hong Kong, China, November 2009:2061-2064. [4] Johnson, Rie, and Z. Tong. “Learning Nonlinear Functions Using Regularized Greedy Forest.” IEEE Transactions on Pattern Analysis & Machine Intelligence 36.5(2013):942-54. [5] Friedman, Jerome H., and B. E. Popescu. “Importance Sampled Learning Ensembles.” (2003). [6] Li, Ping, C. J. C. Burges, and Q. Wu. “McRank: Learning to Rank Using Multiple Classification and Gradient Boosting.” Advances in Neural Information Processing Systems (2007):897-904. [7] Bekkerman, Ron, M. Bilenko, and J. Langford. “Scaling up machine learning: parallel and distributed approaches.” ACM SIGKDD International Conference Tutorials ACM, 2011:1-1. [8] Tyree, Stephen, et al. “Parallel boosted regression trees for web search ranking.” International Conference on World Wide Web ACM, 2011:387-396. [9] Greenwald, Michael. “Space-efficient online computation of quantile summaries.” Acm Sigmod Record 30.2(2001):58–66. [10] Zhang, Qi, and W. Wang. “A Fast Algorithm for Approximate Quantiles in High Speed Data Streams.” (2007):29-29. [11]Chen, Tianqi, and C. Guestrin. “XGBoost: A Scalable Tree Boosting System.” (2016). [12] xgboost导读和实战(百度云地址 ),王超,陈帅华 [13] xgboost代码参数说明 , @zc02051126译 [14]xgboost: 速度快效果好的boosting模型 ,何通 [15]Introduction to Boosted Trees , 官网
思考 [1].不能直接看明白,手痒推导一把就通顺多了。函数f ( x ) f ( x ) 在x 0 x 0 处的二阶展开式为:f ( x ) = f ( x 0 ) + f ′ ( x 0 ) ( x − x 0 ) + f ′′ ( x 0 ) ( x − x 0 ) 2 f ( x ) = f ( x 0 ) + f ′ ( x 0 ) ( x − x 0 ) + f ″ ( x 0 ) ( x − x 0 ) 2 我们对l ( y i , x ) l ( y i , x ) 在^ y ( t − 1 ) i y ^ i ( t − 1 ) 处进行二阶展开得到l ( y i , x ) = l ( y i , ^ y ( t − 1 ) ) + ∂ l ( y i , ^ y ( t − 1 ) ) ∂ ^ y ( t − 1 ) ( x − ^ y ( t − 1 ) ) + ∂ 2 l ( y i , ^ y ( t − 1 ) ) ∂ ^ y ( t − 1 ) ( x − ^ y ( t − 1 ) ) 2 l ( y i , x ) = l ( y i , y ^ ( t − 1 ) ) + ∂ l ( y i , y ^ ( t − 1 ) ) ∂ y ^ ( t − 1 ) ( x − y ^ ( t − 1 ) ) + ∂ 2 l ( y i , y ^ ( t − 1 ) ) ∂ y ^ ( t − 1 ) ( x − y ^ ( t − 1 ) ) 2 令x = ^ y ( t − 1 ) + f t ( x i ) x = y ^ ( t − 1 ) + f t ( x i ) ,且记一阶导为g i = ∂ l ( y i , ^ y ( t − 1 ) ) ∂ ^ y ( t − 1 ) g i = ∂ l ( y i , y ^ ( t − 1 ) ) ∂ y ^ ( t − 1 ) ,二阶导为h i = ∂ 2 l ( y i , ^ y ( t − 1 ) ) ∂ ^ y ( t − 1 ) h i = ∂ 2 l ( y i , y ^ ( t − 1 ) ) ∂ y ^ ( t − 1 ) 。 我们得到l ( y i , ^ y ( t − 1 ) + f t ( x i ) ) l ( y i , y ^ ( t − 1 ) + f t ( x i ) ) 的二阶泰勒展开:l ( y i , ^ y ( t − 1 ) ) + g i f t ( x i ) + 1 2 h i f 2 t ( x i ) l ( y i , y ^ ( t − 1 ) ) + g i f t ( x i ) + 1 2 h i f t 2 ( x i ) 带入目标函数可得:L ( t ) ≃ n ∑ i = 1 [ l ( y i , ^ y ( t − 1 ) ) + g i f t ( x i ) + 1 2 h i f 2 t ( x i ) ] + Ω ( f t ) L ( t ) ≃ ∑ i = 1 n [ l ( y i , y ^ ( t − 1 ) ) + g i f t ( x i ) + 1 2 h i f t 2 ( x i ) ] + Ω ( f t )
[2]:csr格式是什么?类似的格式有什么,它们之间的区别是什么? 参见:稀疏矩阵存储格式总结+存储效率对比:COO,CSR,DIA,ELL,HYB CSR有行偏移,列下标,值三种元素。行偏移数组大小为(总行数目+1),行偏移表示某一行的第一个元素在values里面的起始偏移位置。数值和列号与COO一致,表示一个元素以及其列号。如上图中,第一行元素1是0偏移,第二行元素2是2偏移,第三行元素5是4偏移,第4行元素6是7偏移。在行偏移的最后补上矩阵总的元素个数,本例中是9。
[3]思考:通用的工厂类 ,@tenfyzhong
ShawnXiao@baidu