[机器学习] Boosting算法4 --- LightGBM介绍与分布式

[机器学习] Boosting算法1 --- AdaBoost

[机器学习] Boosting算法2 --- GBDT

[机器学习] Boosting算法3 --- XGBoost

[机器学习] Boosting算法4 --- LightGBM

目录

一 LightGBM特点

二 Histogram算法

三 LightGBM的细节技术

1. Histogram optimization

2 内存消耗和计算上优化

3 带深度限制的Leaf-wise的叶子生长策略

4、直方图做差优化

5、 增加缓存命中率

6、支持类别特征

7、支持并行学习

7.1 特征并行

7.2 数据并行

7.3 投票并行

8、网络通信的优化

四、支持的应用和度量

1 应用

2 度量

3 其他


一  LightGBM特点

LightGBM(Light Gradient Boosting Machine)是微软的开源分布式高性能Gradient Boosting框架,使用基于决策树的学习算法。

相比XGBoost有如下优点:

  • 基于Histogram的决策树算法, 更快的训练速度和更高的效率:LightGBM使用基于直方图的算法。例如,它将连续的特征值分桶(buckets)装进离散的箱子(bins),这是的训练过程中变得更快。

  • 带深度限制的Leaf-wise的叶子生长策略,   LightGBM的分裂节点的方式与XGBoost不一样。LGB避免了对整层节点分裂法,而采用了对增益最大的节点进行深入分解的方法。这样节省了大量分裂节点的资源。

  • 更低的内存占用:使用离散的箱子(bins)保存并替换连续值导致更少的内存占用。

  • 更高的准确率(相比于其他任何提升算法):它通过leaf-wise分裂方法产生比level-wise分裂方法更复杂的树,这就是实现更高准确率的主要因素。然而,它有时候或导致过拟合,但是我们可以通过设置 max-depth 参数来防止过拟合的发生。

  • 大数据处理能力:相比于XGBoost,由于它在训练时间上的缩减,它同样能够具有处理大数据的能力。

  • 支持并行学习

  • Cache命中率优化

  • 基于直方图的稀疏特征优化

  1. Histogram算法:直方图加速算法。
  2. GOSS算法:基于梯度的单边采样算法。
  3. EFB算法:互斥特征捆绑算法。

可以用如下一个简单公式来说明LightGBM和XGBoost的关系:

LightGBM = XGBoost + Histogram + GOSS + EFB

XGBoost模型训练的总体的复杂度可以粗略估计为:

训练复杂度 = 树的棵数✖️每棵树上叶子的数量✖️生成每片叶子的复杂度

由于XGBoost采用的基模型是二叉树,因此生成每片叶子需要分裂一次。

而每次分裂,需要遍历所有特征上所有候选分裂点位,计算按照这些候选分裂点位分裂后的全部样本的目标函数增益,找到最大的那个增益对应的特征和候选分裂点位,从而生成一片新叶子。因此生成一片叶子的复杂度可以粗略估计为:

生成一片叶子的复杂度 = 特征数量✖️候选分裂点位数量✖️样本的数量。

而Hitogram算法的作用是减少候选分裂点位数量,GOSS算法的作用是减少样本的数量,EFB算法的作用是减少特征的数量。

通过这3个算法的引入,LightGBM生成一片叶子需要的复杂度大大降低了,从而极大节约了计算时间。

同时Histogram算法还将特征由浮点数转换成0~255位的整数进行存储,从而极大节约了内存存储。

Histogram算法

直方图算法的基本思想:先把连续的浮点特征值离散化成k个整数,同时构造一个宽度为k的直方图。遍历数据时,根据离散化后的值作为索引在直方图中累积统计量,当遍历一次数据后,直方图累积了需要的统计量,然后根据直方图的离散值,遍历寻找最优的分割点。

LightGBM里默认的训练决策树时使用直方图算法(直方图算法是替代XGBoost的预排序(pre-sorted)算法的),XGBoost里现在也提供了这一选项,不过默认的方法是对特征预排序,计算过程当中是按照value的排序,逐个数据样本来计算划分收益,这样的算法能够精确的找到最佳划分值,但是代价比较大同时也没有较好的推广性。

预排序算法首先将样本按照特征取值排序,然后从全部特征取值中找到最优的分裂点位,该算法的候选分裂点数量与样本数量成正比。

 

而直方图算法通过将连续特征值离散化到固定数量(如255个)的bins上,使得候选分为点位为常数个(num_bins -1)

 

a. 降低计算分裂增益的成本

  1. 基于预排序的算法具有时间复杂性 O(#𝑑𝑎𝑡𝑎),计算直方图具有时间复杂度O(#𝑑𝑎𝑡𝑎)----(初始构造直方图是需要一次O(#data)的时间复杂度,不过这里只涉及到加和操作),  但这仅当在执行总结操作时发生;
  2. 构建完直方图后,基于直方图的算法具有时间复杂度O(#𝑏𝑖𝑛𝑠),因为某个特征不同值的个数远小于训练样本的个数;

b. 直方图做差进一步提高效率

计算某一节点的叶节点的直方图可以通过将该节点的直方图与另一子节点的直方图做差得到,所以每次分裂只需计算分裂后样本数较少的子节点的直方图然后通过做差的方式获得另一个子节点的直方图,进一步提高效率。

c. 节省内存

  • 将连续数据离散化为直方图的形式,对于数据量较小的情形可以使用小型的数据类型来保存训练数据
  • 不必像预排序一样保留额外的对特征值进行预排序的信息

d. 减少了并行训练的通信代价

现在来看看直方图优化是如何优化的,当然这个优化也是在处理节点分裂的时候。在处理连续特征的时候,如果你想要快速找到最佳的分裂节点要么像之前说到的那样对特征值采用预排序的方式来快速得到最佳的分裂特征值,在这里直方图就是先将特征值先做装箱处理,装箱处理是特征工程中常见的处理方式之一

以浮点型数据来举例,一个区间的值会被作为一个筒,然后以这些筒为精度单位的直方图来做。这样一来,数据的表达变得更加简化,减少了内存的使用,而且直方图带来了一定的正则化的效果,能够使我们做出来的模型避免过拟合且具有更好的推广性。

histogram算法简单来说,就是先对特征值进行装箱处理,形成一个一个的bins。对于连续特征来说,装箱处理就是特征工程中的离散化:如[0,0.3)—>0,[0.3,0.7)—->1等。

一个区间的范围内作为一个bin,简化为以分桶为粒度的直方图来做,这样一来,数据的表示更加简化,减少了内存的适用,而且直方图带来了一定的正则化的效果,使得我们训练出的模型不容易over-fitting到training-data上面,从而具备更好的推广性。

e. 特征的最优分割点

通常使用独热编码来转换分类特征,但这种方法对于决策树的学习并不是有益的。特别是对于不同值较多的特征,独热编码后构建的树往往是不平衡的,并且需要非常大的深度才能获得较好的准确率。
事实上,最佳解决方案是通过将类别划分为2个子集。如果特征具有K个不同的值,就是在2^(k-1) - 1种情况里找到最优的分割点。对于回归树而言,有一种解决方案可以保证在O(k * log(k))的时间复杂度内找到最优分割点。
找到特征的最优分割点的基本思想是根据训练目标的相关性对类别进行重排序。 更具体的说,根据累加值(sum_gradient / sum_hessian)重新对(类别特征的)直方图进行排序,然后在排好序的直方图中寻找最优的分割点。

三、LightGBM的细节技术

1. Histogram optimization

上图是做过直方图优化之后的求解直方图的算法细节。这是按照bin来索引histogram的,所以不需要按照每个feature来排序,也不需要一一地对比不同feature的值,大大地减少了运算量。

在Lightgbm中默认的#bins为256(1个字节的能表示的长度,可以设置)。对于分类特征来说,则是每一种取值放入一个bin,且当取值的个数大于max bin数时,会忽略那些很少出现的category值。在节点分裂的时候,这时候就不需要按照预排序算法那样,对于每个特征都计算#data遍了,而是只需要计算#bins遍,这样就大大加快了训练速度。

2 内存消耗和计算上优化

相比于另一个主流的算法 pre-sorted(如 xgboost 中的 exact 算法)histogram 在内存消耗和计算代价上都有不少优势。


a. 内存上优势

1. 当我们用feature的bin来描述数据的特征的时候,带来的变化,首先是我们不需要像预排序算法那样去存储每一个feature排序后对应的data的序列,也就是上图最左边的灰色方块。Pre-sorted 算法需要的内存约是训练数据的两倍(2 * #data * #features* 4Bytes),因为xgboost既要保存原始feature的值,也要保存这个值的顺序索引,这些值需要32位的浮点数来保存它需要用32位浮点来保存 feature value,并且对每一列特征,都需要一个额外的排好序的索引,这也需要32位的存储空间。

2. 我们使用bin来表示feature,一般bin的个数都是控制在比较小的范围内,这样我们可以使用更少的Byte来存储,如上图,使用Byte来存,而原先的feature value可能是float,需要用4个Bytes来存储。对于 histogram 算法,则只需要(#data* #features * 1Bytes)的内存消耗,仅为 pre-sorted算法的1/8。因为 histogram 算法仅需要存储 feature bin value (离散化后的数值),不需要原始的 feature value,也不用排序,而 bin value 用 uint8_t (256 bins) 的类型一般也就足够了。

当我们用数据的bin描述数据特征的时候带来的变化:首先是不需要像预排序算法那样去存储每一个排序后数据的序列,也就是下图灰色的表,在LightGBM中,这部分的计算代价是0;第二个,一般bin会控制在一个比较小的范围,所以我们可以用更小的内存来存储
b. 计算上的优势

针对稀疏特征优化  对于稀疏的特征只需要O(2 * 非零值的样本个数)的时间复杂度来构造直方图

计算上的优势则主要体现在“数据分割”。决策树算法有两个主要操作组成,一个是“寻找分割点”,另一个是“数据分割”。从算法时间复杂度来看,Histogram 算法和 pre-sorted 算法在“寻找分割点”的代价是一样的,都是O(#feature*#data)。而在“数据分割”时,pre-sorted 算法需要O(#feature*#data),而 histogram 算法是O(#data)。因为 pre-sorted 算法的每一列特征的顺序都不一样,分割的时候需要对每个特征单独进行一次分割。Histogram算法不需要排序,所有特征共享同一个索引表,分割的时候仅需对这个索引表操作一次就可以。(更新:这一点不完全正确,pre-sorted 与 level-wise 结合的时候,其实可以共用一个索引表(row_idx_to_tree_node_idx)。然后在寻找分割点的时候,同时操作同一层的节点,省去分割的步骤。但这样做的问题是会有非常多随机访问,有很大的chche miss,速度依然很慢。

另一个计算上的优势则是大幅减少了计算分割点增益的次数。对于一个特征,pre-sorted 需要对每一个不同特征值都计算一次分割增益 时间为(#data),而 histogram 直方图算法只需要遍历桶就行了,只需要计算 #bin (histogram 的横轴的数量) 次。

最后,在数据并行的时候,用 histgoram 可以大幅降低通信代价。用 pre-sorted 算法的话,通信代价是非常大的(几乎是没办法用的)。所以 xgoobst 在并行的时候也使用 histogram 进行通信。

histogram 算法也有缺点:

  • 当然,Histogram算法并不是完美的。由于特征被离散化后,找到的并不是很精确的分割点,训练误差没有 pre-sorted 好, 所以会对结果产生影响。但在不同的数据集上的结果表明,离散化的分割点对最终的精度影响并不是很大,甚至有时候会更好一点。原因是决策树本来就是弱模型,分割点是不是精确并不是太重要;较粗的分割点也有正则化的效果,可以有效地防止过拟合;即使单棵树的训练误差比精确分割的算法稍大,但在梯度提升(Gradient Boosting)的框架下没有太大的影响。
  • 预处理能够忽略零值特征,减少训练代价;而直方图不能对稀疏进行优化,只是计算累加值(累加梯度和样本数)。但是,LightGBM 对稀疏进行了优化:只用非零特征构建直方图。

LightGBM 为何使用直方图这种比较粗的分割节点方法,还能达到比较好的效果?

虽然分割的精度变差了,但是对最后结果的影响不是很大,主要由于决策树是弱模型, 分割点是不是精确并不是太重要 ;较粗的分割点也有正则化的效果,可以有效地防止过拟合;即使单棵树的训练误差比精确分割的算法稍大,但在梯度提升(Gradient Boosting)的框架下没有太大的影响。

xgboost的近似直方图算法也类似于lightgbm这里的直方图算法,为什么xgboost的近似算法比lightgbm还是慢很多呢?
xgboost在每一层都动态构建直方图, 因为xgboost的直方图算法不是针对某个特定的feature,而是所有feature共享一个直方图(每个样本的权重是二阶导),所以每一层都要重新构建直方图,而lightgbm中对每个特征都有一个直方图,所以构建一次直方图就够了。

3 带深度限制的Leaf-wise的叶子生长策略

LightGBM使用了带有深度限制的节点展开方法(Leaf-wise)来提高模型精度,这是比XGBoost中Level-wise更高效的方法。

它可以降低训练误差得到更好的精度。但是单纯的使用Leaf-wise可能会生长出比较深的树,在小数据集上可能会造成过拟合,因此在Leaf-wise之上多加一个深度限制. 它抛弃了大多数 GBDT 工具使用的按层生长(level-wise) 的决策树生长策略,而使用了带有深度限制的按叶子生长 (leaf-wise) 算法。 level-wise 过一次数据可以同时分裂同一层的叶子,容易进行多线程优化,不容易过拟合。

Level-wise(xgboost)过一次数据可以同时分裂同一层的叶子,容易进行多线程优化,也好控制模型复杂度,不容易过拟合。但实际上Level-wise是一种低效算法,因为它不加区分的对待同一层的叶子,带来了很多没必要的开销,因为实际上很多叶子的分裂增益较低,没必要进行搜索和分裂。

Leaf-wise是一种更为高效的策略:每次从当前所有叶子中,找到分裂增益最大的一个叶子,然后分裂,如此循环。因此同Level-wise相比,在分裂次数相同的情况下,Leaf-wise可以降低更多的误差,得到更好的精度。

Leaf-wise的缺点:可能会长出比较深的决策树,产生过拟合。因此LightGBM在Leaf-wise之上增加了一个最大深度限制,在保证高效率的同时防止过拟合。

4、直方图做差优化

LightGBM还使用了直方图做差的优化,达到了两倍的加速。

可以观察到:一个叶子节点的直方图,可以由它的父亲节点的直方图减去它的兄弟节点的直方图得到。

通常构造直方图,需要遍历该叶子上的所有数据,但直方图做差仅需遍历直方图的 k 个桶。利用这个方法,LightGBM 可以在构造一个叶子的直方图后,可以用非常微小的代价得到它兄弟叶子的直方图,在速度上可以提升一倍。

根据这一点我们可以构造出来数据量比较小的叶子节点上的直方图,然后用直方图做差来得到数据量比较大的叶子节点上的直方图,从而达到加速的效果。

5、 增加缓存命中率

预排序算法中有两个频繁的操作会导致cache-miss,也就是缓存消失(对速度的影响很大,特别是数据量很大的时候,顺序访问比随机访问的速度快4倍以上  )。

  1. 对梯度的访问:在计算增益的时候需要利用梯度,对于不同的特征,访问梯度的顺序是不一样的,并且是随机的
  2. 对于索引表的访问:预排序算法使用了行号和叶子节点号的索引表,防止数据切分的时候对所有的特征进行切分。同访问梯度一样,所有的特征都要通过访问这个索引表来索引。都是随机的访问,会给系统性能带来非常大的下降。

LightGBM使用的直方图算法能很好的解决这类问题。首先。对梯度的访问,因为不用对特征进行排序,同时,所有的特征都用同样的方式来访问,所以只需要对梯度访问的顺序进行重新排序,所有的特征都能连续的访问梯度。并且直方图算法不需要把数据id到叶子节点号上(不需要这个索引表,没有这个缓存消失问题)

LightGBM使用直方图算法则是天然的cache friendly,首先,对梯度的访问,因为不需要对feature进行排序,同时,所有的feature都采用同样的方式进行访问,所以只需要对梯度访问的顺序进行一个重新的排序,所有的feature都能连续地访问梯度。

此外,直方图算法不需要数据id到叶子id的一个索引表,没有这样一个cache-miss的问题。事实上,在cache-miss这样一个方面,对速度的影响是很大的,尤其在数据量很大的时候,MRSA研究人员进行过测试,在数据量很多的时候,相比于随机访问,顺序访问的速度可以快4倍以上,这其中速度的差异基本上就是由cache-miss而带来的。

6、支持类别特征

传统的机器学习一般不能支持直接输入类别特征,需要先转化成多维的0-1特征,这样无论在空间上还是时间上效率都不高。LightGBM通过更改决策树算法的决策规则,直接原生支持类别特征,不需要转化,并且通过一些实验,MRSA研究人员验证了直接使用离散特征可以比使用0-1离散化后的特征,提高了近8倍的速度

四 GOSS算法

GOSS算法全称为Gradient-based One-Side Sampling,即基于梯度的单边采样算法。(其实就是行采样)

其主要思想是通过对样本采样的方法来减少计算目标函数增益时候的复杂度。

但如果对全部样本进行随机采样,势必会对目标函数增益的计算精度造成较大的影响。

GOSS算法的创新之处在于它只对梯度绝对值较小的样本按照一定比例进行采样,而保留了梯度绝对值较大的样本。

这就是所谓的单边采样。由于目标函数增益主要来自于梯度绝对值较大的样本,因此这种方法在计算性能和计算精度之间取得了很好的平衡。

三个关键词:梯度、单边、采样。简单来说,就是根据样本梯度来对梯度小的这边样本进行采样,而对梯度大的这边样本保留。

比如,我有训练数据1000w,设置梯度大的样本的保留10%,而梯度小的样本保留20%。算法上就是先按样本梯度对样本降序排序,保留梯度处于前10%的样本(100w),再从剩下的900w梯度较小样本随机挑选200w(1000w*20%)样本。这样的话样本量就从1000w减小到了300w,加快训练速度。

如果样本的梯度很小,则该样本的训练误差也很小(gbdt拟合的就是负梯度),表明其是很好训练的,考虑性能的情况下可以对其丢弃。但为什么不全部丢弃而用采样的方法呢?主要还是因为会改变样本的分布情况,伤害模型的准确度。这里尽管会对梯度小的样本进行采样,但是会对采样的样本梯度乘以一个常数因子,将样本分布尽可能拉回来 

五 EFB算法

EFB算法全称是Exclusive Feature Bundling,即互斥特征绑定算法。(其实就是列采样,降维)

EFB算法可以有效减少用于构建直方图的特征数量,从而降低计算复杂度,尤其是特征中包含大量稀疏特征的时候。

在许多应用场景下,数据集中会有大量的稀疏特征,这些稀疏特征大部分样本都取值为0,只有少数样本取值非0。通常可以认为这些稀疏特征是互斥的,即它们几乎不会同时取非零值。

利用这种特性,可以通过对某些特征的取值重新编码,将多个这样互斥的特征捆绑成为一个新的特征。有趣的是,对于类别特征,如果转换成onehot编码,则这些onehot编码后的多个特征相互之间是互斥的,从而可以被捆绑成为一个特征。因此,对于指定为类别特征的特征,LightGBM可以直接将每个类别取值和一个bin关联,从而自动地处理它们。而无需预处理成onehot编码多此一举。

六 支持分布式(并行学习)

LightGBM提供以下并行学习算法的优化:特征并行、数据并行、投票并行。

LightGBM原生支持并行学习,特征并行(Featrue Parallelization)和数据并行(Data Parallelization),还有一种是基于投票的数据并行(Voting Parallelization)

  • 特征并行的主要思想是在不同机器、在不同的特征集合上分别寻找最优的分割点,然后在机器间同步最优的分割点。
  • 数据并行则是让不同的机器先在本地构造直方图,然后进行全局的合并,最后在合并的直方图上面寻找最优分割点。

  1. 特征并行算法中,通过在本地保存全部数据避免对数据切分结果的通信。通常适用于小数据且feature比较多的场景
  2. 数据并行中使用分散规约 (Reduce scatter) 把直方图合并的任务分摊到不同的机器,降低通信和计算,并利用直方图做差,进一步减少了一半的通信量。则适用于数据量比较大,但feature比较少的场景
  3. 基于投票的数据并行(Voting Parallelization)则进一步优化数据并行中的通信代价,使通信代价变成常数级别。在数据量很大的时候,使用投票并行可以得到非常好的加速效果。适用于数据量比较大,feature也比较多的场景。

1 特征并行

特征并行算法目的是在决策树生成过程中的每次迭代,高效地找到最优特征分裂点。特征并行的主要思想是在不同机器在不同的特征集合上分别寻找最优的分割点,然后在机器间同步最优的分割点。

传统算法中的特征并行,主要是体现在找到最好的分割点,其步骤为:

  1. 根据不同的特征子集,将数据集进行垂直切分。(不同机器worker有不同的特征子集)
  2. 每个worker寻找局部的最优分裂(包括特征,阈值)以及分裂点
  3. 不同worker之间进行网络传输,交换最优分裂信息,最终得到最优的分裂信息。
  4. 具有最优分裂特征的worker,局部进行分裂,并将分裂结果广播到其他worker。
  5. 其他worker根据接收到的数据进行切分数据。

传统特征并行的缺点:

  1. 计算成本较大,传统特征并行没有实现得到"split"(时间复杂度为“O(训练样本的个数)")的加速。当数据量很大的时候,难以加速;
  2. 需要对划分的结果进行通信整合,其额外的时间复杂度约为 “O(训练样本的个数/8)”(一个数据一个字节);

LightGBM中的并行特征

由于特征并行在训练样本的个数大的时候不能很好地加速,LightGBM做了以下优化:不是垂直分割数据,而是每个线程都拥有完整的全部数据。因此,LightGBM不需要为分割数据结果进行通信,因为每个线程都知道如何划分数据。并且训练样本的个数不会变大,因此这种方案是合理的。

LightGBM中实现特征并行的过程:

  1. 每个worker在本地数据集上找到最佳分割点,包括特征,阈值;
  2. worker间传输最优分裂信息,并得到全局最优分裂信息。
  3. 每个worker基于全局最优分裂信息,在本地进行数据分裂,生成决策树。

但是这样仍然有缺点:

  1. split过程的复杂度仍是O(#data),当数据量大的时候效率不高
  2. 每个worker保存所有数据,存储代价高

因此,建议在数据量很大时使用数据并行。

2 数据并行

传统算法数据并行旨在并行化整个决策学习。数据并行的过程是:

  1. 水平划分数据
  2. 每个worker基于数据集构建局部特征直方图(Histogram)
  3. 归并所有局部的特征直方图,得到全局直方图
  4. 在全局直方图中找到最优分裂信息,进行数据分裂.

在第3步中,有两种合并的方式:

  • 采用点对点方式(point-to-point communication algorithm)进行通讯,每个worker通讯量为O(#machine∗#feature∗#bin)
  • 采用collective communication algorithm(如“All Reduce”)进行通讯(相当于有一个中心节点,通讯后在返回结果),每个worker的通讯量为O(2∗#feature∗#bin)

可以看出通信的代价是很高的,这也是数据并行的缺点 通信成本高。如果使用点对点通信算法,则一台机器的通信成本约为O(#machine * #feature * #bin)。如果使用聚合通信算法(例如“All Reduce”),通信成本约为O(2 * #feature * #bin)。

LightGBM中的数据并行

LightGBM中通过下面方法来降低数据并行的通信成本:

  1. 不同于“整合所有本地直方图以形成全局直方图”的方式,LightGBM算法使用Reduce Scatter并行算子归并来自不同worker的不同特征子集的直方图,然后在局部归并的直方图中找到最优局部分裂信息,最终同步找到最优的分裂信息
  2. LightGBM使用直方图减法加快训练速度。我们只需要对其中一个子节点进行数据传输,另一个子节点可以通过相邻直方图上作减法 histogram subtraction得到。

通过上述方法,LightGBM 将数据并行中的通讯开销减少到O(0.5 * #feature * #bin)。

第一步,使用本地数据计算特征分桶,并将特征值压缩为 int 桶号;

第二步,本地计算所有特征的直方图,通过 reducescatter 得到每个 work 分配到的那两个特征的全局直方图;

第三步,每个 work 求出本地最优分裂(最优分裂节点,分裂的特征,以及特征的分裂阈值);通过全局归约得到全局最优分裂;

第四步,每个 work 根据全局最优分裂对本地模型进行分裂。计算叶子节点的权重;

第五步,重新计算分裂出的叶子节点的直方图,重复 2,3,4 步骤直到收敛;

分桶并行化

计算特征分桶是求直方图的先决条件,给定每个特征要分成的桶数,计算每桶的特征值上下界。在分布式计算中,每个 work 计算自己负责的特征的 bin_mapper,之后再通过 allreduce 得到所有特征的 bin_mapper。最后可以根据 bin_mapper,将 float 的特征值映射到 bin 中,就可以用 int 桶编号来表示

直方图并行化

本地建立所有特征的直方图,每个特征直方图可以通过遍历已经编码为 bin_id 的数据快速实现,最终得到 6 个直方图,包含样本数,以及样本的一阶二阶导数之和。

合并全局直方图,传统的 xgboost 在这里使用一个 allreduce 操作使每个 work 都同步了 6 个全局直方图。但实际上每个 worker 其实只需要关心自己分得的特征的直方图,这里 lightGBM 对 AllReduce 操作进行优化,使用 ReduceScatter 算法,最终每个 worker 只得到自己分配到的特征的直方图,有效的降低了数据通信量,提高了训练效率.

举例:4 个 worker,R0-R3,总共 8 个特征,每个 work 已经计算完本地直方图,下面要进行合并直方图。

通过递归调用,一半一半的进行归约操作,优点是大大减少了通信量,不需要向 AllReduce 每次都需要传递所有的信息,这个通信量是巨大的,缺点是只能用于 2^k worker。

最佳分裂并行化

每个 worker 得到分配到的两个的特征的全局直方图之后,即开始在本地遍历叶子节点和特征,计算本地的最大分裂增益及分列方式。采用 allgather+ 本地 reduce 操作得到全局最优分裂。

xgboost 通过 allreduce 方式计算全局最优分裂,而 lgb 采用 allgather+ 本地 reduce 操作得到全局最优分裂
 

整个 AllReduce 有两个过程 bottom up 和 bottom down, 完成本地计算之后,我们需要把多个本地计算结果挑出全局最优特征,这个在 XGB 里面也是基于 all reduce 实现的。在 LGB 里面使用 all Gather。

假设我们有5个节点,

第一步: R1 给 R0,这个时候 R0 的 V0 是自己的,V1从 R1 拿的(R0有 V0, V1)

第二步: R2 同步给 R0,这个时候 R0 的 V0 是自己的,V2、V3 从 R2 拿的 (R0有 V0, V1, V2, V3)

第三步: 五个节点的内容 R0 知道了四个。最终通过补全的方式,比如 R4 把剩下的几个结果一一补到对应的位置上去,通过这样的过程,每个节点都知道整个集群里面我对应的结果是怎么样。

第四步:然后在本地做一次 reduce 操作,这样每个节点都知道全局的结果。

在存储和计算上面,AllGather 和 AllReduce 相比有什么不一样呢?

存储上,左节点接收一个,右节点接收一个,累计的结果往上传,看过 AllReduce 代码后我们会发现这个只需要一份内存 +Buff 的空间,比较节约空间,AllGather 呢?只要有几个节点,我就会存储几个结果;计算上,和 AllReduce 对比,少一次 BottomDown 广播;综上 AllGather 会更加吃内存、速度会更加快,而树模型本身占的空间并不大,这个也是 AllGather 在树模型上适用的原因

3 投票并行

LightGBM采用一种称为PV-Tree的算法进行投票并行(Voting Parallel),其实这本质上也是一种数据并行

PV-Tree和普通的决策树差不多,只是在寻找最优切分点上有所不同。

  1. 水平切分数据,不同的worker拥有部分数据。
  2. Local voting: 每个worker构建直方图,找到top-k个最优的本地划分特征
  3. Global voting: 中心节点聚合得到最优的top-2k个全局划分特征(top-2k是看对各个worker选择特征的个数进行计数,取最多的2k个)
  4. Best Attribute Identification: 中心节点向worker收集这top-2k个特征的直方图,并进行合并,然后计算得到全局的最优划分
  5. 中心节点将全局最优划分广播给所有的worker,worker进行本地划分。

投票并行进一步降低了数据并行中的通信成本,使其减少至常数级别。它使用两阶段投票来降低特征直方图的通信成本

可以看出,PV-tree将原本需要#feature×#bin 变为了2k×#bin,通信开销得到降低。此外,可以证明,当每个worker的数据足够多的时候,top-2k个中包含全局最佳切分点的概率非常高。

4 网络通信的优化

在LightGBM的并行学习中,它只需要使用一些聚合通信算法,如“All reduce”,“All gather”和“Reduce scatter”。LightGBM实现了最先进的state-of-art算法。这些聚合通信算法可以提供比点对点通信更好的性能

[机器学习] LightGBM中常用并行计算算子原理以及在LightGBM中的具体实现

五、支持的应用和度量

1 应用

  • 回归,目标函数是L2损失
  • 二进制分类,目标函数是logloss(对数损失)
  • 多分类
  • 交叉熵,目标函数是logloss,支持非二进制标签的训练
  • lambdarank,目标函数为基于NDCG的lambdarank

2 度量

  • L1 loss:绝对值损失
  • L2 loss:MSE,平方损失
  • Log loss:对数损失
  • 分类错误率
  • AUC(Area Under Curve):ROC曲线下的面积
  • NDCG(Normalized Discounted Cumulative Gain):归一化折损累积增益
  • MAP(Mean Average Precision):平均精度均值
  • 多类别对数损失
  • 多类别分类错误率
  • Fair损失
  • Huber损失
  • Possion:泊松回归
  • Quantile:分位数回归
  • MAPE(Mean Absolute Percent Error):平均绝对百分比误差
  • kullback_leibler:Kullback-Leibler divergence
  • gamma:negative log-likelihood for Gamma regression
  • tweedie:negative log-likelihood for Tweedie regression
  • 更多阅读原文

3 其他

  • 限制树的最大深度max_depth
  • DART:Dropouts meet Multiple Additive Regression Trees
  • L1 / L2正则化
  • 套袋
  • 随即选择列(特征)子集
  • Continued train with input GBDT model
  • Continued train with the input score file
  • Weighted training
  • Validation metric output during training
  • 交叉验证
  • Multi metrics
  • 提前停止(训练和预测)
  • Prediction for leaf index

参考:

LightGBM | 赵大寳

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值