如何有效地在XGBoost模型中使用它

最近,我和我的同事们一直在开发一个大型高负载服务,该服务利用Xgboost机器学习模型和Dask作为分布式数据处理和预测生成工具。在这里,我想分享我们在数据准备和ML模型拟合方面能够最大化使用Dask的一些发现。
Dask是什么?
Dask是一个用于处理大量数据的分布式处理库。其基本概念是将大型数组分割成小的部分(分区)。
这就是Dask数据帧的存储和处理方式:表可以被分割成小的数据帧(可以将其视为pandas数据帧),因此无需将整个表存储在内存中。整个源表可能太大而无法加载到内存中,但是单独的分区可以加载。此外,此类数据存储方式可以有效利用多个处理器核心并行化计算。
同时,这些分区(块)的大小由开发人员确定。因此,可以使用例如“Split 1”或“Split 2”将同一数据帧分割成多个分区(见图1)。

选择最佳的分区大小至关重要,因为如果分区大小不合适,数据处理可能会变慢。最佳的分区大小取决于整个数据集的大小以及服务器(或笔记本电脑)的资源:CPU的数量和可用的内存。
免责声明:在接下来的内容中,为了方便起见,我们将以数据集的行数来衡量数据集的大小。所有表都由4列组成(3个特征+1个目标)。在系统中实现算法时,我们建立了对表中元素总数(行数×列数)而不是表中行数的依赖关系。
问题
Dask可以用于计算简单的统计数据和聚合,也可以用于训练大型机器学习模型(使用大量数据),例如XGBoost。由于我们开发的服务可能需要在仅有8-16GB RAM的情况下对200万至1000万条记录进行模型训练(当使用小型虚拟机时),因此我们决定进行实验。
即使在计算简单统计数据的情况下,分区的大小也非常重要,因为它可以在两种情况下显着减慢计算算法的速度:
- 分区过大,因此在RAM中处理它们需要太多的时间和资源
- 分区过小,因此为了处理所有分区,Dask需要频繁将这些表加载到RAM中,这会导致更多的时间用于同步和上传/下载而不是计算本身
因此,通过选择非最佳的分区大小,即使使用相同的计算资源,也会严重降低程序的性能(图2)。图2显示了使用不同分区大小的Dask数据帧拟合XGBoost模型的时间。显示了5次运行的平均执行时间。

在这篇文章中,我们讨论了寻找Dask数据框的最佳分区大小的算法。本文中展示的所有表格都是用于拟合Dask Xgboost机器学习模型的。我们还会分享一些可能对你有帮助的技巧。
文档提示
在官方的Dask文档中,有一些关于如何正确处理Dask对象(数据框、数组等)的技巧的网页,比如Dask数据框最佳实践。
在这个页面上,你可以看到如下的建议:
你应该让每个分区的数据量约为100MB。
然而,这个建议是粗略的,没有考虑到服务器的计算规格、源数据集的大小以及解决问题的具体情况。
实验设置
如上所述,假设最佳分区大小取决于以下三个条件:
- 完整数据集的大小;
- XGBoost和Dask可以使用的CPU资源(进程数);
- 可用的随机存取内存(RAM)。
因此,在实验过程中,计算资源的数量以及源数据集的大小是变化的。考虑的情况包括:
- 分区大小,以千行计:[5, 10, 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000](13种情况)
- 完整数据集的大小,以千行计:[100, 200, 300, 400, 500, 600, 1000, 2000, 3000, 4000](10种情况)
- CPU资源(工作进程数):[2, 3, 4](3种情况)
- 每个工作进程可用的随机存取内存(RAM):[1GB, 2GB, 4GB](3种情况)
注意:Dask中的Worker是计算机(在服务器上)中使用分配给它的计算资源运行并与其他Worker隔离并并行工作的进程。
因此,总共分析了1170个(13 x 10 x 3 x 3)情况。为了获得更稳健的执行时间估计,每个情况都被运行了5次,然后取平均值作为指标。
作为研究的一部分,我们想要找出数据集大小的极限,虚拟机在这个极限下无法处理负载,以便更成功地扩展服务。
结果
首先,让我们来看看实验中的一般可视化结果。我们进行了不同数量的CPU核心和不同数量的RAM的运行,同时改变了原始数据集的大小和分区的大小。完成实验后,我们准备了一张仅显示最佳解决方案(分区大小)的表格。最佳分区大小是在给定条件(RAM、CPU和源数据集大小)下执行时间最短的大小。收集到的指标的相关矩阵如图3所示。

从图中可以看出,对执行时间影响最大的显然是源数据集的大小。工作进程的数量和内存的容量对拟合时间也有显著影响。块大小的影响相对较小。不过,这可能是因为执行时间和分区大小之间的依赖关系是非线性的,这也通过图2中的曲线得到了证实。此外,图4证实了测量结果的准确性,因为结果与我们的预期是一致的。
让我们来看一下带有3D图的动画(动画1)。

在动画中,最优解(对于每个进程数和每个工作节点的RAM的组合)用红色圈出。也就是说,对于给定的数据集大小、核心数、RAM和分区大小,算法的执行时间最小的条件被显示出来。图表还以灰色显示了分段恒定的最优曲面(注:曲面对所有情况全局有效)。
从动画中可以看到,在某些帧中没有实验数据(没有点)(图4)。这意味着提出的计算资源不足以运行模型。

从图中可以观察到,在这个数据集大小下,如果核心数较小,则应该形成更大的分区。请注意,这种关联性并非对所有情况都适用。
基于对计算资源不足的执行结果,制作了如下可视化材料(图5)。

此外,根据关于失败运行的统计数据,得出了以下结论(提示):如果内存量有限,则使用较小的分区大小更可靠。
讨论
基于此研究,形成了一些关于基于Dask XGBoost模型更有效配置系统的建议。请注意,这项研究是为了在相对较小的服务器上更高效地运行Dask(而不是拥有数百吉字节RAM和数十个CPU的服务器)。
实验揭示了最优超平面。它们使用高斯过程建模。根据此算法,自动选择最佳分区大小(动画2)。

从动画中可以看出,平均而言,源数据集中的行数增加时,最佳分区大小会减小。
结论(及提示)
希望您对了解XGBoost模型的最佳分区大小有兴趣。
我知道这篇文章变得非常“技术性”。因此,对于那些成功读到文章结尾的人,我将给出一些提示:
- 如果您正在测量执行时间,请多次运行计算并平均结果,因为运行时间是随机的;
- 如果您对分区大小有疑问,最好做一个小错误(否则算法不仅会运行很长时间,还可能会出现错误导致崩溃);
- 要在Dask中本地初始化集群,使用cluster = LocalCluster()和Client(cluster) 命令。我们强烈建议仅在代码中使用单例模式初始化此类集群。您可以在此处查看如何在Python中实现单例模式。否则,每次启动时都会初始化一个新的集群;
- 平均而言,源数据集中的行数增加时,最佳分区大小会减小。
关于Dask和机器学习的故事由Mikhail Sarafanov和Wiredhut团队展示。