LightGBM
LightGBM原理及实现
LigthGBM是boosting集合模型中的新进成员,它和xgboost一样是对GBDT的高效实现,很多方面会比xgboost表现的更为优秀。原理上它和GBDT及xgboot类似,都采用损失函数的负梯度作为当前决策树的残差近似值,去拟合新的决策树。
LightGBM vs xGBoost
xgBoost算法的优点:
- XGB利用了二阶梯度来对节点进行划分,相对其他GBM来说,精度更高。
- 利用局部近似算法对分裂节点的贪心算法优化,取适当的eps时,可以保持算法的性能且提高算法的运算速度。
- 在损失函数中加入了L1/L2项,控制模型的复杂度,提高模型的鲁棒性。
- 提供并行计算能力,主要是在树节点求不同的候选的分裂点的Gain Infomation(分裂后,损失函数的差值)
- Tree Shrinkage,column subsampling等不同的处理细节。
- 需要pre-sorted,这个会耗掉很多的内存空间(2 * #data * # features)
- 数据分割点上,由于XGB对不同的数据特征使用pre-sorted算法而不同特征其排序顺序是不同的,所以分裂时需要对每个特征单独做依次分割,遍历次数为#data * #features来将数据分裂到左右子节点上。
- 尽管使用了局部近似计算,但是处理粒度还是太细了
- 由于pre-sorted处理数据,在寻找特征分裂点时(level-wise),会产生大量的cache随机访问。
2、在机器学习当中,面对大数据量时候都会使用采样的方式(根据样本权值)来提高训练速度。又或者在训练的时候赋予样本权值来关于于某一类样本(如Adaboost)。LightGBM利用了GOSS(基于梯度的one-side采样) GOSS来做采样算法。
3、由于histogram算法对稀疏数据的处理时间复杂度没有pre-sorted好。因为histogram并不管特征值是否为0。因此采用EFB(互斥的特征捆绑)来预处理稀疏数据。
直方图算法(Histogram)
直方图算法是先把连续的浮点特征值离散化成k个整数,同时构造一个宽度为k的直方图。遍历数据时,根据离散化后的值作为索引在直方图中积累统计量,当遍历一次数据后,直方图积累了需要的统计量,然后根据直方图的离散值,遍历寻找最优的分割点。
文章图片
优点如下:
- 直方图只需对直方图统计量计算信息增益,相比较于预排序算法每次都遍历所有的值,信息增益的计算量要小很多。
- 相对于pre-sorted算法,它的内存空间需要相对小很多。因为pre-sorted算法需要保存起来每一个特征的排序结构,所以其需要的内存大小是2 * #data * #feature * 4Bytes(起始我认为保存排序后的数据可以用row_id来代替)而histogram只需保存离散值bin value(EFB会谈到bin)而且我们不需要原始的feature value,所以占用的内存大小为:#data * # feature * 1Byte,因为离散值bin value使用uint8_t已经足够了。
- 求子节点相应的feature histogram时,只需构造一个子节点的feature histogram,另外一个子节点的feature histogram用父节点的histogram减去刚构造出来的子节点的histogram便可,时间复杂度就压缩到O(k),k为histogram的桶数。这是一个很巧妙的做差法。
【LightGBM】GOSS是通过区分不同梯度的实例,保留较大梯度实例同时对较小梯度随机采样的方式减少计算量,从而达到提升效率的目的。
这里有一个问题,为什么只对梯度小的样本进行采样呢?
因为在提升树训练过程中目标函数学习的就是负梯度(近似残差),梯度小说明训练误差已经很小了,对这部分数据的进一步学习的效果不如对梯度大的样本进行学习的效果好或者说对梯度小的样本进行进一步学习对改善结果精度帮助其实并不大。
GOSS的计算步骤如下:
- 选取前a%个较大梯度的值作为大梯度值的训练样本
- 从剩余的1 - a%个较小梯度的值中,我们随机选取其中的b%个作为小梯度值的训练样本
- 对于较小梯度的样本,也就是b% * (1 - 1%) * #samples,我们在计算信息增益时将其放大(1 - a) / b倍
Exclusive Feature Bundling(独立特征合并)
EFB是通过特征捆绑的方式减少特征维度(其实是降维技术)的方式来提升计算效率。通常被捆绑的特征都是互斥的(一个特征值为零一个特征值不为零),这样两个特征捆绑起来才不会丢失信息。如果两个特征并不是完全互斥(部分情况下两个特征都是非零值),可以用一个指标对特征不互斥程度进行衡量,称之为冲突比率,当这个值较小时,可以选择把不完全互斥的两个特征捆绑,而不影响最后的精度。
这里就有两个问题:1. 如何确定哪些特征用于融合且效果为较好。2. 如何将这些特征合并到一起。
1、问题1是一个NP-hard问题。把feature看作是图中的点(V),feature之间的总冲突看作是图中的边(E)。而寻找寻找合并特征且使得合并的bundles个数最小,这是一个图着色问题。所以这个找出合并的特征且使得bundles个数最小的问题需要使用近似的贪心算法来完成。
构建一个以feature为图中的点(V),以feature之间的总冲突为图中的边(E)这里说的冲突值应该是feature之间cos夹角值,因为要尽可能保证feature之间非0元素不在同一个row上。首先按照度来对每个点(feature)做降序排序(度数越大与其他点的冲突越大),然后将特征合并到冲突数小于K的bundle或者新建另外一个bundle。算法的时间复杂度为O(#feature^2)。
2、第二问题是将这些bundles中的特征合并起来。由于每一个bundle当中,features的range都是不一样,所以我们需要重新构建合并后bundle feature的range。在第一个for循环当中,我们记录每个feature与之前features累积totalRange。在第二个for循环当中,根据之前的binRanges重新计算出新的bin value(F[j]bin[i] + binRanges[j])保证feature之间的值不会冲突。这是针对于稀疏矩阵进行优化。由于之前Greedy Bundling算法对features进行冲突检查确保bundle内特征冲突尽可能少,所以特征之间的非零元素不会有太多的冲突。
EBF的算法步骤如下:
- 将特征按照非零值的个数进行排序
- 计算不同特征之间的冲突比率
- 遍历每个特征并尝试合并特征,使冲突比率最小化
大部分决策树的学习算法通过 level-wise 策略生长树,记一次分裂同一层的叶子,不加区分的对待同一层的叶子,而实际上很多叶子的分裂增益较低没必要进行分裂,带来了没必要的开销。如下图:
文章图片
LightGBM 通过 leaf-wise 策略来生长树。每次从当前所有叶子中,找到分裂增益最大的一个叶子,然后分裂,如此循环。因此同Level-wise相比,在分裂次数相同的情况下,Leaf-wise可以降低更多的误差,得到更好的精度。但是,当样本量较小的时候,leaf-wise 可能会造成过拟合。 所以,LightGBM 可以利用额外的参数 max_depth 来限制树的深度并避免过拟合。
文章图片
支持并行学习
LightGBM原生支持并行学习,目前支持特征并行(Featrue Parallelization)和数据并行(Data Parallelization)两种,还有一种是基于投票的数据并行(Voting Parallelization)。
- 特征并行的主要思想是在不同机器、在不同的特征集合上分别寻找最优的分割点,然后在机器间同步最优的分割点。
- 数据并行则是让不同的机器先在本地构造直方图,然后进行全局的合并,最后在合并的直方图上面寻找最优分割点。
- 特征并行算法中,(1)每个Worker都在本地特征集上寻找最佳划分点{特征, 阈值};(2)本地进行各个划分的通信整合并得到最佳划分;(3)执行最佳划分。
- 数据并行中使用分散规约 (Reduce scatter) 把直方图合并的任务分摊到不同的机器,降低通信和计算,并利用直方图做差,进一步减少了一半的通信量。
- 基于投票的数据并行(Voting Parallelization)则进一步优化数据并行中的通信代价,使通信代价变成常数级别。在数据量很大的时候,使用投票并行可以得到非常好的加速效果。
文章图片
文章图片
在直方图合并的时候,通信代价比较大,基于投票的数据并行能够很好的解决这一点。
LightGBM——提升机器算法(图解+理论+安装方法+python代码)
LightGBM原理分析
机器学习——LightGBM
LightGBM,XGBoost
推荐阅读
- 做一件事情的基本原理是什么()
- 【读书笔记】贝叶斯原理
- SG平滑轨迹算法的原理和实现
- “写作宝典”《金字塔原理》之读书笔记
- Spring|Spring 框架之 AOP 原理剖析已经出炉!!!预定的童鞋可以识别下发二维码去看了
- Spring|Spring Boot 自动配置的原理、核心注解以及利用自动配置实现了自定义 Starter 组件
- Vue源码分析—响应式原理(二)
- MYSQL主从同步的实现
- (1)redis集群原理及搭建与使用(1)
- Git学习-笔记摘要