benchm-ml
benchm-ml 是一个专注于评估主流开源机器学习库在二分类任务中可扩展性、运行速度与预测准确度的最小化基准测试项目。它旨在解决开发者在面对海量数据时,难以直观判断哪种算法实现(如随机森林、梯度提升树或深度神经网络)能在有限硬件资源下高效运行的痛点。
该项目特别适合数据科学家、算法工程师及研究人员使用,帮助他们在信用评分、欺诈检测等典型商业场景中,为百万级样本和千维特征的数据集选择最合适的工具链。benchm-ml 涵盖了 R、Python scikit-learn、XGBoost、LightGBM、H2O 及 Spark MLlib 等多种流行实现,通过控制变量法,在单台具备多核处理器和充足内存的普通服务器上,系统性地对比了不同方案的表现。
其独特之处在于不追求复杂的分布式架构评测,而是聚焦于“单机极限”,真实反映算法在内存约束下的崩溃临界点与计算效率。测试以 AUC 作为准确度指标,生成从 1 万到 1000 万不等的训练数据集,让用户能清晰看到随着数据规模扩大,各工具的性能变化趋势。如果你正在为大规模数据建模选型,benchm-ml 提供的实测数据将是一份极具参考价值的避坑指南。
使用场景
某金融科技公司数据团队正面临千万级用户交易数据的二分类建模任务(如欺诈检测),需在有限内存的单台服务器上快速筛选出兼顾速度与精度的最佳算法组合。
没有 benchm-ml 时
- 选型盲目:团队需在 R、Python scikit-learn、XGBoost、Spark MLlib 等众多库中手动逐一测试,缺乏统一标准,耗时数周仍难定夺。
- 资源浪费:直接在全量数据上试错,常因算法内存优化不足导致程序崩溃(OOM),反复调试严重拖慢项目进度。
- 性能误判:仅凭小样本数据评估模型,上线后发现随着数据量从 10 万增至 1000 万,部分算法训练时间呈指数级增长,无法满足业务时效。
- 基准缺失:缺乏针对“百万行数据、千维特征”这一典型业务场景的权威速度与精度(AUC)对照,难以向管理层证明技术选型的合理性。
使用 benchm-ml 后
- 精准导航:直接参考 benchm-ml 对随机森林、GBDT 及深度学习在不同规模数据下的评测报告,迅速锁定 LightGBM 和 H2O 为候选方案,将选型周期缩短至 2 天。
- 规避风险:依据工具提供的内存消耗数据,提前排除无法在单机处理 1000 万条记录的实现方式,确保生产环境运行稳定。
- 预期可控:通过查看不同数据量级(10K 到 10M)下的速度曲线,准确预估全量训练耗时,合理制定计算资源预算与交付时间表。
- 决策有据:利用工具生成的 AUC 与耗时对比图表,清晰展示为何放弃线性模型而选择梯度提升树,以数据实证赢得业务方信任。
benchm-ml 通过提供标准化的最小基准测试,帮助团队在海量开源实现中快速定位最适合大规模二分类任务的算法,显著降低了试错成本并提升了决策效率。
运行环境要求
- 未说明
- 非必需
- 若进行深度学习测试,需使用配备 12GB 显存的 GPU(测试环境为 AWS p2.xlarge 实例,含 1 个 GPU)
最低 60GB(针对大规模数据集测试);部分内存密集型模型在大数据量下可能需要 250GB。

快速开始
用于分类的机器学习库在可扩展性、速度和准确度方面的简单/有限/不完整基准测试
所有基准测试都有其局限性,但有些仍然有用
本项目旨在为几种常用机器学习算法的实现提供一个最小化的基准测试,重点评估其在可扩展性、速度和准确度方面的表现。研究对象是二分类问题,输入数据包含数值型和类别型特征(类别数量有限,即非非常稀疏),且无缺失值——这可能是商业应用中最常见的场景,例如信用评分、欺诈检测或客户流失预测。假设输入矩阵为 n × p,其中 n 分别取 1万、10万、100万、1000万,而 p 约为 1000(通过将类别型变量转换为哑变量/独热编码后得到)。这种特定的数据结构和规模(最大规模)源于作者对某些特定商业应用的兴趣。
该基准测试的大部分工作完成于2015年,此后随着技术发展进行了一些更新。请务必阅读本仓库的结尾部分,了解研究重点随时间的变化,以及为何我没有继续维护此基准测试,而是启动了一个新的项目(新项目地址见文末)。
所研究的算法包括:
- 线性模型(逻辑回归、线性支持向量机)
- 随机森林
- 梯度提升树
- 深度神经网络
这些算法分别由多种常用的开源实现来执行,例如:
- R 包
- Python 的 scikit-learn
- Vowpal Wabbit
- H2O
- XGBoost
- LightGBM(2017 年加入)
- Spark MLlib。
更新(2015年6月): 事实证明,这些正是目前机器学习领域中最受欢迎的工具。如果你使用的工具未在此列出,只需按照以下说明即可轻松完成一个最小化的基准测试。
随机森林、梯度提升树以及近年来兴起的深度神经网络,预计将在上述数据结构和规模下表现出最佳性能(相较于 k 近邻、朴素贝叶斯、决策树、线性模型等其他方法而言)。非线性支持向量机通常也具有较高的准确度,但在处理较大规模的 n 时会变得缓慢或无法扩展。相比之下,线性模型的准确度较低,因此仅作为基准参考;不过,它们在可扩展性方面表现更好,且部分模型能够处理非常稀疏的特征,因此在其他应用场景中仍具优势。
此处所说的“可扩展性”是指算法能够在给定数据规模下,在内存资源受限的情况下(即运行过程中不会因内存不足而崩溃)以合理的时间完成训练。部分算法或实现支持分布式计算,但本研究中最大的数据集规模仅为 1000 万条记录,数据量不足 1GB,因此无需扩展到多台机器上进行计算,这也并非本研究的重点。此外,某些算法在多节点环境下由于通信依赖网络而非共享内存,性能反而会有所下降。
单节点环境下的速度主要取决于算法的计算复杂度,同时也受是否能利用多核处理器的影响。准确度则通过 AUC 指标进行衡量。本项目并不关注模型的可解释性。
综上所述,本研究聚焦于哪些算法或实现能够在普通硬件设备上(主要是具备足够内存和多核处理器的一台机器)训练出相对准确的二分类模型,用于处理拥有数百万条样本、数千个特征的数据集。
数据
训练数据集的规模分别为 1万、10万、100万和 1000 万条记录,均基于著名的航空数据集生成(使用 2005 年和 2006 年的数据)。测试集规模为 10 万条记录,同样来自该数据集(使用 2007 年的数据)。任务是预测航班是否会晚点超过 15 分钟。尽管我们主要关注算法或实现的可扩展性,但同时也可以观察到,随着数据量的增加(即观测样本的增多),同一模型所能获取的信息量及准确度会有何变化,这也是一个有趣的问题。
环境搭建
测试在 Amazon EC2 c3.8xlarge 实例上进行(32 核,60GB 内存)。所用工具均为免费软件,安装过程十分简单(安装说明见附录)。对于在较大数据规模下出现内存不足的模型,偶尔也会使用 r3.8xlarge 实例(32 核,250GB 内存)。而在 GPU 上进行深度学习时,则采用了 p2.xlarge 实例(1 块 GPU,显存 12GB,4 核 CPU,60GB 内存)。
更新(2018年1月): 更现代的做法是使用 Docker 完全自动地安装所有机器学习软件,并自动进行计时与测试运行,这样可以更方便地针对工具的新版本重新运行测试,提高结果的可重复性等。这种方法已被应用于本基准测试的一个后续项目,该项目专注于性能最佳的 GBM 实现,详情请参阅此处。
结果
对于每个算法/工具以及每种 n 规模,我们记录了以下指标:训练时间、训练过程中占用的最大内存、各核心的 CPU 使用率,以及作为预测准确度指标的 AUC 值。此外,还记录了读取数据、数据预处理和测试集评分所需的时间,但由于这些步骤并非瓶颈,因此未予报告。
线性模型
线性模型并非本研究的主要关注点,因为在该类型的数据上,它们的准确率不如更复杂的模型。此处分析线性模型仅是为了获得一个基准参考。
R语言中的glm函数(用于逻辑回归的基本工具)速度非常慢,在样本量n=10万的情况下耗时500秒,AUC为70.6。因此,在R中使用了glmnet包。而在Python/scikit-learn中,则使用了基于LIBLINEAR C++库的LogisticRegression。
| 工具 | n | 时间(秒) | 内存(GB) | AUC |
|---|---|---|---|---|
| R | 1万 | 0.1 | 1 | 66.7 |
| . | 10万 | 0.5 | 1 | 70.3 |
| . | 100万 | 5 | 1 | 71.1 |
| . | 1000万 | 90 | 5 | 71.1 |
| Python | 1万 | 0.2 | 2 | 67.6 |
| . | 10万 | 2 | 3 | 70.6 |
| . | 100万 | 25 | 12 | 71.1 |
| . | 1000万 | 崩溃/360 | 71.1 | |
| VW | 1万 | 0.3 (/10) | 66.6 | |
| . | 10万 | 3 (/10) | 70.3 | |
| . | 100万 | 10 (/10) | 71.0 | |
| . | 1000万 | 15 | 71.0 | |
| H2O | 1万 | 1 | 1 | 69.6 |
| . | 10万 | 1 | 1 | 70.3 |
| . | 100万 | 2 | 2 | 70.8 |
| . | 1000万 | 5 | 3 | 71.0 |
| Spark | 1万 | 1 | 1 | 66.6 |
| . | 10万 | 2 | 1 | 70.2 |
| . | 100万 | 5 | 2 | 70.9 |
| . | 1000万 | 35 | 10 | 70.9 |
Python在60GB内存的机器上会崩溃,但当内存增加到250GB时则可以完成训练(使用稀疏格式将有助于减少内存占用,并可能同时缩短运行时间)。表中列出的Vowpal Wabbit(VW)运行时间是针对较小数据规模进行10次遍历(在线学习)的结果。尽管VW可以在多个核心上运行(通过多个进程相互通信),但此处仍以最简单的方式(单核)执行。此外,还需注意的是,VW是在数据流式读取的过程中进行处理的,而其他工具的时间统计则不包括将数据加载到内存中的时间。
用户可以调整各种参数(如正则化),甚至通过交叉验证在参数空间中进行搜索以提高准确率。然而,快速实验表明,至少对于较大的数据规模而言,正则化并不能显著提升准确率(这也是意料之中的,因为样本量n远大于特征数p)。

此处的主要结论是:即使在样本量达到1000万行的情况下,使用这些工具中的任意一种,也几乎可以在任何一台机器上在几秒钟内完成线性模型的训练。 H2O和VW在内存效率方面表现最佳(VW每次只需在内存中保存一条记录,因此是真正可扩展的解决方案)。同时,H2O和VW也是最快的(VW的运行时间包含了数据流式读取的时间)。再次强调,内存效率和速度上的差异只有在更大的数据规模下才会变得显著,而这已超出了本研究的范围。
线性模型与非线性模型的学习曲线
对于该数据集而言,线性模型的准确率在数据规模达到中等水平时便趋于稳定,而非线性模型(例如随机森林)的准确率则会随着数据量的增加而持续提升。这是因为简单的线性结构已经可以从较小的数据集中提取出来,再增加数据点并不会显著改变分类边界。另一方面,像随机森林这样的复杂模型则可以通过进一步调整分类边界来随着数据量的增加而不断提升性能。
这意味着,拥有更多数据(“大数据”)并不会进一步提升线性模型的准确率(至少对于该数据集而言)。
此外值得注意的是,无论数据规模如何,随机森林模型的准确率都高于线性模型;并且与“数据越多算法越优”的传统观点相反,随机森林模型在仅使用1%数据(10万条记录)的情况下,其表现就已经优于线性模型在整个数据集(1000万条记录)上的表现。

类似的现象也可以在其他非稀疏数据集中观察到,例如Higgs数据集。如果您有其他数据集(密集或稀疏)上线性模型与非线性模型的学习曲线,请与我联系(例如提交一个github问题)。
另一方面,更高的准确率无疑需要付出更大的代价,即更长的训练(CPU)时间。
最终,数据规模、算法复杂度、计算成本与准确率之间存在一个权衡关系(将在后续研究中进一步探讨)。以下是H2O的一些初步结果:
| n | 模型 | 时间(秒) | AUC |
|---|---|---|---|
| 1000万 | 线性 | 5 | 71.0 |
| 10万 | 雷达森林 | 150 | 72.5 |
| 1000万 | 雷达森林 | 4000 | 77.8 |
随机森林
注: 随机森林的相关结果已在一篇更加系统化和自包含的博客文章中发布,详见这篇博文。
在每个工具中,均使用500棵树的随机森林模型进行训练,并将默认的分裂变量数量设置为特征数p的平方根。
| 工具 | n | 时间(秒) | 内存(GB) | AUC |
|---|---|---|---|---|
| R | 1万 | 50 | 10 | 68.2 |
| . | 10万 | 1200 | 35 | 71.2 |
| . | 100万 | 崩溃 | ||
| Python | 1万 | 2 | 2 | 68.4 |
| . | 10万 | 50 | 5 | 71.4 |
| . | 100万 | 900 | 20 | 73.2 |
| . | 1000万 | 崩溃 | ||
| H2O | 1万 | 15 | 2 | 69.8 |
| . | 10万 | 150 | 4 | 72.5 |
| . | 100万 | 600 | 5 | 75.5 |
| . | 1000万 | 4000 | 25 | 77.8 |
| Spark | 1万 | 50 | 10 | 69.1 |
| . | 10万 | 270 | 30 | 71.3 |
| . | 100万 | 崩溃/2000 | 71.4 | |
| xgboost | 1万 | 4 | 1 | 69.9 |
| . | 10万 | 20 | 1 | 73.2 |
| . | 100万 | 170 | 2 | 75.3 |
| . | 1000万 | 3000 | 9 | 76.3 |

R 实现(randomForest 包)速度较慢,内存使用效率低下。默认情况下,它无法处理大量类别,因此数据必须进行独热编码。该实现仅使用一个处理器核心,但只需添加两行代码,即可利用所有核心并行构建决策树,并在最后将它们合并。然而,当样本量 n = 100 万时,它就已经耗尽了内存。需要强调的是,这与 R 语言本身无关(我仍然认为 R 是最佳的数据科学平台,尤其是在结构化数据的清洗和可视化方面),问题在于 randomForest 包所使用的这一特定 C 和 Fortran 实现效率较低。
Python (scikit-learn) 实现速度更快、内存利用率更高,并且可以充分利用所有核心。变量同样需要进行独热编码(相比 R 更为复杂),但在 n = 1000 万的情况下,这一过程会耗尽所有内存。即使使用配备 250GB 内存的机器(在完成所有数据转换后,RF 还有 140GB 可用),Python 实现仍会在更大规模的数据上因内存不足而崩溃。不过,如果采用简单的整数编码方式,在更大的机器上运行该算法则能成功完成(对于某些数据集或场景,这可能实际上是一个不错的近似或选择)。
H2O 实现速度快、内存效率高,并且能够利用所有核心。它能够自动处理分类变量,其准确性也高于所研究的 R 和 Python 包,这可能是因为它在算法内部直接正确地处理了分类变量,而不是基于预先进行独热编码的数据集(后者会导致属于同一原始变量的虚拟变量之间的关联丢失)。
Spark (MLlib) 实现速度较慢,内存占用较大。在 n = 100 万时就会出现内存不足的情况(虽然在 250GB RAM 的机器上可以完成 n = 100 万的任务,但在 n = 1000 万时会崩溃)。不过,由于 Spark 可以在集群上运行,可以通过增加节点来进一步扩展内存。我也尝试过将分类变量简单地编码为整数,并传递 categoricalFeaturesInfo 参数,但这使得训练速度大幅下降。此外,数据读取操作需要多行代码,而在本基准测试项目开始时,Spark 尚未提供用于分类数据的独热编码器(因此我使用 R 来完成这一步骤)。后来这个问题得到了解决,感谢 @jkbradley 提供的原生独热编码代码 链接。在此之前的版本中,Spark 随机森林的预测准确率低于其他方法,这是由于其采用投票机制而非概率加权所致。@jkbradley 已经通过这段代码解决了该问题 链接,预计将在下一次 Spark 发布中正式纳入。尽管如此,对于 n = 100 万的数据,准确率仍然存在一些问题(见 AUC 曲线中的下降趋势)。有关上述问题的更多见解,请参阅 Databricks/Spark 项目负责人 Joseph Bradley (@jkbradley) 的评论 链接(感谢 Joseph)。
更新(2016年9月): Spark 2.0 引入了新的 API(Pipeline/"Spark ML" vs "Spark MLlib"),相关代码 链接 显得更加简洁。此外,Spark 1.5、1.6 和 2.0 版本引入了多项优化技术(如 Tungsten),显著提升了查询速度(例如 SparkSQL)。然而,随机森林的性能并未得到改善,反而略有下降 链接。
我还尝试了 xgboost(2-rf/6-xgboost.R),这是一个流行的梯度提升库,同样可以构建随机森林。它速度快、内存效率高,且具有较高的准确率。请注意,H2O 和 xgboost 在 AUC 和运行时间随数据集规模变化的曲线形状上存在差异,相关讨论请参见 此处。
H2O 和 xgboost 均提供了 R 和 Python 接口。
此外,还有一些其他开源和商业的随机森林实现,已在 100 万条记录上进行了快速基准测试,其运行时间和 AUC 结果已在此处公布 链接。
理想情况下,应深入研究算法运行时间和准确率与超参数值之间的关系,但以 H2O 实现为例,我们可以通过下表(n = 1000 万,250GB RAM)快速获得初步了解:
| ntree | depth | nbins | mtries | 时间(小时) | AUC |
|---|---|---|---|---|---|
| 500 | 20 | 20 | -1 (2) | 1.2 | 77.8 |
| 500 | 50 | 200 | -1 (2) | 4.5 | 78.9 |
| 500 | 50 | 200 | 3 | 5.5 | 78.9 |
| 5000 | 50 | 200 | -1 (2) | 45 | 79.0 |
| 500 | 100 | 1000 | -1 (2) | 8.3 | 80.1 |
其他超参数包括每棵树的采样比例、节点中最小观测数以及不纯度函数等。可以看出,AUC 还有进一步提升的空间,而该数据集上随机森林的最佳 AUC 约为 80(线性模型的最佳 AUC 约为 71,后续我们将比较梯度提升和深度学习的结果)。
梯度提升(梯度提升树/梯度提升机)
与随机森林相比,GBM 的超参数与准确率(以及运行时间)之间的关系更为复杂。主要超参数包括学习率(收缩率)、树的数量、树的最大深度;其他参数还有分箱数、每棵树的采样比例以及节点中的最小观测数。更复杂的是,GBM 容易发生过拟合——在某个点之后,继续增加树的数量反而会导致测试集上的准确率下降(而训练集上的“准确率”仍在上升)。
例如,使用 xgboost 对 n = 10 万的数据进行训练,设置 learn_rate = 0.01、max_depth = 16,并启用 printEveryN = 100 和 eval_metric = "auc" 选项后,训练集和测试集在不同迭代次数后的 AUC 如下图所示:

可以看到,测试集的 AUC 在经过 1000 次迭代后开始下降,即发生了过拟合。xgboost 提供了一个便捷的早停选项(early_stop_round = k——如果在验证集等指标上连续 k 轮表现持续恶化,则停止训练)。如果不掌握合适的停止时机,就可能造成欠拟合(迭代次数不足)或过拟合(迭代次数过多),从而导致最终模型的准确率不理想(见上图)。
对最佳模型进行广泛搜索并非本项目的首要目标。 尽管如此,我们还是利用XGBoost(开启早停机制)在超参数空间中进行了一次快速的 探索性搜索。 为此,我们从2007年的数据中单独划分出一个10万条记录的验证集,该集合未被用于测试集。 我们的目标是找到能够提供合理准确率的参数值,然后使用这些参数值运行所有GBM实现(R、Python scikit-learn等),以比较其速度和可扩展性(以及准确率)。
learn_rate越小,AUC越高,但当取值非常小时,训练时间会急剧增加。因此,我们选择learn_rate = 0.01作为折衷方案。
与许多文献中的建议不同,浅层树并未带来最佳(或接近最佳)的结果;网格搜索显示,例如当max_depth = 16时,准确率更高。
对于上述超参数值而言,达到最优结果所需的树的数量则取决于训练集的大小。
对于n_trees = 1000,无论数据规模如何,我们都未进入过拟合状态,因此采用此值来研究不同实现的速度与可扩展性。
(其他表现较好的超参数取值为:sample_rate = 0.5、min_obs_node = 1。)我们将这一实验称为实验A(见下表)。
遗憾的是,某些实现方式在上述参数设置下耗时过长(且Spark会因内存不足而崩溃)。因此,我们还采用了另一组参数值(虽然准确率较低,但训练速度更快)来研究速度和可扩展性:learn_rate = 0.1、max_depth = 6、n_trees = 300。我们将这一实验称为实验B。
我必须强调,尽管我努力使所有算法和实现的参数保持一致,但每种实现都有所不同——有些并不具备全部上述参数,而有些可能以略有不同的方式使用现有参数(您也可以看到,最终生成的模型及其AUC确实存在差异)。尽管如此,以下结果仍能让我们大致了解各实现之间的相对表现。
| 工具 | n | 时间(秒)A | 时间(秒)B | AUC A | AUC B | 内存(GB)A | 内存(GB)B |
|---|---|---|---|---|---|---|---|
| R | 1万 | 20 | 3 | 64.9 | 63.1 | 1 | 1 |
| . | 10万 | 200 | 30 | 72.3 | 71.6 | 1 | 1 |
| . | 100万 | 3000 | 400 | 74.1 | 73.9 | 1 | 1 |
| . | 1000万 | 5000 | 74.3 | 4 | |||
| Python | 1万 | 1100 | 120 | 69.9 | 69.1 | 2 | 2 |
| . | 10万 | 1500 | 72.9 | 3 | |||
| . | 100万 | ||||||
| . | 1000万 | ||||||
| H2O | 1万 | 90 | 7 | 68.2 | 67.7 | 3 | 2 |
| . | 10万 | 500 | 40 | 71.8 | 72.3 | 3 | 2 |
| . | 100万 | 900 | 60 | 75.9 | 74.3 | 9 | 2 |
| . | 1000万 | 3500 | 300 | 78.3 | 74.6 | 11 | 20 |
| Spark | 1万 | 180000 | 700 | 66.4 | 67.8 | 30 | 10 |
| . | 10万 | 1200 | 72.3 | 30 | |||
| . | 100万 | 6000 | 73.8 | 30 | |||
| . | 1000万 | (60000) | (74.1) | 崩溃(110) | |||
| xgboost | 1万 | 6 | 1 | 70.3 | 69.8 | 1 | 1 |
| . | 10万 | 40 | 4 | 74.1 | 73.5 | 1 | 1 |
| . | 100万 | 400 | 45 | 76.9 | 74.5 | 1 | 1 |
| . | 1000万 | 9000 | 1000 | 78.7 | 74.7 | 6 | 5 |

GBM的内存占用通常比随机森林要小,因此瓶颈主要在于训练时间(尽管除了速度慢之外,Spark在内存使用方面也效率低下,尤其是在处理较深的树时,这导致它容易崩溃)。
与随机森林类似,H2O和XGBoost的速度最快(两者都支持多线程)。R的表现相对较好,考虑到它是一个单线程实现。Python在对分类变量进行独热编码时速度很慢,但在采用简单整数编码的情况下,其速度几乎与R相当(仅慢1.5倍)。Spark既慢又浪费内存,不过至少对于浅层树而言,它的准确率与其他方法相近(不同于随机森林的情况,在随机森林中,Spark的准确率低于同类方法)。
相较于随机森林,提升法需要更多的调优才能选出合适的超参数。以下是针对H2O和XGBoost在n = 1000万(最大数据量)、learn_rate = 0.01(越小AUC越高,但训练时间也会越来越长)、max_depth = 20(经过初步搜索,分别尝试了max_depth = 2, 5, 10, 20, 50)、n_trees = 5000(接近XGBoost的早停条件)、min_obs_node = 1(以及XGBoost的sample_rate = 0.5、H2O的n_bins = 1000)时的快速结果:
| 工具 | 时间(小时) | AUC |
|---|---|---|
| H2O | 7.5 | 79.8 |
| H2O-3 | 9.5 | 81.2 |
| xgboost | 14 | 81.1 |
相比之下,前一节中H2O随机森林的结果为:时间8.3小时,AUC80.1。H2O-3是H2O的新一代版本。
更新(2017年5月): 最近推出了一款新的GBM工具LightGBM。虽然它目前尚未像上述工具那样广泛应用,但已经是目前最快的工具之一。此外,最近还有将XGBoost和LightGBM运行在GPU上的研究进展。因此,我创建了一个更精简的GitHub仓库来跟踪最佳的GBM工具: 这里(并忽略诸如Spark之类的平庸工具)。
更新(2018年1月): 我已将H2O、XGBoost和LightGBM(包括CPU和GPU版本)的GBM性能测试容器化。上一段中链接的仓库将包含所有关于GBM实现的后续开发工作。GBM通常是结构化/表格型数据监督学习中最准确的算法,因此也是我的主要研究兴趣所在(例如,与本次基准测试中讨论的其他三种算法——线性模型、随机森林和神经网络相比)。通过容器化,可以更方便地保持该仓库的最新状态,定期测试最新版本的工具,并有可能添加新的机器学习工具。因此,这个新的GBM-perf仓库可以被视为当前仓库的“继任者”。
深度神经网络
深度学习在几类数据和机器学习问题上取得了巨大成功,例如图像、语音和文本处理(监督学习)以及游戏(强化学习)。然而,在“传统”机器学习问题中,比如欺诈检测、信用评分或客户流失预测,深度学习的表现似乎并不理想,其准确率往往低于随机森林或梯度提升机。我在2015年11月对该仓库中使用的航空公司数据集以及其他商业数据集进行的实验也得出了类似的结论,并在这里提出了这一猜想。但遗憾的是,围绕深度学习和“人工智能”的炒作掩盖了这一现实,关于这一话题的讨论和文献相对较少,例如这里、这里以及这里。
以下是使用H2O框架在1000万条样本的数据集上训练的几种全连接网络架构的结果,采用了不同的优化方法(自适应、学习率退火、动量等)以及正则化手段(Dropout、L1、L2),并结合了早停策略:
| 参数 | AUC | 时间 (秒) | 轮数 |
|---|---|---|---|
默认:activation = "Rectifier", hidden = c(200,200) |
73.1 | 270 | 1.8 |
hidden = c(50,50,50,50), input_dropout_ratio = 0.2 |
73.2 | 140 | 2.7 |
hidden = c(50,50,50,50) |
73.2 | 110 | 1.9 |
hidden = c(20,20) |
73.1 | 100 | 4.6 |
hidden = c(20) |
73.1 | 120 | 6.7 |
hidden = c(10) |
73.2 | 150 | 12 |
hidden = c(5) |
72.9 | 110 | 9.3 |
hidden = c(1) (~逻辑回归) |
71.2 | 120 | 13 |
hidden = c(200,200), l1 = 1e-5, l2 = 1e-5 |
73.1 | 260 | 1.8 |
RectifierWithDropout, c(200,200,200,200), dropout=c(0.2,0.1,0.1,0) |
73.3 | 440 | 2.0 |
ADADELTA rho = 0.95, epsilon = 1e-06 |
71.1 | 240 | 1.7 |
rho = 0.999, epsilon = 1e-08 |
73.3 | 270 | 1.9 |
adaptive = FALSE 默认:rate = 0.005, decay = 1, momentum = 0 |
73.0 | 340 | 1.1 |
rate = 0.001, momentum = 0.5 / 1e5 / 0.99 |
73.2 | 410 | 0.7 |
rate = 0.01, momentum = 0.5 / 1e5 / 0.99 |
73.3 | 280 | 0.9 |
rate = 0.01, rate_annealing = 1e-05, momentum = 0.5 / 1e5 / 0.99 |
73.5 | 360 | 1 |
rate = 0.01, rate_annealing = 1e-04, momentum = 0.5 / 1e5 / 0.99 |
72.7 | 3700 | 8.7 |
rate = 0.01, rate_annealing = 1e-05, momentum = 0.5 / 1e5 / 0.9 |
73.4 | 350 | 0.9 |
从结果来看,这些神经网络似乎存在欠拟合现象,无法像随机森林或梯度提升机那样捕捉到数据中的复杂结构(AUC达到80–81)。因此,添加各种形式的正则化措施并未显著提升模型的准确率。此外,值得注意的是,通过基于验证集准确率下降的早停机制,训练时间相对较短(相比随机森林和梯度提升机而言),这也表明模型的复杂度确实较低。令人惊讶的是,更深的网络结构(多层)并没有比仅有一层隐藏层且该层神经元数量较少(10个)的简单网络表现更好。
以下是在100万条样本的数据集上对不同工具进行的计时结果(全连接网络,两层隐藏层,每层200个神经元,ReLU激活函数,SGD优化器,学习率0.01,动量0.9,训练1轮):
| 工具 | GPU时间 | CPU时间 |
|---|---|---|
| h2o | - | 50 |
| mxnet | 35 | 65 |
| keras+TF | 35 | 60 |
| keras+theano | 25 | 70 |
(GPU为p2.xlarge,CPU为r3.8xlarge 32核用于h2o/mxnet;p2.xlarge 4核用于TF/theano;theano仅使用1个核心)
尽管在上述类型的表格数据上,深度学习的性能并不突出,但它在图像、语音以及一定程度上在文本处理等领域却表现出色。因此,我计划在这些领域也开展一次工具基准测试,主要聚焦于卷积神经网络和RNN/LSTM等模型。
大(更)数据
虽然我的主要兴趣在于处理1000万条记录的数据集上的机器学习,但你可能对更大的数据集更感兴趣。有些问题确实需要使用集群,不过最近有一种倾向,即无论是否必要,都倾向于用分布式计算来解决所有问题。需要注意的是,通过网络传输数据与使用共享内存相比,速度差异非常大。此外,一些流行的分布式系统存在显著的计算和内存开销,更根本的是,它们的通信模式(例如Map-Reduce风格)并不适合许多机器学习算法。
更大数据规模(单机)
对于线性模型,大多数工具,包括单核R,在单台服务器上仍然可以很好地处理1亿条记录(此处使用32核、250GB内存的r3.8xlarge实例)。
(这里使用了1000万条记录数据集的10倍副本,因此关于AUC与数据规模关系的信息无效,未在此考虑。)
线性模型,1亿行:
| 工具 | 时间[s] | 内存[GB] |
|---|---|---|
| R | 1000 | 60 |
| Spark | 160 | 120 |
| H2O | 40 | 20 |
| VW | 150 |
某些工具甚至可以在单台机器上处理10亿条记录。 (实际上,VW永远不会耗尽内存,因此如果可以接受更长的运行时间,你还可以在单机上进一步扩展。)
线性模型,10亿行:
| 工具 | 时间[s] | 内存[GB] |
|---|---|---|
| H2O | 500 | 100 |
| VW | 1400 |
对于基于树的集成模型(随机森林、梯度提升机),H2O和XGBoost可以在单台服务器上训练1亿条记录,不过训练时间会达到数小时:
随机森林/梯度提升机,1亿行:
| 算法 | 工具 | 时间[s] | 时间[小时] | 内存[GB] |
|---|---|---|---|---|
| 随机森林 | H2O | 40000 | 11 | 80 |
| . | XGBoost | 36000 | 10 | 60 |
| 梯度提升机 | H2O | 35000 | 10 | 100 |
| . | XGBoost | 110000 | 30 | 50 |
通常情况下,人们期望在这种情况下获得比线性模型高得多的准确率,尽管训练时间增加了1000倍。
分布式系统
一些快速结果如下:
H2O逻辑回归运行时间(秒):
| 规模 | 1节点 | 5节点 |
|---|---|---|
| 1亿 | 42 | 9.9 |
| 10亿 | 480 | 101 |
H2O随机森林运行时间(秒)(5棵树):
| 规模 | 1节点 | 5节点 |
|---|---|---|
| 1000万 | 42 | 41 |
| 1亿 | 405 | 122 |
总结
截至2018年1月:
当我于2015年3月开始这项基准测试时,“大数据”炒作正盛行,狂热者们热衷于使用分布式计算(Hadoop、Spark等)来进行“大数据”机器学习。然而,对于大多数人拥有的数据集而言,单机工具不仅足够好,而且速度更快、功能更丰富、Bug也更少。自2015年起,我在各种会议和聚会中多次分享这些基准测试的结果。起初,不少人对我关于Spark的结果感到愤怒,但到了2017年,大多数人已经意识到,对于大多数机器学习问题,单机工具要好得多。尽管Spark在原始数据的ETL任务中表现尚可(而这类数据往往确实是“大”的),但其机器学习库却非常糟糕,在训练时间、内存占用,甚至准确率方面,都被其他更好的工具远远超越。此外,近年来服务器及云环境中可用内存的不断增加,以及机器学习中通常会将原始数据提炼成规模小得多的数据矩阵这一事实,使得那些性能卓越的单机工具(如XGBoost、LightGBM、Vowpal Wabbit,以及H2O)成为当前大多数实际应用中的最佳选择。大数据的炒作终于结束了。
如今,新的炒作浪潮正在兴起,那就是深度学习。狂热者们认为深度学习(或者他们错误地称之为“AI”)是解决所有机器学习问题的最佳方案。诚然,深度学习在图像、语音以及部分文本(监督学习)和游戏/虚拟环境(强化学习)等领域取得了巨大成功,但在商业中常见的“传统”机器学习问题,比如欺诈检测、信用评分或客户流失预测(涉及结构化/表格型数据),深度学习的表现并不理想,其准确率往往低于随机森林或梯度提升机(GBM)。因此,近来我将基准测试的重点放在GBM实现上,并创建了一个新的GitHub仓库GBM-perf,它更加“聚焦”且精简,同时采用了更现代的工具(如Docker),以提高基准测试的可维护性和可重复性。此外,最近还发现GPU也可以成为GBM的强大计算平台,因此新仓库中也包含了现有GPU实现的基准测试结果。
我最初进行这些基准测试主要是出于好奇心和学习的愿望(同时也是为了能够为自己的项目选择合适的工具)。这是一段非常宝贵的经历,我要感谢所有参与者(尤其是各工具的开发者),感谢他们帮助我优化并充分发挥各自机器学习工具的潜力。作为这项工作的副产品,我有幸受邀在多个会议上发表演讲(KDD、R-Finance、useR!、eRum、H2O World、Crunch、Predictive Analytics World、EARL、Domino Data Science Popup、Big Data Day LA、Budapest Data Forum),并在十余次聚会上发言,例如:
- KDD 特邀演讲 - 实践中的机器学习软件:何去何从? - 加拿大哈利法克斯,2017年8月
- R in Finance 主题演讲 - 真实无虚的数据科学 - 美国芝加哥,2017年5月
- LA数据科学聚会 - 生产环境中的机器学习 - 美国洛杉矶,2017年5月
- useR! 2016 - 分析用数据集规模及其对R的影响 - 美国斯坦福,2016年6月
- H2O World - 开源机器学习平台基准测试 - 美国山景城,2015年11月
- LA机器学习聚会 - 机器学习工具的可扩展性、速度和准确率基准测试 - 美国洛杉矶,2015年6月
(相关代码、幻灯片以及部分视频录像请参见这里。)这些演讲和材料也是了解本次基准测试成果的最佳途径(如果你想选择最新且最全面的总结,可以观看我的KDD演讲视频链接)。这项工作仍在继续,敬请期待更多成果……
引用
如果benchm-ml对你的研究有所帮助,请考虑引用它,例如使用最新的提交版本:
@misc{,
author = {Pafka, Szilard},
title = {benchm-ml},
publisher = {GitHub},
year = {2019},
journal = {GitHub repository},
url = {https://github.com/szilard/benchm-ml},
howpublished = {\url{https://github.com/szilard/benchm-ml}},
commit = {13325ce3edd7c902390197f43bcc7938c306bbe3}
}
相似工具推荐
openclaw
OpenClaw 是一款专为个人打造的本地化 AI 助手,旨在让你在自己的设备上拥有完全可控的智能伙伴。它打破了传统 AI 助手局限于特定网页或应用的束缚,能够直接接入你日常使用的各类通讯渠道,包括微信、WhatsApp、Telegram、Discord、iMessage 等数十种平台。无论你在哪个聊天软件中发送消息,OpenClaw 都能即时响应,甚至支持在 macOS、iOS 和 Android 设备上进行语音交互,并提供实时的画布渲染功能供你操控。 这款工具主要解决了用户对数据隐私、响应速度以及“始终在线”体验的需求。通过将 AI 部署在本地,用户无需依赖云端服务即可享受快速、私密的智能辅助,真正实现了“你的数据,你做主”。其独特的技术亮点在于强大的网关架构,将控制平面与核心助手分离,确保跨平台通信的流畅性与扩展性。 OpenClaw 非常适合希望构建个性化工作流的技术爱好者、开发者,以及注重隐私保护且不愿被单一生态绑定的普通用户。只要具备基础的终端操作能力(支持 macOS、Linux 及 Windows WSL2),即可通过简单的命令行引导完成部署。如果你渴望拥有一个懂你
n8n
n8n 是一款面向技术团队的公平代码(fair-code)工作流自动化平台,旨在让用户在享受低代码快速构建便利的同时,保留编写自定义代码的灵活性。它主要解决了传统自动化工具要么过于封闭难以扩展、要么完全依赖手写代码效率低下的痛点,帮助用户轻松连接 400 多种应用与服务,实现复杂业务流程的自动化。 n8n 特别适合开发者、工程师以及具备一定技术背景的业务人员使用。其核心亮点在于“按需编码”:既可以通过直观的可视化界面拖拽节点搭建流程,也能随时插入 JavaScript 或 Python 代码、调用 npm 包来处理复杂逻辑。此外,n8n 原生集成了基于 LangChain 的 AI 能力,支持用户利用自有数据和模型构建智能体工作流。在部署方面,n8n 提供极高的自由度,支持完全自托管以保障数据隐私和控制权,也提供云端服务选项。凭借活跃的社区生态和数百个现成模板,n8n 让构建强大且可控的自动化系统变得简单高效。
stable-diffusion-webui
stable-diffusion-webui 是一个基于 Gradio 构建的网页版操作界面,旨在让用户能够轻松地在本地运行和使用强大的 Stable Diffusion 图像生成模型。它解决了原始模型依赖命令行、操作门槛高且功能分散的痛点,将复杂的 AI 绘图流程整合进一个直观易用的图形化平台。 无论是希望快速上手的普通创作者、需要精细控制画面细节的设计师,还是想要深入探索模型潜力的开发者与研究人员,都能从中获益。其核心亮点在于极高的功能丰富度:不仅支持文生图、图生图、局部重绘(Inpainting)和外绘(Outpainting)等基础模式,还独创了注意力机制调整、提示词矩阵、负向提示词以及“高清修复”等高级功能。此外,它内置了 GFPGAN 和 CodeFormer 等人脸修复工具,支持多种神经网络放大算法,并允许用户通过插件系统无限扩展能力。即使是显存有限的设备,stable-diffusion-webui 也提供了相应的优化选项,让高质量的 AI 艺术创作变得触手可及。
everything-claude-code
everything-claude-code 是一套专为 AI 编程助手(如 Claude Code、Codex、Cursor 等)打造的高性能优化系统。它不仅仅是一组配置文件,而是一个经过长期实战打磨的完整框架,旨在解决 AI 代理在实际开发中面临的效率低下、记忆丢失、安全隐患及缺乏持续学习能力等核心痛点。 通过引入技能模块化、直觉增强、记忆持久化机制以及内置的安全扫描功能,everything-claude-code 能显著提升 AI 在复杂任务中的表现,帮助开发者构建更稳定、更智能的生产级 AI 代理。其独特的“研究优先”开发理念和针对 Token 消耗的优化策略,使得模型响应更快、成本更低,同时有效防御潜在的攻击向量。 这套工具特别适合软件开发者、AI 研究人员以及希望深度定制 AI 工作流的技术团队使用。无论您是在构建大型代码库,还是需要 AI 协助进行安全审计与自动化测试,everything-claude-code 都能提供强大的底层支持。作为一个曾荣获 Anthropic 黑客大奖的开源项目,它融合了多语言支持与丰富的实战钩子(hooks),让 AI 真正成长为懂上
opencode
OpenCode 是一款开源的 AI 编程助手(Coding Agent),旨在像一位智能搭档一样融入您的开发流程。它不仅仅是一个代码补全插件,而是一个能够理解项目上下文、自主规划任务并执行复杂编码操作的智能体。无论是生成全新功能、重构现有代码,还是排查难以定位的 Bug,OpenCode 都能通过自然语言交互高效完成,显著减少开发者在重复性劳动和上下文切换上的时间消耗。 这款工具专为软件开发者、工程师及技术研究人员设计,特别适合希望利用大模型能力来提升编码效率、加速原型开发或处理遗留代码维护的专业人群。其核心亮点在于完全开源的架构,这意味着用户可以审查代码逻辑、自定义行为策略,甚至私有化部署以保障数据安全,彻底打破了传统闭源 AI 助手的“黑盒”限制。 在技术体验上,OpenCode 提供了灵活的终端界面(Terminal UI)和正在测试中的桌面应用程序,支持 macOS、Windows 及 Linux 全平台。它兼容多种包管理工具,安装便捷,并能无缝集成到现有的开发环境中。无论您是追求极致控制权的资深极客,还是渴望提升产出的独立开发者,OpenCode 都提供了一个透明、可信
ComfyUI
ComfyUI 是一款功能强大且高度模块化的视觉 AI 引擎,专为设计和执行复杂的 Stable Diffusion 图像生成流程而打造。它摒弃了传统的代码编写模式,采用直观的节点式流程图界面,让用户通过连接不同的功能模块即可构建个性化的生成管线。 这一设计巧妙解决了高级 AI 绘图工作流配置复杂、灵活性不足的痛点。用户无需具备编程背景,也能自由组合模型、调整参数并实时预览效果,轻松实现从基础文生图到多步骤高清修复等各类复杂任务。ComfyUI 拥有极佳的兼容性,不仅支持 Windows、macOS 和 Linux 全平台,还广泛适配 NVIDIA、AMD、Intel 及苹果 Silicon 等多种硬件架构,并率先支持 SDXL、Flux、SD3 等前沿模型。 无论是希望深入探索算法潜力的研究人员和开发者,还是追求极致创作自由度的设计师与资深 AI 绘画爱好者,ComfyUI 都能提供强大的支持。其独特的模块化架构允许社区不断扩展新功能,使其成为当前最灵活、生态最丰富的开源扩散模型工具之一,帮助用户将创意高效转化为现实。