根据 KDNuggets 网站的介绍,增强决策树正支撑着 Kaggle 机器学习挑战赛中超过半数的胜出解决方案。除了卓越的性能表现之外,这些算法亦拥有现实层面的吸引力——即最大程度降低调整需求。在今天的文章中,我们将评估两款高人气升级包:XGBoost 与 LightGBM,亦包括其 GPU 实现方案。如果您觉得文章太长而不想通读,那么我们会将对六套数据集进行测试所得出的结论总结如下:
- XGBoost 与 LightGBM 拥有相似的准确度水平。
- LightGBM 对于全部测试数据集,无论是在 CPU 抑或 GPU 之上,LightGBM 的训练时长都要短于 XGBoost 及其基于直方图方法的 XGBoost hist。两套库之间的训练时间差异主要取决于实际数据集,且时耗差别可高达 25 倍。
- XGBoost GPU 实现方案无法有效扩展至大型数据集当中,并曾在测试过程当中发生内存不足问题。
- 当特征维度较高时,XGBoost hist 的执行速度往往明显低于原始 XGBoost。
我们的全部代码皆属于开源成果,且可从此 repo 当中获取。我们将解释这些库当中所使用的具体算法,同时立足不同数据集对其加以评估。您是否希望自己的机器学习方案拥有更快的运行速度?如果是,请跟着我们的脚步继续推进。
增强决策树基础知识
梯度增强属于一种机器学习技术,其能够以弱分类器集合的形式生成预测模型,同时对可微损失函数进行优化。目前最具人气的梯度增强类型之一正是增强决策树,其内部由一组弱决策树集合组成。目前有两种不同策略可进行树计算:逐级与逐叶。其中逐级策略以逐级方式进行树状结构创建。通过这种策略,各个节点通过分割数据对靠近树根处的节点进行优先级排序。逐叶策略则立足损失变化最大的节点处进行数据分割。对于规模较小的数据集而言,逐级增长往往效果更好(逐叶增长在这类场景下往往存在过度拟合问题); 而逐叶增长则比较合适应用于大规模数据集——这是因为其速度表现要明显优于逐级增长。
(点击放大图像)
逐级增长策略对逐叶增长策略。其中逐级增长策略会随着树状层级数量的增加而带来较高复杂性。相比之下,逐叶策略则通过优化损失函数的方式生成分支。
训练强化决策树过程中的一大挑战,在于为各个“叶”找到最佳分割计算成本。对于常规技术而言,要找到各叶的精确分割方式,需要对每一次迭代当中的全部数据进行扫描。而另一种可行方法则通过构建特征直方图找出粗略分割方式。如此一来,算法本身将不必评估特征中的每个单一值,而只需计算直方图边界即可完成分割计算。这样的处理方式对于大型数据集而言效率更高,且不致对准确度产生不利影响。
XGBoost 项目始于 2014 年,且目前已经在多轮 Kaggle 挑战赛中取得优胜并积累起可观人气。最初的 XGBoost 基于一套逐级增长算法,但近期其亦添加了新的逐叶增长选项,旨在利用直方图实现近似分割。我们将这套版本称为 XGBoost hist。LightGBM 的面世时间则更晚,始于 2016 年 3 月,并于同年 8 月转为开源项目。其基于逐叶算法与直方近似值,且凭借着出色的速度表现而得到高度关注(免责声明:本篇文章的联合作者之一 Guolin Ke 为 LightGBM 项目的核心贡献者之一)。除了多线程 CPU 之外,目前 XGBoost 与 LightGBM 亦皆可利用 GPU 实现加速。
评估 XGBoost 与 LightGBM
我们面向六组不同数据集进行了机器学习测试。这些实验皆被保存在我们 GitHub repo 当中的 Python notebook 当中,感兴趣的朋友可以点击此处查看。我们还展示了实验中使用的 XGBoost 与 LightGBM 具体编译版本,同时提供实验的安装与设置步骤说明。另外,我们还尝试利用CPU 与GPU 处理分类与回归问题。全部实验皆运行在一套Azure NV24 虚拟机当中,其拥有24 个计算核心、224 GB 内存以及英伟达M60 GPU。操作系统选择了Utuntu 16.04。在全部实验当中,我们发现XGBoost 与LightGBM 的准确度表现基本相当(可参见F1 评分),因此本文将专注于讨论其训练时间差异。下表所示为这两套库在CPU 与GPU 场景下的训练时长与训练时间比。
(点击放大图像)
CPU 与 GPU 场景下 XGBoost 与 LightGBM 训练时间与训练时间比测试结果比较。其中 XGBoost GPU 训练时间并未显示(-),因为我们在过程中遭遇内存不足问题。而在 CPU 场景下利用 XGBoost 处理 Airline 数据集时(-*),我们在 5 小时后停止了计算。各组数据集的最佳训练时间以黑体显示。
来自测试的启示
虽然基准测试不能代表一切,但其中部分结论确实有其价值。通过实验,我们发现逐叶方法一般而言较逐级方法速度更快。然而,CPU 场景下的 BCI 与 Planet Kaglle 数据集处理结果,以及 GPU 场景下的 GCI 处理结果显示,XGBoost hist 的处理时长要远长于标准 XGBoost。这主要是由于数据集本身拥有庞大的体积与特征数量,导致 XGBoost 需要耗费极为可观的内存资源。
我们同时发现,XGBoost 的 GPU 实现方案在扩展性方面表现较差——其在 3 套规模较大的数据集处理过程中皆引发了内存错误。此外,我们不得不在 5 个小时之后人为中止了 XGBoost 在 Airline 数据集上的训练。
最后,在 LightGBM 与 XGBoost 之间,我们发现 LightGBM 在全部测试中皆带来优于 XGBoost 与 XGBoost hist 的速度表现,且实际速度最高可达 XGBoost 的 25 倍与 XGBoost hist 的 15 倍。
我们希望调查不同数据集规模及轮数对于 CPU 及 GPU 性能的影响。在下表当中,我们展示了使用 Airline 数据集内某一子集时的处理结果。在对 CPU 及 GPU 的训练时间进行比较时,我们发现 LightGBM 的 GPU 版本在数据集较大且轮数越多时,拥有超越 CPU 版本的表现。而正如预期那样,在使用小型数据集时,RAM 与 GPU 内存之间的数据复制 IO 开销被 GPU 自身的计算速度优势所抵消。而值得一提的是,我们在使用 XGBoost hist GPU 版本时并没有发现任何性能提升效果。顺带解释一句,根据近期的其它研究文章,与多核心 CPU 相比,XGBoost 的标准版本(即采用精确分割而非直方图方法)同样无法在 GPU 场景下得到提升。
(点击放大图像)
.XGBoost、XGBoost hist 以及 LightGBM 训练时间基准测试与不同数据规模及轮数情况下的 AUC 结果。与之前一样,XGBoost 在 GPU 场景下的 1 亿行实验同样因内存不足而未能得出结果(-)。XGBoost 的 1 亿行 500 轮训练则在运行 5 小时后被我们人为中止(-*)。各示例的最佳训练时间与最高 AUC 结果以黑体显示。
总体而言,我们发现 LightGBM 在 CPU 与 GPU 场景下的速度表现皆优于 XGBoost。另外,如果大家决定使用 XGBoost,我们建议您密切关注特征维度与内存消耗情况。LightGBM 显著的速度优势将可转化为对更多迭代进行搜索的能力及 / 或更快的超参数搜索速度。因此,如果您可用于模型优化的时间较为有限,或者希望尝试更多不同的特征工程思路,那么 LightGBM 无疑将成为更理想的选择。
祝各位工作愉快!
评论