梯度提升算法(Gradient Boosting)
基本原理:根据当前模型损失函数的负梯度信息来训练新加入的弱分类器,然后将训练好的弱分类器以累加的形式结合到现有模型中。
GBDT
GBDT就是以决策树CART为弱分类器的梯度提升算法。
GBDT可以用于回归,二分类,多分类,首先对回归进行讲解
回归算法过程:
给定训练集 T = { ( x 1 , y 1 ) , ( x 2 , y 2 ) , . . . , ( x N , y N ) } T=\{(x_1,y_1),(x_2,y_2),...,(x_N,y_N)\} T={(x1,y1),(x2,y2),...,(xN,yN)}
-
初始化第一个弱学习器 F 0 ( x ) F_0(x) F0(x):
F 0 ( x ) = a r g m i n c ∑ i = 1 N L ( y i , c ) F_0(x)=\mathop{argmin}\limits_{c}\sum_{i=1}^N L(y_i,c) F0(x)=cargmin∑i=1NL(yi,c)
此时c为所有y的平均值。 -
开始迭代:
a)对第m棵树,计算负梯度, 即伪残差:
r m , i = − ∂ L ( y , F m − 1 ( x i ) ) ∂ F m − 1 ( x i ) r_{m,i}=-\frac{ \partial{L(y,F_{m-1}(x_i))}}{\partial{F_{m-1}(x_i)}} rm,i=−∂Fm−1(xi)∂L(y,Fm−1(xi))
b)用计算出的 r m , i r_{m,i} rm,i与 x x x组成数据集 ( x i , r m , i ) (x_i, r_{m,i}) (xi,rm,i),并构建一颗CART树拟合该数据,得到第m颗回归树,其叶子结点对应的区域为 R m , i R_{m,i} Rm,i, J m J_m Jm为第m颗回归树的叶子结点个数。
c)接下来计算每个叶子结点的拟合值,计算公式如下:
c m , i = a r g m i n c L ( y i , F m − 1 ( x i ) + c ) c_{m,i}=\mathop{argmin}\limits_{c} L(y_i,F_{m-1}(x_i)+c) cm,i=cargminL(yi,Fm−1(xi)+c)
d)更新强学习器 F m ( x ) = ∑ j = 1 J m c m , j I ( x ∈ R m , i ) F_m(x)=\sum_{j=1}^{J_m}c_{m,j}I(x\in R_{m,i}) Fm(x)=∑j=1Jmcm,jI(x∈Rm,i) -
得到最终强学习器的表达式:
F ( x ) = F 0 ( x ) + ∑ m = 1 M ∑ j = 1 J m c m , j I ( x ∈ R m , i ) F(x) = F_0(x)+\sum_{m=1}^{M}\sum_{j=1}^{J_m}c_{m,j}I(x\in R_{m,i}) F(x)=F0(x)+m=1∑Mj=1∑Jmcm,jI(x∈Rm,i)
二分类算法过程
二分类和回归的区别就是在叶子结点上加了一层Sigmoid激活函数
XGBoost
1. 目标函数与GBDT相比多了一个正则项:
O b j = L ( y i , y i ^ ) + ∑ i = 1 t Ω ( f i ) Obj=L(y_i, \hat{y_i})+\sum_{i=1}^{t} \Omega(f_i) Obj=L(yi,yi^)+i=1∑tΩ(fi)
2. 泰勒展开,与GBDT相比用到了2阶泰勒展开:
- 对于函数
f
(
x
)
f(x)
f(x)二阶泰勒展开如下:
f
(
x
+
Δ
x
)
=
f
(
x
)
+
f
′
(
x
)
Δ
x
+
1
2
f
′
′
(
x
)
Δ
x
2
f(x+\Delta x)=f(x)+f'(x)\Delta x +\frac{1}{2}f''(x)\Delta x^2
f(x+Δx)=f(x)+f′(x)Δx+21f′′(x)Δx2
则对于正在训练的树的损失函数为 L ( y i , y i ^ ( t − 1 ) + f t ( x i ) ) L(y_i, \hat{y_i}^{(t-1)}+f_t(x_i)) L(yi,yi^(t−1)+ft(xi))用二阶泰勒展开如下:
L ( y i , y i ^ ( t − 1 ) + f t ( x i ) ) = L ( y i , y i ^ ( t − 1 ) ) + g i f t ( x i ) + 1 2 h i f t ( x i ) 2 L(y_i, \hat{y_i}^{(t-1)}+f_t(x_i))=L(y_i, \hat{y_i}^{(t-1)})+g_if_t(x_i)+\frac{1}{2}h_if_t(x_i)^2 L(yi,yi^(t−1)+ft(xi))=L(yi,yi^(t−1))+gift(xi)+21hift(xi)2
这里 g i g_i gi为损失函数的一阶导数, h i h_i hi为损失函数的二阶导数 - 则在第t颗树的训练的目标函数为:
O b j ( t ) = ∑ i = 1 N [ g i f t ( x i ) + 1 2 h i f t ( x i ) 2 ] + Ω ( f t ) Obj_{(t)}=\sum_{i=1}^N[g_if_t(x_i)+\frac{1}{2}h_if_t(x_i)^2]+\Omega(f_t) Obj(t)=i=1∑N[gift(xi)+21hift(xi)2]+Ω(ft) - 所以我们只需要求出每一步损失函数的一阶导和二阶导的值(由于前一步的正则项和损失是已知的,所以这两个值就是常数),然后最优化目标函数,就可以得到每一步的 f t f_t ft ,最后根据加法模型得到一个整体模型。
3.结点切分
当建立第t棵树时,一个非常关键的问题是如何找到叶子节点的最优切分点。XGBoost支持两种分裂节点的方法——贪心算法和近似算法。
从树的深度为0开始:
-
贪心算法:
a) 对每个叶节点枚举所有的可用特征
b)针对每个特征,把属于该节点的训练样本根据该特征值进行升序排列,通过线性扫描的方式来决定该特征的最佳分裂点,并记录该特征的分裂收益;
c) 选择收益最大的特征作为分裂特征,用该特征的最佳分裂点作为分裂位置,在该节点上分裂出左右两个新的叶节点,并为每个新节点关联对应的样本集;
d) 回到第1步,递归执行直到满足特定条件为止;
对于每次分裂,我们都需要枚举所有特征可能的分割方案,如何高效地枚举所有的分割呢?
对于所有的分裂点 ,只要做一遍从左到右的扫描就可以枚举出所有分割的梯度和 。
-
近似算法
贪心算法可以得到最优解,但当数据量太大时则无法读入内存进行计算,近似算法主要针对贪心算法这一缺点给出了近似最优解。对于每个特征,只考察分位点可以减少计算复杂度。
该算法首先根据特征分布的分位数提出候选划分点,然后将连续型特征映射到由这些候选点划分的桶中,然后聚合统计信息找到所有区间的最佳分裂点。在提出候选切分点时有两种策略:
a) Global:学习每棵树前就提出候选切分点,并在每次分裂时都采用这种分割;
b) Local:每次分裂前将重新提出候选切分点。直观上来看,Local策略需要更多的计算步骤,而Global策略因为节点已有划分所以需要更多的候选点。
![图片名称](https://img-blog.csdnimg.cn/de8bcd1be5d84df084e25468ed351633.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA6LCB6L-Y5LiN5piv5LuZ5aWz5LqG5ZWK5ZCn5ZWK5ZCn,size_18,color_FFFFFF,t_70,g_se,x_16)
4. 稀疏感知算法(缺失值处理)
XGBoost在构建树的节点过程中只考虑非缺失值的数据遍历,而为每个节点增加了一个缺省方向,当样本相应的特征值缺失时,可以被归类到缺省方向上,因为在算法的迭代中只考虑了非缺失值数据的遍历,缺失值数据直接被分配到缺省方向节点,所需要遍历的样本量大大减小。
其中缺省值的方向选取的算法如下,从左到右和从右到左分别计算信息增益。选取增益最大的方向作为default direction。
![图片名称](https://img-blog.csdnimg.cn/5940ac5207f64fc88e30378b2f90bd06.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA6LCB6L-Y5LiN5piv5LuZ5aWz5LqG5ZWK5ZCn5ZWK5ZCn,size_18,color_FFFFFF,t_70,g_se,x_16)
5. 列块并行学习
在树生成过程中,最耗时的一个步骤就是在每次寻找最佳分裂点时都需要对特征的值进行排序。而 XGBoost 在训练之前会根据特征对数据进行排序,然后保存到块结构中,并在每个块结构中都采用了稀疏矩阵存储格式。
缓存访问
XGBoost为每个线程分配一个连续的缓存区,将需要的梯度信息存放在缓冲区中,这样就实现了非连续空间到连续空间的转换,提高了算法效率。此外适当调整块大小,也可以有助于缓存优化。
XGBoost的优缺点:
优点:
- 精度更高:
- 灵活性更强:
- 正则化:
- Shrinkage(缩减):相当于学习速率。XGBoost 在进行完一次迭代后,会将叶子节点的权重乘上该系数,主要是为了削弱每棵树的影响
- 列抽样: XGBoost 借鉴了随机森林的做法,支持列抽样
- 缺失值处理: 对于特征的值有缺失的样本,XGBoost 采用的稀疏感知算法可以自动学习出它的分裂方向
- XGBoost工具支持并行,XGBoost的并行是在特征粒度上的。
- 可并行的近似算法: 树节点在进行分裂时,我们需要计算每个特征的每个分割点对应的增益,即用贪心法枚举所有可能的分割点。高效地生成候选的分割点。
缺点
- 虽然利用预排序和近似算法可以降低寻找最佳分裂点的计算量,但在节点分裂过程中仍需要遍历数据集;
- 预排序过程的空间复杂度过高,不仅需要存储特征值,还需要存储特征对应样本的梯度统计值的索引,相当于消耗了两倍的内存。
LightGBM
LightGBM是XGBoost的改进版,相比于前者,它添加了很多新的方法来改进模型,包括:并行方案、基于梯度的单边检测、排他性特征捆绑等。
1. 基于梯度的单边检测(GOSS)
如果实例梯度值小,这个实例的误差就小,说明这个实例已经训练的很好了,直接的想法就是抛弃拥有小梯度的实例数据,这样一来数据的分布就会发生改变,会损失学到的模型的精确度。为了避免这个问题,我们提出了一种叫做GOSS的方法。GOSS保持有较大梯度的实例,在小梯度数据上运行随机采样。原文是这样描述的:“only randomly drop those instances with small gradients.”
在lightgbm模型中相关的参数:subsample
2. 排他性特征捆绑(EFB)
文章中指出有的特征是互斥的,他们不会同时不为0,原文将这样的特征压缩为一个特征,原文描述为:“We can safely bundle exclusive features into a single feature”。这样可以加快模型的训练的同时不影响精度。
3. 使用直方图特征分裂(Histogram-based)
在LGB中,将这些连续的或者精确的每一个 feature value 划分到一系列的离散值,也就是所说的桶里面。
![图片名称](https://img-blog.csdnimg.cn/49378e07481b4e6e873c7de334621c75.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA6LCB6L-Y5LiN5piv5LuZ5aWz5LqG5ZWK5ZCn5ZWK5ZCn,size_16,color_FFFFFF,t_70,g_se,x_16)
Algo1解读:最外面的 for 循环表示的意思是对当前模型下所有的叶子节点处理,需要遍历所有的特征,来找到增益最大的特征及其划分值,以此来分裂该叶子节点。
在某个叶子上,第二个 for 循环就开始遍历所有的特征了。对于每个特征,首先为其创建一个直方图。这个直方图存储了两类信息,分别是每个bin中样本的梯度之和(H [ f . b i n s [ i ] ] . g H[ f.bins[i] ].gH[f.bins[i]].g),还有就是每个bin中样本数量(H [ f . b i n s [ i ] ] . n H[ f.bins[i] ].nH[f.bins[i]].n)
第三个 for 循环遍历所有样本,累积上述的两类统计值到样本所属的bin中。即直方图的每个 bin 中包含了一定的样本,在此计算每个 bin 中的样本的梯度之和并对 bin 中的样本记数。
最后一个for循环,遍历所有bin,分别以当前bin作为分割点,累加其左边的bin至当前bin的梯度和(S L S_LS L )以及样本数量(n L n_Ln L),并与父节点上的总梯度和(S p S_pS p )以及总样本数量(n p n_pn p )相减,得到右边所有bin的梯度和(S R S_RS R )以及样本数量(n R n_Rn R ),带入公式,计算出增益,在遍历过程中取最大的增益,以此时的特征和bin的特征值作为分裂节点的特征和分裂特征取值。
带有深度限制的 Leaf-wise learning
leaf-wise 相对于 level-wise ,更加的高效,还可以降低更多的训练误差,得到更好的精度,但单纯使用它来进行生长,可能会长出比较深的树,在小数据集上可能造成过拟合,因此在 leaf-wise 上,多加了深度的限制。
直方图做差
lgb还使用了直方图做差的优化,可以观察到一个叶子节点上的直方图可以由它的 父节点直方图减去兄弟节点的直方图来得到,根据这点,我们可以构造出来计算数据量比较小的叶子节点直方图,然后用直方图做差得到中间较大的叶子节点的直方图,达到加速的效果。
支持直接输入类别特征
传统对的机器学习算法不能直接输入类别特征,需要先离散化,这样的空间或者时间效率都不高。lgb通过更改决策树算法的决策规则,直接原生支持类别特征,不许额外离散化。速度快了8倍以上。
并行化
特征并行的主要思想是在不同机器在不同的特征集合上分别寻找最优的分割点,然后在机器间同步最优分割点
数据并行是让不同的机器先构造本地直方图,然后进行全局的合并,最后在合并的直方图上面寻找最优分割点。