XGBoost: A Scalable Tree Boosting System论文研读

(1)正则化目标函数(Regularized Learning Objective)

假设m维特征n个样本的数据集 D = { ( x i , y i ) } D=\{(x_i,y_i)\} D={(xi,yi)},其中, ∣ D ∣ = n , x i ∈ R m , y i ∈ R |D|=n,x_i \in R^m,y_i \in R D=n,xiRm,yiR,使用K棵树进行预测:
y i ^ = ∑ k = 1 K f k ( x i ) , f k ∈ Γ (1) \hat {y_i}=\sum_{k=1}^K {f_k(x_i)},f_k \in \varGamma \tag{1} yi^=k=1Kfk(xi),fkΓ(1)
其中, Γ = { f ( x ) = w q ( x ) } , q : R m → T , w ∈ R T \varGamma=\{f(x)=w_{q(x)}\},q:R^m \to T,w \in R^T Γ={f(x)=wq(x)},q:RmT,wRT,q表示样本映射到树叶节点索引的映射关系,T表示叶节点的类别数, w i w_i wi表示第i个叶节点的回归值,对于每一棵树 f k f_k fk都有自己的q和w,不同树之间的q和w是相互独立的。对于一个给定的样本i,我们可以通过q确定其落到哪个叶节点,再通过w得到该样本在树k上的预测值,最后通过把所有决策树的预测值累加起来得到该样本最终的预测值。
接下来,为了训练这K棵树,最小化以下正则化目标函数:
L = ∑ i = 1 n l ( y i , y i ^ ) + ∑ k = 1 K Ω ( f k ) (2) L=\sum_{i=1}^n l(y_i,\hat{y_i}) + \sum_{k=1}^K \Omega(f_k) \tag{2} L=i=1nl(yi,yi^)+k=1KΩ(fk)(2)
w h e r e   Ω ( f ) = γ T + 1 2 λ ∑ j = 1 T w 2 where \space \Omega(f)=\gamma T+\frac{1}{2}\lambda \sum_{j=1}^T w^2 where Ω(f)=γT+21λj=1Tw2
其中,等式右边的第一项为损失函数,第二项为模型复杂度, Ω ( f k ) \Omega(f_k) Ω(fk)表示第k棵树的模型复杂度, γ , λ \gamma,\lambda γ,λ分别为叶节点个数和叶节点取值的权重。当正则化项等于0时,目标函数就是传统的梯度提升树(traditional gradient tree boosting)。

(2)梯度提升树(Gradient Tree Boosting)

当训练第t棵树时, y i ^ ( t − 1 ) \hat{y_i}^{(t-1)} yi^(t1) ∑ k = 1 t − 1 Ω ( f k ) \sum_{k=1}^{t-1}\Omega(f_{k}) k=1t1Ω(fk)可以看作是常数,我们需要优化以下目标函数:
L ( t ) = ∑ i = 1 n l ( y i , y i ^ ( t − 1 ) + f t ( x i ) ) + Ω ( f t ) (3) L^{(t)} =\sum_{i=1}^n l(y_i,\hat{y_i}^{(t-1)}+f_t(x_i)) + \Omega(f_t) \tag{3} L(t)=i=1nl(yi,yi^(t1)+ft(xi))+Ω(ft)(3)
使用泰勒级数近似目标函数,按二阶泰勒级数展开:

泰勒展开式: f ( x + Δ x ) = f ( x ) + f ′ ( x ) 1 ! Δ x + f ′ ′ ( x ) 2 ! ( Δ x ) 2 + . . . + f ( n ) ( x ) n ! ( Δ x ) n + R n f(x+\Delta x)=f(x)+\frac{f'(x)}{1!} \Delta x+\frac{f''(x)}{2!}(\Delta x)^2+...+\frac{f^{(n)}(x)}{n!}(\Delta x)^n+R_n f(x+Δx)=f(x)+1!f(x)Δx+2!f(x)(Δx)2+...+n!f(n)(x)(Δx)n+Rn,其中, R n = o [ ( Δ x ) n ] R_n=o[(\Delta x)^n] Rn=o[(Δx)n]

L ( t ) ≃ ∑ i = 1 n [ l ( y i , y i ^ ( t − 1 ) ) + g i f t ( x i ) ) + 1 2 h i f t 2 ( x i ) ) ] + Ω ( f t ) (4) L^{(t)} \simeq \sum_{i=1}^n [l(y_i,\hat{y_i}^{(t-1)})+g_i f_t(x_i))+\frac{1}{2}h_i f^2_t(x_i))] + \Omega(f_t) \tag{4} L(t)i=1n[l(yi,yi^(t1))+gift(xi))+21hift2(xi))]+Ω(ft)(4)
其中, g i = ∂ y ^ ( t − 1 ) l ( y i , y ^ ( t − 1 ) ) , h i = ∂ y ^ ( t − 1 ) 2 l ( y i , y ^ ( t − 1 ) ) g_i=\partial_{\hat y^{(t-1)}}l(y_i,\hat y^{(t-1)}),h_i=\partial_{\hat y^{(t-1)}}^2l(y_i,\hat y^{(t-1)}) gi=y^(t1)l(yi,y^(t1)),hi=y^(t1)2l(yi,y^(t1)),去掉常数项,目标函数变为:
L ~ ( t ) = ∑ i = 1 n [ g i f t ( x i ) ) + 1 2 h i f t 2 ( x i ) ) ] + Ω ( f t ) (5) \tilde L^{(t)} = \sum_{i=1}^n [g_i f_t(x_i))+\frac{1}{2}h_i f^2_t(x_i))] + \Omega(f_t) \tag{5} L~(t)=i=1n[gift(xi))+21hift2(xi))]+Ω(ft)(5)
定义 I j = { i ∣ q ( x i ) = j } I_j=\{i|q(x_i)=j\} Ij={iq(xi)=j},表示第j类叶节点的样本集合
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 = ∑ i = 1 n [ g i w q ( x i ) + 1 2 h i w q ( x i ) 2 ] + γ 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 + 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 (6) \begin{aligned} \tilde L^{(t)} &= \sum_{i=1}^n [g_i f_t(x_i) + \frac{1}{2}{h_i}f_t^2(x_i)] + \gamma T+\frac{1}{2}\lambda \sum_{j=1}^T w_j^2 \\ &= \sum_{i=1}^n [g_i w_{q(x_i)} + \frac{1}{2}{h_i}w_{q(x_i)}^2] + \gamma T+\frac{1}{2}\lambda \sum_{j=1}^T w_j^2 \\ &= \sum_{j=1}^T [(\sum_{i \in I_j}g_i) w_j + \frac{1}{2} (\sum_{i \in I_j}h_i) w_j^2] + \gamma T+\frac{1}{2}\lambda \sum_{j=1}^T w_j^2 \\ &= \sum_{j=1}^T [(\sum_{i \in I_j}g_i) w_j + \frac{1}{2} (\sum_{i \in I_j}h_i +\lambda) w_j^2] + \gamma T \\ \end{aligned} \tag{6} L~(t)=i=1n[gift(xi)+21hift2(xi)]+γT+21λj=1Twj2=i=1n[giwq(xi)+21hiwq(xi)2]+γT+21λj=1Twj2=j=1T[(iIjgi)wj+21(iIjhi)wj2]+γT+21λj=1Twj2=j=1T[(iIjgi)wj+21(iIjhi+λ)wj2]+γT(6)
q ( x ) q(x) q(x)是已知的,也就是说,树的形状是已知的,那么此时决策树的最优解及其目标值为:
w j ∗ = − ∑ i ∈ I j g i ∑ i ∈ I j h i + λ (7) w_j^*=-\frac{\sum_{i \in I_j}g_i}{\sum_{i \in I_j}h_i +\lambda} \tag{7} wj=iIjhi+λiIjgi(7)

L ~ ( t ) ∗ = − 1 2 ∑ j = 1 T ( ∑ i ∈ I j g i ) 2 ∑ i ∈ I j h i + λ + γ T (8) \tilde L^{(t)*}=-\frac{1}{2} \sum_{j=1}^T \frac{(\sum_{i \in I_j}g_i)^2}{\sum_{i \in I_j}h_i+\lambda} + \gamma T \tag{8} L~(t)=21j=1TiIjhi+λ(iIjgi)2+γT(8)

目标值类似于信息熵的概念,可以用来衡量该决策树的优劣。由于我们不可能列举出 q ( x ) q(x) q(x)的所有可能取值,所以这里可以采用贪心算法求解,也就是说,选择一个叶节点,在此基础上选择是否分支,假定 I L I_L IL I R I_R IR分别是该叶节点分支后左子节点和右子结点的样本集合,即 I = I L ∪ I R I=I_L\cup I_R I=ILIR,那么分支后损失函数的减少为:
L s p l i t = 1 2 [ ∑ j = 1 T ( ∑ i ∈ I L g i ) 2 ∑ i ∈ I L h i + λ + ∑ j = 1 T ( ∑ i ∈ I R g i ) 2 ∑ i ∈ I R h i + λ − ∑ j = 1 T ( ∑ i ∈ I g i ) 2 ∑ i ∈ I h i + λ ] − γ (9) L_{split}=\frac{1}{2} [\sum_{j=1}^T \frac{(\sum_{i \in I_L}g_i)^2}{\sum_{i \in I_L}h_i+\lambda}+ \sum_{j=1}^T \frac{(\sum_{i \in I_R}g_i)^2}{\sum_{i \in I_R}h_i+\lambda} - \sum_{j=1}^T \frac{(\sum_{i \in I}g_i)^2}{\sum_{i \in I}h_i+\lambda} ] - \gamma \tag{9} Lsplit=21[j=1TiILhi+λ(iILgi)2+j=1TiIRhi+λ(iIRgi)2j=1TiIhi+λ(iIgi)2]γ(9)

若分支前目标值大于分支后目标值,则进行分支,否则不进行分支。

除了可以采用正则化目标函数避免过拟合之外,还有两种避免过拟合的技巧:1)收缩率,在每一步的提升树之后新增加的权重都会按 η \eta η缩减,类似于动态优化的学习率,收缩率减少了每棵独立树的权重,为未来树留出提升的空间;2)列采样,随机森林的特征选择就是列采样,一般来说,列采样优于行采样。引入列采样可以提升并行算法的计算效率。

(3)分割点搜索算法(Split Finding Algorithm)
  • 基于精确的贪心算法(Exact Greedy Algorithm)
    穷举所有特征的所有可能切分点,找出最佳划分特征及其最佳切分点。假设有m个特征,对于每个特征先把所有可能值升序排列,遍历所有可能切分点j,找到最佳切分点,然后遍历m个特征找到最佳特征及其最佳切分点。
    在这里插入图片描述
  • 基于近似的贪心算法(Approximate Algorithm)
    精确的贪心算法不能有效地处理数据量大和分布式场景,因此提出近似的贪心算法。近似的贪心算法,不再是穷举所有的切分点,而是只选几个切分点作为候选切分点,具体来说,就是先根据特征分布的分位数选出 l l l个候选切分点(除了分位数策略,还可以用其他的分桶策略),再根据这些候选点把特征的所有取值进行分桶,计算第v桶的一阶导数和二阶导数,即 G k v G_{kv} Gkv H k v H_{kv} Hkv,最后按照前面的方法计算损失函数的减少,以此判断是否分支。近似的贪心算法有两种形式:1)全局算法(global),在开始构建决策树之前先确定好候选切分点,在树的生成过程中使用同样的候选切分点进行分支;2)局部算法(local),每次分支时都重新确定候选切分点。全局算法确定候选点的次数少,但需要更多的候选点,局部算法确定候选点的次数多,但允许更少的候选点,可以到达更深的决策树。
    在这里插入图片描述

下面是在Higgs 10M数据集上测试集AUC的对比。eps参数表示分桶的精度,如果eps=0.05,表示样本按照选定的特征分为1/0.05组,即分桶。

  • 跟全局算法相比,局部算法达到同样的效果所需要的候选点更少

  • 全局算法只要分桶够多,便能达到局部算法的效果

  • 近似贪心算法可以达到精确贪心算法同样的准确度,只要分桶策略足够合理。
    在这里插入图片描述

  • 加权分位法(Weighted Quantile Sketch)

    在近似贪心算法中,很重要的一步是确定候选切分点,通常使用的是分位法。我们定义 D k = { ( x 1 k , h 1 ) , ( x 2 k , h 2 ) , . . . , ( x n k , h n ) } D_k=\{(x_{1k},h_1),(x_{2k},h_2),...,(x_{nk},h_n)\} Dk={(x1k,h1),(x2k,h2),...,(xnk,hn)} x i k x_{ik} xik表示样本i第k个特征的取值, h i h_i hi是其对应的二阶梯度统计值,即(4)式的 h i h_i hi,定义排序函数 r k r_k rk
    r k ( z ) = 1 ∑ ( x , h ) ∈ D k h ∑ ( x , h ) ∈ D k , x < z h (10) r_k(z)=\frac{1}{\sum_{(x,h) \in D_k} h} \sum_{(x,h) \in D_k,x<z} h \tag{10} rk(z)=(x,h)Dkh1(x,h)Dk,x<zh(10)
    它表示第k个特征的取值小于等于z的样本占比。我们的目标是从第k个特征的所有取值中找到 l l l个候选切分点,即候选切分点 { s k 1 , s k 2 , . . . , s k l } \{s_{k1},s_{k2},...,s_{kl}\} {sk1,sk2,...,skl}满足:
    ∣ 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 (11) |r_k(s_{k,j})-r_k(s_{k,j+1})|<\epsilon,s_{k1}=\min_i \space x_{ik},s_{kl}=\max_i \space x_{ik} \tag{11} rk(sk,j)rk(sk,j+1)<ϵ,sk1=imin xik,skl=imax xik(11)
    其中, ϵ \epsilon ϵ是近似参数,值越小,选取的候选点越多,候选点最多有 1 ϵ \frac{1}{\epsilon} ϵ1个。这里,每个样本的权重都是 h i h_i hi,至于为什么 h i h_i hi表示样本权重,我们等式(5)重写为:
    L ~ ( t ) = ∑ i = 1 n 1 2 h i ( f t ( x i ) + g i / h i ) 2 + Ω ( f t ) + c o n s t a n t (12) \tilde L^{(t)} = \sum_{i=1}^n \frac{1}{2}h_i (f_t(x_i)+g_i/h_i)^2 + \Omega(f_t) + constant \tag{12} L~(t)=i=1n21hi(ft(xi)+gi/hi)2+Ω(ft)+constant(12)
    此时,目标函数可以看作是 f t ( x i ) f_t(x_i) ft(xi) − g i / h i -g_i/h_i gi/hi带权重 h i h_i hi的平方损失函数。当每个样本权重相同时,可以使用分位法,当权重不同时,需要引入加权分位法

  • 稀疏性自适应分割算法(Sparsity-aware Split Finding)

    在真实世界中,输入数据常常是稀疏的,稀疏性原因可能有:1)输入数据存在缺失;2)统计数据中存在大量0值;3)特征工程的产物,比如one-hot编码。所以,分支搜索算法需要考虑到稀疏性的情况,因此引入稀疏性自适应分割算法

    稀疏性感知算法的大致思路:在结点处先利用非缺失数据进行分支,然后把缺失值当作一种取值,为缺失值寻找最优划分方向(要么在左子树要么在右子树)。引入稀疏性感知的算法与非缺失数据是线性时间复杂度,也就是说,稀疏性感知算法的执行效率还是较好的。
    在这里插入图片描述

(4)系统设计
  • 分块并行(Column Block for Parallel Learning)

    训练决策树最耗时的部分是对数据进行排序,为了减少排序成本,我们提出“block”的概念,即数据存储的内存单元,每个block的数据都是以压缩列(CSC)格式存储,每列都是按照对应的特征值排序存储,也就是说,先把每一列特征提前进行排序,以块(Block)的形式储存在缓存中,并以索引将特征值和梯度统计量 g i , h i g_i,h_i gi,hi对应起来,每次节点分裂时会重复调用排好序的块。而不同特征会分布在独立的块中,因此可以进行分布式或多线程的计算。

在这里插入图片描述

【时间复杂度分析】假设 d d d是树的最大深度, K K K是树的数量。对于精确的贪心算法,原始的稀疏性自适应分割算法时间复杂度是 O ( K d ∣ ∣ x ∣ ∣ 0 log ⁡ n ) O(Kd||x||_0 \log n) O(Kdx0logn)(注:快排的时间复杂度为 O ( n log ⁡ n ) ) O(n\log n)) O(nlogn)),这里 ∣ ∣ x ∣ ∣ 0 ||x||_0 x0是数据集非零实体个数,假设特征i有 ∣ ∣ x ∣ ∣ 0 i ||x||_{0i} x0i个非零值,那么 ∣ ∣ x ∣ ∣ 0 = ∑ i = 1 m ∣ ∣ x ∣ ∣ 0 i ||x||_0=\sum_{i=1}^m ||x||_{0i} x0=i=1mx0i,而block结构的时间复杂度是 O ( K d ∣ ∣ x ∣ ∣ 0 + ∣ ∣ x ∣ ∣ 0 log ⁡ n ) O(Kd||x||_0 +||x||_0 \log n) O(Kdx0+x0logn),其中, ∣ ∣ x ∣ ∣ 0 log ⁡ n ||x||_0 \log n x0logn是一开始特征排序的时间复杂度,每个特征最多有n个取值,如果我们使用block结构时,由于在一开始我们就已经对特征进行了排序,之后就不需要在每个节点都排序,只需要通过一次扫描就可以得到各个结点的最优划分点,于是时间复杂度降为 O ( K d ∣ ∣ x ∣ ∣ 0 ) O(Kd||x||_0) O(Kdx0)。对于近似的贪心算法,原始的稀疏性自适应分割算法时间复杂度为 O ( K d ∣ ∣ x ∣ ∣ 0 log ⁡ q ) O(Kd||x||_0 \log q) O(Kdx0logq),q是最大候选点数量,block结构的时间复杂度是 O ( K d ∣ ∣ x ∣ ∣ 0 + ∣ ∣ x ∣ ∣ 0 log ⁡ B ) O(Kd||x||_0 +||x||_0 \log B) O(Kdx0+x0logB),B是每个block的最大行数。

  • 缓存访问(Cache-aware Access)

    尽管block结构能够帮助优化分割点搜索的时间复杂度,但新算法是通过索引来获取梯度统计值的,这是非连续的内存访问,这可能会使CPU缓存命中率低,从而影响算法效率。因此,在精确的贪心算法中,使用缓存预取(cache-aware prefetching algorithm),也就是先为每个线程分配一个连续的buffer(内存缓冲区),然后读取梯度统计值到buffer里(实现非连续到连续的转化),最后以小批量方式执行累加操作。我们发现,精确的贪心算法中加入缓存预取比原始版本的效率要快两倍。而在近似的贪心算法中,使用适合的block大小来缓解该问题,我们定义block大小为block中最大的样本数,block大小太小,会导致并行化效率低效,block大小太大会导致缓存丢失,所以需要平衡好这两个因素。

  • 核外块计算(Blocks for Out-of-core Computation)

    系统的目标除了使得运行效率和内存资源利用最大化以外,还要对磁盘空间利用最大化。为了保证核外块的计算,我们把数据划分为多个block,然后把block存储到磁盘上。在计算时,使用独立线程把block读取到buffer上,这样使得计算操作和读取操作能够同时进行,但这个并不能很好地解决问题,因为磁盘读取操作还是占据了大量的处理时间,所以减少读取数据的开销是非常重要,我们主要是使用两种方法来提高核外块的计算效率:1)block压缩,即block先被列压缩,当加载到主内存中时被独立线程解压缩,相当于用解压缩的计算时间换取了磁盘读取成本,较为常见的列压缩算法是记录block的第一个行索引,然后记录每一个行索引与第一个行索引的偏移量offset,一共用16个bits来存储,所以每个block最多有 2 16 2^{16} 216个样本;2)block拆分,即把数据拆分到多个磁盘上,为每个磁盘分配一个预取线程,把数据读取到内存缓冲区,然后训练线程再从每个内存缓冲区读取数据,这有助于提高磁盘的吞吐量。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值